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 long MyCode(); 30 static long Entry(void*); 31 thread_id tid; 32 sem_id sem; 33 area_id area; 34 uint8* save_buffer; 35 uint8* frame_buffer; 36 ulong line_length; 37 bool thread_is_locked; // small hack to allow to quit the 38 // app from ScreenConnected() 39 blit_hook blit; // hooks to the graphics driver functions 40 sync_hook sync; 41 }; 42 43 int main(int, char**) { 44 NApplication app; 45 } 46 47 NApplication::NApplication() 48 :BApplication("application/x-vnd.Be-sample-jbq1") { 49 Run(); // see you in ReadyToRun() 50 } 51 52 void NApplication::ReadyToRun() { 53 status_t ret=B_ERROR; 54 is_quitting=false; 55 NWindowScreen* ws=new NWindowScreen(&ret); 56 // exit if constructing the WindowScreen failed. 57 if ((ws==NULL)||(ret<B_OK)) 58 PostMessage(B_QUIT_REQUESTED); 59 } 60 61 bool NApplication::QuitRequested() { 62 is_quitting=true; 63 return true; 64 } 65 66 NWindowScreen::NWindowScreen(status_t* ret) 67 :BWindowScreen("Example",B_8_BIT_640x480,ret) { 68 thread_is_locked=true; 69 tid=0; 70 if (*ret==B_OK) { 71 // this semaphore controls the access to the WindowScreen 72 sem=create_sem(0,"WindowScreen Access"); 73 // this area is used to save the whole framebuffer when 74 // switching workspaces. (better than malloc()). 75 area=create_area("save",(void**)&save_buffer,B_ANY_ADDRESS 76 ,640*2048,B_NO_LOCK,B_READ_AREA|B_WRITE_AREA); 77 // exit if an error occured. 78 if ((sem<B_OK)||(area<B_OK)) *ret=B_ERROR; 79 else Show(); // let's go. See you in ScreenConnected. 80 } 81 } 82 83 void NWindowScreen::ScreenConnected(bool connected) { 84 if (connected) { 85 if ((SetSpace(B_8_BIT_640x480)<B_OK) 86 ||(SetFrameBuffer(640,2048)<B_OK)) { 87 // properly set the framebuffer. exit if an error occurs. 88 be_app->PostMessage(B_QUIT_REQUESTED); 89 return; 90 } 91 // get the hardware acceleration hooks. get them each time 92 // the WindowScreen is connected, because of multiple 93 // monitor support 94 blit=(blit_hook)CardHookAt(7); 95 sync=(sync_hook)CardHookAt(10); 96 // cannot work with no hardware blitting 97 if (blit==NULL) { 98 be_app->PostMessage(B_QUIT_REQUESTED); 99 return; 100 } 101 // get the framebuffer-related info, each time the 102 // WindowScreen is connected (multiple monitor) 103 frame_buffer=(uint8*)(CardInfo()->frame_buffer); 104 line_length=FrameBufferInfo()->bytes_per_row; 105 if (tid==0) { 106 // clean the framebuffer 107 memset(frame_buffer,0,2048*line_length); 108 // spawn the rendering thread. exit if an error occurs. 109 if (((tid=spawn_thread(Entry,"rendering thread", 110 B_URGENT_DISPLAY_PRIORITY,this))<B_OK) 111 ||(resume_thread(tid)<B_OK)) 112 be_app->PostMessage(B_QUIT_REQUESTED); 113 } else for (int y=0;y<2048;y++) 114 // restore the framebuffer when switching back from 115 // another workspace. 116 memcpy(frame_buffer+y*line_length, 117 save_buffer+640*y,640); 118 // set our color list. 119 rgb_color palette[256]; 120 for (int i=0;i<128;i++) { 121 rgb_color c1={i*2,i*2,i*2}; 122 rgb_color c2={127+i,2*i,254}; 123 palette[i]=c1; 124 palette[i+128]=c2; 125 } 126 SetColorList(palette); 127 // allow the rendering thread to run. 128 thread_is_locked=false; 129 release_sem(sem); 130 } else { 131 // block the rendering thread. 132 if (!thread_is_locked) { 133 acquire_sem(sem); 134 thread_is_locked=true; 135 } 136 // kill the rendering and clean up when quitting 137 if ((((NApplication*)be_app)->is_quitting)) { 138 status_t ret; 139 kill_thread(tid); 140 wait_for_thread(tid,&ret); 141 delete_sem(sem); 142 delete_area(area); 143 } else { 144 // set the color list black so that the screen doesn't seem 145 // to freeze while saving the framebuffer 146 rgb_color c={0,0,0}; 147 rgb_color palette[256]; 148 for (int i=0;i<256;i++) 149 palette[i]=c; 150 SetColorList(palette); 151 152 // save the framebuffer 153 for (int y=0;y<2048;y++) 154 memcpy(save_buffer+640*y, 155 frame_buffer+y*line_length,640); 156 } 157 } 158 } 159 160 long NWindowScreen::Entry(void* p) { 161 return ((NWindowScreen*)p)->MyCode(); 162 } 163 164 long NWindowScreen::MyCode() { 165 // gain access to the framebuffer before writing to it. 166 167 acquire_sem(sem); 168 169 for (int j=1440;j<2048;j++) { 170 for (int i=0;i<640;i++) { 171 // draw the backgroud ripple pattern 172 float val=63.99*(1+cos(2*M_PI*((i-320)*(i-320) 173 +(j-1744)*(j-1744))/1216)); 174 frame_buffer[i+line_length*j]=int(val); 175 } 176 } 177 ulong numframe=0; 178 bigtime_t trgt=0; 179 ulong y_origin; 180 uint8* current_frame; 181 while(true) { 182 // the framebuffer coordinates of the next frame 183 y_origin=480*(numframe%3); 184 // and a pointer to it 185 current_frame=frame_buffer+y_origin*line_length; 186 // copy the background 187 int ytop=numframe%608,ybot=ytop+479; 188 if (ybot<608) { 189 blit(0,1440+ytop,0,y_origin,639,479); 190 } else { 191 blit(0,1440+ytop,0,y_origin,639,1086-ybot); 192 blit(0,1440,0,y_origin+1087-ybot,639,ybot-608); 193 } 194 // calculate the circle position. doing such calculations 195 // between blit() and sync() is a good idea. 196 uint32 x=(uint32)(287.99*(1+sin(numframe/72.))); 197 uint32 y=(uint32)(207.99*(1+sin(numframe/52.))); 198 if (sync) sync(); 199 // draw the circle 200 for (int j=0;j<64;j++) { 201 for (int i=0;i<64;i++) { 202 if ((i-31)*(i-32)+(j-31)*(j-32)<=1024) 203 current_frame[x+i+line_length*(y+j)]+=128; 204 } 205 } 206 // release the semaphore while waiting. gotta release it 207 // at some point or nasty things will happen! 208 release_sem(sem); 209 // try to sync with the vertical retrace 210 if (BScreen(this).WaitForRetrace()!=B_OK) { 211 // we're doing some triple buffering. unwanted things would 212 // happen if we rendered more pictures than the card can 213 // display. we here make sure not to render more than 55.5 214 // pictures per second if the card does not support retrace 215 // syncing 216 if (system_time()<trgt) snooze(trgt-system_time()); 217 trgt=system_time()+18000; 218 } 219 // acquire the semaphore back before talking to the driver 220 acquire_sem(sem); 221 // do the page-flipping 222 MoveDisplayArea(0,y_origin); 223 // and go to the next frame! 224 numframe++; 225 } 226 return 0; 227 } 228