vfs: check userland buffers before reading them.
[haiku.git] / src / tests / servers / app / bitmap_drawing / main.cpp
blobd2d6a582ac6ad0052f8d00d12dde3774a6203652
1 // main.cpp
3 #include <math.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
8 #include <Application.h>
9 #include <Bitmap.h>
10 #include <Button.h>
11 #include <Message.h>
12 #include <MessageRunner.h>
13 #include <Messenger.h>
14 #include <View.h>
15 #include <Window.h>
17 #include "bitmap.h"
19 enum {
20 MSG_RESET = 'rset',
21 MSG_TICK = 'tick',
24 #define SPEED 2.0
26 // random_number_between
27 float
28 random_number_between(float v1, float v2)
30 if (v1 < v2)
31 return v1 + fmod(rand() / 1000.0, (v2 - v1));
32 else if (v2 < v1)
33 return v2 + fmod(rand() / 1000.0, (v1 - v2));
34 return v1;
37 // TestView
38 class TestView : public BView {
40 public:
41 TestView(BRect frame, const char* name,
42 uint32 resizeFlags, uint32 flags);
44 virtual void AttachedToWindow();
45 virtual void MessageReceived(BMessage* message);
47 virtual void Draw(BRect updateRect);
49 virtual void MouseDown(BPoint where);
50 virtual void MouseUp(BPoint where);
51 virtual void MouseMoved(BPoint where, uint32 transit,
52 const BMessage* dragMessage);
54 private:
55 void _ResetRect();
56 void _InvalidateBitmapRect(BRect r);
57 void _DrawCross(BPoint where, rgb_color c);
59 struct point {
60 double x;
61 double y;
62 double direction_x;
63 double direction_y;
64 double velocity_x;
65 double velocity_y;
67 struct color_cycle {
68 uint8 value;
69 double direction;
72 void _FillBitmap(point* polygon);
73 void _InitPolygon(const BRect& b, point* polygon) const;
74 void _InitColor(color_cycle* color) const;
75 void _MorphPolygon(const BRect& b, point* polygon);
76 void _MorphColor(color_cycle* color);
78 BBitmap* fBitmap;
79 BView* fOffscreenView;
80 BMessageRunner* fTicker;
81 BRect fBitmapRect;
83 enum {
84 TRACKING_NONE = 0,
86 TRACKING_LEFT,
87 TRACKING_RIGHT,
88 TRACKING_TOP,
89 TRACKING_BOTTOM,
91 TRACKING_LEFT_TOP,
92 TRACKING_RIGHT_TOP,
93 TRACKING_LEFT_BOTTOM,
94 TRACKING_RIGHT_BOTTOM,
96 TRACKING_ALL
99 uint32 fTracking;
100 BPoint fLastMousePos;
102 point fPolygon[4];
103 color_cycle fColor[3];
106 // constructor
107 TestView::TestView(BRect frame, const char* name,
108 uint32 resizeFlags, uint32 flags)
109 : BView(frame, name, resizeFlags, flags),
110 // fBitmap(new BBitmap(BRect(0, 0, kBitmapWidth - 1, kBitmapHeight -1), 0, kBitmapFormat)),
111 // fBitmap(new BBitmap(BRect(0, 0, 32 - 1, 8 - 1), 0, B_CMAP8)),
112 // fBitmap(new BBitmap(BRect(0, 0, 32 - 1, 8 - 1), 0, B_GRAY8)),
113 fBitmap(new BBitmap(BRect(0, 0, 199, 99), B_RGB32, true)),
114 // fBitmap(new BBitmap(BRect(0, 0, 639, 479), B_RGB32, true)),
115 // fBitmap(new BBitmap(BRect(0, 0, 639, 479), B_CMAP8, true)),
116 // fBitmap(new BBitmap(BRect(0, 0, 199, 99), B_CMAP8, true)),
117 // fBitmap(new BBitmap(BRect(0, 0, 199, 99), B_GRAY8, true)),
118 fOffscreenView(new BView(fBitmap->Bounds(), "Offscreen view",
119 B_FOLLOW_ALL, B_WILL_DRAW | B_SUBPIXEL_PRECISE)),
120 fTicker(NULL),
121 fBitmapRect(),
122 fTracking(TRACKING_NONE),
123 fLastMousePos(-1.0, -1.0)
125 SetViewColor(B_TRANSPARENT_COLOR);
126 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
127 // uint32 size = min_c((uint32)fBitmap->BitsLength(), sizeof(kBitmapBits));
128 // memcpy(fBitmap->Bits(), kBitmapBits, size);
129 /* uint8* bits = (uint8*)fBitmap->Bits();
130 uint32 width = fBitmap->Bounds().IntegerWidth() + 1;
131 uint32 height = fBitmap->Bounds().IntegerHeight() + 1;
132 uint32 bpr = fBitmap->BytesPerRow();
133 printf("width: %ld, height: %ld, bpr: %ld\n", width, height, bpr);
134 int32 index = 0;
135 for (uint32 y = 0; y < height; y++) {
136 uint8* h = bits;
137 for (uint32 x = 0; x < width; x++) {
138 *h = index++;
139 h++;
141 bits += bpr;
143 BRect a(0.0, 10.0, 20.0, 10.0);
144 BRect b(0.0, 10.0, 10.0, 30.0);
145 printf("Intersects: %d\n", a.Intersects(b));*/
146 if (fBitmap->Lock()) {
147 fBitmap->AddChild(fOffscreenView);
148 fOffscreenView->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
149 fBitmap->Unlock();
152 srand((long int)system_time());
153 _InitPolygon(fBitmap->Bounds(), fPolygon);
154 _InitColor(fColor);
156 _ResetRect();
159 // AttachedToWindow
160 void
161 TestView::AttachedToWindow()
163 BMessenger mess(this, Window());
164 BMessage msg(MSG_TICK);
165 fTicker = new BMessageRunner(mess, &msg, 40000LL);
168 // MessageReceived
169 void
170 TestView::MessageReceived(BMessage* message)
172 switch (message->what) {
173 case MSG_RESET: {
174 BRect old = fBitmapRect;
175 _ResetRect();
176 _InvalidateBitmapRect(old | fBitmapRect);
177 break;
179 case MSG_TICK:
180 _MorphPolygon(fBitmap->Bounds(), fPolygon);
181 _MorphColor(fColor);
182 _FillBitmap(fPolygon);
183 Invalidate(fBitmapRect);
184 break;
185 default:
186 BView::MessageReceived(message);
187 break;
191 // Draw
192 void
193 TestView::Draw(BRect updateRect)
195 SetDrawingMode(B_OP_ALPHA);
196 DrawBitmap(fBitmap, fBitmap->Bounds(), fBitmapRect);
198 SetDrawingMode(B_OP_COPY);
199 // background arround bitmap
200 BRect topOfBitmap(updateRect.left, updateRect.top, updateRect.right, fBitmapRect.top - 1);
201 if (topOfBitmap.IsValid())
202 FillRect(topOfBitmap, B_SOLID_LOW);
204 BRect leftOfBitmap(updateRect.left, fBitmapRect.top, fBitmapRect.left - 1, fBitmapRect.bottom);
205 if (leftOfBitmap.IsValid())
206 FillRect(leftOfBitmap, B_SOLID_LOW);
208 BRect rightOfBitmap(fBitmapRect.right + 1, fBitmapRect.top, updateRect.right, fBitmapRect.bottom);
209 if (rightOfBitmap.IsValid())
210 FillRect(rightOfBitmap, B_SOLID_LOW);
212 BRect bottomOfBitmap(updateRect.left, fBitmapRect.bottom + 1, updateRect.right, updateRect.bottom);
213 if (bottomOfBitmap.IsValid())
214 FillRect(bottomOfBitmap, B_SOLID_LOW);
216 // indicate the frame to see any errors in the drawing code
217 rgb_color red = (rgb_color){ 255, 0, 0, 255 };
218 _DrawCross(fBitmapRect.LeftTop() + BPoint(-1.0, -1.0), red);
219 _DrawCross(fBitmapRect.RightTop() + BPoint(1.0, -1.0), red);
220 _DrawCross(fBitmapRect.LeftBottom() + BPoint(-1.0, 1.0), red);
221 _DrawCross(fBitmapRect.RightBottom() + BPoint(1.0, 1.0), red);
223 // text
224 SetDrawingMode(B_OP_ALPHA);
225 const char* message = "Click and drag to move and resize the bitmap!";
226 BPoint textPos(20.0, 30.0);
227 SetHighColor(255, 255, 255, 180);
228 DrawString(message, textPos);
229 SetHighColor(0, 0, 0, 180);
230 DrawString(message, textPos + BPoint(-1.0, -1.0));
233 // hit_test
234 bool
235 hit_test(BPoint where, BPoint p)
237 BRect r(p, p);
238 r.InsetBy(-5.0, -5.0);
239 return r.Contains(where);
242 // hit_test
243 bool
244 hit_test(BPoint where, BPoint a, BPoint b)
246 BRect r(a, b);
247 if (a.x == b.x)
248 r.InsetBy(-3.0, 0.0);
249 else
250 r.InsetBy(0.0, -3.0);
251 return r.Contains(where);
254 // MouseDown
255 void
256 TestView::MouseDown(BPoint where)
258 fTracking = TRACKING_NONE;
260 // check if we hit a corner
261 if (hit_test(where, fBitmapRect.LeftTop()))
262 fTracking = TRACKING_LEFT_TOP;
263 else if (hit_test(where, fBitmapRect.RightTop()))
264 fTracking = TRACKING_RIGHT_TOP;
265 else if (hit_test(where, fBitmapRect.LeftBottom()))
266 fTracking = TRACKING_LEFT_BOTTOM;
267 else if (hit_test(where, fBitmapRect.RightBottom()))
268 fTracking = TRACKING_RIGHT_BOTTOM;
269 // check if we hit a side
270 else if (hit_test(where, fBitmapRect.LeftTop(), fBitmapRect.RightTop()))
271 fTracking = TRACKING_TOP;
272 else if (hit_test(where, fBitmapRect.LeftTop(), fBitmapRect.LeftBottom()))
273 fTracking = TRACKING_LEFT;
274 else if (hit_test(where, fBitmapRect.RightTop(), fBitmapRect.RightBottom()))
275 fTracking = TRACKING_RIGHT;
276 else if (hit_test(where, fBitmapRect.LeftBottom(), fBitmapRect.RightBottom()))
277 fTracking = TRACKING_BOTTOM;
278 // check if we hit inside the rect
279 else if (fBitmapRect.Contains(where))
280 fTracking = TRACKING_ALL;
282 fLastMousePos = where;
285 // MouseUp
286 void
287 TestView::MouseUp(BPoint where)
289 fTracking = TRACKING_NONE;
292 // MouseMoved
293 void
294 TestView::MouseMoved(BPoint where, uint32 transit,
295 const BMessage* dragMessage)
297 if (fTracking > TRACKING_NONE) {
298 BRect old = fBitmapRect;
299 BPoint offset = where - fLastMousePos;
300 switch (fTracking) {
301 case TRACKING_LEFT_TOP:
302 fBitmapRect.Set(fBitmapRect.left + offset.x,
303 fBitmapRect.top + offset.y,
304 fBitmapRect.right,
305 fBitmapRect.bottom);
306 break;
307 case TRACKING_RIGHT_BOTTOM:
308 fBitmapRect.Set(fBitmapRect.left,
309 fBitmapRect.top,
310 fBitmapRect.right + offset.x,
311 fBitmapRect.bottom + offset.y);
312 break;
313 case TRACKING_LEFT_BOTTOM:
314 fBitmapRect.Set(fBitmapRect.left + offset.x,
315 fBitmapRect.top,
316 fBitmapRect.right,
317 fBitmapRect.bottom + offset.y);
318 break;
319 case TRACKING_RIGHT_TOP:
320 fBitmapRect.Set(fBitmapRect.left,
321 fBitmapRect.top + offset.y,
322 fBitmapRect.right + offset.x,
323 fBitmapRect.bottom);
324 break;
325 case TRACKING_LEFT:
326 fBitmapRect.Set(fBitmapRect.left + offset.x,
327 fBitmapRect.top,
328 fBitmapRect.right,
329 fBitmapRect.bottom);
330 break;
331 case TRACKING_TOP:
332 fBitmapRect.Set(fBitmapRect.left,
333 fBitmapRect.top + offset.y,
334 fBitmapRect.right,
335 fBitmapRect.bottom);
336 break;
337 case TRACKING_RIGHT:
338 fBitmapRect.Set(fBitmapRect.left,
339 fBitmapRect.top,
340 fBitmapRect.right + offset.x,
341 fBitmapRect.bottom);
342 break;
343 case TRACKING_BOTTOM:
344 fBitmapRect.Set(fBitmapRect.left,
345 fBitmapRect.top,
346 fBitmapRect.right,
347 fBitmapRect.bottom + offset.y);
348 break;
349 case TRACKING_ALL:
350 default:
351 fBitmapRect.OffsetBy(offset);
352 break;
354 fLastMousePos = where;
355 if (old != fBitmapRect)
356 _InvalidateBitmapRect(old | fBitmapRect);
360 // _ResetRect
361 void
362 TestView::_ResetRect()
364 fBitmapRect = fBitmap->Bounds();
365 fBitmapRect.OffsetBy(floorf((Bounds().Width() - fBitmapRect.Width()) / 2.0 + 0.5),
366 floorf((Bounds().Height() - fBitmapRect.Height()) / 2.0 + 0.5));
369 // _InvalidateBitmapRect
370 void
371 TestView::_InvalidateBitmapRect(BRect r)
373 r.InsetBy(-4.0, -4.0);
374 Invalidate(r);
377 // _DrawCross
378 void
379 TestView::_DrawCross(BPoint where, rgb_color c)
381 BeginLineArray(4);
382 AddLine(BPoint(where.x, where.y - 3),
383 BPoint(where.x, where.y - 1), c);
384 AddLine(BPoint(where.x, where.y + 1),
385 BPoint(where.x, where.y + 3), c);
386 AddLine(BPoint(where.x - 3, where.y),
387 BPoint(where.x - 1, where.y), c);
388 AddLine(BPoint(where.x + 1, where.y),
389 BPoint(where.x + 3, where.y), c);
390 EndLineArray();
393 // _FillBitmap
394 void
395 TestView::_FillBitmap(point* polygon)
397 if (fBitmap->Lock()) {
398 fOffscreenView->SetDrawingMode(B_OP_COPY);
399 fOffscreenView->SetHighColor(0, 0, 0, 30);
400 fOffscreenView->FillRect(fOffscreenView->Bounds());
402 fOffscreenView->SetDrawingMode(B_OP_ALPHA);
403 fOffscreenView->SetHighColor(fColor[0].value,
404 fColor[1].value,
405 fColor[2].value,
406 30);
407 fOffscreenView->SetPenSize(4);
408 fOffscreenView->SetLineMode(B_BUTT_CAP, B_ROUND_JOIN);
410 BPoint pointList[4];
411 pointList[0].x = polygon[0].x;
412 pointList[0].y = polygon[0].y;
413 pointList[1].x = polygon[1].x;
414 pointList[1].y = polygon[1].y;
415 pointList[2].x = polygon[2].x;
416 pointList[2].y = polygon[2].y;
417 pointList[3].x = polygon[3].x;
418 pointList[3].y = polygon[3].y;
420 fOffscreenView->StrokePolygon(pointList, 4);
422 fOffscreenView->Sync();
423 fBitmap->Unlock();
427 // _InitPolygon
428 void
429 TestView::_InitPolygon(const BRect& b, point* polygon) const
431 polygon[0].x = b.left;
432 polygon[0].y = b.top;
433 polygon[0].direction_x = random_number_between(-SPEED, SPEED);
434 polygon[0].direction_y = random_number_between(-SPEED, SPEED);
435 polygon[0].velocity_x = 0.0;
436 polygon[0].velocity_y = 0.0;
437 polygon[1].x = b.right;
438 polygon[1].y = b.top;
439 polygon[1].direction_x = random_number_between(-SPEED, SPEED);
440 polygon[1].direction_y = random_number_between(-SPEED, SPEED);
441 polygon[1].velocity_x = 0.0;
442 polygon[1].velocity_y = 0.0;
443 polygon[2].x = b.right;
444 polygon[2].y = b.bottom;
445 polygon[2].direction_x = random_number_between(-SPEED, SPEED);
446 polygon[2].direction_y = random_number_between(-SPEED, SPEED);
447 polygon[2].velocity_x = 0.0;
448 polygon[2].velocity_y = 0.0;
449 polygon[3].x = b.left;
450 polygon[3].y = b.bottom;
451 polygon[3].direction_x = random_number_between(-SPEED, SPEED);
452 polygon[3].direction_y = random_number_between(-SPEED, SPEED);
453 polygon[3].velocity_x = 0.0;
454 polygon[3].velocity_y = 0.0;
457 // _InitColor
458 void
459 TestView::_InitColor(color_cycle* color) const
461 color[0].value = 0;
462 color[0].direction = random_number_between(-SPEED * 4, SPEED * 4);
463 color[1].value = 0;
464 color[1].direction = random_number_between(-SPEED * 4, SPEED * 4);
465 color[2].value = 0;
466 color[2].direction = random_number_between(-SPEED * 4, SPEED * 4);
469 // morph
470 inline void
471 morph(double* value, double* direction, double* velocity, double min, double max)
473 *value += *velocity;
475 // flip direction if necessary
476 if (*value < min && *direction < 0.0) {
477 *direction = -*direction;
478 } else if (*value > max && *direction > 0.0) {
479 *direction = -*direction;
482 // accelerate velocity
483 if (*direction < 0.0) {
484 if (*velocity > *direction)
485 *velocity += *direction / 10.0;
486 // truncate velocity
487 if (*velocity < *direction)
488 *velocity = *direction;
489 } else {
490 if (*velocity < *direction)
491 *velocity += *direction / 10.0;
492 // truncate velocity
493 if (*velocity > *direction)
494 *velocity = *direction;
498 // morph
499 inline void
500 morph(uint8* value, double* direction)
502 int32 v = (int32)(*value + *direction);
503 if (v < 0) {
504 v = 0;
505 *direction = -*direction;
506 } else if (v > 255) {
507 v = 255;
508 *direction = -*direction;
510 *value = (uint8)v;
513 // _MorphPolygon
514 void
515 TestView::_MorphPolygon(const BRect& b, point* polygon)
517 morph(&polygon[0].x, &polygon[0].direction_x, &polygon[0].velocity_x, b.left, b.right);
518 morph(&polygon[1].x, &polygon[1].direction_x, &polygon[1].velocity_x, b.left, b.right);
519 morph(&polygon[2].x, &polygon[2].direction_x, &polygon[2].velocity_x, b.left, b.right);
520 morph(&polygon[3].x, &polygon[3].direction_x, &polygon[3].velocity_x, b.left, b.right);
521 morph(&polygon[0].y, &polygon[0].direction_y, &polygon[0].velocity_y, b.top, b.bottom);
522 morph(&polygon[1].y, &polygon[1].direction_y, &polygon[1].velocity_y, b.top, b.bottom);
523 morph(&polygon[2].y, &polygon[2].direction_y, &polygon[2].velocity_y, b.top, b.bottom);
524 morph(&polygon[3].y, &polygon[3].direction_y, &polygon[3].velocity_y, b.top, b.bottom);
527 // _MorphColor
528 void
529 TestView::_MorphColor(color_cycle* color)
531 morph(&color[0].value, &color[0].direction);
532 morph(&color[1].value, &color[1].direction);
533 morph(&color[2].value, &color[2].direction);
536 // show_window
537 void
538 show_window(BRect frame, const char* name)
540 BWindow* window = new BWindow(frame, name,
541 B_TITLED_WINDOW,
542 B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE);
544 BView* view = new TestView(window->Bounds(), "test", B_FOLLOW_ALL,
545 B_WILL_DRAW/* | B_FULL_UPDATE_ON_RESIZE*/);
547 window->AddChild(view);
548 BRect b(0.0, 0.0, 60.0, 15.0);
549 b.OffsetTo(5.0, view->Bounds().bottom - (b.Height() + 15.0));
550 BButton* control = new BButton(b, "button", "Reset", new BMessage(MSG_RESET),
551 B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
552 view->AddChild(control);
553 control->SetTarget(view);
554 control->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
556 window->Show();
559 // main
561 main(int argc, char** argv)
563 BApplication* app = new BApplication("application/x.vnd-Haiku.BitmapDrawing");
565 // BRect frame(10.0, 30.0, 790.0, 590.0);
566 BRect frame(10.0, 30.0, 330.0, 220.0);
567 show_window(frame, "BitmapDrawing");
569 app->Run();
571 delete app;
572 return 0;