1// main.cpp
2
3#include <stdio.h>
4
5#include <Application.h>
6#include <Bitmap.h>
7#include <GraphicsDefs.h>
8#include <Region.h>
9#include <Window.h>
10
11#include "BitmapView.h"
12#include "BitmapBuffer.h"
13#include "FontManager.h"
14#include "Painter.h"
15
16const pattern kStripes = (pattern){ { 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 } };
17const pattern kDotted = (pattern){ { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa } };
18const pattern kDottedBigger = (pattern){ { 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc } };
19
20// test_straight_lines
21template<class Surface>
22bigtime_t
23test_straight_lines(Surface& s, uint32 width, uint32 height)
24{
25	bigtime_t now = system_time();
26
27	s.SetPenSize(1.0);
28	s.SetDrawingMode(B_OP_COPY);
29	s.SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
30
31	s.SetHighColor(0, 0, 0, 255);
32	s.SetLowColor(130, 0, 20, 255);
33
34	const pattern pat = B_SOLID_HIGH;
35
36	for (uint32 y = 0; y <= height; y += 5) {
37		s.StrokeLine(BPoint(0, y), BPoint(width - 1, y), pat);
38	}
39	for (uint32 x = 0; x <= width; x += 5) {
40		s.StrokeLine(BPoint(x, 0), BPoint(x, height - 1), pat);
41	}
42
43	s.Sync();
44
45	return system_time() - now;
46}
47
48// test_fill_rect
49template<class Surface>
50bigtime_t
51test_fill_rect(Surface& s, uint32 width, uint32 height)
52{
53	bigtime_t now = system_time();
54
55	s.SetPenSize(1.0);
56	s.SetDrawingMode(B_OP_COPY);
57	s.SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
58
59	s.SetHighColor(0, 0, 0, 255);
60	s.SetLowColor(130, 0, 20, 255);
61
62	const pattern pat = B_SOLID_HIGH;
63
64	BRect r;
65	for (uint32 y = 10; y <= height; y += 20) {
66		for (uint32 x = 10; x <= width; x += 20) {
67			r.Set(x - 9, y - 9, x + 9, y + 9);
68			s.FillRect(r, pat);
69		}
70	}
71
72	s.Sync();
73
74	return system_time() - now;
75}
76
77// test_ellipses
78template<class Surface>
79bigtime_t
80test_ellipses(Surface& s, uint32 width, uint32 height)
81{
82	bigtime_t now = system_time();
83
84	s.SetPenSize(2.0);
85	s.SetDrawingMode(B_OP_COPY);
86	s.SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
87
88	s.SetHighColor(0, 0, 0, 255);
89	s.SetLowColor(130, 0, 20, 255);
90
91	const pattern pat = B_SOLID_HIGH;
92
93	BPoint center(floorf(width / 2.0), floorf(height / 2.0));
94	float xRadius = width / 2.0;
95	float yRadius = height / 2.0;
96
97	uint32 count = 40;
98	for (uint32 i = 0; i < count; i ++) {
99		s.StrokeEllipse(center, xRadius * (i / (float)count),
100								yRadius * (i / (float)count), pat);
101	}
102
103	s.Sync();
104
105	return system_time() - now;
106}
107
108// test_lines
109template<class Surface>
110bigtime_t
111test_lines(Surface& s, uint32 width, uint32 height)
112{
113	bigtime_t now = system_time();
114
115	s.SetPenSize(1.0);
116	s.SetDrawingMode(B_OP_COPY);
117	s.SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
118
119	s.SetHighColor(0, 0, 0, 255);
120	s.SetLowColor(130, 0, 20, 255);
121
122	const pattern pat = B_SOLID_HIGH;
123
124	for (uint32 y = 0; y <= height; y += 10) {
125		s.StrokeLine(BPoint(0, 0), BPoint(width, y), pat);
126		s.StrokeLine(BPoint(width - 1, 0), BPoint(0, y), pat);
127	}
128	for (uint32 x = 0; x <= width; x += 10) {
129		s.StrokeLine(BPoint(0, 0), BPoint(x, height), pat);
130		s.StrokeLine(BPoint(width - 1, 0), BPoint(x, height), pat);
131	}
132
133	s.Sync();
134
135	return system_time() - now;
136}
137
138// test
139template<class Surface>
140bigtime_t
141test(Surface& s, uint32 width, uint32 height, BBitmap* testBitmap)
142{
143	bigtime_t now = system_time();
144
145// TODO: Painter behaves differently when origin has subpixel offset
146//	BPoint origin(20.3, 10.8);
147	BPoint origin(20, 10);
148
149	BPoint center(width / 2.0, height / 2.0);
150	float xRadius = 30.0;
151	float yRadius = 20.0;
152
153	s.SetOrigin(origin);
154	s.SetScale(1.0);
155
156	s.SetDrawingMode(B_OP_COPY);
157//	s.SetDrawingMode(B_OP_SUBTRACT);
158//	s.SetDrawingMode(B_OP_OVER);
159	s.SetHighColor(20, 20, 20, 255);
160	s.SetLowColor(220, 120, 80, 255);
161	for (uint32 y = 0; y <= height / 2; y += 10)
162		s.StrokeLine(BPoint(0, 0), BPoint(width / 2, y)/*, kDottedBigger*/);
163	for (uint32 x = 0; x <= width; x += 10)
164		s.StrokeLine(BPoint(0, 0), BPoint(x, height)/*, kDottedBigger*/);
165	s.SetPenSize(1.0 * 5);
166	s.SetHighColor(255, 0, 0, 255);
167	s.SetLowColor(0, 0, 255, 255);
168//	s.SetScale(1.0);
169//	s.SetOrigin(B_ORIGIN);
170//	s.SetDrawingMode(B_OP_INVERT);
171	s.SetDrawingMode(B_OP_COPY);
172//	s.StrokeRect(BRect(20.2, 45.6, 219.0, 139.0));
173	s.StrokeRect(BRect(20.2, 45.6, 219.0, 139.0), kStripes);
174
175//	s.ConstrainClipping(noClip);
176/*	s.SetPenLocation(BPoint(230.0, 30.0));
177	s.StrokeLine(BPoint(250.0, 30.0));
178	s.StrokeLine(BPoint(250.0, 50.0));
179	s.StrokeLine(BPoint(230.0, 50.0));
180	s.StrokeLine(BPoint(230.0, 30.0));*/
181
182	s.SetHighColor(255, 255, 0, 255);
183	s.SetLowColor(128, 0, 50, 255);
184//	s.SetDrawingMode(B_OP_OVER);
185	s.SetDrawingMode(B_OP_ERASE);
186	s.StrokeEllipse(center, xRadius, yRadius, kDottedBigger);
187	s.SetHighColor(255, 0, 0, 255);
188	s.SetDrawingMode(B_OP_INVERT);
189	s.FillArc(center, xRadius * 2, yRadius * 2, 40.0, 230.0);
190//	s.StrokeArc(center, xRadius * 2, yRadius * 2, 40.0, 230.0);
191	s.SetDrawingMode(B_OP_OVER);
192	s.SetPenSize(2.0);
193	s.StrokeEllipse(center, xRadius * 3, yRadius * 2);
194//	s.FillEllipse(center, xRadius * 3, yRadius * 2);
195//	s.StrokeLine(bounds.RightTop());
196//	s.FillRect(rect);
197	s.SetHighColor(0, 0, 255, 255);
198	s.SetLowColor(255, 0, 0, 255);
199	s.SetPenSize(1.0);
200//	s.SetDrawingMode(B_OP_SELECT);
201	s.StrokeRoundRect(BRect(40, 100, 250, 220.0), 40, 40);
202//	s.FillRoundRect(BRect(40, 100, 250, 220.0), 40, 40);
203
204	// text rendering
205	const char* string1 = "The Quick Brown Fox...";
206	const char* string2 = "jumps!";
207	BPoint stringLocation1(10.0, 220.0);
208	BPoint stringLocation2(30.0 / 2.5, 115.0 / 2.5);
209
210	BFont font(be_plain_font);
211	font.SetSize(12.0);
212	font.SetRotation(8.0);
213//	font.SetFamilyAndStyle(1);
214
215	s.SetFont(&font);
216	s.SetHighColor(91, 105, 98, 120);
217	s.SetDrawingMode(B_OP_OVER);
218	s.DrawString(string1, stringLocation1);
219	s.DrawString(string2);
220	s.StrokeLine(BPoint(width - 1, 0));
221
222//	s.SetScale(2.5);
223	s.SetDrawingMode(B_OP_INVERT);
224	s.SetHighColor(200, 200, 200, 255);
225	s.DrawString("H", stringLocation2);
226	s.DrawString("e");
227	s.DrawString("l");
228	s.DrawString("l");
229	s.DrawString("o");
230	s.DrawString(" ");
231	s.DrawString("N");
232	s.DrawString("u");
233	s.DrawString("r");
234	s.DrawString("s");
235	s.DrawString("e");
236	s.DrawString("!");
237	// do the char locations match up?
238//	s.SetHighColor(0, 60, 240);
239//	s.DrawString("Hello Nurse!", stringLocation2);
240
241	// bitmap drawing
242	BRect testBitmapCrop(testBitmap->Bounds());
243	testBitmapCrop.left += 20.0;
244	BRect testBitmapDestRect(testBitmapCrop);
245	testBitmapDestRect.OffsetBy(50, 20);
246
247	s.SetScale(1.5);
248	s.SetDrawingMode(B_OP_ALPHA);
249	s.SetHighColor(0, 0, 0, 120);
250	s.DrawBitmap(testBitmap, testBitmapCrop, testBitmapDestRect);
251
252	s.Sync();
253
254	return system_time() - now;
255}
256
257
258
259// main
260int
261main(int argc, char **argv)
262{
263	BApplication* app = new BApplication("application/x.vnd-YellowBites.TestApp");
264
265	// create the default instance of the FontManager
266	// It takes a bit to scan through the font files;
267	// "true" means to do the font scanning inline, not
268	// in a separate thread.
269	fprintf(stdout, "scanning font files...");
270	fflush(stdout);
271	FontManager::CreateDefault(true);
272	fprintf(stdout, "done\n");
273
274	BRect bounds(0.0, 0.0, 319.0, 239.0);
275
276	// test the clipping
277	BRegion noClip(bounds);
278
279	int32 clipCount = 5;
280	BRegion clip;
281	float h = bounds.Width() / clipCount;
282	float v = bounds.Height() / clipCount;
283	float hInset = (h / 2.0) * 0.5;
284	float vInset = (v / 2.0) * 0.5;
285	for (int32 i = 0; i < clipCount; i++) {
286/*		BRect b(h * i, bounds.top, h * i, bounds.bottom);
287		b.InsetBy(-hInset, 0.0);
288		clip.Include(b);
289		b.Set(bounds.left, v * i, bounds.right, v * i);
290		b.InsetBy(0.0, -vInset);
291		clip.Include(b);*/
292		BRect b(bounds.left, v * i, bounds.right, v * i);
293		b.InsetBy(0.0, -vInset);
294		clip.Include(b);
295		b.Set(h * i, bounds.top, h * i, bounds.bottom);
296		b.InsetBy(-hInset, 0.0);
297		clip.Include(b);
298	}
299
300	// prepare a test bitmap for bitmap rendering
301	BBitmap* testBitmap = new BBitmap(BRect(20, 0, 150, 50), 0, B_RGB32);
302	// fill testBitmap with content
303	uint8* bits = (uint8*)testBitmap->Bits();
304	uint32 bitmapWidth = testBitmap->Bounds().IntegerWidth() + 1;
305	uint32 bitmapHeight = testBitmap->Bounds().IntegerHeight() + 1;
306	uint32 bpr = testBitmap->BytesPerRow();
307	for (uint32 y = 0; y < bitmapHeight; y++) {
308		uint8* h = bits;
309		for (uint32 x = 0; x < bitmapWidth; x++) {
310			h[0] = (uint8)((float)x / (float)bitmapWidth * 255.0);
311			h[1] = (uint8)((float)y / (float)bitmapHeight * 255.0);
312			h[2] = 255 - (uint8)((float)y / (float)bitmapHeight * 255.0);
313			h[3] = (uint8)((float)y / (float)bitmapHeight * 255.0);
314			h += 4;
315		}
316		bits += bpr;
317	}
318	// make corners a black pixel for testing
319	bits = (uint8*)testBitmap->Bits();
320	*(uint32*)(&bits[0]) = 0;
321	*(uint32*)(&bits[(bitmapWidth - 1) * 4]) = 0;
322	*(uint32*)(&bits[(bitmapHeight - 1) * bpr]) = 0;
323	*(uint32*)(&bits[(bitmapHeight - 1) * bpr + (bitmapWidth - 1) * 4]) = 0;
324
325	// create a frame buffer
326	BBitmap* bitmap = new BBitmap(bounds, B_RGB32);
327//memset(bitmap->Bits(), 0, bitmap->BitsLength());
328	BitmapBuffer* buffer = new BitmapBuffer(bitmap);
329	Painter painter;
330	painter.AttachToBuffer(buffer);
331
332	uint32 width = buffer->Width();
333	uint32 height = buffer->Height();
334
335//	painter.ConstrainClipping(clip);
336
337	int32 iterations = 40;
338
339	fprintf(stdout, "Painter...");
340	fflush(stdout);
341
342	bigtime_t painterNow = 0;
343	for (int32 i = 0; i < iterations; i++) {
344		// reset bitmap contents
345		memset(bitmap->Bits(), 255, bitmap->BitsLength());
346		// run test
347//		painterNow += test(painter, width, height, testBitmap);
348//		painterNow += test_lines(painter, width, height);
349//		painterNow += test_straight_lines(painter, width, height);
350		painterNow += test_fill_rect(painter, width, height);
351//		painterNow += test_ellipses(painter, width, height);
352	}
353
354fprintf(stdout, " %lld µsecs\n", painterNow / iterations);
355
356	BitmapView* painterView = new BitmapView(bounds, "view", bitmap);
357
358	bitmap = new BBitmap(bounds, B_RGB32, true);
359	BView* view = new BView(bounds, NULL, B_FOLLOW_NONE, B_WILL_DRAW);
360//memset(bitmap->Bits(), 0, bitmap->BitsLength());
361	bitmap->Lock();
362	bitmap->AddChild(view);
363
364//	view->ConstrainClippingRegion(&clip);
365
366	fprintf(stdout, "BView...");
367	fflush(stdout);
368
369	bigtime_t viewNow = 0;
370	for (int32 i = 0; i < iterations; i++) {
371		// reset bitmap contents
372		memset(bitmap->Bits(), 255, bitmap->BitsLength());
373		// run test
374//		viewNow += test(*view, width, height, testBitmap);
375//		viewNow += test_lines(*view, width, height);
376//		viewNow += test_straight_lines(*view, width, height);
377		viewNow += test_fill_rect(*view, width, height);
378//		viewNow += test_ellipses(*view, width, height);
379	}
380
381	bitmap->Unlock();
382
383	fprintf(stdout, " %lld µsecs\n", viewNow / iterations);
384
385	if (painterNow > viewNow)
386		printf("BView is %.2f times faster.\n", (float)painterNow / (float)viewNow);
387	else
388		printf("Painter is %.2f times faster.\n", (float)viewNow / (float)painterNow);
389
390
391	BitmapView* bViewView = new BitmapView(bounds, "view", bitmap);
392	bViewView->MoveTo(BPoint(bounds.left, bounds.bottom + 1));
393
394	BWindow* window = new BWindow(BRect(50.0, 50.0, 50.0 + bounds.Width(), 50.0 + bounds.Height() * 2 + 1), "Painter Test",
395								  B_TITLED_WINDOW,
396								  B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE);
397
398	window->AddChild(painterView);
399	window->AddChild(bViewView);
400
401	window->Show();
402	app->Run();
403	delete app;
404	return 0;
405}
406