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 ) |