vfs: check userland buffers before reading them.
[haiku.git] / src / tests / kits / game / page_flipper / page_flip.cpp
blob20477b3baa9f34080d2982cb2036f5f08eb6e812
1 /*
2 Copyright 1999, Be Incorporated. All Rights Reserved.
3 This file may be used under the terms of the Be Sample Code License.
4 */
6 #include <Application.h>
7 #include <WindowScreen.h>
8 #include <Screen.h>
9 #include <string.h>
11 typedef long (*blit_hook)(long,long,long,long,long,long);
12 typedef long (*sync_hook)();
14 class NApplication:public BApplication {
15 public:
16 NApplication();
17 bool is_quitting; // So that the WindowScreen knows what
18 // to do when disconnected.
19 private:
20 bool QuitRequested();
21 void ReadyToRun();
24 class NWindowScreen:public BWindowScreen {
25 public:
26 NWindowScreen(status_t*);
27 private:
28 void ScreenConnected(bool);
29 int32 DrawingCode();
31 static int32 Entry(void*);
33 thread_id fThreadId;
34 sem_id fSem;
35 area_id fArea;
36 uint8* fSaveBuffer;
37 uint8* fFrameBuffer;
38 ulong fLineLength;
39 bool fThreadIsLocked; // small hack to allow to quit the
40 // app from ScreenConnected()
41 blit_hook fBlitHook; // hooks to the graphics driver functions
42 sync_hook fSyncHook;
46 int
47 main()
49 NApplication app;
53 NApplication::NApplication()
54 :BApplication("application/x-vnd.Be-sample-jbq1")
56 Run(); // see you in ReadyToRun()
60 void
61 NApplication::ReadyToRun()
63 status_t ret = B_ERROR;
64 is_quitting = false;
65 NWindowScreen* windowScreen = new NWindowScreen(&ret);
66 // exit if constructing the WindowScreen failed.
67 if (windowScreen == NULL || ret < B_OK)
68 PostMessage(B_QUIT_REQUESTED);
72 bool
73 NApplication::QuitRequested()
75 is_quitting = true;
76 return true;
80 NWindowScreen::NWindowScreen(status_t* ret)
82 BWindowScreen("Example", B_8_BIT_640x480, ret),
83 fThreadId(-1),
84 fSem(-1),
85 fArea(-1),
86 fSaveBuffer(NULL),
87 fFrameBuffer(NULL),
88 fLineLength(0),
89 fThreadIsLocked(true),
90 fBlitHook(NULL),
91 fSyncHook(NULL)
93 if (*ret < B_OK)
94 return;
96 // this semaphore controls the access to the WindowScreen
97 fSem = create_sem(0, "WindowScreen Access");
98 if (fSem < B_OK) {
99 *ret = fSem;
100 return;
103 // this area is used to save the whole framebuffer when
104 // switching workspaces. (better than malloc()).
105 fArea = create_area("save", (void**)&fSaveBuffer, B_ANY_ADDRESS,
106 640 * 2048, B_NO_LOCK, B_READ_AREA|B_WRITE_AREA);
107 if (fArea < B_OK) {
108 *ret = fArea;
109 delete_sem(fSem);
110 fSem = -1;
111 return;
114 Show(); // let's go. See you in ScreenConnected.
118 void
119 NWindowScreen::ScreenConnected(bool connected)
121 if (connected) {
122 if (SetSpace(B_8_BIT_640x480) < B_OK || SetFrameBuffer(640, 2048) < B_OK) {
123 // properly set the framebuffer. exit if an error occurs.
124 be_app->PostMessage(B_QUIT_REQUESTED);
125 return;
128 // get the hardware acceleration hooks. get them each time
129 // the WindowScreen is connected, because of multiple
130 // monitor support
131 fBlitHook = (blit_hook)CardHookAt(7);
132 fSyncHook = (sync_hook)CardHookAt(10);
134 // cannot work with no hardware blitting
135 if (fBlitHook == NULL) {
136 be_app->PostMessage(B_QUIT_REQUESTED);
137 return;
139 // get the framebuffer-related info, each time the
140 // WindowScreen is connected (multiple monitor)
141 fFrameBuffer = (uint8 *)(CardInfo()->frame_buffer);
142 fLineLength = FrameBufferInfo()->bytes_per_row;
143 if (fThreadId == 0) {
144 // clean the framebuffer
145 memset(fFrameBuffer, 0, 2048 * fLineLength);
146 // spawn the rendering thread. exit if an error occurs.
147 fThreadId = spawn_thread(Entry, "rendering thread", B_URGENT_DISPLAY_PRIORITY, this);
148 if (fThreadId < B_OK || resume_thread(fThreadId) < B_OK)
149 be_app->PostMessage(B_QUIT_REQUESTED);
150 } else {
151 for (int y = 0; y < 2048; y++) {
152 // restore the framebuffer when switching back from
153 // another workspace.
154 memcpy(fFrameBuffer + y * fLineLength, fSaveBuffer + 640 * y, 640);
158 // set our color list.
159 rgb_color palette[256];
160 for (int i = 0; i < 128; i++) {
161 rgb_color c1 = {i * 2, i * 2, i * 2};
162 rgb_color c2 = {127 + i, 2 * i, 254};
163 palette[i] = c1;
164 palette[i + 128] = c2;
166 SetColorList(palette);
167 // allow the rendering thread to run.
168 fThreadIsLocked = false;
169 release_sem(fSem);
170 } else {
171 // block the rendering thread.
172 if (!fThreadIsLocked) {
173 acquire_sem(fSem);
174 fThreadIsLocked = true;
177 // kill the rendering and clean up when quitting
178 if ((((NApplication*)be_app)->is_quitting)) {
179 status_t ret;
180 kill_thread(fThreadId);
181 wait_for_thread(fThreadId, &ret);
182 delete_sem(fSem);
183 delete_area(fArea);
184 } else {
185 // set the color list black so that the screen doesn't seem
186 // to freeze while saving the framebuffer
187 rgb_color c = { 0, 0, 0 };
188 rgb_color palette[256];
189 for (int i = 0; i < 256; i++)
190 palette[i] = c;
191 SetColorList(palette);
193 // save the framebuffer
194 for (int y = 0; y < 2048; y++)
195 memcpy(fSaveBuffer + 640 * y, fFrameBuffer + y * fLineLength, 640);
201 int32
202 NWindowScreen::Entry(void* castToThis)
204 return ((NWindowScreen *)castToThis)->DrawingCode();
208 int32
209 NWindowScreen::DrawingCode()
211 // gain access to the framebuffer before writing to it.
213 acquire_sem(fSem);
215 for (int j = 1440; j < 2048; j++) {
216 for (int i; i < 640; i++) {
217 // draw the backgroud ripple pattern
218 float val=63.99*(1+cos(2*M_PI*((i-320)*(i-320)+(j-1744)*(j-1744))/1216));
219 fFrameBuffer[i + fLineLength*j]=int(val);
223 ulong numframe = 0;
224 bigtime_t trgt = 0;
225 ulong y_origin;
226 uint8* current_frame;
227 while (true) {
228 // the framebuffer coordinates of the next frame
229 y_origin = 480 * (numframe % 3);
230 // and a pointer to it
231 current_frame = fFrameBuffer + y_origin * fLineLength;
232 // copy the background
233 int ytop = numframe % 608, ybot = ytop + 479;
234 if (ybot < 608) {
235 fBlitHook(0,1440+ytop,0,y_origin,639,479);
236 } else {
237 fBlitHook(0,1440+ytop,0,y_origin,639,1086-ybot);
238 fBlitHook(0,1440,0,y_origin+1087-ybot,639,ybot-608);
240 // calculate the circle position. doing such calculations
241 // between blit() and sync() is a good idea.
242 uint32 x=(uint32)(287.99*(1+sin(numframe/72.)));
243 uint32 y=(uint32)(207.99*(1+sin(numframe/52.)));
244 if (fSyncHook)
245 fSyncHook();
246 // draw the circle
247 for (int j = 0; j < 64; j++) {
248 for (int i = 0; i < 64; i++) {
249 if ((i-31)*(i-32)+(j-31)*(j-32)<=1024)
250 current_frame[x + i + fLineLength * (y + j)] += 128;
253 // release the semaphore while waiting. gotta release it
254 // at some point or nasty things will happen!
255 release_sem(fSem);
256 // try to sync with the vertical retrace
257 if (BScreen(this).WaitForRetrace() != B_OK) {
258 // we're doing some triple buffering. unwanted things would
259 // happen if we rendered more pictures than the card can
260 // display. we here make sure not to render more than 55.5
261 // pictures per second if the card does not support retrace
262 // syncing
263 if (system_time() < trgt)
264 snooze(trgt - system_time());
265 trgt = system_time() + 18000;
267 // acquire the semaphore back before talking to the driver
268 acquire_sem(fSem);
269 // do the page-flipping
270 MoveDisplayArea(0, y_origin);
271 // and go to the next frame!
272 numframe++;
274 return 0;