//void set_shadow_dRGB32(int mode, int dr, int dg, int db, bool noclip); //------------------------------------------------- // configure_rgb_shadows - configure shadows // for the RGB tables //------------------------------------------------- void configure_rgb_shadows(int mode, float factor) { // only applies to RGB direct modes assert(m_format != bitmap_format.BITMAP_FORMAT_IND16); // verify the shadow table assert(mode >= 0 && mode < m_shadow_tables.Length); shadow_table_data stable = m_shadow_tables[mode]; assert(stable.base_ != null); // regenerate the table int ifactor = (int)(factor * 256.0f); for (int rgb555 = 0; rgb555 < 32768; rgb555++) { u8 r = rgb_t.clamp((pal5bit((uint8_t)(rgb555 >> 10)) * ifactor) >> 8); u8 g = rgb_t.clamp((pal5bit((uint8_t)(rgb555 >> 5)) * ifactor) >> 8); u8 b = rgb_t.clamp((pal5bit((uint8_t)(rgb555 >> 0)) * ifactor) >> 8); // store either 16 or 32 bit rgb_t final = new rgb_t(r, g, b); if (m_format == bitmap_format.BITMAP_FORMAT_RGB32) { stable.base_[rgb555] = final; } else { stable.base_[rgb555] = final.as_rgb15(); } } }
/** * @fn void palette_t::update_adjusted_color(UINT32 group, UINT32 index) * * @brief ------------------------------------------------- * update_adjusted_color - update a color index by group and index pair * -------------------------------------------------. * * @param group The group. * @param index Zero-based index of the. */ void update_adjusted_color(uint32_t group, uint32_t index) { // compute the adjusted value rgb_t adjusted = adjust_palette_entry(m_entry_color[index], m_group_bright[group] + m_brightness, m_group_contrast[group] * m_entry_contrast[index] * m_contrast, m_gamma_map); // if not different, ignore uint32_t finalindex = group * m_numcolors + index; if (m_adjusted_color[finalindex] == adjusted) { return; } // otherwise, modify the adjusted color array m_adjusted_color[finalindex] = adjusted; m_adjusted_rgb15[finalindex] = adjusted.as_rgb15(); // mark dirty in all clients for (palette_client client = m_client_list; client != null; client = client.next()) { client.mark_dirty(finalindex); } }
//------------------------------------------------- // allocate_color_tables - allocate memory for // pen and color tables //------------------------------------------------- void allocate_color_tables() { int total_colors = m_palette.num_colors() * m_palette.num_groups(); // allocate memory for the pen table switch (m_format) { case bitmap_format.BITMAP_FORMAT_IND16: // create a dummy 1:1 mapping { m_pen_array.resize(total_colors + 2); ListPointer <rgb_t> pentable = new ListPointer <rgb_t>(m_pen_array); //pen_t *pentable = &m_pen_array[0]; m_pens = new ListPointer <rgb_t>(m_pen_array); //m_pens = &m_pen_array[0]; for (int i = 0; i < total_colors + 2; i++) { pentable[i] = new rgb_t((UInt32)i); //pentable[i] = i; } } break; case bitmap_format.BITMAP_FORMAT_RGB32: m_pens = new ListPointer <rgb_t>(m_palette.entry_list_adjusted()); // reinterpret_cast<const pen_t *>(m_palette.entry_list_adjusted()); break; default: m_pens = null; break; } }
// internal helpers //------------------------------------------------- // adjust_palette_entry - adjust a palette // entry for brightness //------------------------------------------------- rgb_t adjust_palette_entry(rgb_t entry, float brightness, float contrast, uint8_t [] gamma_map) { int r = rgb_t.clamp((int)((float)(gamma_map[entry.r()]) * contrast + brightness)); int g = rgb_t.clamp((int)((float)(gamma_map[entry.g()]) * contrast + brightness)); int b = rgb_t.clamp((int)((float)(gamma_map[entry.b()]) * contrast + brightness)); int a = entry.a(); return(new rgb_t((uint8_t)a, (uint8_t)r, (uint8_t)g, (uint8_t)b)); }
public glyph() { width = -1; xoffs = -1; yoffs = -1; bmwidth = 0; bmheight = 0; rawdata = null; texture = null; bitmap = new bitmap_argb32(); color = new rgb_t(); }
protected void vg_add_point_buf(int x, int y, rgb_t color, int intensity) { if (m_nvect < MAXVECT) { m_vectbuf[m_nvect].status = VGVECTOR; m_vectbuf[m_nvect].x = x; m_vectbuf[m_nvect].y = y; m_vectbuf[m_nvect].color = color; m_vectbuf[m_nvect].intensity = intensity; m_nvect++; } }
// entry setters //------------------------------------------------- // entry_set_color - set the raw RGB color for a // given palette index //------------------------------------------------- public void entry_set_color(uint32_t index, rgb_t rgb) { // if unchanged, ignore if (m_entry_color[index] == rgb) { return; } assert(index < m_numcolors); // set the color m_entry_color[index] = rgb; // update across all groups for (int groupnum = 0; groupnum < m_numgroups; groupnum++) { update_adjusted_color((uint32_t)groupnum, index); } }
public void add_point(int x, int y, rgb_t color, int intensity) { //point *newpoint; intensity = std.clamp(intensity, 0, 255); m_min_intensity = intensity > 0 ? std.min(m_min_intensity, intensity) : m_min_intensity; m_max_intensity = intensity > 0 ? std.max(m_max_intensity, intensity) : m_max_intensity; if (vector_options.s_flicker != 0 && (intensity > 0)) { float random = (float)(machine().rand() & 255) / 255.0f; // random value between 0.0 and 1.0 intensity -= (int)(intensity * random * vector_options.s_flicker); intensity = std.clamp(intensity, 0, 255); } ref point newpoint = ref m_vector_list[m_vector_index];
//------------------------------------------------- // set_indirect_color - set an indirect color //------------------------------------------------- public void set_indirect_color(int index, rgb_t rgb) { // make sure we are in range assert(index < m_indirect_colors.size()); // alpha doesn't matter rgb.set_a(255); // update if it has changed if (m_indirect_colors[index] != rgb) { m_indirect_colors[index] = rgb; // update the palette for any colortable entries that reference it for (UInt32 pen = 0; pen < m_indirect_pens.size(); pen++) { if (m_indirect_pens[(int)pen] == index) { m_palette.entry_set_color(pen, rgb); } } } }
// utilities public void normalize_range(uint32_t start, uint32_t end, int lum_min = 0, int lum_max = 255) { // clamp within range // start = std::max(start, 0U); ==> reduces to start = start end = std.min(end, m_numcolors - 1); // find the minimum and maximum brightness of all the colors in the range int32_t ymin = 1000 * 255; int32_t ymax = 0; for (uint32_t index = start; index <= end; index++) { rgb_t rgb = m_entry_color[index]; uint32_t y = (uint32_t)(299 * rgb.r() + 587 * rgb.g() + 114 * rgb.b()); ymin = (int32_t)std.min((uint32_t)ymin, y); ymax = (int32_t)std.max((uint32_t)ymax, y); } // determine target minimum/maximum int32_t tmin = (lum_min < 0) ? ((ymin + 500) / 1000) : lum_min; int32_t tmax = (lum_max < 0) ? ((ymax + 500) / 1000) : lum_max; // now normalize the palette for (uint32_t index = start; index <= end; index++) { rgb_t rgb = m_entry_color[index]; int32_t y = 299 * rgb.r() + 587 * rgb.g() + 114 * rgb.b(); int32_t u = ((int32_t)rgb.b() - y / 1000) * 492 / 1000; int32_t v = ((int32_t)rgb.r() - y / 1000) * 877 / 1000; int32_t target = tmin + ((y - ymin) * (tmax - tmin + 1)) / (ymax - ymin); uint8_t r = rgb_t.clamp(target + 1140 * v / 1000); uint8_t g = rgb_t.clamp(target - 395 * u / 1000 - 581 * v / 1000); uint8_t b = rgb_t.clamp(target + 2032 * u / 1000); entry_set_color(index, new rgb_t(r, g, b)); } }
void background_draw_colorsplit(bitmap_rgb32 bitmap, rectangle cliprect, rgb_t color, int split, int split_flipped) { /* horizontal bgcolor split */ if (m_flipscreen_x != 0) { rectangle draw = cliprect; draw.max_x = std.min(draw.max_x, split_flipped * m_x_scale - 1); if (draw.min_x <= draw.max_x) { bitmap.fill(rgb_t.black(), draw); } draw = cliprect; draw.min_x = std.max(draw.min_x, split_flipped * m_x_scale); if (draw.min_x <= draw.max_x) { bitmap.fill(color, draw); } } else { rectangle draw = cliprect; draw.max_x = std.min(draw.max_x, split * m_x_scale - 1); if (draw.min_x <= draw.max_x) { bitmap.fill(color, draw); } draw = cliprect; draw.min_x = std.max(draw.min_x, split * m_x_scale); if (draw.min_x <= draw.max_x) { bitmap.fill(rgb_t.black(), draw); } } }
/*------------------------------------------------- * resample_argb_bitmap_average - resample a texture * by performing a true weighted average over * all contributing pixels * -------------------------------------------------*/ static void resample_argb_bitmap_average(PointerU32 dest, u32 drowpixels, u32 dwidth, u32 dheight, PointerU32 source, u32 srowpixels, u32 swidth, u32 sheight, render_color color, u32 dx, u32 dy) //static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) { u64 sumscale = (u64)dx * (u64)dy; u32 r; u32 g; u32 b; u32 a; u32 x; u32 y; /* precompute premultiplied R/G/B/A factors */ r = (u32)(color.r * color.a * 256.0f); g = (u32)(color.g * color.a * 256.0f); b = (u32)(color.b * color.a * 256.0f); a = (u32)(color.a * 256.0f); /* loop over the target vertically */ for (y = 0; y < dheight; y++) { u32 starty = y * dy; /* loop over the target horizontally */ for (x = 0; x < dwidth; x++) { u64 sumr = 0; u64 sumg = 0; u64 sumb = 0; u64 suma = 0; u32 startx = x * dx; u32 xchunk; u32 ychunk; u32 curx; u32 cury; u32 yremaining = dy; /* accumulate all source pixels that contribute to this pixel */ for (cury = starty; yremaining != 0; cury += ychunk) { u32 xremaining = dx; /* determine the Y contribution, clamping to the amount remaining */ ychunk = 0x1000 - (cury & 0xfff); if (ychunk > yremaining) { ychunk = yremaining; } yremaining -= ychunk; /* loop over all source pixels in the X direction */ for (curx = startx; xremaining != 0; curx += xchunk) { u32 factor; /* determine the X contribution, clamping to the amount remaining */ xchunk = 0x1000 - (curx & 0xfff); if (xchunk > xremaining) { xchunk = xremaining; } xremaining -= xchunk; /* total contribution = x * y */ factor = xchunk * ychunk; /* fetch the source pixel */ rgb_t pix = new rgb_t(source[(cury >> 12) * srowpixels + (curx >> 12)]); //rgb_t pix = source[(cury >> 12) * srowpixels + (curx >> 12)]; /* accumulate the RGBA values */ sumr += factor * pix.r(); sumg += factor * pix.g(); sumb += factor * pix.b(); suma += factor * pix.a(); } } /* apply scaling */ suma = (suma / sumscale) * a / 256; sumr = (sumr / sumscale) * r / 256; sumg = (sumg / sumscale) * g / 256; sumb = (sumb / sumscale) * b / 256; /* if we're translucent, add in the destination pixel contribution */ if (a < 256) { rgb_t dpix = new rgb_t(dest[y * drowpixels + x]); //rgb_t dpix = dest[y * drowpixels + x]; suma += dpix.a() * (256 - a); sumr += dpix.r() * (256 - a); sumg += dpix.g() * (256 - a); sumb += dpix.b() * (256 - a); } /* store the target pixel, dividing the RGBA values by the overall scale factor */ dest[y * drowpixels + x] = new rgb_t((u8)suma, (u8)sumr, (u8)sumg, (u8)sumb); //dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb); } } }
public void set_indirect_color(int index, rgb_t rgb) { dipalette.set_indirect_color(index, rgb); }
public void set_pen_color(pen_t pen, rgb_t rgb) { dipalette.set_pen_color(pen, rgb); }
protected virtual uint32_t screen_update(screen_device screen, bitmap_rgb32 bitmap, rectangle cliprect) { //printf("%f %f\n", m_state.m_fragments[0].y, m_state.m_fragments[m_state.m_fragments.size()-1].y); bool force_vector = screen.screen_type() == SCREEN_TYPE_VECTOR || (m_vector.op0.read() & 1) != 0; bool debug_timing = (m_enable.op0.read() & 2) == 2; bool test_pat = (m_enable.op0.read() & 4) == 4; rgb_t backcol = debug_timing ? new rgb_t(0xff, 0xff, 0x00, 0x00) : new rgb_t(0xff, 0x00, 0x00, 0x00); if (!force_vector) { screen.set_video_attributes(0); bitmap.fill(backcol); foreach (var f in m_state.m_fragments) { if (f.y < bitmap.height()) { bitmap.plot_box((int32_t)f.x, (int32_t)f.y, (int32_t)(f.xr - f.x), 1, f.col); } } if (test_pat) { draw_testpat(screen, bitmap, cliprect); } } else { screen.set_video_attributes(VIDEO_SELF_RENDER); uint32_t flags = PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD) | (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1) : 0); rectangle visarea = screen.visible_area(); float xscale = 1.0f / (float)visarea.width(); float yscale = 1.0f / (float)visarea.height(); float xoffs = (float)visarea.min_x; float yoffs = (float)visarea.min_y; screen.container().empty(); screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, new rgb_t(0xff, 0x00, 0x00, 0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTORBUF(1) : 0)); float last_y = -1e6f; foreach (var f in m_state.m_fragments) { float x0 = (f.x - xoffs) * xscale; float y0 = (f.y - yoffs) * yscale; float x1 = (f.xr - xoffs) * xscale; rgb_t col = (debug_timing && f.y < last_y) ? backcol : new rgb_t(f.col); // FIXME: Debug check for proper vsync timing #if false auto w = m_scanline_height * xscale * 0.5; screen.container().add_line( x0 + w, y0, x1 - w, y0, m_scanline_height * yscale, nom_col(f.col), // (0xff << 24) | (f.col & 0xffffff), flags); #elif true float y1 = (f.y + m_scanline_height - yoffs) * yscale; screen.container().add_rect( x0, y0, x1, y1, new rgb_t(nom_col(col)), // (0xaf << 24) | (f.col & 0xffffff), flags); #else const float y1((f.y + m_scanline_height - yoffs) *yscale); // Crashes with bgfx screen.container().add_quad( x0, y0, x1, y1, rgb_t(nom_col(f.col)), // (0xaf << 24) | (f.col & 0xffffff), m_texture, flags); #endif last_y = f.y; } } m_state.m_fragments.clear(); return(0); }
//------------------------------------------------- // char_expand - expand the raw data for a // character into a bitmap //------------------------------------------------- void char_expand(char32_t chnum, glyph gl) { LOG("render_font::char_expand: expanding character {0}\n", chnum); rgb_t fgcol = (gl.color != 0 ? gl.color : new rgb_t(0xff, 0xff, 0xff, 0xff)); rgb_t bgcol = new rgb_t(0x00, 0xff, 0xff, 0xff); bool is_cmd = ((chnum >= COMMAND_UNICODE) && (chnum < COMMAND_UNICODE + MAX_GLYPH_FONT)); if (is_cmd) { throw new emu_unimplemented(); #if false // punt if nothing there if (gl.bmwidth == 0 || gl.bmheight == 0 || gl.rawdata == null) { return; } // allocate a new bitmap of the size we need gl.bitmap.allocate(gl.bmwidth, m_height_cmd); gl.bitmap.fill(0); // extract the data const char *ptr = gl.rawdata; byte accum = 0; byte accumbit = 7; for (int y = 0; y < gl.bmheight; y++) { int desty = y + m_height_cmd + m_yoffs_cmd - gl.yoffs - gl.bmheight; u32 *dest = (desty >= 0 && desty < m_height_cmd) ? &gl.bitmap.pix(desty, 0) : nullptr; { for (int x = 0; x < gl.bmwidth; x++) { if (accumbit == 7) { accum = *ptr++; } if (dest != null) { *dest++ = (accum & (1 << accumbit)) ? color : rgb_t(0x00, 0xff, 0xff, 0xff); } accumbit = (accumbit - 1) & 7; } } } #endif } else if (m_format == format.OSD) { throw new emu_unimplemented(); #if false // if we're an OSD font, query the info #endif } else if (gl.bmwidth == 0 || gl.bmheight == 0 || gl.rawdata == null) { // abort if nothing there LOG("render_font::char_expand: empty bitmap bounds or no raw data\n"); return; } else { // other formats need to parse their data LOG("render_font::char_expand: building bitmap from raw data\n"); // allocate a new bitmap of the size we need gl.bitmap.allocate(gl.bmwidth, m_height); gl.bitmap.fill(0); // extract the data Pointer <u8> ptr = new Pointer <u8>(gl.rawdata); //const char *ptr = gl.rawdata; u8 accum = 0; u8 accumbit = 7; for (int y = 0; y < gl.bmheight; y++) { int desty = y + m_height + m_yoffs - gl.yoffs - gl.bmheight; PointerU32 dest = ((0 <= desty) && (m_height > desty)) ? gl.bitmap.pix(desty) : null; //u32 *dest(((0 <= desty) && (m_height > desty)) ? &gl.bitmap.pix(desty) : nullptr); if (m_format == format.TEXT) { if (dest != null) { for (int x = 0; gl.bmwidth > x;) { // scan for the next hex digit int bits = -1; while ('\r' != ptr[0] && '\n' != ptr[0] && 0 > bits) // while (('\r' != *ptr) && ('\n' != *ptr) && (0 > bits)) { if (ptr[0] >= '0' && ptr[0] <= '9') { bits = ptr[0] - '0'; //bits = *ptr++ - '0'; ptr++; } else if (ptr[0] >= 'A' && ptr[0] <= 'F') { bits = ptr[0] - 'A' + 10; ptr++; } else if (ptr[0] >= 'a' && ptr[0] <= 'f') { bits = ptr[0] - 'a' + 10; ptr++; } else { ptr++; } } // expand the four bits dest[0] = (bits & 8) != 0 ? fgcol : bgcol; dest++; //*dest++ = (bits & 8) ? fgcol : bgcol; if (gl.bmwidth > ++x) { dest[0] = (bits & 4) != 0 ? fgcol : bgcol; dest++; } //*dest++ = (bits & 4) ? fgcol : bgcol; if (gl.bmwidth > ++x) { dest[0] = (bits & 2) != 0 ? fgcol : bgcol; dest++; } //*dest++ = (bits & 2) ? fgcol : bgcol; if (gl.bmwidth > ++x) { dest[0] = (bits & 1) != 0 ? fgcol : bgcol; dest++; } //*dest++ = (bits & 1) ? fgcol : bgcol; x++; } // advance to the next line ptr = next_line(ptr); } } else if (m_format == format.CACHED) { for (int x = 0; x < gl.bmwidth; x++) { if (accumbit == 7) { accum = ptr[0]; ptr++; } if (dest != null) { dest[0] = (accum & (1 << accumbit)) != 0 ? fgcol : bgcol; dest++; } //*dest++ = (accum & (1 << accumbit)) ? fgcol : bgcol; accumbit = (u8)((accumbit - 1) & 7); } } } } // wrap a texture around the bitmap gl.texture = m_manager.texture_alloc(render_texture.hq_scale); gl.texture.set_bitmap(gl.bitmap, gl.bitmap.cliprect(), texture_format.TEXFORMAT_ARGB32); }
// updates //void animate(u16 auto_time); //void draw(render_container &container, u8 fade); // private helpers //------------------------------------------------- // create_bitmap - create the rendering // structures for the given player //------------------------------------------------- void create_bitmap() { rgb_t color = m_player < (int)std.size(crosshair_colors) ? crosshair_colors[m_player] : rgb_t.white(); // if we have a bitmap and texture for this player, kill it if (m_bitmap == null) { m_bitmap = new bitmap_argb32(); m_texture = m_machine.render().texture_alloc(render_texture.hq_scale); } else { m_bitmap.reset(); } emu_file crossfile = new emu_file(m_machine.options().crosshair_path(), OPEN_FLAG_READ); if (!m_name.empty()) { // look for user specified file if (!crossfile.open(m_name + ".png")) { render_load_png(out m_bitmap, crossfile.core_file_get()); crossfile.close(); } } else { // look for default cross?.png in crsshair/game dir string filename = util.string_format("cross{0}.png", m_player + 1); if (!crossfile.open(m_machine.system().name + (PATH_SEPARATOR + filename))) { render_load_png(out m_bitmap, crossfile.core_file_get()); crossfile.close(); } // look for default cross?.png in crsshair dir if (!m_bitmap.valid() && !crossfile.open(filename)) { render_load_png(out m_bitmap, crossfile.core_file_get()); crossfile.close(); } } /* if that didn't work, use the built-in one */ if (!m_bitmap.valid()) { /* allocate a blank bitmap to start with */ m_bitmap.allocate(CROSSHAIR_RAW_SIZE, CROSSHAIR_RAW_SIZE); m_bitmap.fill(new rgb_t(0x00, 0xff, 0xff, 0xff)); /* extract the raw source data to it */ for (int y = 0; y < CROSSHAIR_RAW_SIZE / 2; y++) { /* assume it is mirrored vertically */ PointerU32 dest0 = m_bitmap.pix(y); //u32 *dest0 = &m_bitmap->pix(y); PointerU32 dest1 = m_bitmap.pix(CROSSHAIR_RAW_SIZE - 1 - y); //u32 *dest1 = &m_bitmap->pix(CROSSHAIR_RAW_SIZE - 1 - y); /* extract to two rows simultaneously */ for (int x = 0; x < CROSSHAIR_RAW_SIZE; x++) { if (((crosshair_raw_top[y * CROSSHAIR_RAW_ROWBYTES + x / 8] << (x % 8)) & 0x80) != 0) { dest0[x] = dest1[x] = new rgb_t(0xff, 0x00, 0x00, 0x00) | color; } } } } /* reference the new bitmap */ m_texture.set_bitmap(m_bitmap, m_bitmap.cliprect(), texture_format.TEXFORMAT_ARGB32); }
/*------------------------------------------------- * resample_argb_bitmap_bilinear - perform texture * sampling via a bilinear filter * -------------------------------------------------*/ static void resample_argb_bitmap_bilinear(PointerU32 dest, u32 drowpixels, u32 dwidth, u32 dheight, PointerU32 source, u32 srowpixels, u32 swidth, u32 sheight, render_color color, u32 dx, u32 dy) //static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) { u32 maxx = swidth << 12; u32 maxy = sheight << 12; u32 r; u32 g; u32 b; u32 a; u32 x; u32 y; /* precompute premultiplied R/G/B/A factors */ r = (u32)(color.r * color.a * 256.0f); g = (u32)(color.g * color.a * 256.0f); b = (u32)(color.b * color.a * 256.0f); a = (u32)(color.a * 256.0f); /* loop over the target vertically */ for (y = 0; y < dheight; y++) { u32 starty = y * dy; /* loop over the target horizontally */ for (x = 0; x < dwidth; x++) { u32 startx = x * dx; rgb_t pix0; rgb_t pix1; rgb_t pix2; rgb_t pix3; u32 sumr; u32 sumg; u32 sumb; u32 suma; u32 nextx; u32 nexty; u32 curx; u32 cury; u32 factor; /* adjust start to the center; note that this math will tend to produce */ /* negative results on the first pixel, which is why we clamp below */ curx = startx + dx / 2 - 0x800; cury = starty + dy / 2 - 0x800; /* compute the neighboring pixel */ nextx = curx + 0x1000; nexty = cury + 0x1000; /* fetch the four relevant pixels */ pix0 = pix1 = pix2 = pix3 = new rgb_t(0); if ((int)cury >= 0 && cury < maxy && (int)curx >= 0 && curx < maxx) { pix0 = new rgb_t(source[(cury >> 12) * srowpixels + (curx >> 12)]); //pix0 = source[(cury >> 12) * srowpixels + (curx >> 12)]; } if ((int)cury >= 0 && cury < maxy && (int)nextx >= 0 && nextx < maxx) { pix1 = new rgb_t(source[(cury >> 12) * srowpixels + (nextx >> 12)]); //pix1 = source[(cury >> 12) * srowpixels + (nextx >> 12)]; } if ((int)nexty >= 0 && nexty < maxy && (int)curx >= 0 && curx < maxx) { pix2 = new rgb_t(source[(nexty >> 12) * srowpixels + (curx >> 12)]); //pix2 = source[(nexty >> 12) * srowpixels + (curx >> 12)]; } if ((int)nexty >= 0 && nexty < maxy && (int)nextx >= 0 && nextx < maxx) { pix3 = new rgb_t(source[(nexty >> 12) * srowpixels + (nextx >> 12)]); //pix3 = source[(nexty >> 12) * srowpixels + (nextx >> 12)]; } /* compute the x/y scaling factors */ curx &= 0xfff; cury &= 0xfff; /* contributions from pixel 0 (top,left) */ factor = (0x1000 - curx) * (0x1000 - cury); sumr = factor * pix0.r(); sumg = factor * pix0.g(); sumb = factor * pix0.b(); suma = factor * pix0.a(); /* contributions from pixel 1 (top,right) */ factor = curx * (0x1000 - cury); sumr += factor * pix1.r(); sumg += factor * pix1.g(); sumb += factor * pix1.b(); suma += factor * pix1.a(); /* contributions from pixel 2 (bottom,left) */ factor = (0x1000 - curx) * cury; sumr += factor * pix2.r(); sumg += factor * pix2.g(); sumb += factor * pix2.b(); suma += factor * pix2.a(); /* contributions from pixel 3 (bottom,right) */ factor = curx * cury; sumr += factor * pix3.r(); sumg += factor * pix3.g(); sumb += factor * pix3.b(); suma += factor * pix3.a(); /* apply scaling */ suma = (suma >> 24) * a / 256; sumr = (sumr >> 24) * r / 256; sumg = (sumg >> 24) * g / 256; sumb = (sumb >> 24) * b / 256; /* if we're translucent, add in the destination pixel contribution */ if (a < 256) { rgb_t dpix = new rgb_t(dest[y * drowpixels + x]); //rgb_t dpix = dest[y * drowpixels + x]; suma += dpix.a() * (256 - a); sumr += dpix.r() * (256 - a); sumg += dpix.g() * (256 - a); sumb += dpix.b() * (256 - a); } /* store the target pixel, dividing the RGBA values by the overall scale factor */ dest[y * drowpixels + x] = new rgb_t((u8)suma, (u8)sumr, (u8)sumg, (u8)sumb); //dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb); } } }
public abstract bool add_sound_to_recording(object sound, int numsamples); //virtual bool add_sound_to_recording(const s16 *sound, int numsamples) = 0; // statics //static movie_recording::ptr create(running_machine &machine, screen_device *screen, format fmt, std::unique_ptr<emu_file> &&file, bitmap_rgb32 &snap_bitmap); //static const char *format_file_extension(format fmt); // virtuals protected abstract bool append_single_video_frame(bitmap_rgb32 bitmap, rgb_t palette, int palette_entries); //virtual bool append_single_video_frame(bitmap_rgb32 &bitmap, const rgb_t *palette, int palette_entries) = 0;
/*************************************************************************** * * Centipede doesn't have a color PROM. Eight RAM locations control * the color of characters and sprites. The meanings of the four bits are * (all bits are inverted): * * bit 3 alternate * blue * green * bit 0 red * * The alternate bit affects blue and green, not red. The way I weighted its * effect might not be perfectly accurate, but is reasonably close. * * Centipede is unusual because the sprite color code specifies the * colors to use one by one, instead of a combination code. * * FIXME: handle this using standard indirect colors instead of * custom implementation * * bit 5-4 = color to use for pen 11 * bit 3-2 = color to use for pen 10 * bit 1-0 = color to use for pen 01 * pen 00 is transparent * ***************************************************************************/ //WRITE8_MEMBER(centiped_state::centiped_paletteram_w) public void centiped_paletteram_w(address_space space, offs_t offset, u8 data, u8 mem_mask = 0xff) { m_paletteram[offset] = data; /* bit 2 of the output palette RAM is always pulled high, so we ignore */ /* any palette changes unless the write is to a palette RAM address */ /* that is actually used */ if ((offset & 4) != 0) { rgb_t color; int r = 0xff * ((~data >> 0) & 1); int g = 0xff * ((~data >> 1) & 1); int b = 0xff * ((~data >> 2) & 1); if ((~data & 0x08) != 0) /* alternate = 1 */ { /* when blue component is not 0, decrease it. When blue component is 0, */ /* decrease green component. */ if (b != 0) { b = 0xc0; } else if (g != 0) { g = 0xc0; } } color = new rgb_t((byte)r, (byte)g, (byte)b); /* character colors, set directly */ if ((offset & 0x08) == 0) { m_palette.target.palette_interface.set_pen_color(offset & 0x03, color); } /* sprite colors - set all the applicable ones */ else { int i; offset = offset & 0x03; for (i = 0; i < 0x100; i += 4) { if (offset == ((i >> 2) & 0x03)) { m_palette.target.palette_interface.set_pen_color((UInt32)i + 4 + 1, color); } if (offset == ((i >> 4) & 0x03)) { m_palette.target.palette_interface.set_pen_color((UInt32)i + 4 + 2, color); } if (offset == ((i >> 6) & 0x03)) { m_palette.target.palette_interface.set_pen_color((UInt32)i + 4 + 3, color); } } } } }
/************************************* * * Bullet rendering * *************************************/ void galaxian_draw_pixel(bitmap_rgb32 bitmap, rectangle cliprect, int y, int x, rgb_t color) { if (y >= cliprect.min_y && y <= cliprect.max_y) { x *= GALAXIAN_XSCALE; x += GALAXIAN_H0START; if (x >= cliprect.min_x && x <= cliprect.max_x) { //bitmap.pix32(y, x) = color; RawBuffer bitmapBuf; UInt32 bitmapBufOffset = bitmap.pix32(out bitmapBuf, y, x); bitmapBuf.set_uint32((int)bitmapBufOffset, color); } x++; if (x >= cliprect.min_x && x <= cliprect.max_x) { //bitmap.pix32(y, x) = color; RawBuffer bitmapBuf; UInt32 bitmapBufOffset = bitmap.pix32(out bitmapBuf, y, x); bitmapBuf.set_uint32((int)bitmapBufOffset, color); } x++; if (x >= cliprect.min_x && x <= cliprect.max_x) { //bitmap.pix32(y, x) = color; RawBuffer bitmapBuf; UInt32 bitmapBufOffset = bitmap.pix32(out bitmapBuf, y, x); bitmapBuf.set_uint32((int)bitmapBufOffset, color); } } }
/************************************* * * Palette setup * *************************************/ void galaxian_palette(palette_device palette) { Pointer <uint8_t> color_prom = new Pointer <uint8_t>(memregion("proms").base_()); //const uint8_t *color_prom = memregion("proms")->base(); int [] rgb_resistances3 = new int [3] { 1000, 470, 220 }; int [] rgb_resistances2 = new int [2] { 470, 220 }; /* * Sprite/tilemap colors are mapped through a color PROM as follows: * * bit 7 -- 220 ohm resistor -- BLUE * -- 470 ohm resistor -- BLUE * -- 220 ohm resistor -- GREEN * -- 470 ohm resistor -- GREEN * -- 1 kohm resistor -- GREEN * -- 220 ohm resistor -- RED * -- 470 ohm resistor -- RED * bit 0 -- 1 kohm resistor -- RED * * Note that not all boards have this configuration. Namco PCBs may * have 330 ohm resistors instead of 220, but the default setup has * also been used by Namco. * * In parallel with these resistors are a pair of 150 ohm and 100 ohm * resistors on each R,G,B component that are connected to the star * generator. * * And in parallel with the whole mess are a set of 100 ohm resistors * on each R,G,B component that are enabled when a shell/missile is * enabled. * * When computing weights, we use RGB_MAXIMUM as the maximum to give * headroom for stars and shells/missiles. This is not fully accurate, * but if we included all possible sources in parallel, the brightness * of the main game would be very low to allow for all the oversaturation * of the stars and shells/missiles. */ double [] rweights = new double[3]; double [] gweights = new double[3]; double [] bweights = new double[2]; compute_resistor_weights(0, RGB_MAXIMUM, -1.0, 3, rgb_resistances3, out rweights, 470, 0, 3, rgb_resistances3, out gweights, 470, 0, 2, rgb_resistances2, out bweights, 470, 0); // decode the palette first int len = (int)memregion("proms").bytes(); for (int i = 0; i < len; i++) { uint8_t bit0; uint8_t bit1; uint8_t bit2; /* red component */ bit0 = (uint8_t)BIT(color_prom[i], 0); bit1 = (uint8_t)BIT(color_prom[i], 1); bit2 = (uint8_t)BIT(color_prom[i], 2); int r = combine_weights(rweights, bit0, bit1, bit2); /* green component */ bit0 = (uint8_t)BIT(color_prom[i], 3); bit1 = (uint8_t)BIT(color_prom[i], 4); bit2 = (uint8_t)BIT(color_prom[i], 5); int gr = combine_weights(gweights, bit0, bit1, bit2); /* blue component */ bit0 = (uint8_t)BIT(color_prom[i], 6); bit1 = (uint8_t)BIT(color_prom[i], 7); int b = combine_weights(bweights, bit0, bit1); palette.set_pen_color((pen_t)i, new rgb_t((uint8_t)r, (uint8_t)gr, (uint8_t)b)); } /* * The maximum sprite/tilemap resistance is ~130 Ohms with all RGB * outputs enabled (1/(1/1000 + 1/470 + 1/220)). Since we normalized * to RGB_MAXIMUM, this maps RGB_MAXIMUM -> 130 Ohms. * * The stars are at 150 Ohms for the LSB, and 100 Ohms for the MSB. * This means the 3 potential values are: * * 150 Ohms -> RGB_MAXIMUM * 130 / 150 * 100 Ohms -> RGB_MAXIMUM * 130 / 100 * 60 Ohms -> RGB_MAXIMUM * 130 / 60 * * Since we can't saturate that high, we instead approximate this * by compressing the values proportionally into the 194->255 range. */ int minval = RGB_MAXIMUM * 130 / 150; int midval = RGB_MAXIMUM * 130 / 100; int maxval = RGB_MAXIMUM * 130 / 60; // compute the values for each of 4 possible star values uint8_t [] starmap = new uint8_t [4] { 0, (uint8_t)minval, (uint8_t)(minval + (255 - minval) * (midval - minval) / (maxval - minval)), 255 }; // generate the colors for the stars for (int i = 0; i < 64; i++) { uint8_t bit0; uint8_t bit1; // bit 5 = red @ 150 Ohm, bit 4 = red @ 100 Ohm bit0 = (uint8_t)BIT(i, 5); bit1 = (uint8_t)BIT(i, 4); int r = starmap[(bit1 << 1) | bit0]; // bit 3 = green @ 150 Ohm, bit 2 = green @ 100 Ohm bit0 = (uint8_t)BIT(i, 3); bit1 = (uint8_t)BIT(i, 2); int gr = starmap[(bit1 << 1) | bit0]; // bit 1 = blue @ 150 Ohm, bit 0 = blue @ 100 Ohm bit0 = (uint8_t)BIT(i, 1); bit1 = (uint8_t)BIT(i, 0); int b = starmap[(bit1 << 1) | bit0]; // set the RGB color m_star_color[i] = new rgb_t((uint8_t)r, (uint8_t)gr, (uint8_t)b); } // default bullet colors are white for the first 7, and yellow for the last one for (int i = 0; i < 7; i++) { m_bullet_color[i] = new rgb_t(0xff, 0xff, 0xff); } m_bullet_color[7] = new rgb_t(0xff, 0xff, 0x00); }
//pen_t white_pen() const { return m_white_pen; } //bool shadows_enabled() const { return palette_shadows_enabled(); } //bool hilights_enabled() const { return palette_hilights_enabled(); } // setters public void set_pen_color(pen_t pen, rgb_t rgb) { m_palette.entry_set_color(pen, rgb); }
/************************************* * * Bullet rendering * *************************************/ void galaxian_draw_pixel(bitmap_rgb32 bitmap, rectangle cliprect, int y, int x, rgb_t color) { if (y >= cliprect.min_y && y <= cliprect.max_y) { x *= GALAXIAN_XSCALE; x += GALAXIAN_H0START; if (x >= cliprect.min_x && x <= cliprect.max_x) { bitmap.pix(y, x)[0] = color; } x++; if (x >= cliprect.min_x && x <= cliprect.max_x) { bitmap.pix(y, x)[0] = color; } x++; if (x >= cliprect.min_x && x <= cliprect.max_x) { bitmap.pix(y, x)[0] = color; } } }
// updates //void animate(u16 auto_time); //void draw(render_container &container, u8 fade); // private helpers //------------------------------------------------- // create_bitmap - create the rendering // structures for the given player //------------------------------------------------- void create_bitmap() { int x; int y; rgb_t color = m_player < crosshair_colors.Length ? crosshair_colors[m_player] : rgb_t.white(); // if we have a bitmap and texture for this player, kill it if (m_bitmap == null) { m_bitmap = new bitmap_argb32(); m_texture = m_machine.render().texture_alloc(render_texture.hq_scale); } emu_file crossfile = new emu_file(m_machine.options().crosshair_path(), OPEN_FLAG_READ); if (!m_name.empty()) { // look for user specified file string filename = m_name + ".png"; render_load_png(out m_bitmap, crossfile, null, filename.c_str()); } else { // look for default cross?.png in crsshair/game dir string filename = string.Format("cross{0}.png", m_player + 1); render_load_png(out m_bitmap, crossfile, m_machine.system().name, filename.c_str()); // look for default cross?.png in crsshair dir if (!m_bitmap.valid()) { render_load_png(out m_bitmap, crossfile, null, filename.c_str()); } } crossfile.close(); /* if that didn't work, use the built-in one */ if (!m_bitmap.valid()) { /* allocate a blank bitmap to start with */ m_bitmap.allocate(CROSSHAIR_RAW_SIZE, CROSSHAIR_RAW_SIZE); m_bitmap.fill(new rgb_t(0x00, 0xff, 0xff, 0xff)); /* extract the raw source data to it */ for (y = 0; y < CROSSHAIR_RAW_SIZE / 2; y++) { /* assume it is mirrored vertically */ //u32 *dest0 = &m_bitmap->pix32(y); RawBuffer dest0Buf; UInt32 dest0Offset = m_bitmap.pix32(out dest0Buf, y); //u32 *dest1 = &m_bitmap->pix32(CROSSHAIR_RAW_SIZE - 1 - y); RawBuffer dest1Buf; UInt32 dest1Offset = m_bitmap.pix32(out dest1Buf, CROSSHAIR_RAW_SIZE - 1 - y); /* extract to two rows simultaneously */ for (x = 0; x < CROSSHAIR_RAW_SIZE; x++) { if (((crosshair_raw_top[y * CROSSHAIR_RAW_ROWBYTES + x / 8] << (x % 8)) & 0x80) != 0) { //dest0[x] = dest1[x] = new rgb_t(0xff,0x00,0x00,0x00) | color; dest0Buf.set_uint32((int)dest0Offset + x, new rgb_t(0xff, 0x00, 0x00, 0x00) | color); dest1Buf.set_uint32((int)dest1Offset + x, new rgb_t(0xff, 0x00, 0x00, 0x00) | color); } } } } /* reference the new bitmap */ m_texture.set_bitmap(m_bitmap, m_bitmap.cliprect(), texture_format.TEXFORMAT_ARGB32); }