//------------------------------------------------- // transpen_mask - return a mask of pens that // whose indirect values match the given // transcolor //------------------------------------------------- public u32 transpen_mask(gfx_element gfx, u32 color, indirect_pen_t transcolor) { u32 entry = gfx.colorbase() + (color % gfx.colors()) * gfx.granularity(); // make sure we are in range assert(entry < m_indirect_pens.size()); assert(gfx.depth() <= 32); // either gfx->color_depth entries or as many as we can get up until the end int count = (int)Math.Min((UInt32)gfx.depth(), m_indirect_pens.size() - entry); // set a bit anywhere the transcolor matches u32 mask = 0; for (int bit = 0; bit < count; bit++) { if (m_indirect_pens[(int)entry++] == transcolor) { mask |= (UInt32)1 << bit; } } // return the final mask return(mask); }
// decoding //------------------------------------------------- // decode_gfx - parse gfx decode info and // create gfx elements //------------------------------------------------- void decode_gfx(gfx_decode_entry [] gfxdecodeinfo) { // skip if nothing to do if (gfxdecodeinfo == null) { return; } // local variables to hold mutable copies of gfx layout data gfx_layout glcopy; std.vector <u32> extxoffs = new std.vector <u32>(0); std.vector <u32> extyoffs = new std.vector <u32>(0); // loop over all elements for (u8 curgfx = 0; curgfx < digfx_global.MAX_GFX_ELEMENTS && curgfx < gfxdecodeinfo.Length && gfxdecodeinfo[curgfx].gfxlayout != null; curgfx++) { gfx_decode_entry gfx = gfxdecodeinfo[curgfx]; // extract the scale factors and xormask u32 xscale = GFXENTRY_GETXSCALE(gfx.flags); u32 yscale = GFXENTRY_GETYSCALE(gfx.flags); u32 xormask = GFXENTRY_ISREVERSE(gfx.flags) ? 7U : 0U; // resolve the region u32 region_length; ListBytesPointer region_base; //const u8 *region_base; u8 region_width; endianness_t region_endianness; if (gfx.memory_region != null) { device_t basedevice = (GFXENTRY_ISDEVICE(gfx.flags)) ? device() : device().owner(); if (GFXENTRY_ISRAM(gfx.flags)) { memory_share share = basedevice.memshare(gfx.memory_region); //assert(share != NULL); region_length = (UInt32)(8 * share.bytes()); region_base = share.ptr(); //region_base = reinterpret_cast<u8 *>(share->ptr()); region_width = share.bytewidth(); region_endianness = share.endianness(); } else { memory_region region = basedevice.memregion(gfx.memory_region); //assert(region != NULL); region_length = 8 * region.bytes(); region_base = new ListBytesPointer(region.base_(), 0); //region_base = region->base(); region_width = region.bytewidth(); region_endianness = region.endianness(); } } else { region_length = 0; region_base = null; region_width = 1; region_endianness = ENDIANNESS_NATIVE; } if (region_endianness != ENDIANNESS_NATIVE) { switch (region_width) { case 2: xormask |= 0x08; break; case 4: xormask |= 0x18; break; case 8: xormask |= 0x38; break; } } // copy the layout into our temporary variable glcopy = new gfx_layout(gfx.gfxlayout); //memcpy(&glcopy, gfx.gfxlayout, sizeof(gfx_layout)); // if the character count is a region fraction, compute the effective total if (IS_FRAC(glcopy.total)) { //assert(region_length != 0); glcopy.total = region_length / glcopy.charincrement * FRAC_NUM(glcopy.total) / FRAC_DEN(glcopy.total); } // for non-raw graphics, decode the X and Y offsets if (glcopy.planeoffset[0] != digfx_global.GFX_RAW) { // copy the X and Y offsets into our temporary arrays extxoffs.resize((int)(glcopy.width * xscale)); extyoffs.resize((int)(glcopy.height * yscale)); //memcpy(&extxoffs[0], (glcopy.extxoffs != null) ? glcopy.extxoffs : glcopy.xoffset, glcopy.width * sizeof(UInt32)); //memcpy(&extyoffs[0], (glcopy.extyoffs != null) ? glcopy.extyoffs : glcopy.yoffset, glcopy.height * sizeof(UInt32)); for (int i = 0; i < glcopy.width; i++) { extxoffs[i] = glcopy.extxoffs != null ? glcopy.extxoffs[i] : glcopy.xoffset[i]; } for (int i = 0; i < glcopy.height; i++) { extyoffs[i] = glcopy.extyoffs != null ? glcopy.extyoffs[i] : glcopy.yoffset[i]; } // always use the extended offsets here glcopy.extxoffs = extxoffs; glcopy.extyoffs = extyoffs; // expand X and Y by the scale factors if (xscale > 1) { glcopy.width *= (UInt16)xscale; for (int j = glcopy.width - 1; j >= 0; j--) { extxoffs[j] = extxoffs[(int)(j / xscale)]; } } if (yscale > 1) { glcopy.height *= (UInt16)yscale; for (int j = glcopy.height - 1; j >= 0; j--) { extyoffs[j] = extyoffs[(int)(j / yscale)]; } } // loop over all the planes, converting fractions for (int j = 0; j < glcopy.planes; j++) { u32 value1 = glcopy.planeoffset[j]; if (IS_FRAC(value1)) { //assert(region_length != 0); glcopy.planeoffset[j] = FRAC_OFFSET(value1) + region_length * FRAC_NUM(value1) / FRAC_DEN(value1); } } // loop over all the X/Y offsets, converting fractions for (int j = 0; j < glcopy.width; j++) { u32 value2 = extxoffs[j]; if (digfx_global.IS_FRAC(value2)) { //assert(region_length != 0); extxoffs[j] = FRAC_OFFSET(value2) + region_length * FRAC_NUM(value2) / FRAC_DEN(value2); } } for (int j = 0; j < glcopy.height; j++) { u32 value3 = extyoffs[j]; if (IS_FRAC(value3)) { //assert(region_length != 0); extyoffs[j] = FRAC_OFFSET(value3) + region_length * FRAC_NUM(value3) / FRAC_DEN(value3); } } } // otherwise, just use the line modulo else { int base_ = (int)gfx.start; int end = (int)(region_length / 8); int linemod = (int)glcopy.yoffset[0]; while (glcopy.total > 0) { int elementbase = (int)(base_ + (glcopy.total - 1) * glcopy.charincrement / 8); int lastpixelbase = elementbase + glcopy.height * linemod / 8 - 1; if (lastpixelbase < end) { break; } glcopy.total--; } } // allocate the graphics //m_gfx[curgfx] = new gfx_element(m_palette, glcopy, region_base != null ? region_base + gfx.start : null, xormask, gfx.total_color_codes, gfx.color_codes_start); m_gfx[curgfx] = new gfx_element(m_paletteDevice.target.palette_interface, glcopy, region_base != null ? new ListBytesPointer(region_base, (int)gfx.start) : null, xormask, gfx.total_color_codes, gfx.color_codes_start); } m_decoded = true; }
public u32 transpen_mask(gfx_element gfx, u32 color, indirect_pen_t transcolor) { return(dipalette.transpen_mask(gfx, color, transcolor)); }
//------------------------------------------------- // 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 apply_stain(bitmap_ind16 &bitmap, uint16_t *pf, uint16_t *mo, int x, int y); // memory access //uint16_t &slipram(int offset) { return m_slipram[offset]; } // device-level overrides //------------------------------------------------- // device_start: Start up the device //------------------------------------------------- protected override void device_start() { // call parent base.device_start(); // verify configuration gfx_element gfx = m_gfxdecode.op0.gfx(m_atari_motion_objects_config.m_gfxindex); if (gfx == null) { throw new emu_fatalerror("No gfxelement #{0}!", m_atari_motion_objects_config.m_gfxindex); } // determine the masks m_linkmask.set(m_atari_motion_objects_config.m_link_entry); m_codemask.set(m_atari_motion_objects_config.m_code_entry); m_colormask.set(m_atari_motion_objects_config.m_color_entry); m_xposmask.set(m_atari_motion_objects_config.m_xpos_entry); m_yposmask.set(m_atari_motion_objects_config.m_ypos_entry); m_widthmask.set(m_atari_motion_objects_config.m_width_entry); m_heightmask.set(m_atari_motion_objects_config.m_height_entry); m_hflipmask.set(m_atari_motion_objects_config.m_hflip_entry); m_vflipmask.set(m_atari_motion_objects_config.m_vflip_entry); m_prioritymask.set(m_atari_motion_objects_config.m_priority_entry); m_neighbormask.set(m_atari_motion_objects_config.m_neighbor_entry); m_absolutemask.set(m_atari_motion_objects_config.m_absolute_entry); // derive tile information m_tilewidth = gfx.width(); m_tileheight = gfx.height(); m_tilexshift = compute_log(m_tilewidth); m_tileyshift = compute_log(m_tileheight); // derive bitmap information m_bitmapwidth = round_to_powerof2(m_xposmask.mask()); m_bitmapheight = round_to_powerof2(m_yposmask.mask()); m_bitmapxmask = m_bitmapwidth - 1; m_bitmapymask = m_bitmapheight - 1; // derive sprite information m_entrycount = round_to_powerof2(m_linkmask.mask()); m_entrybits = compute_log(m_entrycount); m_spriteramsize = m_atari_motion_objects_config.m_bankcount * m_entrycount; m_spriterammask = m_spriteramsize - 1; m_slipshift = (m_atari_motion_objects_config.m_slipheight != 0) ? compute_log(m_atari_motion_objects_config.m_slipheight) : 0; m_slipramsize = m_bitmapheight >> m_slipshift; m_sliprammask = m_slipramsize - 1; if (m_atari_motion_objects_config.m_maxperline == 0) { m_atari_motion_objects_config.m_maxperline = MAX_PER_BANK; } // Get the slipram from the share if not already explicitly set if (m_slipram == null) { m_slipram = new Pointer <u16>(m_slipramshare.op); } // allocate and initialize the code lookup int codesize = round_to_powerof2((int)m_codemask.mask()); m_codelookup.resize((size_t)codesize); for (int i = 0; i < codesize; i++) { m_codelookup[i] = (uint32_t)i; } // allocate and initialize the color lookup int colorsize = round_to_powerof2((int)m_colormask.mask()); m_colorlookup.resize((size_t)colorsize); for (int i = 0; i < colorsize; i++) { m_colorlookup[i] = (uint8_t)i; } // allocate and the gfx lookup int gfxsize = codesize / 256; m_gfxlookup.resize((size_t)gfxsize); for (int i = 0; i < gfxsize; i++) { m_gfxlookup[i] = m_atari_motion_objects_config.m_gfxindex; } // allocate a timer to periodically force update m_force_update_timer = timer_alloc(TID_FORCE_UPDATE); m_force_update_timer.adjust(m_divideo.screen().time_until_pos(0)); // register for save states save_item(NAME(new { m_bank })); save_item(NAME(new { m_xscroll })); save_item(NAME(new { m_yscroll })); }