//------------------------------------------------- // render_object: Internal processing callback // that renders to the backing bitmap and then // copies the result to the destination. //------------------------------------------------- void render_object(bitmap_ind16 bitmap, rectangle cliprect, Pointer <uint16_t> entry) //void atari_motion_objects_device::render_object(bitmap_ind16 &bitmap, const rectangle &cliprect, const uint16_t *entry) { // select the gfx element and save off key information int rawcode = (int)m_codemask.extract(entry); gfx_element gfx = m_gfxdecode.op0.gfx(m_gfxlookup[rawcode >> 8]); int save_granularity = gfx.granularity(); int save_colorbase = (int)gfx.colorbase(); int save_colors = (int)gfx.colors(); gfx.set_granularity(1); gfx.set_colorbase(0); gfx.set_colors(65536); // extract data from the various words int code = (int)m_codelookup[rawcode]; int color = m_colorlookup[m_colormask.extract(entry)]; int xpos = m_xposmask.extract(entry) + m_xoffset; int ypos = -m_yposmask.extract(entry); int hflip = m_hflipmask.extract(entry); int vflip = m_vflipmask.extract(entry); int width = m_widthmask.extract(entry) + 1; int height = m_heightmask.extract(entry) + 1; int priority = m_prioritymask.extract(entry); // compute the effective color, merging in priority color = (color * save_granularity) | (priority << PRIORITY_SHIFT); color += m_atari_motion_objects_config.m_palettebase; // add in the scroll positions if we're not in absolute coordinates if (m_absolutemask.extract(entry) == 0) { xpos -= (int)m_xscroll; ypos -= (int)m_yscroll; } // adjust for height ypos -= height << m_tileyshift; // handle previous hold bits if (m_next_xpos != 123456) { xpos = (int)m_next_xpos; } m_next_xpos = 123456; // check for the hold bit if (m_neighbormask.extract(entry) != 0) { if (!m_atari_motion_objects_config.m_nextneighbor) { xpos = (int)m_last_xpos + m_tilewidth; } else { m_next_xpos = (uint32_t)(xpos + m_tilewidth); } } m_last_xpos = (uint32_t)xpos; // adjust the final coordinates xpos &= m_bitmapxmask; ypos &= m_bitmapymask; if (xpos >= bitmap.width()) { xpos -= m_bitmapwidth; } if (ypos >= bitmap.height()) { ypos -= m_bitmapheight; } // is this one special? if (m_specialmask.mask() == 0 || m_specialmask.extract(entry) != m_atari_motion_objects_config.m_specialvalue) { // adjust for h flip int xadv = m_tilewidth; if (hflip != 0) { xpos += (width - 1) << m_tilexshift; xadv = -xadv; } // adjust for v flip int yadv = m_tileheight; if (vflip != 0) { ypos += (height - 1) << m_tileyshift; yadv = -yadv; } // standard order is: loop over Y first, then X if (!m_atari_motion_objects_config.m_swapxy) { // loop over the height for (int y = 0, sy = ypos; y < height; y++, sy += yadv) { // clip the Y coordinate if (sy <= cliprect.top() - m_tileheight) { code += width; continue; } else if (sy > cliprect.bottom()) { break; } // loop over the width for (int x = 0, sx = xpos; x < width; x++, sx += xadv, code++) { // clip the X coordinate if (sx <= -cliprect.left() - m_tilewidth || sx > cliprect.right()) { continue; } // draw the sprite gfx.transpen_raw(bitmap, cliprect, (u32)code, (u32)color, hflip, vflip, sx, sy, m_atari_motion_objects_config.m_transpen); mark_dirty(sx, sx + m_tilewidth - 1, sy, sy + m_tileheight - 1); } } } // alternative order is swapped else { // loop over the width for (int x = 0, sx = xpos; x < width; x++, sx += xadv) { // clip the X coordinate if (sx <= cliprect.left() - m_tilewidth) { code += height; continue; } else if (sx > cliprect.right()) { break; } // loop over the height for (int y = 0, sy = ypos; y < height; y++, sy += yadv, code++) { // clip the X coordinate if (sy <= -cliprect.top() - m_tileheight || sy > cliprect.bottom()) { continue; } // draw the sprite gfx.transpen_raw(bitmap, cliprect, (u32)code, (u32)color, hflip, vflip, sx, sy, m_atari_motion_objects_config.m_transpen); mark_dirty(sx, sx + m_tilewidth - 1, sy, sy + m_tileheight - 1); } } } } // restore original gfx information gfx.set_granularity((u16)save_granularity); gfx.set_colorbase((u16)save_colorbase); gfx.set_colors((u32)save_colors); }
} //void set_config(const atari_motion_objects_config &config) { static_cast<atari_motion_objects_config &>(*this) = config; } //void set_xoffset(int xoffset) { m_xoffset = xoffset; } // getters //int bank() const { return m_bank; } //int xscroll() const { return m_xscroll; } //int yscroll() const { return m_yscroll; } //std::vector<uint32_t> &code_lookup() { return m_codelookup; } //std::vector<uint8_t> &color_lookup() { return m_colorlookup; } //std::vector<uint8_t> &gfx_lookup() { return m_gfxlookup; } // setters //void set_bank(int bank) { m_bank = bank; } //void set_xscroll(int xscroll) { m_xscroll = xscroll & m_bitmapxmask; } //void set_yscroll(int yscroll) { m_yscroll = yscroll & m_bitmapymask; } //void set_scroll(int xscroll, int yscroll) { set_xscroll(xscroll); set_yscroll(yscroll); } //void set_slipram(uint16_t *ram) { m_slipram = ram; } // rendering //------------------------------------------------- // draw: Render the motion objects to the // destination bitmap. //------------------------------------------------- protected override void draw(bitmap_ind16 bitmap, rectangle cliprect) { // compute start/stop bands int startband = ((cliprect.top() + (int)m_yscroll - m_atari_motion_objects_config.m_slipoffset) & m_bitmapymask) >> m_slipshift; int stopband = ((cliprect.bottom() + (int)m_yscroll - m_atari_motion_objects_config.m_slipoffset) & m_bitmapymask) >> m_slipshift; if (startband > stopband) { startband -= m_bitmapheight >> m_slipshift; } if (m_slipshift == 0) { stopband = startband; } // loop over SLIP bands for (int band = startband; band <= stopband; band++) { // compute the starting link and clip for the current band rectangle bandclip = cliprect; int link = 0; if (m_slipshift != 0) { // extract the link from the SLIP RAM link = (m_slipram[band & m_sliprammask] >> m_linkmask.shift()) & m_linkmask.mask(); // compute minimum Y and wrap around if necessary bandclip.min_y = ((band << m_slipshift) - (int)m_yscroll + m_atari_motion_objects_config.m_slipoffset) & m_bitmapymask; if (bandclip.min_y >= bitmap.height()) { bandclip.min_y -= m_bitmapheight; } // maximum Y is based on the minimum bandclip.set_height(1 << m_slipshift); // keep within the cliprect bandclip &= cliprect; } // if this matches the last link, we don't need to re-process the list build_active_list(link); // initialize the parameters m_next_xpos = 123456; // safety check if (m_activelist == m_activelast.Buffer && m_activelast.Offset == 0) //if (m_activelist == m_activelast) { continue; } // set the start and end points Pointer <uint16_t> first; //uint16_t *first, *last; Pointer <uint16_t> last; int step; if (m_atari_motion_objects_config.m_reverse) { first = m_activelast - 4; last = new Pointer <uint16_t>(m_activelist); step = -4; } else { first = new Pointer <uint16_t>(m_activelist); last = m_activelast - 4; step = 4; } // render the mos for (Pointer <uint16_t> current = new Pointer <uint16_t>(first); ; current += step) //for (uint16_t *current = first; ; current += step) { render_object(bitmap, bandclip, current); if (current.Buffer == last.Buffer && current.Offset == last.Offset) //if (current == last) { break; } } } }