Cleaned up software bilinear filtering code. Added bounds checking.

Enabled by default for snapshots and movie rendering.

Added new option: -snapsize, which lets you specify the target
resolution for snapshots and movies. The existing behavior is still
the default: create snapshots and movies at native pixel 
resolutions.

Added new option: -snapview, which lets you specify a particular
view to use for rendering snapshots and movies. The existing 
behavior is still the default: use a special internal view and 
render each screen to its own snapshot in its own file. When using 
this option to specify a view other than 'internal', only a single 
snapshot file will be produced regardless of how many screens the 
game has.

Improved AVI and MNG recording to properly duplicate/skip frames
as appropriate to keep the correct framerate.
This commit is contained in:
Aaron Giles 2008-06-16 16:34:51 +00:00
parent a93fb6b1bf
commit 69ba0bd294
8 changed files with 373 additions and 251 deletions

View File

@ -467,6 +467,29 @@ Core state/playback options
and names the snapshots under it starting with 0000 and increasing
from there.
-snapsize <width>x<height>
Hard-codes the size for snapshots and movie recording. By default,
MAME will create snapshots at the game's current resolution in raw
pixels, and will create movies at the game's starting resolution in
raw pixels. If you specify this option, then MAME will create both
snapshots and movies at the size specified, and will bilinear filter
the result. Note that this size does not automatically rotate if the
game is vertically oriented. The default is 'auto'.
-snapview <viewname>
Specifies the view to use when rendering snapshots and movies. By
default, both use a special 'internal' view, which renders a separate
snapshot per screen or renders movies only of the first screen. By
specifying this option, you can override this default behavior and
select a single view that will apply to all snapshots and movies.
Note that <viewname> does not need to be a perfect match; rather, it
will select the first view whose name matches all the characters
specified by <viewname>. For example, -snapview native will match the
"Native (15:14)" view even though it is not a perfect match. The
default value is 'internal'.
-mngwrite <filename>
Writes each video frame to the given <filename> in MNG format,

View File

@ -2028,7 +2028,7 @@ static void execute_snap(int ref, int params, const char *param[])
return;
}
video_screen_save_snapshot(screen, fp);
video_screen_save_snapshot(screen->machine, screen, fp);
mame_fclose(fp);
debug_console_printf("Saved screen #%d snapshot as '%s'\n", scrnum, filename);
}

View File

@ -64,10 +64,12 @@ const options_entry mame_core_options[] =
{ "autosave", "0", OPTION_BOOLEAN, "enable automatic restore at startup, and automatic save at exit time" },
{ "playback;pb", NULL, 0, "playback an input file" },
{ "record;rec", NULL, 0, "record an input file" },
{ "snapname", "%g/%i", 0, "override of the default snapshot naming; %g == gamename, %i == index" },
{ "mngwrite", NULL, 0, "optional filename to write a MNG movie of the current session" },
{ "aviwrite", NULL, 0, "optional filename to write an AVI movie of the current session" },
{ "wavwrite", NULL, 0, "optional filename to write a WAV file of the current session" },
{ "snapname", "%g/%i", 0, "override of the default snapshot/movie naming; %g == gamename, %i == index" },
{ "snapsize", "auto", 0, "specify snapshot/movie resolution (<width>x<height>) or 'auto' to use minimal size " },
{ "snapview", "internal", 0, "specify snapshot/movie view or 'internal' to use internal pixel-aspect views" },
/* performance options */
{ NULL, NULL, OPTION_HEADER, "CORE PERFORMANCE OPTIONS" },

View File

@ -63,10 +63,12 @@
#define OPTION_AUTOSAVE "autosave"
#define OPTION_PLAYBACK "playback"
#define OPTION_RECORD "record"
#define OPTION_SNAPNAME "snapname"
#define OPTION_MNGWRITE "mngwrite"
#define OPTION_AVIWRITE "aviwrite"
#define OPTION_WAVWRITE "wavwrite"
#define OPTION_SNAPNAME "snapname"
#define OPTION_SNAPSIZE "snapsize"
#define OPTION_SNAPVIEW "snapview"
/* core performance options */
#define OPTION_AUTOFRAMESKIP "autoframeskip"

View File

