1 // tiledAggCanvas.cpp
2 // Context Free
3 // ---------------------
4 // Copyright (C) 2012-2013 John Horigan - john@glyphic.com
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 //
20 // John Horigan can be contacted at john@glyphic.com or at
21 // John Horigan, 1209 Villa St., Mountain View, CA 94041-1123, USA
22 //
23 //
24 
25 #include "abstractPngCanvas.h"
26 #include "tiledCanvas.h"
27 #include "makeCFfilename.h"
28 #include <string>
29 #include <iostream>
30 #include <algorithm>
31 #include "prettyint.h"
32 
33 using std::cout;
34 using std::endl;
35 
36 
abstractPngCanvas(const char * outfilename,bool quiet,int width,int height,aggCanvas::PixelFormat pixfmt,bool crop,int frameCount,int variation,bool wallpaper,Renderer * r,int mx,int my)37 abstractPngCanvas::abstractPngCanvas(const char* outfilename, bool quiet, int width, int height,
38                                      aggCanvas::PixelFormat pixfmt, bool crop, int frameCount,
39                                      int variation, bool wallpaper, Renderer *r, int mx, int my)
40 : aggCanvas(pixfmt), mOutputFileName(outfilename), mFrameCount(frameCount),
41   mCurrentFrame(1), mVariation(variation), mPixelFormat(pixfmt),
42   mCrop(crop), mQuiet(quiet), mWallpaper(wallpaper), mRenderer(r), mFullWidth(width),
43   mFullHeight(height), mOriginX(0), mOriginY(0)
44 {
45     if (outfilename)
46         mFileName = outfilename;
47     if (wallpaper) {
48         mWidth = r->m_width;
49         mHeight = r->m_height;
50         mFullWidth = width;
51         mFullHeight = height;
52 
53         double scalex = static_cast<double>(width) /  ( mWidth * mx);
54         double scaley = static_cast<double>(height) / (mHeight * my);
55         double scale = scalex < scaley ? scalex : scaley;
56         mWidth = static_cast<int>(mWidth * scale);
57         mHeight = static_cast<int>(mHeight * scale);
58     } else {
59         mWidth = width;
60         mHeight = height;
61         mFullWidth = mWidth * mx;
62         mFullHeight = mHeight * my;
63     }
64 
65     mOriginX = (mFullWidth - mWidth) / 2;
66     mOriginY = (mFullHeight - mHeight) / 2;
67 
68     int bpp = BytesPerPixel.at(mPixelFormat);
69     mStride = mFullWidth * bpp;
70 #ifdef _WIN32
71     mStride += ((-mStride) & 3);
72 #endif
73     mData = std::make_unique<unsigned char[]>(mStride * mFullHeight);
74     attach(mData.get() + mOriginY * mStride + mOriginX * bpp, mWidth, mHeight, mStride);
75 
76     if (quiet) return;
77     cout << prettyInt(static_cast<unsigned long>(mFullWidth)) << "w x " <<
78             prettyInt(static_cast<unsigned long>(mFullHeight)) << "h pixel image." << endl;
79     cout << "Generating..." << endl;
80 }
81 
82 abstractPngCanvas::~abstractPngCanvas() = default;
83 
84 void
start(bool clear,const agg::rgba & bk,int width,int height)85 abstractPngCanvas::start(bool clear, const agg::rgba &bk, int width, int height)
86 {
87     if (!mFrameCount && !mQuiet)
88         cout << endl << "Rendering..." << endl;
89 
90     aggCanvas::start(clear, bk, width, height);
91 }
92 
93 void
end()94 abstractPngCanvas::end()
95 {
96     aggCanvas::end();
97 
98     if (mRenderer && mRenderer->m_tiledCanvas) {
99         tileList points = mRenderer->m_tiledCanvas->getTessellation(mFullWidth, mFullHeight,
100                                                                     mOriginX, mOriginY, true);
101         std::reverse(points.begin(), points.end());     // could use reverse adapter
102 
103         for (auto&& pt: points) {
104             if (pt.x != mOriginX || pt.y != mOriginY)
105                 copyImageUnscaled(pt.x, pt.y);
106         }
107 
108     }
109 
110     std::string name = makeCFfilename(mOutputFileName, mCurrentFrame, mFrameCount,
111                                  mVariation);
112 
113     if (mFrameCount) {
114         output(name.c_str(), mCurrentFrame++);
115     } else {
116         output(name.c_str());
117     }
118 }
119 
120 void
copyImageUnscaled(int destx,int desty)121 abstractPngCanvas::copyImageUnscaled(int destx, int desty)
122 {
123     int bpp = BytesPerPixel.at(mPixelFormat);
124     destx *= bpp;
125     int srcx = mOriginX * bpp;
126     int srcy = mOriginY;
127     for (int y = 0; y < mHeight; ++y) {
128         if (y + desty < 0 || y + desty >= mFullHeight) continue;
129         for (int x = 0; x < mWidth * bpp; ++x) {
130             if (destx + x >= 0 && destx + x < mStride)
131                 mData[(y + desty) * mStride + destx + x] = mData[(y + srcy) * mStride + srcx + x];
132         }
133     }
134 }
135