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 */ 5 6 #include <Application.h> 7 #include <WindowScreen.h> 8 #include <Screen.h> 9 #include <string.h> 10 11 typedef long (*blit_hook)(long,long,long,long,long,long); 12 typedef long (*sync_hook)(); 13 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(); 22 }; 23 24 class NWindowScreen:public BWindowScreen { 25 public: 26 NWindowScreen(status_t*); 27 private: 28 void ScreenConnected(bool); 29 int32 DrawingCode(); 30 31 static int32 Entry(void*); 32 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; 43 }; 44 45 46 int 47 main() 48 { 49 NApplication app; 50 } 51 52 53 NApplication::NApplication() 54 :BApplication("application/x-vnd.Be-sample-jbq1") 55 { 56 Run(); // see you in ReadyToRun() 57 } 58 59 60 void 61 NApplication::ReadyToRun() 62 { 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); 69 } 70 71 72 bool 73 NApplication::QuitRequested() 74 { 75 is_quitting = true; 76 return true; 77 } 78 79 80 NWindowScreen::NWindowScreen(status_t* ret) 81 : 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) 92 { 93 if (*ret < B_OK) 94 return; 95 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; 101 } 102 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; 112 } 113 114 Show(); // let's go. See you in ScreenConnected. 115 } 116 117 118 void 119 NWindowScreen::ScreenConnected(bool connected) 120 { 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; 126 } 127 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); 133 134 // cannot work with no hardware blitting 135 if (fBlitHook == NULL) { 136 be_app->PostMessage(B_QUIT_REQUESTED); 137 return; 138 } 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); 155 } 156 } 157 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; 165 } 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; 175 } 176 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); 192 193 // save the framebuffer 194 for (int y = 0; y < 2048; y++) 195 memcpy(fSaveBuffer + 640 * y, fFrameBuffer + y * fLineLength, 640); 196 } 197 } 198 } 199 200 201 int32 202 NWindowScreen::Entry(void* castToThis) 203 { 204 return ((NWindowScreen *)castToThis)->DrawingCode(); 205 } 206 207 208 int32 209 NWindowScreen::DrawingCode() 210 { 211 // gain access to the framebuffer before writing to it. 212 213 acquire_sem(fSem); 214 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); 220 } 221 } 222 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); 239 } 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; 251 } 252 } 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; 266 } 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++; 273 } 274 return 0; 275 } 276