trunk/src/mame/drivers/littlerb.c
r17603 | r17604 | |
11 | 11 | |
12 | 12 | /* |
13 | 13 | |
14 | | strange vdp/memory access chip.. |
15 | | at the moment gfx / palettes etc. get drawn then erased, I think it's a blitter, with multiple layers |
16 | | some of the 'sprite entries' seem a different size, or alignment, hence the bad sprites on the title |
17 | | screen. no idea how layers are seleced / cleared right now either |
| 14 | Notes: |
18 | 15 | |
| 16 | VDP (Blitter) handling is not 100% correct |
| 17 | A brief original video (recorded by Dox) can be seen at https://www.youtube.com/watch?v=8THpeogarUk |
19 | 18 | |
20 | | maybe it needs read commands working so it knows how many sprites are in |
21 | | the list? |
| 19 | Overall addressing / auto-increment etc. of the VDP device is not fully understood, but for now |
| 20 | appears to be good enough for the game. |
22 | 21 | |
23 | | maybe the vdp 'commands' can be used to store and get back |
24 | | write addresses? |
| 22 | How we distinguish between mode setting (clear, copy, cliprect etc.) VDP commands and actual sprite |
| 23 | commands is not yet understood. All 'sprite' sections of the blit list seem to be terminated with |
| 24 | a 0x0000 word, but it isn't clear how the blocks are started, the current method relies on some bits |
| 25 | of the sprite data offset to determine if we're sprite data, or a command. Maybe this is just a |
| 26 | quirk of the hardware, and you can't have sprites at those offsets? |
25 | 27 | |
26 | | most graphics are stored as packed 4bpp in RAM, expanded before |
27 | | writing to the vdp device. actual gfx are 8bpp. |
| 28 | Copy / Scroll are not yet implemented, see the Smileys between scenes in the original video. |
| 29 | (Clipping is implemented, but might be per layer, so you do see the sprites vanish, but no |
| 30 | smileys are drawn) |
28 | 31 | |
| 32 | How big are the actual framebuffers? Are both also double buffered? |
| 33 | |
29 | 34 | Sound pitch is directly correlated with irqs, scanline timings and pixel clock, |
30 | 35 | so it's surely not 100% correct. Sound sample playbacks looks fine at current time tho. |
31 | 36 | |
| 37 | ------ |
32 | 38 | |
| 39 | |
| 40 | |
33 | 41 | Dip sw.1 |
34 | 42 | -------- |
35 | 43 | | Coin 1 | Coin 2 | |
r17603 | r17604 | |
88 | 96 | m_dacl(*this, "dacl"), |
89 | 97 | m_dacr(*this, "dacr"), |
90 | 98 | m_region4(*this, "region4") |
91 | | { |
| 99 | { |
92 | 100 | m_1ff80804 = -1; |
93 | 101 | } |
94 | 102 | |
r17603 | r17604 | |
111 | 119 | UINT32 m_lasttype2pc; |
112 | 120 | UINT8 m_sound_index_l,m_sound_index_r; |
113 | 121 | UINT16 m_sound_pointer_l,m_sound_pointer_r; |
| 122 | |
| 123 | bitmap_ind16 *m_temp_bitmap_sprites; |
| 124 | bitmap_ind16 *m_temp_bitmap_sprites_back; |
114 | 125 | |
115 | | bitmap_ind16 m_temp_bitmap_sprites; |
116 | | bitmap_ind16 m_temp_bitmap_sprites_back; // not currently used |
117 | 126 | |
118 | | |
119 | 127 | DECLARE_WRITE16_MEMBER(spritelist_w); |
120 | 128 | DECLARE_WRITE16_MEMBER(region4_w); |
121 | 129 | DECLARE_READ16_MEMBER(buffer_status_r); |
r17603 | r17604 | |
155 | 163 | { |
156 | 164 | littlerb_printf("littlerb_1ff80804_w %04x\n", data); |
157 | 165 | |
158 | | if ((!(m_spritelist[2] & 0x1000)) && (!(m_spritelist[1] & 0x1000))) |
| 166 | if ((!(m_spritelist[2] & 0x1000)) && (!(m_spritelist[1] & 0x1000))) |
159 | 167 | { |
160 | 168 | |
161 | 169 | } |
162 | | else |
| 170 | else |
163 | 171 | { |
164 | 172 | if (!(m_spritelist[2] & 0x1000)) |
165 | | m_temp_bitmap_sprites_back.fill(0, m_temp_bitmap_sprites_back.cliprect()); |
| 173 | m_temp_bitmap_sprites_back->fill(0, m_temp_bitmap_sprites_back->cliprect()); |
166 | 174 | |
167 | 175 | } |
168 | | |
| 176 | |
169 | 177 | littlerb_draw_sprites(space.machine()); |
170 | 178 | |
171 | 179 | |
r17603 | r17604 | |
507 | 515 | PORT_DIPNAME( 0x2000, 0x2000, DEF_STR( Unknown ) ) |
508 | 516 | PORT_DIPSETTING( 0x2000, DEF_STR( Off ) ) |
509 | 517 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) |
510 | | PORT_DIPNAME( 0x4000, 0x4000, "GAME/TEST??" ) // changes what gets uploaded |
511 | | PORT_DIPSETTING( 0x4000, DEF_STR( Off ) ) |
512 | | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) |
| 518 | PORT_SERVICE( 0x4000, IP_ACTIVE_LOW ) |
513 | 519 | PORT_DIPNAME( 0x8000, 0x8000, DEF_STR( Unknown ) ) |
514 | 520 | PORT_DIPSETTING( 0x8000, DEF_STR( Off ) ) |
515 | 521 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) |
r17603 | r17604 | |
552 | 558 | littlerb_state *state = screen.machine().driver_data<littlerb_state>(); |
553 | 559 | bitmap.fill(0, cliprect); |
554 | 560 | |
555 | | copybitmap_trans(bitmap, state->m_temp_bitmap_sprites_back, 0, 0, 0, 0, cliprect, 0); |
556 | | copybitmap_trans(bitmap, state->m_temp_bitmap_sprites, 0, 0, 0, 0, cliprect, 0); |
| 561 | copybitmap_trans(bitmap, *state->m_temp_bitmap_sprites_back, 0, 0, 0, 0, cliprect, 0); |
| 562 | copybitmap_trans(bitmap, *state->m_temp_bitmap_sprites, 0, 0, 0, 0, cliprect, 0); |
557 | 563 | |
558 | 564 | return 0; |
559 | 565 | } |
r17603 | r17604 | |
588 | 594 | VIDEO_START( littlerb ) |
589 | 595 | { |
590 | 596 | littlerb_state *state = machine.driver_data<littlerb_state>(); |
| 597 | // machine.primary_screen->register_screen_bitmap(state->m_temp_bitmap_sprites_back); |
| 598 | // machine.primary_screen->register_screen_bitmap(state->m_temp_bitmap_sprites); |
591 | 599 | |
| 600 | state->m_temp_bitmap_sprites_back = auto_bitmap_ind16_alloc(machine,512,512); |
| 601 | state->m_temp_bitmap_sprites = auto_bitmap_ind16_alloc(machine,512,512); |
592 | 602 | |
593 | | machine.primary_screen->register_screen_bitmap(state->m_temp_bitmap_sprites_back); |
594 | | machine.primary_screen->register_screen_bitmap(state->m_temp_bitmap_sprites); |
| 603 | |
595 | 604 | state->m_spritelist = (UINT16*)auto_alloc_array_clear(machine, UINT16, 0x20000); |
596 | 605 | |
597 | 606 | } |
r17603 | r17604 | |
616 | 625 | drawxpos = xpos+x; |
617 | 626 | drawypos = ypos+y; |
618 | 627 | |
| 628 | // odd clipping behavior, count is only increased for visible lines? |
| 629 | // I suspect the sprite corruption if you're near the top of the screen |
| 630 | // between level changes is related to this too, data offset values are |
| 631 | // probably being adjusted as layer is scrolled (and the cliprect is changed) |
| 632 | // even if they don't move. |
| 633 | if(drawypos>=cliprect.min_y) |
| 634 | { |
| 635 | fulloffs++; |
| 636 | } |
| 637 | |
619 | 638 | if(cliprect.contains(drawxpos, drawypos)) |
620 | 639 | { |
621 | 640 | if(pix&0xff) bitmap.pix16(drawypos, drawxpos) = pix; |
622 | 641 | } |
623 | 642 | |
624 | 643 | drawxpos++; |
625 | | fulloffs++; |
626 | 644 | } |
627 | 645 | } |
628 | 646 | } |
r17603 | r17604 | |
634 | 652 | int xsize,ysize; |
635 | 653 | UINT16* spriteregion = state->m_spritelist; |
636 | 654 | //littlerb_printf("frame\n"); |
637 | | /* the spriteram format is something like this .. */ |
638 | | // for (offs=2;offs<0xc00;offs+=6) // this will draw different hud gfx.. meaning not ALL entries are 6 words(?!) command based blitter rather than RAM? (but MODE is 3800 when both the sprite 'list' is written, and gfx data?, |
639 | 655 | |
640 | 656 | int layer = 0; |
| 657 | int yoffset = 0; |
641 | 658 | |
642 | | |
643 | 659 | littlerb_printf("m_listoffset %04x\n", state->m_listoffset ); |
644 | 660 | |
645 | 661 | littlerb_printf("%04x %04x %04x %04x\n", spriteregion[0], spriteregion[1], spriteregion[2], spriteregion[3]); |
646 | 662 | |
647 | 663 | littlerb_alt_printf("start\n"); |
648 | 664 | |
| 665 | int minx = 0 , maxx = 0x14f; |
| 666 | int miny = 0 , maxy = 0x11f; |
| 667 | |
649 | 668 | for (offs=0;offs<(state->m_listoffset);) |
650 | 669 | { |
651 | 670 | |
r17603 | r17604 | |
664 | 683 | else if (spriteregion[offs+0] == 0x0040) |
665 | 684 | { |
666 | 685 | littlerb_alt_printf("Control Word %04x %04x %04x %04x %04x %04x ---- ---- ---- ----\n", spriteregion[offs+0], spriteregion[offs+1], spriteregion[offs+2], spriteregion[offs+3], spriteregion[offs+4], spriteregion[offs+5]); |
667 | | |
| 686 | |
668 | 687 | // some scroll stuff is here (title -> high score transition) |
669 | 688 | // maybe also copy area operations? |
670 | 689 | |
671 | | // probably wrong |
672 | | if ((spriteregion[offs+4]==0x6000) && (spriteregion[offs+3] & 0x1000)) |
673 | | state->m_temp_bitmap_sprites_back.fill(0, state->m_temp_bitmap_sprites_back.cliprect()); |
| 690 | |
| 691 | // this isn't understood ... note, we still have a hack before draw_sprites is called too |
| 692 | |
| 693 | // usual start of frame |
| 694 | // Control Word 0040 0090 6000 0026 0000 0012 ---- ---- ---- ---- |
| 695 | |
| 696 | // happens in the middle of list during boss death, causes sprites to vanish atm |
| 697 | // Control Word 0040 ffd6 00aa 00f8 0088 0018 ---- ---- ---- ---- |
| 698 | if (spriteregion[offs+4]==0x6000) |
| 699 | { |
| 700 | if (spriteregion[offs+3] & 0x1000) |
| 701 | state->m_temp_bitmap_sprites_back->fill(0, state->m_temp_bitmap_sprites_back->cliprect()); |
| 702 | } |
674 | 703 | else |
675 | | state->m_temp_bitmap_sprites.fill(0, state->m_temp_bitmap_sprites.cliprect()); |
| 704 | { |
| 705 | if (spriteregion[offs+1] != 0xffd6) state->m_temp_bitmap_sprites->fill(0, state->m_temp_bitmap_sprites->cliprect()); |
| 706 | } |
| 707 | |
676 | 708 | |
677 | 709 | |
| 710 | // this is some kind of scroll or copy area.. |
| 711 | // also some of the other values change |
| 712 | // this is set AFTER the graphics which need to be scrolled are sent and causes the credit text to bounce up and down instead of |
| 713 | // anything scrolling |
| 714 | //yoffset = spriteregion[offs+1] - 0x90; |
| 715 | |
| 716 | |
678 | 717 | offs += 6; |
679 | 718 | } |
680 | 719 | else if (read_dword == 0x00e40020) |
681 | 720 | { |
682 | 721 | littlerb_alt_printf("Control Word %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n", spriteregion[offs+0], spriteregion[offs+1], spriteregion[offs+2], spriteregion[offs+3], spriteregion[offs+4], spriteregion[offs+5], spriteregion[offs+6], spriteregion[offs+7], spriteregion[offs+8], spriteregion[offs+9]); |
683 | | |
| 722 | |
684 | 723 | if (spriteregion[offs+4]==0x6000) |
685 | 724 | layer = 1; |
686 | 725 | else |
687 | 726 | layer = 0; |
688 | 727 | |
689 | 728 | |
| 729 | minx = spriteregion[offs+6]; |
| 730 | maxx = spriteregion[offs+8]; |
| 731 | |
| 732 | miny = spriteregion[offs+7]; |
| 733 | maxy = spriteregion[offs+9]; |
| 734 | |
| 735 | |
690 | 736 | offs += 10; |
691 | 737 | } |
692 | 738 | else if (read_dword == 0x00e40000) |
693 | 739 | { |
| 740 | // same as above? |
694 | 741 | littlerb_alt_printf("Control Word %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n", spriteregion[offs+0], spriteregion[offs+1], spriteregion[offs+2], spriteregion[offs+3], spriteregion[offs+4], spriteregion[offs+5], spriteregion[offs+6], spriteregion[offs+7], spriteregion[offs+8], spriteregion[offs+9]); |
695 | | |
| 742 | |
696 | 743 | if (spriteregion[offs+4]==0x6000) |
697 | 744 | layer = 1; |
698 | 745 | else |
699 | 746 | layer = 0; |
700 | 747 | |
| 748 | minx = spriteregion[offs+6]; |
| 749 | maxx = spriteregion[offs+8]; |
| 750 | |
| 751 | miny = spriteregion[offs+7]; |
| 752 | maxy = spriteregion[offs+9]; |
| 753 | |
| 754 | |
701 | 755 | offs += 10; |
702 | 756 | } |
703 | 757 | else if (read_dword == 0x00000000) |
r17603 | r17604 | |
714 | 768 | if (x&0x400) x-=0x800; |
715 | 769 | if (y&0x200) y-=0x400; |
716 | 770 | |
| 771 | y+= yoffset; |
| 772 | |
717 | 773 | xsize = (spriteregion[offs+4] & 0x01ff); // background gfx for many places at 0x1ff wide |
718 | 774 | ysize = (spriteregion[offs+5] & 0x00ff); // player1/player2 texts in service mode sides are 0xff high |
719 | 775 | |
720 | 776 | |
| 777 | rectangle clip; |
| 778 | |
| 779 | clip.min_x = minx; |
| 780 | clip.max_x = maxx; |
| 781 | |
| 782 | clip.min_y = miny; |
| 783 | clip.max_y = maxy; |
| 784 | |
| 785 | // used between levels, and on boss death to clip sprite at the ground for sinking effect |
| 786 | |
| 787 | |
| 788 | if (clip.min_x > state->m_temp_bitmap_sprites->cliprect().max_x) |
| 789 | clip.min_x = state->m_temp_bitmap_sprites->cliprect().max_x; |
| 790 | |
| 791 | if (clip.min_x < state->m_temp_bitmap_sprites->cliprect().min_x) |
| 792 | clip.min_x = state->m_temp_bitmap_sprites->cliprect().min_x; |
| 793 | |
| 794 | if (clip.max_x > state->m_temp_bitmap_sprites->cliprect().max_x) |
| 795 | clip.max_x = state->m_temp_bitmap_sprites->cliprect().max_x; |
| 796 | |
| 797 | if (clip.max_x < state->m_temp_bitmap_sprites->cliprect().min_x) |
| 798 | clip.max_x = state->m_temp_bitmap_sprites->cliprect().min_x; |
| 799 | |
| 800 | |
| 801 | if (clip.min_y > state->m_temp_bitmap_sprites->cliprect().max_y) |
| 802 | clip.min_y = state->m_temp_bitmap_sprites->cliprect().max_y; |
| 803 | |
| 804 | if (clip.min_y < state->m_temp_bitmap_sprites->cliprect().min_y) |
| 805 | clip.min_y = state->m_temp_bitmap_sprites->cliprect().min_y; |
| 806 | |
| 807 | if (clip.max_y > state->m_temp_bitmap_sprites->cliprect().max_y) |
| 808 | clip.max_y = state->m_temp_bitmap_sprites->cliprect().max_y; |
| 809 | |
| 810 | if (clip.max_y < state->m_temp_bitmap_sprites->cliprect().min_y) |
| 811 | clip.max_y = state->m_temp_bitmap_sprites->cliprect().min_y; |
| 812 | |
| 813 | |
721 | 814 | littlerb_alt_printf("%04x %04x %04x %04x %04x %04x\n", spriteregion[offs+0], spriteregion[offs+1], spriteregion[offs+2], spriteregion[offs+3], spriteregion[offs+4], spriteregion[offs+5]); |
722 | 815 | |
723 | | if (layer==0) draw_sprite(machine, state->m_temp_bitmap_sprites, state->m_temp_bitmap_sprites.cliprect(),xsize,ysize,fullcode,x,y); |
724 | | else draw_sprite(machine, state->m_temp_bitmap_sprites_back, state->m_temp_bitmap_sprites_back.cliprect(),xsize,ysize,fullcode,x,y); |
| 816 | if (layer==0) draw_sprite(machine, *state->m_temp_bitmap_sprites, clip,xsize,ysize,fullcode,x,y); |
| 817 | else draw_sprite(machine, *state->m_temp_bitmap_sprites_back, clip,xsize,ysize,fullcode,x,y); |
725 | 818 | |
726 | | |
| 819 | |
727 | 820 | offs += 6; |
728 | 821 | } |
729 | 822 | } |
r17603 | r17604 | |
771 | 864 | ROM_END |
772 | 865 | |
773 | 866 | |
774 | | GAME( 1993, littlerb, 0, littlerb, littlerb, driver_device, 0, ROT0, "TCH", "Little Robin", GAME_NOT_WORKING|GAME_IMPERFECT_GRAPHICS|GAME_IMPERFECT_SOUND ) |
| 867 | GAME( 1994, littlerb, 0, littlerb, littlerb, driver_device, 0, ROT0, "TCH", "Little Robin", GAME_IMPERFECT_GRAPHICS|GAME_IMPERFECT_SOUND ) |