@ -171,9 +171,10 @@ INLINE UINT32 ycc_to_rgb(UINT32 ycc)
16bpp source
-------------------------------------------------*/
INLINE UINT32 get_texel_palette16_nearest(const UINT16 *texbase, INT32 texrp, INT32 curu, INT32 curv, const rgb_t *palbase)
INLINE UINT32 get_texel_palette16_nearest(const render_texinfo *texture, INT32 curu, INT32 curv)
{
return palbase[texbase[(curv >> 16) * texrp + (curu >> 16)]];
const UINT16 *texbase = (const UINT16 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 16);
return texture->palette[texbase[0]];
}
@ -183,14 +184,17 @@ INLINE UINT32 get_texel_palette16_nearest(const UINT16 *texbase, INT32 texrp, IN
16bpp source
-------------------------------------------------*/
INLINE UINT32 get_texel_palette16_bilinear(const UINT16 *texbase, INT32 texrp, INT32 curu, INT32 curv, const rgb_t *palbase)
INLINE UINT32 get_texel_palette16_bilinear(const render_texinfo *texture, INT32 curu, INT32 curv)
{
const UINT16 *texbase = (const UINT16 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 16);
INT32 u1 = (((curu >> 16) + 1) < texture->width) ? 1 : 0;
INT32 v1 = (((curv >> 16) + 1) < texture->height) ? texture->rowpixels : 0;
rgb_t pix00, pix01, pix10, pix11;
texbase += (curv >> 16) * texrp + (curu >> 16);
pix00 = palbase[texbase[0]];
pix01 = palbase[texbase[1]];
pix10 = palbase[texbase[texrp + 0]];
pix11 = palbase[texbase[texrp + 1]];
pix00 = texture->palette[texbase[0]];
pix01 = texture->palette[texbase[u1]];
pix10 = texture->palette[texbase[v1]];
pix11 = texture->palette[texbase[u1 + v1]];
return rgb_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
}
@ -200,9 +204,10 @@ INLINE UINT32 get_texel_palette16_bilinear(const UINT16 *texbase, INT32 texrp, I
nearest neighbor texel from a 15bpp RGB source
-------------------------------------------------*/
INLINE UINT32 get_texel_rgb15_nearest(const UINT16 *texbase, INT32 texrp, INT32 curu, INT32 curv)
INLINE UINT32 get_texel_rgb15_nearest(const render_texinfo *texture, INT32 curu, INT32 curv)
{
return texbase[(curv >> 16) * texrp + (curu >> 16)];
const UINT16 *texbase = (const UINT16 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 16);
return texbase[0];
}
@ -212,14 +217,17 @@ INLINE UINT32 get_texel_rgb15_nearest(const UINT16 *texbase, INT32 texrp, INT32
source
-------------------------------------------------*/
INLINE UINT32 get_texel_rgb15_bilinear(const UINT16 *texbase, INT32 texrp, INT32 curu, INT32 curv)
INLINE UINT32 get_texel_rgb15_bilinear(const render_texinfo *texture, INT32 curu, INT32 curv)
{
const UINT16 *texbase = (const UINT16 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 16);
INT32 u1 = (((curu >> 16) + 1) < texture->width) ? 1 : 0;
INT32 v1 = (((curv >> 16) + 1) < texture->height) ? texture->rowpixels : 0;
rgb_t pix00, pix01, pix10, pix11, filtered;
texbase += (curv >> 16) * texrp + (curu >> 16);
pix00 = texbase[0];
pix01 = texbase[1];
pix10 = texbase[texrp + 0];
pix11 = texbase[texrp + 1];
pix01 = texbase[u1];
pix10 = texbase[v1];
pix11 = texbase[u1 + v1];
pix00 = ((pix00 & 0x7fe0) << 6) | (pix00 & 0x1f);
pix01 = ((pix01 & 0x7fe0) << 6) | (pix01 & 0x1f);
pix10 = ((pix10 & 0x7fe0) << 6) | (pix10 & 0x1f);
@ -235,10 +243,10 @@ INLINE UINT32 get_texel_rgb15_bilinear(const UINT16 *texbase, INT32 texrp, INT32
source (pixel is returned as Cr-Cb-Y
-------------------------------------------------*/
INLINE UINT32 get_texel_yuy16_nearest(const UINT16 *texbase, INT32 texrp, INT32 curu, INT32 curv)
INLINE UINT32 get_texel_yuy16_nearest(const render_texinfo *texture, INT32 curu, INT32 curv)
{
const UINT16 *spix = &texbase[(curv >> 16) * texrp + (curu >> 17) * 2];
return (spix[(curu >> 16) & 1] >> 8) | ((spix[0] & 0xff) << 8) | ((spix[1] & 0xff) << 16);
const UINT16 *texbase = (const UINT16 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 17) * 2;
return (texbase[(curu >> 16) & 1] >> 8) | ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16);
}
@ -248,29 +256,42 @@ INLINE UINT32 get_texel_yuy16_nearest(const UINT16 *texbase, INT32 texrp, INT32
source (pixel is returned as Cr-Cb-Y
-------------------------------------------------*/
INLINE UINT32 get_texel_yuy16_bilinear(const UINT16 *texbase, INT32 texrp, INT32 curu, INT32 curv)
INLINE UINT32 get_texel_yuy16_bilinear(const render_texinfo *texture, INT32 curu, INT32 curv)
{
const UINT16 *texbase = (const UINT16 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 17) * 2;
INT32 u1 = (((curu >> 16) + 1) < texture->width) ? 1 : 0;
INT32 v1 = (((curv >> 16) + 1) < texture->height) ? texture->rowpixels : 0;
rgb_t pix00, pix01, pix10, pix11;
texbase += (curv >> 16) * texrp + (curu >> 17) * 2;
if ((curu & 0x10000) == 0)
{
rgb_t cbcr = ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16);
pix00 = (texbase[0] >> 8) | cbcr;
pix01 = (texbase[1] >> 8) | cbcr;
cbcr = ((texbase[texrp + 0] & 0xff) << 8) | ((texbase[texrp + 1] & 0xff) << 16);
pix10 = (texbase[texrp + 0] >> 8) | cbcr;
pix11 = (texbase[texrp + 1] >> 8) | cbcr;
pix01 = u1 ? ((texbase[1] >> 8) | cbcr) : pix00;
cbcr = ((texbase[v1 + 0] & 0xff) << 8) | ((texbase[v1 + 1] & 0xff) << 16);
pix10 = (texbase[v1 + 0] >> 8) | cbcr;
pix11 = u1 ? ((texbase[v1 + 1] >> 8) | cbcr) : pix10;
}
else
{
rgb_t cbcr = ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16);
pix00 = (texbase[1] >> 8) | cbcr;
cbcr = ((texbase[2] & 0xff) << 8) | ((texbase[3] & 0xff) << 16);
pix01 = (texbase[2] >> 8) | cbcr;
cbcr = ((texbase[texrp + 0] & 0xff) << 8) | ((texbase[texrp + 1] & 0xff) << 16);
pix10 = (texbase[texrp + 1] >> 8) | cbcr;
cbcr = ((texbase[texrp + 2] & 0xff) << 8) | ((texbase[texrp + 3] & 0xff) << 16);
pix11 = (texbase[texrp + 2] >> 8) | cbcr;
if (u1)
{
cbcr = ((texbase[2] & 0xff) << 8) | ((texbase[3] & 0xff) << 16);
pix01 = (texbase[2] >> 8) | cbcr;
}
else
pix01 = pix00;
cbcr = ((texbase[v1 + 0] & 0xff) << 8) | ((texbase[v1 + 1] & 0xff) << 16);
pix10 = (texbase[v1 + 1] >> 8) | cbcr;
if (u1)
{
cbcr = ((texbase[v1 + 2] & 0xff) << 8) | ((texbase[v1 + 3] & 0xff) << 16);
pix11 = (texbase[v1 + 2] >> 8) | cbcr;
}
else
pix11 = pix10;
}
return rgb_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
}
@ -281,9 +302,10 @@ INLINE UINT32 get_texel_yuy16_bilinear(const UINT16 *texbase, INT32 texrp, INT32
nearest neighbor texel from a 32bpp RGB source
-------------------------------------------------*/
INLINE UINT32 get_texel_rgb32_nearest(const UINT32 *texbase, INT32 texrp, INT32 curu, INT32 curv)
INLINE UINT32 get_texel_rgb32_nearest(const render_texinfo *texture, INT32 curu, INT32 curv)
{
return texbase[(curv >> 16) * texrp + (curu >> 16)];
const UINT32 *texbase = (const UINT32 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 16);
return texbase[0];
}
@ -293,14 +315,17 @@ INLINE UINT32 get_texel_rgb32_nearest(const UINT32 *texbase, INT32 texrp, INT32
source
-------------------------------------------------*/
INLINE UINT32 get_texel_rgb32_bilinear(const UINT32 *texbase, INT32 texrp, INT32 curu, INT32 curv)
INLINE UINT32 get_texel_rgb32_bilinear(const render_texinfo *texture, INT32 curu, INT32 curv)
{
const UINT32 *texbase = (const UINT32 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 16);
INT32 u1 = (((curu >> 16) + 1) < texture->width) ? 1 : 0;
INT32 v1 = (((curv >> 16) + 1) < texture->height) ? texture->rowpixels : 0;
rgb_t pix00, pix01, pix10, pix11;
texbase += (curv >> 16) * texrp + (curu >> 16);
pix00 = texbase[0];
pix01 = texbase[1];
pix10 = texbase[texrp + 0];
pix11 = texbase[texrp + 1];
pix01 = texbase[u1];
pix10 = texbase[v1];
pix11 = texbase[u1 + v1];
return rgb_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
}
@ -311,9 +336,10 @@ INLINE UINT32 get_texel_rgb32_bilinear(const UINT32 *texbase, INT32 texrp, INT32
source
-------------------------------------------------*/
INLINE UINT32 get_texel_argb32_nearest(const UINT32 *texbase, INT32 texrp, INT32 curu, INT32 curv)
INLINE UINT32 get_texel_argb32_nearest(const render_texinfo *texture, INT32 curu, INT32 curv)
{
return texbase[(curv >> 16) * texrp + (curu >> 16)];
const UINT32 *texbase = (const UINT32 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 16);
return texbase[0];
}
@ -323,14 +349,17 @@ INLINE UINT32 get_texel_argb32_nearest(const UINT32 *texbase, INT32 texrp, INT32
source
-------------------------------------------------*/
INLINE UINT32 get_texel_argb32_bilinear(const UINT32 *texbase, INT32 texrp, INT32 curu, INT32 curv)
INLINE UINT32 get_texel_argb32_bilinear(const render_texinfo *texture, INT32 curu, INT32 curv)
{
const UINT32 *texbase = (const UINT32 *)texture->base + (curv >> 16) * texture->rowpixels + (curu >> 16);
INT32 u1 = (((curu >> 16) + 1) < texture->width) ? 1 : 0;
INT32 v1 = (((curv >> 16) + 1) < texture->height) ? texture->rowpixels : 0;
rgb_t pix00, pix01, pix10, pix11;
texbase += (curv >> 16) * texrp + (curu >> 16);
pix00 = texbase[0];
pix01 = texbase[1];
pix10 = texbase[texrp + 0];
pix11 = texbase[texrp + 1];
pix01 = texbase[u1];
pix10 = texbase[v1];
pix11 = texbase[u1 + v1];
return rgba_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
}
@ -701,16 +730,13 @@ static void FUNC_PREFIX(draw_rect)(const render_primitive *prim, void *dstdata,
static void FUNC_PREFIX(draw_quad_palette16_none)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT16 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
INT32 x, y;
/* ensure all parameters are valid */
assert(palbase != NULL);
assert(prim->texture.palette != NULL);
/* fast case: no coloring, no alpha */
if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
@ -725,7 +751,7 @@ static void FUNC_PREFIX(draw_quad_palette16_none)(const render_primitive *prim,
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(palette16)(texbase, texrp, curu, curv, palbase);
UINT32 pix = GET_TEXEL(palette16)(&prim->texture, curu, curv);
*dest++ = SOURCE32_TO_DEST(pix);
curu += dudx;
curv += dvdx;
@ -755,7 +781,7 @@ static void FUNC_PREFIX(draw_quad_palette16_none)(const render_primitive *prim,
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(palette16)(texbase, texrp, curu, curv, palbase);
UINT32 pix = GET_TEXEL(palette16)(&prim->texture, curu, curv);
UINT32 r = (SOURCE32_R(pix) * sr) >> 8;
UINT32 g = (SOURCE32_G(pix) * sg) >> 8;
UINT32 b = (SOURCE32_B(pix) * sb) >> 8;
@ -791,7 +817,7 @@ static void FUNC_PREFIX(draw_quad_palette16_none)(const render_primitive *prim,
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(palette16)(texbase, texrp, curu, curv, palbase);
UINT32 pix = GET_TEXEL(palette16)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (SOURCE32_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
UINT32 g = (SOURCE32_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
@ -813,16 +839,13 @@ static void FUNC_PREFIX(draw_quad_palette16_none)(const render_primitive *prim,
static void FUNC_PREFIX(draw_quad_palette16_add)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT16 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
INT32 x, y;
/* ensure all parameters are valid */
assert(palbase != NULL);
assert(prim->texture.palette != NULL);
/* fast case: no coloring, no alpha */
if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
@ -837,7 +860,7 @@ static void FUNC_PREFIX(draw_quad_palette16_add)(const render_primitive *prim, v
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(palette16)(texbase, texrp, curu, curv, palbase);
UINT32 pix = GET_TEXEL(palette16)(&prim->texture, curu, curv);
if ((pix & 0xffffff) != 0)
{
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
@ -878,7 +901,7 @@ static void FUNC_PREFIX(draw_quad_palette16_add)(const render_primitive *prim, v
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(palette16)(texbase, texrp, curu, curv, palbase);
UINT32 pix = GET_TEXEL(palette16)(&prim->texture, curu, curv);
if ((pix & 0xffffff) != 0)
{
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
@ -910,16 +933,13 @@ static void FUNC_PREFIX(draw_quad_palette16_add)(const render_primitive *prim, v
static void FUNC_PREFIX(draw_quad_palettea16_alpha)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT16 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
INT32 x, y;
/* ensure all parameters are valid */
assert(palbase != NULL);
assert(prim->texture.palette != NULL);
/* fast case: no coloring, no alpha */
if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
@ -934,7 +954,7 @@ static void FUNC_PREFIX(draw_quad_palettea16_alpha)(const render_primitive *prim
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(palette16)(texbase, texrp, curu, curv, palbase);
UINT32 pix = GET_TEXEL(palette16)(&prim->texture, curu, curv);
UINT32 ta = pix >> 24;
if (ta != 0)
{
@ -977,7 +997,7 @@ static void FUNC_PREFIX(draw_quad_palettea16_alpha)(const render_primitive *prim
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(palette16)(texbase, texrp, curu, curv, palbase);
UINT32 pix = GET_TEXEL(palette16)(&prim->texture, curu, curv);
UINT32 ta = (pix >> 24) * sa;
if (ta != 0)
{
@ -1010,9 +1030,7 @@ static void FUNC_PREFIX(draw_quad_palettea16_alpha)(const render_primitive *prim
static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT16 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
@ -1034,7 +1052,7 @@ static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(texbase, texrp, curu, curv));
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(&prim->texture, curu, curv));
*dest++ = SOURCE32_TO_DEST(pix);
curu += dudx;
curv += dvdx;
@ -1047,7 +1065,7 @@ static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(texbase, texrp, curu, curv));
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(&prim->texture, curu, curv));
*dest++ = SOURCE32_TO_DEST(pix);
curu += dudx;
curv += dvdx;
@ -1081,7 +1099,7 @@ static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(texbase, texrp, curu, curv));
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(&prim->texture, curu, curv));
UINT32 r = (SOURCE32_R(pix) * sr) >> 8;
UINT32 g = (SOURCE32_G(pix) * sg) >> 8;
UINT32 b = (SOURCE32_B(pix) * sb) >> 8;
@ -1098,7 +1116,7 @@ static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(texbase, texrp, curu, curv));
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(&prim->texture, curu, curv));
UINT32 r = (SOURCE32_R(pix) * sr) >> 8;
UINT32 g = (SOURCE32_G(pix) * sg) >> 8;
UINT32 b = (SOURCE32_B(pix) * sb) >> 8;
@ -1138,7 +1156,7 @@ static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(texbase, texrp, curu, curv));
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(&prim->texture, curu, curv));
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (SOURCE32_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
UINT32 g = (SOURCE32_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
@ -1156,7 +1174,7 @@ static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(texbase, texrp, curu, curv));
UINT32 pix = ycc_to_rgb(GET_TEXEL(yuy16)(&prim->texture, curu, curv));
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (SOURCE32_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
UINT32 g = (SOURCE32_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
@ -1183,9 +1201,7 @@ static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void
static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT16 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
@ -1207,7 +1223,7 @@ static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb15)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb15)(&prim->texture, curu, curv);
*dest++ = SOURCE15_TO_DEST(pix);
curu += dudx;
curv += dvdx;
@ -1220,7 +1236,7 @@ static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb15)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb15)(&prim->texture, curu, curv);
UINT32 r = palbase[(pix >> 10) & 0x1f] >> SRCSHIFT_R;
UINT32 g = palbase[(pix >> 5) & 0x1f] >> SRCSHIFT_G;
UINT32 b = palbase[(pix >> 0) & 0x1f] >> SRCSHIFT_B;
@ -1258,7 +1274,7 @@ static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb15)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb15)(&prim->texture, curu, curv);
UINT32 r = (SOURCE15_R(pix) * sr) >> 8;
UINT32 g = (SOURCE15_G(pix) * sg) >> 8;
UINT32 b = (SOURCE15_B(pix) * sb) >> 8;
@ -1275,7 +1291,7 @@ static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb15)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb15)(&prim->texture, curu, curv);
UINT32 r = (palbase[(pix >> 10) & 0x1f] * sr) >> (8 + SRCSHIFT_R);
UINT32 g = (palbase[(pix >> 5) & 0x1f] * sg) >> (8 + SRCSHIFT_G);
UINT32 b = (palbase[(pix >> 0) & 0x1f] * sb) >> (8 + SRCSHIFT_B);
@ -1315,7 +1331,7 @@ static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb15)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb15)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (SOURCE15_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
UINT32 g = (SOURCE15_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
@ -1333,7 +1349,7 @@ static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb15)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb15)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = ((palbase[(pix >> 10) & 0x1f] >> SRCSHIFT_R) * sr + DEST_R(dpix) * invsa) >> 8;
UINT32 g = ((palbase[(pix >> 5) & 0x1f] >> SRCSHIFT_G) * sg + DEST_G(dpix) * invsa) >> 8;
@ -1361,9 +1377,7 @@ static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dst
static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT32 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
@ -1385,7 +1399,7 @@ static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb32)(&prim->texture, curu, curv);
*dest++ = SOURCE32_TO_DEST(pix);
curu += dudx;
curv += dvdx;
@ -1398,7 +1412,7 @@ static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb32)(&prim->texture, curu, curv);
UINT32 r = palbase[(pix >> 16) & 0xff] >> SRCSHIFT_R;
UINT32 g = palbase[(pix >> 8) & 0xff] >> SRCSHIFT_G;
UINT32 b = palbase[(pix >> 0) & 0xff] >> SRCSHIFT_B;
@ -1436,7 +1450,7 @@ static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb32)(&prim->texture, curu, curv);
UINT32 r = (SOURCE32_R(pix) * sr) >> 8;
UINT32 g = (SOURCE32_G(pix) * sg) >> 8;
UINT32 b = (SOURCE32_B(pix) * sb) >> 8;
@ -1453,7 +1467,7 @@ static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb32)(&prim->texture, curu, curv);
UINT32 r = (palbase[(pix >> 16) & 0xff] * sr) >> (8 + SRCSHIFT_R);
UINT32 g = (palbase[(pix >> 8) & 0xff] * sg) >> (8 + SRCSHIFT_G);
UINT32 b = (palbase[(pix >> 0) & 0xff] * sb) >> (8 + SRCSHIFT_B);
@ -1493,7 +1507,7 @@ static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb32)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (SOURCE32_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
UINT32 g = (SOURCE32_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
@ -1511,7 +1525,7 @@ static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dst
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(rgb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(rgb32)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = ((palbase[(pix >> 16) & 0xff] >> SRCSHIFT_R) * sr + DEST_R(dpix) * invsa) >> 8;
UINT32 g = ((palbase[(pix >> 8) & 0xff] >> SRCSHIFT_G) * sg + DEST_G(dpix) * invsa) >> 8;
@ -1539,9 +1553,7 @@ static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dst
static void FUNC_PREFIX(draw_quad_argb32_alpha)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT32 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
@ -1563,7 +1575,7 @@ static void FUNC_PREFIX(draw_quad_argb32_alpha)(const render_primitive *prim, vo
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 ta = pix >> 24;
if (ta != 0)
{
@ -1587,7 +1599,7 @@ static void FUNC_PREFIX(draw_quad_argb32_alpha)(const render_primitive *prim, vo
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 ta = pix >> 24;
if (ta != 0)
{
@ -1634,7 +1646,7 @@ static void FUNC_PREFIX(draw_quad_argb32_alpha)(const render_primitive *prim, vo
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 ta = (pix >> 24) * sa;
if (ta != 0)
{
@ -1659,7 +1671,7 @@ static void FUNC_PREFIX(draw_quad_argb32_alpha)(const render_primitive *prim, vo
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 ta = (pix >> 24) * sa;
if (ta != 0)
{
@ -1688,9 +1700,7 @@ static void FUNC_PREFIX(draw_quad_argb32_alpha)(const render_primitive *prim, vo
static void FUNC_PREFIX(draw_quad_argb32_multiply)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT32 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
@ -1716,7 +1726,7 @@ static void FUNC_PREFIX(draw_quad_argb32_multiply)(const render_primitive *prim,
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (SOURCE32_R(pix) * DEST_R(dpix)) >> (8 - SRCSHIFT_R);
UINT32 g = (SOURCE32_G(pix) * DEST_G(dpix)) >> (8 - SRCSHIFT_G);
@ -1732,7 +1742,7 @@ static void FUNC_PREFIX(draw_quad_argb32_multiply)(const render_primitive *prim,
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (palbase[(pix >> 16) & 0xff] * DEST_R(dpix)) >> 8;
UINT32 g = (palbase[(pix >> 8) & 0xff] * DEST_G(dpix)) >> 8;
@ -1771,7 +1781,7 @@ static void FUNC_PREFIX(draw_quad_argb32_multiply)(const render_primitive *prim,
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (SOURCE32_R(pix) * sr * DEST_R(dpix)) >> (16 - SRCSHIFT_R);
UINT32 g = (SOURCE32_G(pix) * sg * DEST_G(dpix)) >> (16 - SRCSHIFT_G);
@ -1787,7 +1797,7 @@ static void FUNC_PREFIX(draw_quad_argb32_multiply)(const render_primitive *prim,
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 dpix = NO_DEST_READ ? 0 : *dest;
UINT32 r = (palbase[(pix >> 16) & 0xff] * sr * DEST_R(dpix)) >> 16;
UINT32 g = (palbase[(pix >> 8) & 0xff] * sg * DEST_G(dpix)) >> 16;
@ -1810,9 +1820,7 @@ static void FUNC_PREFIX(draw_quad_argb32_multiply)(const render_primitive *prim,
static void FUNC_PREFIX(draw_quad_argb32_add)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
{
UINT32 *texbase = prim->texture.base;
const rgb_t *palbase = prim->texture.palette;
UINT32 texrp = prim->texture.rowpixels;
INT32 dudx = setup->dudx;
INT32 dvdx = setup->dvdx;
INT32 endx = setup->endx;
@ -1838,7 +1846,7 @@ static void FUNC_PREFIX(draw_quad_argb32_add)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 ta = pix >> 24;
if (ta != 0)
{
@ -1863,7 +1871,7 @@ static void FUNC_PREFIX(draw_quad_argb32_add)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 ta = pix >> 24;
if (ta != 0)
{
@ -1911,7 +1919,7 @@ static void FUNC_PREFIX(draw_quad_argb32_add)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 ta = (pix >> 24) * sa;
if (ta != 0)
{
@ -1936,7 +1944,7 @@ static void FUNC_PREFIX(draw_quad_argb32_add)(const render_primitive *prim, void
/* loop over cols */
for (x = setup->startx; x < endx; x++)
{
UINT32 pix = GET_TEXEL(argb32)(texbase, texrp, curu, curv);
UINT32 pix = GET_TEXEL(argb32)(&prim->texture, curu, curv);
UINT32 ta = (pix >> 24) * sa;
if (ta != 0)
{

View File

@ -1315,14 +1315,14 @@ static UINT32 handler_ingame(running_machine *machine, UINT32 state)
/* toggle movie recording */
if (input_ui_pressed(machine, IPT_UI_RECORD_MOVIE))
{
if (!video_mng_is_movie_active(machine->primary_screen))
if (!video_mng_is_movie_active(machine))
{
video_mng_begin_recording(machine->primary_screen, NULL);
video_mng_begin_recording(machine, NULL);
popmessage("REC START");
}
else
{
video_mng_end_recording(machine->primary_screen);
video_mng_end_recording(machine);
popmessage("REC STOP");
}
}

View File

@ -38,7 +38,8 @@
#define SUBSECONDS_PER_SPEED_UPDATE (ATTOSECONDS_PER_SECOND / 4)
#define PAUSED_REFRESH_RATE (30)
#define MAX_VBLANK_CALLBACKS (10)
#define DEFAULT_FRAME_PERIOD ATTOTIME_IN_HZ(60)
#define DEFAULT_FRAME_RATE 60
#define DEFAULT_FRAME_PERIOD ATTOTIME_IN_HZ(DEFAULT_FRAME_RATE)
@ -78,11 +79,6 @@ struct _screen_state
/* screen specific VBLANK callbacks */
vblank_state_changed_func vblank_callback[MAX_VBLANK_CALLBACKS]; /* the array of callbacks */
/* movie recording */
mame_file * mng_file; /* handle to the open movie file */
avi_file * avi_file; /* handle to the open movie file */
UINT32 movie_frame; /* current movie frame number */
};
@ -128,6 +124,16 @@ struct _video_global
/* snapshot stuff */
render_target * snap_target; /* screen shapshot target */
bitmap_t * snap_bitmap; /* screen snapshot bitmap */
UINT8 snap_native; /* are we using native per-screen layouts? */
INT32 snap_width; /* width of snapshots (0 == auto) */
INT32 snap_height; /* height of snapshots (0 == auto) */
/* movie recording */
mame_file * mng_file; /* handle to the open movie file */
avi_file * avi_file; /* handle to the open movie file */
attotime movie_frame_period; /* period of a single movie frame */
attotime movie_next_frame_time; /* time of next frame */
UINT32 movie_frame; /* current movie frame number */
};
@ -190,8 +196,8 @@ static void create_snapshot_bitmap(const device_config *screen);
static file_error mame_fopen_next(running_machine *machine, const char *pathoption, const char *extension, mame_file **file);
/* movie recording */
static void video_mng_record_frame(const device_config *screen);
static void video_avi_record_frame(const device_config *screen);
static void video_mng_record_frame(running_machine *machine);
static void video_avi_record_frame(running_machine *machine);
/* software rendering */
static void rgb888_draw_primitives(const render_primitive *primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
@ -295,6 +301,7 @@ INLINE int original_speed_setting(void)
void video_init(running_machine *machine)
{
const char *filename;
const char *viewname;
/* validate */
assert(machine != NULL);
@ -339,21 +346,51 @@ void video_init(running_machine *machine)
pdrawgfx_shadow_lowpri = 0;
/* create a render target for snapshots */
if (machine->primary_screen != NULL)
{
viewname = options_get_string(mame_options(), OPTION_SNAPVIEW);
global.snap_native = (machine->primary_screen != NULL && (viewname[0] == 0 || strcmp(viewname, "native") == 0));
if (global.snap_native)
global.snap_target = render_target_alloc(layout_snap, RENDER_CREATE_SINGLE_FILE | RENDER_CREATE_HIDDEN);
assert(global.snap_target != NULL);
else
global.snap_target = render_target_alloc(NULL, RENDER_CREATE_HIDDEN);
assert(global.snap_target != NULL);
/* if we are using the native layout, turn off all accoutrements */
if (global.snap_native)
render_target_set_layer_config(global.snap_target, 0);
/* otherwise, find the requested view and select it */
else
{
int viewindex;
/* scan for a match or partial match */
for (viewindex = 0; ; viewindex++)
{
const char *name = render_target_get_view_name(global.snap_target, viewindex);
/* stop scanning when we hit NULL */
if (name == NULL)
break;
if (mame_strnicmp(name, viewname, strlen(viewname)) == 0)
{
render_target_set_view(global.snap_target, viewindex);
break;
}
}
}
/* extract snap resolution if present */
if (sscanf(options_get_string(mame_options(), OPTION_SNAPSIZE), "%dx%d", &global.snap_width, &global.snap_height) != 2)
global.snap_width = global.snap_height = 0;
/* start recording movie if specified */
filename = options_get_string(mame_options(), OPTION_MNGWRITE);
if (filename[0] != 0 && machine->primary_screen != NULL)
video_mng_begin_recording(machine->primary_screen, filename);
if (filename[0] != 0)
video_mng_begin_recording(machine, filename);
filename = options_get_string(mame_options(), OPTION_AVIWRITE);
if (filename[0] != 0 && machine->primary_screen != NULL)
video_avi_begin_recording(machine->primary_screen, filename);
if (filename[0] != 0)
video_avi_begin_recording(machine, filename);
/* if no screens, create a periodic timer to drive updates */
if (machine->primary_screen == NULL)
@ -379,8 +416,8 @@ static void video_exit(running_machine *machine)
/* stop recording any movie */
if (machine->primary_screen != NULL)
{
video_mng_end_recording(machine->primary_screen);
video_avi_end_recording(machine->primary_screen);
video_mng_end_recording(machine);
video_avi_end_recording(machine);
}
/* free all the graphics elements */
@ -1515,13 +1552,6 @@ static int finish_screen_updates(running_machine *machine)
render_container_empty(render_container_get_screen(screen));
render_screen_add_quad(screen, 0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), state->texture[state->curtexture], PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1));
}
/* update our movie recording state */
if (!mame_is_paused(machine))
{
video_mng_record_frame(screen);
video_avi_record_frame(screen);
}
}
/* reset the screen changed flags */
@ -1530,6 +1560,13 @@ static int finish_screen_updates(running_machine *machine)
state->changed = FALSE;
}
/* update our movie recording state */
if (!mame_is_paused(machine))
{
video_mng_record_frame(machine);
video_avi_record_frame(machine);
}
/* draw any crosshairs */
for (screen = video_screen_first(machine->config); screen != NULL; screen = video_screen_next(screen))
crosshair_render(screen);
@ -2089,7 +2126,7 @@ static void recompute_speed(running_machine *machine, attotime emutime)
filerr = mame_fopen(SEARCHPATH_SCREENSHOT, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
if (filerr == FILERR_NONE)
{
video_screen_save_snapshot(machine->primary_screen, file);
video_screen_save_snapshot(machine, machine->primary_screen, file);
mame_fclose(file);
}
astring_free(fname);
@ -2111,15 +2148,15 @@ static void recompute_speed(running_machine *machine, attotime emutime)
to the given file handle
-------------------------------------------------*/
void video_screen_save_snapshot(const device_config *screen, mame_file *fp)
void video_screen_save_snapshot(running_machine *machine, const device_config *screen, mame_file *fp)
{
const rgb_t *palette;
png_info pnginfo = { 0 };
const rgb_t *palette;
png_error error;
char text[256];
/* validate */
assert(screen != NULL);
assert(!global.snap_native || screen != NULL);
assert(fp != NULL);
/* create the bitmap to pass in */
@ -2128,12 +2165,12 @@ void video_screen_save_snapshot(const device_config *screen, mame_file *fp)
/* add two text entries describing the image */
sprintf(text, APPNAME " %s", build_version);
png_add_text(&pnginfo, "Software", text);
sprintf(text, "%s %s", screen->machine->gamedrv->manufacturer, screen->machine->gamedrv->description);
sprintf(text, "%s %s", machine->gamedrv->manufacturer, machine->gamedrv->description);
png_add_text(&pnginfo, "System", text);
/* now do the actual work */
palette = (screen->machine->palette != NULL) ? palette_entry_list_adjusted(screen->machine->palette) : NULL;
error = png_write_bitmap(mame_core_file(fp), &pnginfo, global.snap_bitmap, screen->machine->config->total_colors, palette);
palette = (machine->palette != NULL) ? palette_entry_list_adjusted(machine->palette) : NULL;
error = png_write_bitmap(mame_core_file(fp), &pnginfo, global.snap_bitmap, machine->config->total_colors, palette);
/* free any data allocated */
png_free(&pnginfo);
@ -2153,18 +2190,33 @@ void video_save_active_screen_snapshots(running_machine *machine)
/* validate */
assert(machine != NULL);
assert(machine->config != NULL);
/* write one snapshot per visible screen */
for (screen = video_screen_first(machine->config); screen != NULL; screen = video_screen_next(screen))
if (render_is_live_screen(screen))
{
file_error filerr = mame_fopen_next(machine, SEARCHPATH_SCREENSHOT, "png", &fp);
if (filerr == FILERR_NONE)
/* if we're native, then write one snapshot per visible screen */
if (global.snap_native)
{
/* write one snapshot per visible screen */
for (screen = video_screen_first(machine->config); screen != NULL; screen = video_screen_next(screen))
if (render_is_live_screen(screen))
{
video_screen_save_snapshot(screen, fp);
mame_fclose(fp);
file_error filerr = mame_fopen_next(machine, SEARCHPATH_SCREENSHOT, "png", &fp);
if (filerr == FILERR_NONE)
{
video_screen_save_snapshot(machine, screen, fp);
mame_fclose(fp);
}
}
}
/* otherwise, just write a single snapshot */
else
{
file_error filerr = mame_fopen_next(machine, SEARCHPATH_SCREENSHOT, "png", &fp);
if (filerr == FILERR_NONE)
{
video_screen_save_snapshot(machine, NULL, fp);
mame_fclose(fp);
}
}
}
@ -2181,12 +2233,18 @@ static void create_snapshot_bitmap(const device_config *screen)
int view_index;
/* select the appropriate view in our dummy target */
view_index = device_list_index(screen->machine->config->devicelist, VIDEO_SCREEN, screen->tag);
assert(view_index != -1);
render_target_set_view(global.snap_target, view_index);
if (global.snap_native && screen != NULL)
{
view_index = device_list_index(screen->machine->config->devicelist, VIDEO_SCREEN, screen->tag);
assert(view_index != -1);
render_target_set_view(global.snap_target, view_index);
}
/* get the minimum width/height and set it on the target */
render_target_get_minimum_size(global.snap_target, &width, &height);
width = global.snap_width;
height = global.snap_height;
if (width == 0 || height == 0)
render_target_get_minimum_size(global.snap_target, &width, &height);
render_target_set_bounds(global.snap_target, width, height, 0);
/* if we don't have a bitmap, or if it's not the right size, allocate a new one */
@ -2285,10 +2343,9 @@ static file_error mame_fopen_next(running_machine *machine, const char *pathopti
MNG movie is currently being recorded
-------------------------------------------------*/
int video_mng_is_movie_active(const device_config *screen)
int video_mng_is_movie_active(running_machine *machine)
{
screen_state *state = get_safe_token(screen);
return (state->mng_file != NULL);
return (global.mng_file != NULL);
}
@ -2297,21 +2354,43 @@ int video_mng_is_movie_active(const device_config *screen)
of a MNG movie
-------------------------------------------------*/
void video_mng_begin_recording(const device_config *screen, const char *name)
void video_mng_begin_recording(running_machine *machine, const char *name)
{
screen_state *state = get_safe_token(screen);
screen_state *state = NULL;
file_error filerr;
png_error pngerr;
int rate;
/* close any existing movie file */
if (state->mng_file != NULL)
video_mng_end_recording(screen);
if (global.mng_file != NULL)
video_mng_end_recording(machine);
/* look up the primary screen */
if (machine->primary_screen != NULL)
state = get_safe_token(machine->primary_screen);
/* create a snapshot bitmap so we know what the target size is */
create_snapshot_bitmap(NULL);
/* create a new movie file and start recording */
if (name != NULL)
filerr = mame_fopen(SEARCHPATH_MOVIE, name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &state->mng_file);
filerr = mame_fopen(SEARCHPATH_MOVIE, name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &global.mng_file);
else
filerr = mame_fopen_next(screen->machine, SEARCHPATH_MOVIE, "mng", &state->mng_file);
state->movie_frame = 0;
filerr = mame_fopen_next(machine, SEARCHPATH_MOVIE, "mng", &global.mng_file);
/* start the capture */
rate = (state != NULL) ? ATTOSECONDS_TO_HZ(state->frame_period) : DEFAULT_FRAME_RATE;
pngerr = mng_capture_start(mame_core_file(global.mng_file), global.snap_bitmap, rate);
if (pngerr != PNGERR_NONE)
{
video_mng_end_recording(machine);
return;
}
/* compute the frame time */
global.movie_next_frame_time = timer_get_time();
global.movie_frame_period = ATTOTIME_IN_HZ(rate);
global.movie_frame = 0;
}
@ -2320,17 +2399,15 @@ void video_mng_begin_recording(const device_config *screen, const char *name)
a MNG movie
-------------------------------------------------*/
void video_mng_end_recording(const device_config *screen)
void video_mng_end_recording(running_machine *machine)
{
screen_state *state = get_safe_token(screen);
/* close the file if it exists */
if (state->mng_file != NULL)
if (global.mng_file != NULL)
{
mng_capture_stop(mame_core_file(state->mng_file));
mame_fclose(state->mng_file);
state->mng_file = NULL;
state->movie_frame = 0;
mng_capture_stop(mame_core_file(global.mng_file));
mame_fclose(global.mng_file);
global.mng_file = NULL;
global.movie_frame = 0;
}
}
@ -2340,49 +2417,50 @@ void video_mng_end_recording(const device_config *screen)
movie
-------------------------------------------------*/
static void video_mng_record_frame(const device_config *screen)
static void video_mng_record_frame(running_machine *machine)
{
screen_state *state = get_safe_token(screen);
const rgb_t *palette;
/* only record if we have a file */
if (state->mng_file != NULL)
if (global.mng_file != NULL)
{
attotime curtime = timer_get_time();
png_info pnginfo = { 0 };
png_error error;
profiler_mark(PROFILER_MOVIE_REC);
/* create the bitmap */
create_snapshot_bitmap(screen);
create_snapshot_bitmap(NULL);
/* track frames */
if (state->movie_frame++ == 0)
/* loop until we hit the right time */
while (attotime_compare(global.movie_next_frame_time, curtime) <= 0)
{
char text[256];
const rgb_t *palette;
/* set up the text fields in the movie info */
sprintf(text, APPNAME " %s", build_version);
png_add_text(&pnginfo, "Software", text);
sprintf(text, "%s %s", screen->machine->gamedrv->manufacturer, screen->machine->gamedrv->description);
png_add_text(&pnginfo, "System", text);
if (global.movie_frame == 0)
{
char text[256];
/* start the capture */
error = mng_capture_start(mame_core_file(state->mng_file), global.snap_bitmap, ATTOSECONDS_TO_HZ(state->frame_period));
sprintf(text, APPNAME " %s", build_version);
png_add_text(&pnginfo, "Software", text);
sprintf(text, "%s %s", machine->gamedrv->manufacturer, machine->gamedrv->description);
png_add_text(&pnginfo, "System", text);
}
/* write the next frame */
palette = (machine->palette != NULL) ? palette_entry_list_adjusted(machine->palette) : NULL;
error = mng_capture_frame(mame_core_file(global.mng_file), &pnginfo, global.snap_bitmap, machine->config->total_colors, palette);
png_free(&pnginfo);
if (error != PNGERR_NONE)
{
png_free(&pnginfo);
video_mng_end_recording(screen);
return;
video_mng_end_recording(machine);
break;
}
}
/* write the next frame */
palette = (screen->machine->palette != NULL) ? palette_entry_list_adjusted(screen->machine->palette) : NULL;
error = mng_capture_frame(mame_core_file(state->mng_file), &pnginfo, global.snap_bitmap, screen->machine->config->total_colors, palette);
png_free(&pnginfo);
if (error != PNGERR_NONE)
video_mng_end_recording(screen);
/* advance time */
global.movie_next_frame_time = attotime_add(global.movie_next_frame_time, global.movie_frame_period);
global.movie_frame++;
}
profiler_mark(PROFILER_END);
}
@ -2399,24 +2477,28 @@ static void video_mng_record_frame(const device_config *screen)
of an AVI movie
-------------------------------------------------*/
void video_avi_begin_recording(const device_config *screen, const char *name)
void video_avi_begin_recording(running_machine *machine, const char *name)
{
screen_state *state = get_safe_token(screen);
screen_state *state = NULL;
avi_movie_info info;
mame_file *tempfile;
file_error filerr;
avi_error avierr;
/* close any existing movie file */
if (state->avi_file != NULL)
video_avi_end_recording(screen);
if (global.avi_file != NULL)
video_avi_end_recording(machine);
/* look up the primary screen */
if (machine->primary_screen != NULL)
state = get_safe_token(machine->primary_screen);
/* create a snapshot bitmap so we know what the target size is */
create_snapshot_bitmap(screen);
create_snapshot_bitmap(NULL);
/* build up information about this new movie */
info.video_format = 0;
info.video_timescale = 1000 * ATTOSECONDS_TO_HZ(state->frame_period);
info.video_timescale = 1000 * ((state != NULL) ? ATTOSECONDS_TO_HZ(state->frame_period) : DEFAULT_FRAME_RATE);
info.video_sampletime = 1000;
info.video_numsamples = 0;
info.video_width = global.snap_bitmap->width;
@ -2425,18 +2507,22 @@ void video_avi_begin_recording(const device_config *screen, const char *name)
info.audio_format = 0;
info.audio_timescale = 1;
info.audio_sampletime = screen->machine->sample_rate;
info.audio_sampletime = machine->sample_rate;
info.audio_numsamples = 0;
info.audio_channels = 2;
info.audio_samplebits = 16;
info.audio_samplerate = screen->machine->sample_rate;
info.audio_samplerate = machine->sample_rate;
/* create a new temporary movie file */
if (name != NULL)
filerr = mame_fopen(SEARCHPATH_MOVIE, name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &tempfile);
else
filerr = mame_fopen_next(screen->machine, SEARCHPATH_MOVIE, "avi", &tempfile);
state->movie_frame = 0;
filerr = mame_fopen_next(machine, SEARCHPATH_MOVIE, "avi", &tempfile);
/* reset our tracking */
global.movie_frame = 0;
global.movie_next_frame_time = timer_get_time();
global.movie_frame_period = attotime_div(ATTOTIME_IN_SEC(1000), info.video_timescale);
/* if we succeeded, make a copy of the name and create the real file over top */
if (filerr == FILERR_NONE)
@ -2445,7 +2531,7 @@ void video_avi_begin_recording(const device_config *screen, const char *name)
mame_fclose(tempfile);
/* create the file and free the string */
avierr = avi_create(astring_c(fullname), &info, &state->avi_file);
avierr = avi_create(astring_c(fullname), &info, &global.avi_file);
astring_free(fullname);
}
}
@ -2456,16 +2542,14 @@ void video_avi_begin_recording(const device_config *screen, const char *name)
a avi movie
-------------------------------------------------*/
void video_avi_end_recording(const device_config *screen)
void video_avi_end_recording(running_machine *machine)
{
screen_state *state = get_safe_token(screen);
/* close the file if it exists */
if (state->avi_file != NULL)
if (global.avi_file != NULL)
{
avi_close(state->avi_file);
state->avi_file = NULL;
state->movie_frame = 0;
avi_close(global.avi_file);
global.avi_file = NULL;
global.movie_frame = 0;
}
}
@ -2475,24 +2559,34 @@ void video_avi_end_recording(const device_config *screen)
movie
-------------------------------------------------*/
static void video_avi_record_frame(const device_config *screen)
static void video_avi_record_frame(running_machine *machine)
{
screen_state *state = get_safe_token(screen);
/* only record if we have a file */
if (state->avi_file != NULL)
if (global.avi_file != NULL)
{
attotime curtime = timer_get_time();
avi_error avierr;
profiler_mark(PROFILER_MOVIE_REC);
/* create the bitmap */
create_snapshot_bitmap(screen);
create_snapshot_bitmap(NULL);
/* write the next frame */
avierr = avi_append_video_frame_rgb32(state->avi_file, global.snap_bitmap);
if (avierr != AVIERR_NONE)
video_avi_end_recording(screen);
/* loop until we hit the right time */
while (attotime_compare(global.movie_next_frame_time, curtime) <= 0)
{
/* write the next frame */
avierr = avi_append_video_frame_rgb32(global.avi_file, global.snap_bitmap);
if (avierr != AVIERR_NONE)
{
video_avi_end_recording(machine);
break;
}
/* advance time */
global.movie_next_frame_time = attotime_add(global.movie_next_frame_time, global.movie_frame_period);
global.movie_frame++;
}
profiler_mark(PROFILER_END);
}
@ -2506,29 +2600,21 @@ static void video_avi_record_frame(const device_config *screen)
void video_avi_add_sound(running_machine *machine, const INT16 *sound, int numsamples)
{
const device_config *screen;
/* loop over screens that might be recording */
for (screen = video_screen_first(machine->config); screen != NULL; screen = video_screen_next(screen))
/* only record if we have a file */
if (global.avi_file != NULL)
{
screen_state *state = get_safe_token(screen);
avi_error avierr;
/* only record if we have a file */
if (state->avi_file != NULL)
{
avi_error avierr;
profiler_mark(PROFILER_MOVIE_REC);
profiler_mark(PROFILER_MOVIE_REC);
/* write the next frame */
avierr = avi_append_sound_samples(global.avi_file, 0, sound + 0, numsamples, 1);
if (avierr == AVIERR_NONE)
avierr = avi_append_sound_samples(global.avi_file, 1, sound + 1, numsamples, 1);
if (avierr != AVIERR_NONE)
video_avi_end_recording(machine);
/* write the next frame */
avierr = avi_append_sound_samples(state->avi_file, 0, sound + 0, numsamples, 1);
if (avierr == AVIERR_NONE)
avierr = avi_append_sound_samples(state->avi_file, 1, sound + 1, numsamples, 1);
if (avierr != AVIERR_NONE)
video_avi_end_recording(screen);
profiler_mark(PROFILER_END);
}
profiler_mark(PROFILER_END);
}
}
@ -2546,5 +2632,6 @@ void video_avi_add_sound(running_machine *machine, const INT16 *sound, int numsa
#define DSTSHIFT_R 16
#define DSTSHIFT_G 8
#define DSTSHIFT_B 0
#define BILINEAR_FILTER 1
#include "rendersw.c"

View File

@ -255,7 +255,7 @@ void video_set_fastforward(int fastforward);
/* ----- snapshots ----- */
/* save a snapshot of a given screen */
void video_screen_save_snapshot(const device_config *screen, mame_file *fp);
void video_screen_save_snapshot(running_machine *machine, const device_config *screen, mame_file *fp);
/* save a snapshot of all the active screens */
void video_save_active_screen_snapshots(running_machine *machine);
@ -263,12 +263,12 @@ void video_save_active_screen_snapshots(running_machine *machine);
/* ----- movie recording ----- */
int video_mng_is_movie_active(const device_config *screen);
void video_mng_begin_recording(const device_config *screen, const char *name);
void video_mng_end_recording(const device_config *screen);
int video_mng_is_movie_active(running_machine *machine);
void video_mng_begin_recording(running_machine *machine, const char *name);
void video_mng_end_recording(running_machine *machine);
void video_avi_begin_recording(const device_config *screen, const char *name);
void video_avi_end_recording(const device_config *screen);
void video_avi_begin_recording(running_machine *machine, const char *name);
void video_avi_end_recording(running_machine *machine);
void video_avi_add_sound(running_machine *machine, const INT16 *sound, int numsamples);
#endif /* __VIDEO_H__ */