annotate src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.cc @ 232:af531fc3f280

- Massive refactoring to make module tree stuff work. In theory we now support configuration files again. The graphics stuff is untested as yet.
author tomwalters
date Mon, 18 Oct 2010 04:42:28 +0000
parents 2aa72aa8a0d4
children 4fb328f81012
rev   line source
tomwalters@227 1 // Copyright 2007, Thomas Walters
tomwalters@116 2 //
tomwalters@116 3 // AIM-C: A C++ implementation of the Auditory Image Model
tomwalters@116 4 // http://www.acousticscale.org/AIMC
tomwalters@116 5 //
tomwalters@116 6 // Licensed under the Apache License, Version 2.0 (the "License");
tomwalters@116 7 // you may not use this file except in compliance with the License.
tomwalters@116 8 // You may obtain a copy of the License at
tomwalters@116 9 //
tomwalters@116 10 // http://www.apache.org/licenses/LICENSE-2.0
tomwalters@116 11 //
tomwalters@116 12 // Unless required by applicable law or agreed to in writing, software
tomwalters@116 13 // distributed under the License is distributed on an "AS IS" BASIS,
tomwalters@116 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
tomwalters@116 15 // See the License for the specific language governing permissions and
tomwalters@116 16 // limitations under the License.
tomwalters@116 17
tomwalters@116 18 /*!
tomwalters@116 19 * \file
tomwalters@116 20 * \brief Output device for output to a graphics file using cairo (LGPL)
tomwalters@116 21 *
tomwalters@116 22 * \author Tom Walters <tom@acousticscale.org> and Willem van Engen <cnbh@willem.engen.nl>
tomwalters@116 23 * \date created 2007/09/17
tomwalters@116 24 * \version \$Header: $
tomwalters@116 25 */
tomwalters@116 26
tomwalters@116 27 #include "Support/Common.h"
tomwalters@116 28
tomwalters@116 29 #include <sys/types.h>
tomwalters@116 30 #include <sys/stat.h>
tomwalters@116 31 #include <string.h>
tomwalters@116 32 #include <stdio.h>
tomwalters@116 33 #include <math.h>
tomwalters@116 34
tom@229 35 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h"
tom@229 36
tom@229 37 namespace aimc {
tomwalters@116 38
tomwalters@116 39 GraphicsOutputDeviceCairo::GraphicsOutputDeviceCairo(Parameters *pParam)
tom@229 40 : GraphicsOutputDevice(pParam) {
tomwalters@228 41 m_bOutputFile = false;
tomwalters@228 42 m_iFileNumber = 0;
tomwalters@228 43 m_iVertexType = VertexTypeNone;
tomwalters@228 44 m_bUseMemoryBuffer=false;
tomwalters@145 45 }
tomwalters@145 46
tomwalters@227 47 bool GraphicsOutputDeviceCairo::Initialize(const char *sDir) {
tomwalters@227 48 Init();
tomwalters@227 49
tomwalters@228 50 //! \todo Output to file if sDir is a file, to directory with
tomwalters@227 51 //! multiple images if it's a directory.
tomwalters@228 52 strncpy(m_sDir, sDir, sizeof(m_sDir)/sizeof(m_sDir[0]));
tomwalters@227 53
tomwalters@228 54 /* Try to open an image to see if everything is allright. We want to avoid
tomwalters@228 55 * errors in the main Process()ing loop. */
tomwalters@228 56 if ( !OpenFile(0) ) {
tomwalters@228 57 //! \todo Better error message that is more specific about the cause.
tom@230 58 LOG_ERROR(_T("Could not open output directory '%s' using graphics format '%s'."),
tomwalters@228 59 m_sDir, m_pParam->GetString("output.img.format") );
tomwalters@228 60 return false;
tomwalters@228 61 }
tomwalters@228 62 CloseFile();
tomwalters@227 63
tomwalters@228 64 return true;
tomwalters@145 65 }
tomwalters@145 66
tomwalters@227 67 bool GraphicsOutputDeviceCairo::Initialize() {
tomwalters@116 68 Init();
tomwalters@116 69 m_bUseMemoryBuffer = true;
tomwalters@116 70 return(true);
tomwalters@227 71 }
tomwalters@116 72
tomwalters@227 73 void GraphicsOutputDeviceCairo::Init() {
tomwalters@228 74 AIM_ASSERT(m_pParam);
tomwalters@228 75 /*
tomwalters@228 76 * Set parameters
tomwalters@228 77 */
tomwalters@228 78 m_pParam->GetString("output.img.color.background");
tomwalters@116 79
tomwalters@228 80 m_bInvertColors = m_pParam->GetBool("output.img.color.invert");
tomwalters@116 81
tomwalters@228 82 // Output size!
tomwalters@228 83 m_iWidth = m_pParam->GetUInt("output.img.width");
tomwalters@228 84 m_iHeight = m_pParam->GetUInt("output.img.height");
tomwalters@116 85 }
tomwalters@116 86
tomwalters@116 87 unsigned char* GraphicsOutputDeviceCairo::GetBuffer() {
tomwalters@116 88 if(m_bUseMemoryBuffer)
tomwalters@116 89 return (cairo_image_surface_get_data (m_cSurface));
tomwalters@116 90 else
tomwalters@116 91 return NULL;
tomwalters@116 92 }
tomwalters@116 93
tomwalters@116 94 bool GraphicsOutputDeviceCairo::OpenFile(unsigned int index) {
tomwalters@227 95 const char *strPlottype = m_pParam->GetString("output.img.format");
tomwalters@116 96 if (!m_bUseMemoryBuffer) {
tomwalters@116 97 struct stat fileinfo;
tomwalters@116 98 // Get filename without trailing slash
tomwalters@227 99 strncpy(m_sFilename, m_sDir, sizeof(m_sFilename)/sizeof(m_sFilename[0]));
tomwalters@116 100 #ifdef _WINDOWS
tomwalters@227 101 if (m_sFilename[strlen(m_sFilename)-1]=='\\') {
tomwalters@227 102 m_sFilename[strlen(m_sFilename)-1]='\0';
tomwalters@116 103 }
tomwalters@116 104 #else
tomwalters@227 105 if (m_sFilename[strlen(m_sFilename)-1]=='/') {
tomwalters@227 106 m_sFilename[strlen(m_sFilename)-1]='\0';
tomwalters@116 107 }
tomwalters@116 108 #endif
tomwalters@116 109 // Enumerate files it m_sDir is a directory.
tomwalters@227 110 if (stat(m_sFilename, &fileinfo) == 0 && (fileinfo.st_mode & S_IFDIR)) {
tomwalters@116 111 // We have a directory: enumerate with index
tomwalters@227 112 snprintf(m_sFilename, sizeof(m_sFilename)/sizeof(m_sFilename[0]),"%s%06d.%s",
tomwalters@227 113 m_sDir,
tomwalters@116 114 index,
tomwalters@116 115 strPlottype);
tomwalters@116 116 // If type is 'auto', fallback to 'png'
tomwalters@116 117 if (strcmp(strPlottype, "auto")==0)
tomwalters@116 118 strPlottype = "png";
tomwalters@116 119 } else {
tomwalters@116 120 // We have a (probably non-existant) file. Auto-detect type by extension if requested
tomwalters@227 121 strncpy(m_sFilename, m_sDir, sizeof(m_sFilename)/sizeof(m_sFilename[0]));
tomwalters@227 122 char *pDot = strrchr(m_sFilename, '.');
tomwalters@116 123 if (!pDot) {
tom@230 124 LOG_ERROR(_T("Please supply extension on filename when using 'auto' format: '%s'"),
tomwalters@227 125 m_sFilename);
tomwalters@116 126 return false;
tomwalters@116 127 }
tomwalters@116 128 strPlottype = &pDot[1];
tomwalters@116 129 }
tomwalters@116 130 m_bOutputFile= true; //! \todo Should check that it's possible to write to the file
tomwalters@116 131 }
tomwalters@227 132 // Cairo's RGB24 format has 32-bit pixels with the upper 8 bits unused.
tomwalters@227 133 // This is not the same as the plotutils PNG format. This information is transferred by the
tomwalters@227 134 // function GetPixelFormat. The pixel format is dealt with by the reciever.
tomwalters@227 135 m_cSurface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
tomwalters@227 136 m_iWidth,
tomwalters@227 137 m_iHeight);
tomwalters@227 138 m_cCr = cairo_create (m_cSurface);
tomwalters@227 139 cairo_scale(m_cCr, (float)m_iWidth, (float)m_iHeight);
tomwalters@228 140 // Now setup things for this plotter.
tomwalters@228 141 cairo_select_font_face(m_cCr,
tomwalters@227 142 m_pParam->GetString("output.img.fontname"),
tomwalters@227 143 CAIRO_FONT_SLANT_NORMAL,
tomwalters@227 144 CAIRO_FONT_WEIGHT_BOLD);
tomwalters@227 145 cairo_set_font_size (m_cCr, 0.015);
tomwalters@228 146 return true;
tomwalters@116 147 }
tomwalters@116 148
tomwalters@116 149 void GraphicsOutputDeviceCairo::CloseFile() {
tomwalters@228 150 // Plotting library
tomwalters@228 151 if (m_iPlotHandle>0) {
tomwalters@228 152 cairo_destroy(m_cCr);
tomwalters@228 153 m_iPlotHandle = 0;
tomwalters@228 154 }
tomwalters@228 155 // And the output file
tomwalters@228 156 if (m_bOutputFile) {
tomwalters@228 157 cairo_surface_write_to_png(m_cSurface, m_sFilename);
tomwalters@228 158 m_bOutputFile = false;
tomwalters@228 159 }
tomwalters@228 160 cairo_surface_destroy(m_cSurface);
tomwalters@116 161 }
tomwalters@116 162
tomwalters@116 163 GraphicsOutputDeviceCairo::~GraphicsOutputDeviceCairo() {
tomwalters@228 164 AIM_ASSERT(!m_iPlotHandle);
tomwalters@228 165 CloseFile();
tomwalters@116 166 }
tomwalters@116 167
tomwalters@116 168 void GraphicsOutputDeviceCairo::gGrab() {
tomwalters@116 169 // Open file.
tomwalters@228 170 if (!OpenFile(m_iFileNumber)) {
tomwalters@228 171 return;
tomwalters@116 172 }
tomwalters@228 173 // Setup plotting area.
tomwalters@228 174 cairo_set_line_width (m_cCr, 0.001f);
tomwalters@228 175 gColor3f (0.0f, 0.0f, 0.0f);
tomwalters@116 176 cairo_paint (m_cCr);
tomwalters@116 177 gColor3f(1.0f, 1.0f, 0.0f);
tomwalters@116 178 }
tomwalters@116 179
tomwalters@116 180 int GraphicsOutputDeviceCairo::GetPixelFormat() {
tomwalters@116 181 return AIM_PIX_FMT_RGB24_32;
tomwalters@116 182 }
tomwalters@116 183
tomwalters@116 184 void GraphicsOutputDeviceCairo::gBeginLineStrip() {
tomwalters@228 185 m_bIsFirstVertex = true;
tomwalters@228 186 m_iVertexType = VertexTypeLine;
tomwalters@228 187 //! \todo Make line width user-settable
tomwalters@228 188 cairo_set_line_width (m_cCr, 0.001f);
tomwalters@116 189 }
tomwalters@116 190
tomwalters@116 191 void GraphicsOutputDeviceCairo::gBeginQuadStrip() {
tomwalters@228 192 m_bIsFirstVertex = true;
tomwalters@228 193 m_iVertexType = VertexTypeQuad;
tomwalters@228 194 m_iPrevVertexCount = 0;
tomwalters@116 195 cairo_set_line_width (m_cCr, 0.001f);
tomwalters@116 196 }
tomwalters@116 197
tomwalters@116 198 void GraphicsOutputDeviceCairo::gColor3f(float r, float g, float b) {
tomwalters@116 199 if (m_bInvertColors) {
tomwalters@228 200 r = 1-r;
tomwalters@228 201 g = 1-g;
tomwalters@228 202 b = 1-b;
tomwalters@228 203 }
tomwalters@116 204 cairo_set_source_rgb (m_cCr, r, g, b);
tomwalters@116 205 }
tomwalters@116 206
tomwalters@116 207 void GraphicsOutputDeviceCairo::gVertex3f(float x, float y, float z) {
tomwalters@228 208 switch(m_iVertexType) {
tomwalters@228 209 case VertexTypeLine:
tomwalters@228 210 if (m_bIsFirstVertex) {
tomwalters@228 211 m_bIsFirstVertex = false;
tomwalters@228 212 //pl_fmove(x, y);
tomwalters@228 213 cairo_move_to(m_cCr, x, 1-y);
tomwalters@228 214 } else {
tomwalters@228 215 //pl_fcont(x, y);
tomwalters@228 216 cairo_line_to(m_cCr, x, 1-y);
tomwalters@228 217 }
tomwalters@228 218 break;
tomwalters@228 219 case VertexTypeQuad:
tomwalters@228 220 /* Store vertices until we got four in a row.
tomwalters@228 221 * The order of vertices when processing quads is:
tomwalters@228 222 * 1-----3-----5
tomwalters@228 223 * | | |
tomwalters@228 224 * 0-----2-----4
tomwalters@228 225 */
tomwalters@228 226 if (m_iPrevVertexCount >= 3) {
tomwalters@228 227 // Plot this quad
tomwalters@228 228 cairo_move_to(m_cCr, m_aPrevX[0], 1-m_aPrevY[0]);
tomwalters@228 229 cairo_line_to(m_cCr, m_aPrevX[1], 1-m_aPrevY[1]);
tomwalters@228 230 cairo_line_to(m_cCr, x, y);
tomwalters@228 231 cairo_line_to(m_cCr, m_aPrevX[2], 1-m_aPrevY[2]);
tomwalters@228 232 cairo_close_path (m_cCr);
tomwalters@145 233
tomwalters@228 234 // Last vertices of this quad are the first of the next
tomwalters@228 235 m_aPrevX[0] = m_aPrevX[2];
tomwalters@228 236 m_aPrevY[0] = m_aPrevY[2];
tomwalters@228 237 m_aPrevX[1] = x;
tomwalters@228 238 m_aPrevY[1] = y;
tomwalters@228 239 m_iPrevVertexCount = 2;
tomwalters@228 240 } else {
tomwalters@228 241 // Not at the fourth, keep storing
tomwalters@228 242 m_aPrevX[m_iPrevVertexCount] = x;
tomwalters@228 243 m_aPrevY[m_iPrevVertexCount] = y;
tomwalters@228 244 m_iPrevVertexCount++;
tomwalters@228 245 }
tomwalters@228 246 break;
tomwalters@228 247 default:
tomwalters@228 248 // Should not happen
tomwalters@228 249 AIM_ASSERT(0);
tomwalters@228 250 }
tomwalters@116 251 }
tomwalters@116 252
tomwalters@116 253 void GraphicsOutputDeviceCairo::gEnd() {
tomwalters@228 254 if(m_iVertexType==VertexTypeLine)
tomwalters@116 255 cairo_stroke (m_cCr);
tomwalters@116 256 else
tomwalters@116 257 cairo_fill (m_cCr);
tomwalters@228 258 m_iVertexType = VertexTypeNone;
tomwalters@116 259 }
tomwalters@116 260
tomwalters@116 261 void GraphicsOutputDeviceCairo::gText3f(float x,
tomwalters@116 262 float y,
tomwalters@116 263 float z,
tomwalters@116 264 const char *sStr,
tomwalters@116 265 bool bRotated) {
tomwalters@232 266 //cairo_text_extents_t te;
tomwalters@228 267 if (bRotated) {
tomwalters@228 268 cairo_rotate(m_cCr, M_PI/2);
tomwalters@228 269 cairo_move_to(m_cCr, x ,1-y);
tomwalters@228 270 cairo_show_text(m_cCr, sStr);
tomwalters@228 271 //cairo_identity_matrix(m_cCr);
tomwalters@228 272 cairo_rotate(m_cCr, -M_PI/2);
tomwalters@228 273 } else {
tomwalters@228 274 cairo_move_to(m_cCr, x ,1-y);
tomwalters@228 275 cairo_show_text(m_cCr, sStr);
tomwalters@228 276 }
tomwalters@116 277 }
tomwalters@116 278
tomwalters@116 279 void GraphicsOutputDeviceCairo::gRelease() {
tomwalters@228 280 AIM_ASSERT(m_iPlotHandle>0);
tomwalters@228 281 CloseFile();
tomwalters@228 282 // Finished this one, up to the next!
tomwalters@228 283 m_iFileNumber++;
tomwalters@116 284 }
tom@229 285 } // namespace aimc