Ticket #9789: PretendoWindow.cc

File PretendoWindow.cc, 25.1 KB (added by scanty, 11 years ago)

source file with BDirectWindow code in it

Line 
1
2#include <iostream>
3#include "Mapper.h"
4#include "NES.h"
5#include "PretendoWindow.h"
6#include "CartInfoWindow.h"
7
8
9PretendoWindow::PretendoWindow()
10 : BDirectWindow (BRect (0, 0, 0, 0), "Pretendo", B_TITLED_WINDOW, B_NOT_RESIZABLE, 0),
11 fView(NULL),
12 fMenu(NULL),
13 fFileMenu(NULL),
14 fEmuMenu(NULL),
15 fVideoMenu(NULL),
16// fAudioMenu(NULL),
17 fOpenPanel(NULL),
18 fCartInfoWindow(NULL),
19 fBitmap(NULL),
20 fOverlayBitmap(NULL),
21 fBitmapBits(NULL),
22 fOverlayBits(NULL),
23 fBitsArea(B_ERROR),
24 fDirtyArea(B_ERROR),
25 fVideoScreen(NULL),
26 fAudioStream(NULL),
27 fPaletteWindow(NULL),
28 fPaused(false),
29 fRunning(false)
30{
31 BRect bounds (Bounds());
32 bounds.OffsetTo (B_ORIGIN);
33 AddMenu();
34 bounds.top = fMenuHeight;
35
36 fView = new BView (bounds, "main_view", B_FOLLOW_ALL, 0);
37 AddChild (fView);
38
39 ResizeTo (SCREEN_WIDTH, SCREEN_HEIGHT);
40 CenterOnScreen();
41
42 fBitmap = new BBitmap (BRect (0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1), B_CMAP8);
43 if (! fBitmap || ! fBitmap->IsValid()) {
44 (new BAlert ("Error", "Not enough memory for video bitmap. Quitting.",
45 "Bummer", NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go();
46 OnQuit();
47 } else {
48 fBitmapBits = reinterpret_cast<uint8 *>(fBitmap->Bits());
49 ClearBitmap (false);
50 }
51
52 void *areaBits = NULL;
53 void *dirtyBits = NULL;
54
55 fBitsArea = create_area ("frame buffer", &areaBits, B_ANY_ADDRESS,
56 ((SCREEN_WIDTH * 2) * (SCREEN_HEIGHT * 2) * 4 + B_PAGE_SIZE-1) &
57 ((uint32)-1 ^ (B_PAGE_SIZE-1)), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
58
59 fDirtyArea = create_area ("dirty buffer", &dirtyBits, B_ANY_ADDRESS,
60 ((SCREEN_WIDTH * 2) * (SCREEN_HEIGHT * 2) * 4 + B_PAGE_SIZE-1) &
61 ((uint32)-1 ^ (B_PAGE_SIZE-1)), B_NO_LOCK,
62 B_READ_AREA | B_WRITE_AREA);
63
64 if (fBitsArea < B_OK || fDirtyArea < B_OK) {
65 (new BAlert ("Error", "Not enough memory for video buffers. Quitting.",
66 "Bummer", NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go();
67 OnQuit();
68 } else {
69 memset (areaBits, 0x00, (SCREEN_WIDTH*2) * (SCREEN_HEIGHT*2) * 4);
70 memset (dirtyBits, 0xff, (SCREEN_WIDTH*2) * (SCREEN_HEIGHT*2) * 4);
71
72 fBackBuffer.bits = reinterpret_cast<uint8 *>(areaBits);
73 fDirtyBuffer.bits = reinterpret_cast<uint8 *>(dirtyBits);
74 }
75
76 // create a BBitmap for overlay framework (checks for overlay support inherently)
77 bool overlayOK = false;
78
79 bounds.Set (0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1);
80 fOverlayBitmap = new BBitmap (bounds, B_BITMAP_WILL_OVERLAY, B_YCbCr422);
81 overlayOK = fOverlayBitmap && fOverlayBitmap->IsValid();
82
83 if (overlayOK) {
84 fVideoMenu->ItemAt(2)->SetEnabled(true);
85 fOverlayBits = reinterpret_cast<uint8 *>(fOverlayBitmap->Bits());
86 ClearBitmap (true);
87 } else {
88 fOverlayBits = NULL;
89 if (fOverlayBitmap) {
90 delete fOverlayBitmap;
91 }
92 fView->SetViewColor(0, 0, 0);
93 ClearBitmap(false);
94 fVideoMenu->ItemAt(2)->SetEnabled(false);
95
96 }
97
98 fDirectConnected =
99 fFullScreen =
100 fFrameworkChanging = false;
101 fFramework =
102 fPrevFramework = NO_FRAMEWORK;
103
104 if (overlayOK) {
105 ChangeFramework (OVERLAY_FRAMEWORK);
106 } else {
107 // things will be boring until we get a hardware cursor
108 //ChangeFramework(DIRECTWINDOW_FRAMEWORK);
109 ChangeFramework(BITMAP_FRAMEWORK);
110 }
111
112 // other things we need
113 fOpenPanel = new ROMFilePanel;
114 //fAudioStream = new AudioStream ("Pretendo", 44100.0, 8, 1, 44100.0 / 60);
115
116 fDoubled = false;
117 fClear = 0;
118
119 if ((fThread = spawn_thread(emulation_thread, "pretendo_thread", B_NORMAL_PRIORITY, reinterpret_cast<void *>(this))) < B_OK) {
120 std::cout << "failed to spawn thread" << std::endl;
121 } else {
122 fRunning = false;
123 }
124
125 fMutex = new SimpleMutex("pretendo_mutex");
126 fMutex->Lock();
127 resume_thread(fThread);
128
129 set_palette(Palette::intensity, Palette::NTSC(
130 Palette::default_saturation,
131 Palette::default_hue,
132 Palette::default_contrast,
133 Palette::default_brightness,
134 Palette::default_gamma));
135}
136
137
138PretendoWindow::~PretendoWindow()
139{
140
141 fRunning = fDirectConnected = false;
142 fThread = B_BAD_THREAD_ID;
143
144 if (fOpenPanel->Window()) {
145 fOpenPanel->Window()->Lock();
146 fOpenPanel->Window()->Quit();
147 fOpenPanel = NULL;
148 }
149
150 if (fBitmap->IsValid()) {
151 delete fBitmap;
152 fBitmap = NULL;
153 }
154
155 if (fOverlayBitmap->IsValid()) {
156 delete fOverlayBitmap;
157 fOverlayBitmap = NULL;
158 }
159
160 delete_area (fBitsArea);
161 delete_area (fDirtyArea);
162
163 fAudioStream->Stop();
164 delete fAudioStream;
165
166 if (fCartInfoWindow != NULL) {
167 fCartInfoWindow->Lock();
168 fCartInfoWindow->Quit();
169 }
170
171 if (fPaletteWindow != NULL) {
172 fPaletteWindow->Lock();
173 fPaletteWindow->Quit();
174 }
175
176 Hide();
177 Sync();
178}
179
180
181void
182PretendoWindow::DirectConnected (direct_buffer_info *info)
183{
184 fMainLocker.Lock();
185
186 switch (info->buffer_state & B_DIRECT_MODE_MASK) {
187 case B_DIRECT_START:
188 fClear = 5;
189 fClipInfo.bounds = info->window_bounds;
190 fClipInfo.bounds.top += fMenuHeight + 1;
191
192 if (fFramework == DIRECTWINDOW_FRAMEWORK) {
193 SetFrontBuffer (reinterpret_cast<uint8 *>(info->bits)
194 + (fClipInfo.bounds.top * info->bytes_per_row), info->pixel_format,
195 info->bits_per_pixel / 8, info->bytes_per_row);
196 }
197
198 fClipInfo.clip_list = NULL;
199 fDirectConnected = true;
200 // intentional fall through //
201 case B_DIRECT_MODIFY:
202 fClear = 5;
203 fClipInfo.clip_count = info->clip_list_count;
204 fClipInfo.clip_list =
205 reinterpret_cast<clipping_rect *>(realloc(fClipInfo.clip_list, fClipInfo.clip_count * sizeof(clipping_rect)));
206 memcpy (fClipInfo.clip_list, info->clip_list,
207 fClipInfo.clip_count * sizeof(clipping_rect));
208
209 for (int32 i = 0; i < fClipInfo.clip_count; i++) {
210 if (fClipInfo.clip_list[i].top <=
211 static_cast<int32>(info->window_bounds.top + fMenuHeight)) {
212 fClipInfo.clip_list[i].top = info->window_bounds.top + fMenuHeight;
213 }
214 }
215 break;
216
217 case B_DIRECT_STOP:
218 fDirectConnected = false;
219 free (fClipInfo.clip_list);
220 break;
221 }
222
223 fMainLocker.Unlock();
224
225 BDirectWindow::DirectConnected(info);
226}
227
228
229void
230PretendoWindow::MessageReceived (BMessage *message)
231{
232 switch (message->what) {
233 case MSG_CHANGE_RENDER:
234 ChangeFramework(
235 (VIDEO_FRAMEWORK)fVideoMenu->IndexOf(fVideoMenu->FindMarked()));
236 break;
237
238 case MSG_LEAVE_FULLSCREEN:
239 ChangeFramework (fPrevFramework);
240 break;
241
242 case MSG_ROM_LOADED:
243 OnLoadCart(message);
244 break;
245
246 case MSG_SHOW_OPEN:
247 fOpenPanel->Show();
248 break;
249
250 case B_REFS_RECEIVED:
251 be_app->PostMessage(message);
252 break;
253
254 case MSG_FREE_ROM:
255 OnFreeCart();
256 break;
257
258 case MSG_CART_INFO:
259 OnCartInfo();
260 break;
261
262 case MSG_ABOUT:
263 be_app->PostMessage (B_ABOUT_REQUESTED);
264 break;
265
266 case MSG_QUIT:
267 OnQuit();
268 break;
269
270 case MSG_CPU_RUN:
271 OnRun();
272 break;
273
274 case MSG_CPU_STOP:
275 OnStop();
276 break;
277
278 case MSG_CPU_PAUSE:
279 OnPause();
280 break;
281
282 case MSG_CPU_DEBUG:
283 OnDebug();
284 break;
285
286 case MSG_RST_SOFT:
287 OnSoftReset();
288 break;
289
290 case MSG_RST_HARD:
291 OnHardReset();
292 break;
293
294 case MSG_DRAW_BITMAP:
295 // this has to go here, since the window is *guaranteed* to be locked
296 fView->DrawBitmap(fBitmap, fView->Bounds());
297 break;
298
299 case MSG_ADJ_PALETTE:
300 //if (fPaletteWindow == NULL) {
301 // fPaletteWindow = new PaletteWindow(this);
302 //}
303
304 fPaletteWindow->Show();
305
306 break;
307
308 default:
309 BDirectWindow::MessageReceived (message);
310 }
311}
312
313
314void
315PretendoWindow::WindowActivated (bool flag)
316{
317 BDirectWindow::WindowActivated (flag);
318}
319
320
321void
322PretendoWindow::MenusBeginning (void)
323{
324 BMenu *menu = BRecentFilesList::NewFileListMenu ("Load ROM"B_UTF8_ELLIPSIS,
325 NULL, NULL, this->PreferredHandler(), 10, false, NULL, 0,
326 "application/x-vnd.scanty-Pretendo");
327
328 fFileMenu->AddItem(new BMenuItem(menu, new BMessage(MSG_SHOW_OPEN)), 0);
329
330 BDirectWindow::MenusBeginning();
331}
332
333
334void
335PretendoWindow::MenusEnded (void)
336{
337 fFileMenu->RemoveItem(0L);
338 BDirectWindow::MenusEnded();
339}
340
341
342bool
343PretendoWindow::QuitRequested()
344{
345 // do not touch this code.
346 // do not even look at it.
347 // do not even breathe on it.
348 status_t ret;
349
350 delete fMutex;
351 wait_for_thread(fThread, &ret);
352
353 fRunning =
354 fDirectConnected = false;
355
356 be_app->PostMessage(B_QUIT_REQUESTED);
357
358 return true;
359}
360
361
362void
363PretendoWindow::ResizeTo (float width, float height)
364{
365 height += fMenuHeight;
366 BDirectWindow::ResizeTo (width, height);
367}
368
369
370void
371PretendoWindow::Zoom (BPoint origin, float width, float height)
372{
373 (void)origin;
374 (void)width;
375 (void)height;
376
377 float w = Bounds().right - Bounds().left;
378
379 if (w == SCREEN_WIDTH) {
380 ResizeTo ((SCREEN_WIDTH*2), (SCREEN_HEIGHT*2));
381 fDoubled = true;
382 } else {
383 if (w == SCREEN_WIDTH*2) {
384 ResizeTo (SCREEN_WIDTH, SCREEN_HEIGHT);
385 }
386
387 fDoubled = false;
388 }
389
390 Hide();
391 Show();
392}
393
394
395void
396PretendoWindow::AddMenu (void)
397{
398 fMenu = new BMenuBar (BRect (0, 0, 0, 0), "menu");
399 AddChild (fMenu);
400
401 fFileMenu = new BMenu ("File");
402 fMenu->AddItem (fFileMenu);
403
404 fEmuMenu = new BMenu ("Emulator");
405 fMenu->AddItem (fEmuMenu);
406
407 fVideoMenu = new BMenu ("Render");
408 fMenu->AddItem (fVideoMenu);
409
410// fAudioMenu = new BMenu ("Audio");
411// fMenu->AddItem (fAudioMenu);
412
413 fVideoMenu->AddItem(new BMenuItem ("No Output", new BMessage (MSG_CHANGE_RENDER)));
414 fVideoMenu->AddItem(new BMenuItem ("BView/BBitmap", new BMessage(MSG_CHANGE_RENDER)));
415 fVideoMenu->AddItem(new BMenuItem ("BView/Overlay", new BMessage(MSG_CHANGE_RENDER)));
416 fVideoMenu->AddItem(new BMenuItem ("BDirectWindow", new BMessage(MSG_CHANGE_RENDER)));
417 fVideoMenu->AddItem(new BMenuItem ("BWindowScreen",
418 new BMessage(MSG_CHANGE_RENDER), 'F'));
419 fVideoMenu->SetRadioMode(true);
420 fVideoMenu->ItemAt(2)->SetMarked(false);
421
422 fFileMenu->AddItem (new BMenuItem ("Free ROM", new BMessage (MSG_FREE_ROM)));
423 fFileMenu->AddItem(new BMenuItem("ROM Info", new BMessage(MSG_CART_INFO)));
424 fFileMenu->AddSeparatorItem();
425 fFileMenu->AddItem (new BMenuItem ("About"B_UTF8_ELLIPSIS, new BMessage(MSG_ABOUT)));
426 fFileMenu->AddSeparatorItem();
427 fFileMenu->AddItem (new BMenuItem ("Quit", new BMessage (MSG_QUIT)));
428
429 fEmuMenu->AddItem (new BMenuItem ("Start", new BMessage (MSG_CPU_RUN)));
430 fEmuMenu->AddItem (new BMenuItem ("Pause", new BMessage (MSG_CPU_PAUSE)));
431 fEmuMenu->AddItem (new BMenuItem ("Stop", new BMessage (MSG_CPU_STOP)));
432 fEmuMenu->AddSeparatorItem();
433 fEmuMenu->AddItem (new BMenuItem ("Reset (soft)", new BMessage (MSG_RST_SOFT)));
434 fEmuMenu->AddItem (new BMenuItem ("Reset (hard)", new BMessage (MSG_RST_HARD)));
435 fEmuMenu->AddSeparatorItem();
436 fEmuMenu->AddItem (new BMenuItem ("Adjust Palette"B_UTF8_ELLIPSIS,
437 new BMessage (MSG_ADJ_PALETTE)));
438 fEmuMenu->AddItem (new BMenuItem ("Debug...", new BMessage(MSG_CPU_DEBUG)));
439 fMenuHeight = fMenu->Bounds().IntegerHeight();
440}
441
442
443void
444PretendoWindow::OnLoadCart (BMessage *message)
445{
446 BString path;
447
448 if (message->FindString ("path", &path) == B_OK) {
449 OnFreeCart();
450 nes::cart.load(path.String());
451
452 if (fFramework == OVERLAY_FRAMEWORK) {
453 ClearBitmap (true);
454 } else {
455 fView->SetViewColor (0, 0, 0);
456 fView->Invalidate();
457 }
458 }
459}
460
461
462void
463PretendoWindow::OnFreeCart (void)
464{
465 OnStop();
466 nes::cart.unload();
467}
468
469
470void
471PretendoWindow::OnCartInfo (void)
472{
473 if (nes::cart.prg() != NULL) {
474 fCartInfoWindow = new CartInfoWindow();
475 fCartInfoWindow->Show();
476 }
477}
478
479void
480PretendoWindow::OnQuit (void)
481{
482 QuitRequested();
483}
484
485
486void
487PretendoWindow::OnRun (void)
488{
489 if (! fRunning) {
490 if(const boost::shared_ptr<Mapper> mapper = nes::cart.mapper()) {
491 reset(nes::HARD_RESET);
492 fMutex->Unlock();
493 fRunning = true;
494 //fAudioStream->Start();
495 }
496 }
497}
498
499
500void
501PretendoWindow::OnStop (void)
502{
503 if (fRunning) {
504 fRunning = false;
505 fMutex->Lock();
506
507 //fAudioStream->Stop();
508
509 if (fFramework == OVERLAY_FRAMEWORK) {
510 ClearBitmap (true);
511 } else {
512 fView->SetViewColor (0, 0, 0);
513 fView->Invalidate();
514 }
515 }
516
517 fPaused = false;
518 fEmuMenu->ItemAt(1)->SetMarked(false);
519
520
521}
522
523
524void
525PretendoWindow::OnPause (void)
526{
527 if (fRunning) {
528 if (fPaused) {
529 fMutex->Unlock();
530 fEmuMenu->ItemAt(1)->SetMarked(false);
531 //fAudioStream->Start();
532 } else {
533 fMutex->Unlock();
534 fEmuMenu->ItemAt(1)->SetMarked(true);
535 //fAudioStream->Stop();
536 }
537
538 fPaused = !fPaused;
539 }
540}
541
542
543void
544PretendoWindow::OnSoftReset (void)
545{
546 reset(nes::SOFT_RESET);
547}
548
549
550void
551PretendoWindow::OnHardReset (void)
552{
553 reset(nes::HARD_RESET);
554}
555
556
557void
558PretendoWindow::OnDebug (void)
559{
560}
561
562
563void
564PretendoWindow::RenderLine8 (uint8 *dest, const uint8 *source, int intensity)
565{
566 int32 width = SCREEN_WIDTH / 4;
567 uint8 *palette = reinterpret_cast<uint8 *>(fMappedPalette[intensity]);
568
569 while (width--) {
570 *(dest+0) = palette[*source++];
571 *(dest+1) = palette[*source++];
572 *(dest+2) = palette[*source++];
573 *(dest+3) = palette[*source++];
574 dest += 4 * sizeof(uint8);
575 }
576}
577
578
579void
580PretendoWindow::RenderLine16 (uint8 *dest, const uint8 *source, int intensity)
581{
582 int32 width = SCREEN_WIDTH / 4;
583 uint16 *palette = reinterpret_cast<uint16 *>(fMappedPalette[intensity]);
584
585 while (width--) {
586 *(uint16 *)(dest+0) = palette[*source++];
587 *(uint16 *)(dest+2) = palette[*source++];
588 *(uint16 *)(dest+4) = palette[*source++];
589 *(uint16 *)(dest+6) = palette[*source++];
590 dest += 4 * sizeof(uint16);
591 }
592}
593
594
595void
596PretendoWindow::RenderLine32 (uint8 *dest, const uint8 *source, int intensity)
597{
598 int32 width = SCREEN_WIDTH / 4;
599 uint32 const *palette = reinterpret_cast<uint32 *>(fMappedPalette[intensity]);
600
601 while (width--) {
602 *(uint32 *)(dest+0) = palette[*source++];
603 *(uint32 *)(dest+4) = palette[*source++];
604 *(uint32 *)(dest+8) = palette[*source++];
605 *(uint32 *)(dest+12) = palette[*source++];
606 dest += 4 * sizeof(uint32);
607 }
608}
609
610
611void
612PretendoWindow::ClearDirty (void)
613{
614 uint32 *start = reinterpret_cast<uint32 *>(fDirtyBuffer.bits);
615 uint32 *end = reinterpret_cast<uint32 *>(fDirtyBuffer.bits) + (SCREEN_WIDTH*2) * (SCREEN_HEIGHT*2);
616
617 if (fClear > 0) {
618 while (start < end) {
619 *start++ ^= 0xffffffff;
620 }
621
622 fClear--;
623 }
624}
625
626
627void
628PretendoWindow::ClearBitmap (bool overlay)
629{
630 if (overlay) {
631 uint8 *bits = fOverlayBits;
632 for (int32 y = 0; y < PretendoWindow::SCREEN_HEIGHT; y++) {
633 for (int32 row = 0; row < fOverlayBitmap->BytesPerRow(); row += 2) {
634 *(uint16 *)(bits+row) = (128 << 8) | (16 >> 0);
635 }
636
637 bits += fOverlayBitmap->BytesPerRow();
638 }
639 } else {
640 memset (fBitmapBits, 0x0, fBitmap->BitsLength());
641 }
642}
643
644
645void
646PretendoWindow::SetRenderer (color_space cs)
647{
648 switch (cs) {
649 default:
650 case B_CMAP8:
651 for (int32 i = 0; i < 8; i++) {
652 fMappedPalette[i] = reinterpret_cast<uint8 *>(&fPalette8[i]);
653 }
654
655 LineRenderer = &PretendoWindow::RenderLine8;
656 break;
657
658 case B_RGB15:
659 for (int32 i = 0; i < 8; i++) {
660 fMappedPalette[i] = reinterpret_cast<uint8 *>(&fPalette15[i]);
661 }
662
663 LineRenderer = &PretendoWindow::RenderLine16;
664 break;
665
666 case B_RGB16:
667 for (int32 i = 0; i < 8; i++) {
668 fMappedPalette[i] = reinterpret_cast<uint8 *>(&fPalette16[i]);
669 }
670
671 LineRenderer = &PretendoWindow::RenderLine16;
672 break;
673
674 case B_RGB32:
675 for (int32 i = 0; i < 8; i++) {
676 fMappedPalette[i] = reinterpret_cast<uint8 *>(&fPalette32[i]);
677 }
678
679 LineRenderer = &PretendoWindow::RenderLine32;
680 break;
681 }
682}
683
684
685void
686PretendoWindow::SetFrontBuffer (uint8 *bits, color_space cs, int32 pixel_width,
687 int32 row_bytes)
688{
689 fFrontBuffer.bits = reinterpret_cast<uint8 *>(bits);
690 fFrontBuffer.pixel_format = cs;
691 fFrontBuffer.pixel_width = pixel_width;
692 fFrontBuffer.row_bytes = row_bytes;
693
694 if (fFramework == WINDOWSCREEN_FRAMEWORK) {
695 memset (fFrontBuffer.bits, 0x0, 480 * fFrontBuffer.row_bytes);
696 memset (fDirtyBuffer.bits, 0xff, 480 * fFrontBuffer.row_bytes);
697 fFrontBuffer.bits += (640 - SCREEN_WIDTH*2) / 2;
698 } else {
699 for (int32 y = 0; y < SCREEN_HEIGHT; y++) {
700 fLineOffsets[y] = fBackBuffer.bits + y * SCREEN_WIDTH * pixel_width;
701 }
702 }
703
704 SetRenderer (cs);
705}
706
707
708void
709PretendoWindow::ChangeFramework (VIDEO_FRAMEWORK fw)
710{
711 if (fFramework == fw) {
712 return;
713 }
714
715 fFrameworkChanging = true;
716 fPrevFramework = fFramework;
717 fFramework = fw;
718
719 fVideoMenu->ItemAt(fFramework)->SetMarked(true);
720
721 fVideoLocker.Lock();
722
723 // tear down previous framework
724 switch (fPrevFramework) {
725 case NO_FRAMEWORK:
726 case DIRECTWINDOW_FRAMEWORK:
727 // nothing to do here
728 break;
729
730 case BITMAP_FRAMEWORK:
731 ClearBitmap (false);
732 break;
733
734 case OVERLAY_FRAMEWORK:
735 ClearBitmap (true);
736 fView->ClearViewOverlay();
737 fView->SetViewColor(0, 0, 0);
738 fView->Invalidate();
739 break;
740
741 case WINDOWSCREEN_FRAMEWORK:
742 fVideoLocker.Unlock();
743
744 if (fVideoScreen->Lock()) {
745 fVideoScreen->Quit();
746 }
747
748 fVideoLocker.Lock();
749 break;
750 }
751
752 // build new framework
753 switch (fFramework) {
754 case NO_FRAMEWORK:
755 // use the bitmap's info as a dummy
756 SetFrontBuffer (fBitmapBits, B_CMAP8, 1, fBitmap->BytesPerRow());
757 fView->Invalidate();
758 break;
759
760 case BITMAP_FRAMEWORK:
761 SetFrontBuffer (fBitmapBits, B_CMAP8, 1, fBitmap->BytesPerRow());
762 ClearBitmap (false);
763 fView->Invalidate();
764 break;
765
766 case OVERLAY_FRAMEWORK:
767 rgb_color key;
768 SetFrontBuffer (fOverlayBits, B_RGB16, 2, fOverlayBitmap->BytesPerRow());
769 ClearBitmap (true);
770 fView->SetViewOverlay (fOverlayBitmap, fOverlayBitmap->Bounds(),
771 fView->Bounds(), &key, B_FOLLOW_ALL, B_OVERLAY_FILTER_HORIZONTAL
772 | B_OVERLAY_FILTER_VERTICAL);
773 fView->SetViewColor (key);
774 fView->Invalidate();
775 break;
776
777 case DIRECTWINDOW_FRAMEWORK:
778 // front buffer *must* be set in DirectConnected(), not here.
779 Hide();
780 Show();
781 SetRenderer (BScreen().ColorSpace());
782 break;
783
784 case WINDOWSCREEN_FRAMEWORK:
785 fVideoLocker.Unlock();
786 fVideoScreen = new VideoScreen (this);
787 fVideoScreen->Show();
788 fVideoLocker.Lock();
789 snooze (1000000); // extent of my current creative side
790 SetFrontBuffer (fVideoScreen->Bits(), B_CMAP8, 1, fVideoScreen->RowBytes());
791 fFullScreen = true;
792 break;
793 }
794
795 fVideoLocker.Unlock();
796 fFrameworkChanging = false;
797}
798
799
800void
801PretendoWindow::DrawDirect (void)
802{
803 clipping_rect *clip = fClipInfo.clip_list;
804 uint8 *dest;
805 uint8 *source;
806 uint8 *dirty;
807 size_t size;
808
809 if (! fDoubled) {
810 for (int32 i = 0; i < fClipInfo.clip_count; i++, clip++) {
811 int32 x = (clip->left - fClipInfo.bounds.left) * fPixelWidth;
812 int32 y = (clip->top - fClipInfo.bounds.top);
813 int32 w = clip->right - clip->left + 1;
814 int32 h = clip->bottom - clip->top + 1;
815
816 dest = fFrontBuffer.bits + y * fFrontBuffer.row_bytes + clip->left
817 * fPixelWidth;
818 source = fBackBuffer.bits + y * fBackBuffer.row_bytes + x;
819 dirty = fDirtyBuffer.bits + y * fBackBuffer.row_bytes + x;
820 size = w * fPixelWidth;
821
822 while (h > 0) {
823 blit_windowed_dirty_mmx (source, dirty, dest, size, fPixelWidth);
824 source += fBackBuffer.row_bytes;
825 dirty += fBackBuffer.row_bytes;
826 dest += fFrontBuffer.row_bytes;
827 h--;
828 }
829 }
830 } else {
831 int32 h = fClipInfo.bounds.bottom - fClipInfo.bounds.top + 1;
832
833 for (int32 i = 0; i < fClipInfo.clip_count; i++, clip++) {
834 int32 x = ((clip->left - fClipInfo.bounds.left) >> 1) * fPixelWidth;
835 int32 w = clip->right - clip->left + 1;
836
837 for (int32 y = 0; y < h; y += 2) {
838 if (clip->top - fClipInfo.bounds.top <= y
839 && clip->bottom - fClipInfo.bounds.top >= y) {
840
841 source = fBackBuffer.bits + (y / 2) * fBackBuffer.row_bytes + x;
842 dirty = fDirtyBuffer.bits + (y / 2) * fBackBuffer.row_bytes + x;
843 dest = fFrontBuffer.bits + y * fFrontBuffer.row_bytes + clip->left
844 * fPixelWidth;
845 size = w * fPixelWidth;
846
847 blit_2x_windowed_dirty_mmx (source, dirty, dest, size,
848 fPixelWidth, fFrontBuffer.row_bytes);
849 }
850 }
851 }
852 }
853}
854
855
856void
857PretendoWindow::BlitScreen (void)
858{
859 if (fFrameworkChanging || ! fFramework) {
860 return;
861 }
862
863 fVideoLocker.Lock();
864 uint8 *source;
865 uint8 *dest;
866 size_t size;
867
868 switch (fFramework) {
869 case NO_FRAMEWORK:
870 ; // we should never be here
871
872 case BITMAP_FRAMEWORK:
873 source = reinterpret_cast<uint8 *>(fBackBuffer.bits);
874 dest = reinterpret_cast<uint8 *>(fBitmapBits);
875 size = PretendoWindow::SCREEN_WIDTH;
876
877 for (int32 y = 0; y < SCREEN_HEIGHT; y++) {
878 sse_copy (dest, source, size);
879 source += fBackBuffer.row_bytes;
880 dest += fBitmap->BytesPerRow();
881 }
882
883 PostMessage (MSG_DRAW_BITMAP);
884 fVideoLocker.Unlock();
885 return;
886
887 case OVERLAY_FRAMEWORK:
888 // blit w/overlay
889 source = reinterpret_cast<uint8 *>(fBackBuffer.bits);
890 dest = reinterpret_cast<uint8 *>(fOverlayBits);
891 size = PretendoWindow::SCREEN_WIDTH / 2;
892
893 // blit_overlay(dest, source, size, fPaletteY, fPaletteYCbCr);
894
895 #if 0
896 for (int32 y = 0; y < PretendoWindow::SCREEN_HEIGHT; y++) {
897 asm volatile ("pushl %%edi\n"
898 "pushl %%esi\n"
899 "pushl %%ebx\n"
900 "pushl %%ebp\n"
901
902 "movl %0, %%edi\n" //dest
903 "movl %1, %%esi\n" //src
904 "movl %2, %%ecx\n" //size
905 "movl %3, %%eax\n" //Y
906 "movl %4, %%edx\n" //YCbCr
907
908 "1:\n"
909 "movl (%%esi), %%ebx\n"
910 "shrl $16, %%ebx\n"
911 "movl (%%eax,%%ebx,4), %%ebx\n"
912 "shll $16, %%ebx\n"
913
914 "movl (%%esi), %%ebp\n"
915 "andl $0xffff, %%ebp\n"
916 "movl (%%edx,%%ebp,4), %%ebp\n"
917
918 "orl %%ebx, %%ebp\n"
919
920 "movl %%ebp, (%%edi)\n"
921 "addl $4, %%edi\n"
922 "addl $4, %%esi\n"
923
924 "subl $1, %%ecx\n"
925 "jnz 1b\n"
926
927 "popl %%ebp\n"
928 "popl %%ebx\n"
929 "popl %%esi\n"
930 "popl %%edi\n"
931 :
932 : "D"(dest), "S"(source), "c"(size),
933 "a"((uint32 *)fPaletteY), "d" ((uint32 *)fPaletteYCbCr)
934 : "%ebx", "%ebp"
935 );
936
937
938
939 source += fBackBuffer.row_bytes;
940 dest += fOverlayBitmap->BytesPerRow();
941 }
942 #endif
943
944 fVideoLocker.Unlock();
945 return;
946
947 case DIRECTWINDOW_FRAMEWORK:
948 if (fDirectConnected) {
949 ClearDirty();
950 DrawDirect();
951 }
952
953 fVideoLocker.Unlock();
954 return;
955
956 case WINDOWSCREEN_FRAMEWORK:
957 if (fFullScreen) {
958 dest = fFrontBuffer.bits;
959 source = fBackBuffer.bits;
960
961 uint8 *dirty = fDirtyBuffer.bits;
962 uint32 dx = fFrontBuffer.row_bytes;
963 uint32 sx = fBackBuffer.row_bytes;
964
965 for (int32 y = 0; y < PretendoWindow::SCREEN_HEIGHT; y++) {
966 blit_2x_dirty_mmx(dest, source, dirty, dx, SCREEN_WIDTH);
967 dest += (dx * 2);
968 source += sx;
969 dirty += sx;
970 }
971 }
972
973 fVideoLocker.Unlock();
974 return;
975 }
976}
977
978
979void
980PretendoWindow::submit_scanline(int scanline, int intensity, const uint8_t *source)
981{
982 (this->*LineRenderer)(fLineOffsets[scanline], source, intensity);
983}
984
985void
986PretendoWindow::set_palette(const color_emphasis_t *intensity, const rgb_color_t *pal)
987{
988 int32 i, j;
989 rgb_color c;
990
991 // rgb palettes
992 for (i = 0; i < 8; i++) {
993 for (j = 0; j < 64; j++) {
994 c.red = (pal[j].r * intensity[i].r);
995 c.green = (pal[j].g * intensity[i].g);
996 c.blue = (pal[j].b * intensity[i].b);
997
998 fPalette8[i][j] = BScreen().IndexForColor (c.red, c.green, c.blue);
999
1000 fPalette15[i][j] = ((c.red & 0xf8) << 7);
1001 fPalette15[i][j] |= ((c.green & 0xf8) << 2);
1002 fPalette15[i][j] |= ((c.blue & 0xf8) >> 3);
1003
1004 fPalette16[i][j] = ((c.red & 0xf8) << 8);
1005 fPalette16[i][j] |= ((c.green & 0xfc) << 3);
1006 fPalette16[i][j] |= ((c.blue & 0xf8) >> 3);
1007
1008 fPalette32[i][j] = (c.red << 16) | (c.green << 8) | (c.blue & 0xff);
1009 }
1010 }
1011
1012 // luma/chroma palette (for overlay)
1013 uint8 y;
1014 uint8 cb[65536];
1015 uint8 cr[65536];
1016
1017 for (i = 0; i < 65536; i++) {
1018 // separate r,g,b components
1019 c.red = ((i & 0xf800) >> 11) << 3;
1020 c.green = ((i & 0x07e0) >> 5) << 2;
1021 c.blue = (i & 0x001f) << 3;
1022
1023 // convert to y,cb,cr components
1024 y = fPaletteY[i] = (uint8)((int16)((double)
1025 (77.0 / 256.0) * (219 * (c.red / 256.0) + 16) +
1026 (150.0 / 256.0) * (219 * (c.green / 256.0) + 16) +
1027 (29.0 / 256.0) * (219 * (c.blue / 256.0) + 16)));
1028
1029 cb[i] = (uint8)((int16)((double)
1030 (-44.0 / 256.0) * (219 * (c.red / 256.0) + 16) -
1031 (87.0 / 256.0) * (219 * (c.green / 256.0) + 16) +
1032 (131.0 / 256.0) * (219 * (c.blue / 256.0) + 16) + 128.0));
1033
1034 cr[i] = (uint8)((int16)((double)
1035 (131.0 / 256.0) * (219 * (c.red / 256.0) + 16) -
1036 (110.0 / 256.0) * (219 * (c.green / 256.0) + 16) -
1037 (21.0 / 256.0) * (219 * (c.blue / 256.0) + 16) + 128.0));
1038
1039 fPaletteYCbCr[i] = (cr[i] << 24) | (0 << 16) | (cb[i] << 8) | (y & 0xff);
1040 }
1041}
1042
1043
1044void
1045PretendoWindow::start_frame()
1046{
1047 fMainLocker.Lock();
1048
1049 if (fDirectConnected) {
1050 fPixelWidth = fFrontBuffer.pixel_width;
1051 fBackBuffer.row_bytes = SCREEN_WIDTH * fPixelWidth;
1052 }
1053}
1054
1055
1056void
1057PretendoWindow::end_frame()
1058{
1059 uint8 *buffer = const_cast<uint8 *>(nes::apu.buffer());
1060 //fAudioStream->Stream(buffer, 735);
1061 BlitScreen();
1062 fMainLocker.Unlock();
1063}
1064
1065
1066status_t
1067PretendoWindow::emulation_thread (void *data)
1068{
1069 PretendoWindow *w = reinterpret_cast<PretendoWindow *>(data);
1070
1071 while (1) {
1072 if (w->Mutex()->Lock() != B_NO_ERROR) {
1073 break;
1074 }
1075
1076 w->start_frame();
1077 nes::run_frame(w);
1078 w->end_frame();
1079 w->ReadKeyStates();
1080 w->Mutex()->Unlock();
1081 }
1082
1083 return B_OK;
1084}
1085
1086
1087inline void
1088PretendoWindow::CheckKey (int32 index, int32 key)
1089{
1090 nes::input.controller1().keystate_[index] =
1091 fKeyStates.key_states[key >> 3] & (1 << (7 - (key % 8)));
1092}
1093
1094void
1095PretendoWindow::ReadKeyStates (void)
1096{
1097 get_key_info(&fKeyStates);
1098
1099 CheckKey(Controller::INDEX_UP, kKeyUp);
1100 CheckKey(Controller::INDEX_DOWN, kKeyDown);
1101 CheckKey(Controller::INDEX_LEFT, kKeyLeft);
1102 CheckKey(Controller::INDEX_RIGHT, kKeyRight);
1103 CheckKey(Controller::INDEX_SELECT, kKeySelect);
1104 CheckKey(Controller::INDEX_START, kKeyStart);
1105 CheckKey(Controller::INDEX_B, kKeyB);
1106 CheckKey(Controller::INDEX_A, kKeyA);
1107}
1108