1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /***************************************************************************
3  *            paintertest.cc
4  *
5  *  Fri Nov 29 18:08:57 CET 2013
6  *  Copyright 2013 Bent Bisballe Nyeng
7  *  deva@aasimon.org
8  ****************************************************************************/
9 
10 /*
11  *  This file is part of DrumGizmo.
12  *
13  *  DrumGizmo is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU Lesser General Public License as published by
15  *  the Free Software Foundation; either version 3 of the License, or
16  *  (at your option) any later version.
17  *
18  *  DrumGizmo is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU Lesser General Public License for more details.
22  *
23  *  You should have received a copy of the GNU Lesser General Public License
24  *  along with DrumGizmo; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
26  */
27 #include <uunit.h>
28 
29 #include "../plugingui/canvas.h"
30 #include "../plugingui/painter.h"
31 #include "../plugingui/image.h"
32 #include "../plugingui/font.h"
33 
34 class TestColour
35 {
36 public:
TestColour(std::uint8_t r,std::uint8_t g,std::uint8_t b,std::uint8_t a)37 	TestColour(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a)
38 		: colour(r, g, b, a) {}
TestColour(const GUI::Colour & colour)39 	TestColour(const GUI::Colour& colour)
40 		: colour(colour) {}
41 
operator !=(const TestColour & other) const42 	bool operator!=(const TestColour& other) const
43 	{
44 		return
45 			colour.red() != other.colour.red() ||
46 			colour.green() != other.colour.green() ||
47 			colour.blue() != other.colour.blue() ||
48 			colour.alpha() != other.colour.alpha()
49 			;
50 	}
51 
52 	const GUI::Colour colour;
53 };
54 
operator <<(std::ostream & stream,const TestColour & col)55 std::ostream& operator<<(std::ostream& stream, const TestColour& col)
56 {
57 	stream << "(" <<
58 		static_cast<int>(col.colour.red()) << ", " <<
59 		static_cast<int>(col.colour.green()) << ", " <<
60 		static_cast<int>(col.colour.blue()) << ", " <<
61 		static_cast<int>(col.colour.alpha()) << ")";
62 	return stream;
63 }
64 
65 class TestableCanvas
66 	: public GUI::Canvas
67 {
68 public:
TestableCanvas(std::size_t width,std::size_t height)69 	TestableCanvas(std::size_t width, std::size_t height)
70 		: pixbuf(width, height)
71 	{}
72 
getPixelBuffer()73 	GUI::PixelBufferAlpha& getPixelBuffer() override
74 	{
75 		return pixbuf;
76 	}
77 
78 private:
79 	GUI::PixelBufferAlpha pixbuf;
80 };
81 
82 class TestImage
83 	: public GUI::Image
84 {
85 public:
TestImage(std::uint8_t width,std::uint8_t height,bool alpha)86 	TestImage(std::uint8_t width, std::uint8_t height, bool alpha)
87 		: GUI::Image(":resources/logo.png") // just load some default image
88 	{
89 		_width = width;
90 		_height = height;
91 		has_alpha = alpha;
92 
93 		image_data.resize(_width * _height);
94 		image_data_raw.resize(_width * _height);
95 
96 		// Store x and y coordinates as red and green colour components
97 		for(std::uint8_t x = 0; x < _width; ++x)
98 		{
99 			for(std::uint8_t y = 0; y < _height; ++y)
100 			{
101 				image_data[x + _width * y] = GUI::Colour(x, y, 0, alpha ? 128 : 255);
102 				image_data_raw[4 * (x + _width * y) + 0] = x;
103 				image_data_raw[4 * (x + _width * y) + 1] = y;
104 				image_data_raw[4 * (x + _width * y) + 2] = 0;
105 				image_data_raw[4 * (x + _width * y) + 3] = alpha ? 128 : 255;
106 			}
107 		}
108 
109 		valid = true;
110 	}
111 };
112 
113 class PainterTest
114 	: public uUnit
115 {
116 public:
PainterTest()117 	PainterTest()
118 	{
119 		uUNIT_TEST(PainterTest::testDrawImage);
120 		uUNIT_TEST(PainterTest::testDrawText);
121 		uUNIT_TEST(PainterTest::testClipping);
122 	}
123 
testDrawImage()124 	void testDrawImage()
125 	{
126 		// Success criterion is simply to not assert in the drawing routines...
127 		GUI::Image image(":resources/logo.png");
128 
129 		{ // Image fits in pixelbuffer
130 			TestableCanvas canvas(image.width(), image.height());
131 			GUI::Painter painter(canvas);
132 			painter.drawImage(0, 0, image);
133 		}
134 
135 		{ // Image fits in pixelbuffer, negative offset
136 			TestableCanvas canvas(image.width(), image.height());
137 			GUI::Painter painter(canvas);
138 			painter.drawImage(-10, -10, image);
139 		}
140 
141 		{ // Image too big for pixelbuffer
142 			TestableCanvas canvas(image.width() / 2, image.height() / 2);
143 			GUI::Painter painter(canvas);
144 			painter.drawImage(0, 0, image);
145 		}
146 
147 		{ // Image fits in pixelbuffer but offset so it is drawn over the edge.
148 			TestableCanvas canvas(image.width(), image.height());
149 			GUI::Painter painter(canvas);
150 			painter.drawImage(10, 10, image);
151 		}
152 
153 		{ // Image is offset to the right and down so nothing is to be drawn.
154 			TestableCanvas canvas(image.width(), image.height());
155 			GUI::Painter painter(canvas);
156 			painter.drawImage(image.width() + 1,
157 			                  image.height() + 1,
158 			                  image);
159 		}
160 
161 		{ // Image is offset to the left and up so nothing is to be drawn.
162 			TestableCanvas canvas(image.width(), image.height());
163 			GUI::Painter painter(canvas);
164 			painter.drawImage(-1 * (image.width() + 1),
165 			                  -1 * (image.height() + 1),
166 			                  image);
167 		}
168 	}
169 
testDrawText()170 	void testDrawText()
171 	{
172 		// Success criterion is simply to not assert in the drawing routines...
173 		GUI::Font font;
174 		// a string with unicode characters
175 		std::string someText = "Hello World - лæ Библиотека";
176 		std::size_t width = font.textWidth(someText);
177 		std::size_t height = font.textHeight(someText);
178 
179 		{ // Text fits in pixelbuffer
180 			TestableCanvas canvas(width, height);
181 			GUI::Painter painter(canvas);
182 			painter.drawText(0, 0, font, someText);
183 		}
184 
185 		{ // Text fits in pixelbuffer, negative offset
186 			TestableCanvas canvas(width, height);
187 			GUI::Painter painter(canvas);
188 			painter.drawText(-10, -10, font, someText);
189 		}
190 
191 		{ // Text too big for pixelbuffer
192 			TestableCanvas canvas(width / 2, height / 2);
193 			GUI::Painter painter(canvas);
194 			painter.drawText(0, 0, font, someText);
195 		}
196 
197 		{ // Text fits in pixelbuffer but offset so it is drawn over the edge.
198 			TestableCanvas canvas(width, height);
199 			GUI::Painter painter(canvas);
200 			painter.drawText(10, 10, font, someText);
201 		}
202 
203 		{ // Text is offset to the right and down so nothing is to be drawn.
204 			TestableCanvas canvas(width, height);
205 			GUI::Painter painter(canvas);
206 			painter.drawText(width + 1,
207 			                 height + 1,
208 			                 font, someText);
209 		}
210 
211 		{ // Text is offset to the left and up so nothing is to be drawn.
212 			TestableCanvas canvas(width, height);
213 			GUI::Painter painter(canvas);
214 			painter.drawText(-1 * (width + 1),
215 			                 -1 * (height + 1),
216 			                 font, someText);
217 		}
218 	}
219 
220 	// Test rendering images outside the container is being clipped correctly.
testClipping()221 	void testClipping()
222 	{
223 		TestableCanvas canvas(100, 100);
224 		GUI::Painter painter(canvas);
225 
226 		{ // Without alpha
227 			TestImage image(16, 16, false);
228 			painter.clear();
229 			painter.drawImage(-10, -10, image);
230 			auto& pixbuf = canvas.getPixelBuffer();
231 
232 			// Top left corner pixel should have the RGBA value (10, 10, 0, 255)
233 			uUNIT_ASSERT_EQUAL(TestColour(10, 10, 0, 255),
234 			                   TestColour(pixbuf.pixel(0, 0)));
235 		}
236 
237 		{ // With alpha (different pipeline)
238 			TestImage image(16, 16, true);
239 			painter.clear();
240 			painter.drawImage(-10, -10, image);
241 			auto& pixbuf = canvas.getPixelBuffer();
242 
243 			// Top left corner pixel should have the RGBA value (10, 10, 0, 128)
244 			uUNIT_ASSERT_EQUAL(TestColour(10, 10, 0, 128),
245 			                   TestColour(pixbuf.pixel(0, 0)));
246 		}
247 	}
248 };
249 
250 // Registers the fixture into the 'registry'
251 static PainterTest test;
252