diff -Nru mame107u2orig\docs\windows.txt mame107u2\docs\windows.txt --- mame107u2orig\docs\windows.txt Sun Jul 16 19:37:46 2006 +++ mame107u2\docs\windows.txt Sun Jul 30 16:35:36 2006 @@ -625,6 +643,28 @@ increases the effective resolution of non-screen elements such as artwork and fonts. The default is 1. +-cleanstretch +-cs + + Stretch the image to integer ratios only. This makes the pixels look less + blurry but may leave a black border around the image. The options are: + + none disable. + horizontal always stretch to integer ratios horizontally. + vertical always stretch to integer ratios vertically. + full always stretch to integer ratios both horizontally + and vertically. + + (horizontal and vertical refers to the monitor's orientation not the game) + (options can be abbreviated down to 1 character: n,h,v,f) + The default is none (-cleanstretch none). This option can also be controlled + via the Video Options menu in the user interface. + + This option is ignored for -video ddraw which always uses integer stretching. + + -cleanstretch full might cause the game to display with slightly wrong + aspect ratio. + -effect Specifies a single PNG file that is used as an overlay over any game diff -Nru mame107u2orig\src\render.c mame107u2\src\render.c --- mame107u2orig\src\render.c Sun Jul 30 16:09:08 2006 +++ mame107u2\src\render.c Mon Aug 07 15:01:42 2006 @@ -904,6 +904,10 @@ render_target_set_layer_config(target, target->layerconfig & ~LAYER_CONFIG_ZOOM_TO_SCREEN); else if (tmpint == 1) render_target_set_layer_config(target, target->layerconfig | LAYER_CONFIG_ZOOM_TO_SCREEN); + tmpint = xml_get_attribute_int(targetnode, "cleanstretch", -1); + if (tmpint >= 0 && tmpint <= 3) + render_target_set_layer_config(target, (target->layerconfig & ~LAYER_CONFIG_CONSTRAIN_MASK) | + (tmpint * LAYER_CONFIG_CONSTRAIN_WIDTH)); /* apply orientation */ tmpint = xml_get_attribute_int(targetnode, "rotate", -1); @@ -1010,6 +1014,8 @@ xml_set_attribute_int(targetnode, "overlays", (target->layerconfig & LAYER_CONFIG_ENABLE_OVERLAY) != 0); xml_set_attribute_int(targetnode, "bezels", (target->layerconfig & LAYER_CONFIG_ENABLE_BEZEL) != 0); xml_set_attribute_int(targetnode, "zoom", (target->layerconfig & LAYER_CONFIG_ZOOM_TO_SCREEN) != 0); + xml_set_attribute_int(targetnode, "cleanstretch", (target->layerconfig & LAYER_CONFIG_CONSTRAIN_MASK) / + LAYER_CONFIG_CONSTRAIN_WIDTH); changed = TRUE; } @@ -1567,6 +1573,144 @@ *visible_height = round_nearest(height * scale); } +void render_target_compute_scale(render_target *target, float *scalex, float *scaley, float *offsx, float *offsy) +{ + view_item *item, *screen = NULL; + render_bounds bounds, rawbounds, scrbounds; + int game_x, game_y; // game size in pixels + int targ_x, targ_y; // available area to fit game within + float game_p, targ_p; // pixel aspect ratio of game and target + // set some sensible default vales + *scalex = target->width; + *scaley = target->height; + *offsx = 0; + *offsy = 0; + + if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR) return; + + scrbounds.x0 = scrbounds.y0 = scrbounds.x1 = scrbounds.y1 = 0.0f; + for (item = target->curview->itemlist[ITEM_LAYER_SCREEN]; item != NULL; item = item->next) { + if (item->element == NULL) + { + if (scrbounds.x0 == scrbounds.x1) + scrbounds = item->bounds; + else + union_render_bounds(&scrbounds, &item->bounds); + // All screens in a target are assumed to have the same pixel size so just pick one + if (screen == NULL) screen = item; + } + } + if (!screen) return; + + apply_orientation(&scrbounds, target->orientation); normalize_bounds(&scrbounds); + bounds = screen->bounds; + apply_orientation(&bounds, target->orientation); normalize_bounds(&bounds); + rawbounds = screen->rawbounds; + apply_orientation(&rawbounds, target->orientation); normalize_bounds(&rawbounds); + // how much of the target can we use? + if (target->layerconfig & LAYER_CONFIG_ZOOM_TO_SCREEN) + { + targ_x = round_nearest(target->width * (bounds.x1 - bounds.x0) / (scrbounds.x1 - scrbounds.x0)); + targ_y = round_nearest(target->height * (bounds.y1 - bounds.y0) / (scrbounds.y1 - scrbounds.y0)); + } + else + { // viewbounds should be (0,0)-(1,1) + targ_x = round_nearest(target->width * (bounds.x1 - bounds.x0)); + targ_y = round_nearest(target->height * (bounds.y1 - bounds.y0)); + } + targ_p = target->pixel_aspect; + { // find game size + const rectangle* visarea; + if (Machine->screen[screen->index].visarea.max_x > Machine->screen[screen->index].visarea.min_x) + visarea = &Machine->screen[screen->index].visarea; + else + visarea = &Machine->drv->screen[screen->index].defstate.visarea; + game_x = visarea->max_x + 1 - visarea->min_x; + game_y = visarea->max_y + 1 - visarea->min_y; + // ensure game got same orientation as target + if ((orientation_add(target->orientation, Machine->gamedrv->flags & ORIENTATION_MASK) & ORIENTATION_SWAP_XY)) + ISWAP(game_x, game_y); + game_p = (game_y * (rawbounds.x1 - rawbounds.x0)) / (game_x * (rawbounds.y1 - rawbounds.y0)); + } + //logerror("itembounds: %4.2f-%4.2f %4.2f-%4.2f\n", bounds.x0, bounds.x1, bounds.y0, bounds.y1); + //logerror("rawbounds: %4.2f-%4.2f %4.2f-%4.2f\n", rawbounds.x0, rawbounds.x1, rawbounds.y0, rawbounds.y1); + //logerror("scrbounds: %4.2f-%4.2f %4.2f-%4.2f\n", scrbounds.x0, scrbounds.x1, scrbounds.y0, scrbounds.y1); + //logerror("target: full: %dx%d limit: %dx%d pixel:%4.2f\n", target->width, target->height, targ_x, targ_y, targ_p); + //logerror("game: %dx%d pixel: %4.2f\n", game_x, game_y, game_p); + if (targ_p != 0.0) + { + switch (target->layerconfig & LAYER_CONFIG_CONSTRAIN_MASK) { + case LAYER_CONFIG_CONSTRAIN_WIDTH: // Only constrained horizontally + { // width required to use full height + const int usey_x = round_nearest(game_x * game_p / targ_p * targ_y / game_y); + const int orig_x = targ_x; + int tmp = (usey_x + game_x / 2) / game_x * game_x; + targ_x = (tmp > targ_x) ? (targ_x / game_x * game_x) : tmp; + if (targ_x == 0) targ_x = orig_x; // too small, ignore constraint + tmp = round_nearest(targ_x * targ_p / game_p * game_y / game_x); + targ_y = (tmp > targ_y) ? targ_y : tmp; + break; + } + case LAYER_CONFIG_CONSTRAIN_HEIGHT: // only constrained vertically + { // height required to use full width + const int usex_y = round_nearest(game_y * targ_p / game_p * targ_x / game_x); + const int orig_y = targ_y; + int tmp = (usex_y + game_y / 2) / game_y * game_y; + targ_y = (tmp > targ_y) ? (targ_y / game_y * game_y) : tmp; + if (targ_y == 0) targ_y = orig_y; // too small, ignore constraint + tmp = round_nearest(targ_y * game_p / targ_p * game_x / game_y); + targ_x = (tmp > targ_x) ? targ_x : tmp; + break; + } + case LAYER_CONFIG_CONSTRAIN_BOTH: + { + const int max_x = targ_x / game_x; // maximum x factor + const int max_y = targ_y / game_y; // maximum y factor + const float aspect = targ_p / game_p; + const int factor_x = round_nearest(max_y / aspect); // x factor with max y factor + const int factor_y = round_nearest(max_x * aspect); // y factor with max x factor + targ_x = max_x; targ_y = max_y; + if ((max_x > max_y && factor_y <= max_y) || + (max_x <= max_y && factor_x > max_x)) + targ_y = factor_y; // y is limiting + else if ((max_x > max_y && factor_y > max_y) || + (max_x <= max_y && factor_x <= max_x)) + targ_x = factor_x; // x is limiting + // just some paranoid checks + if (targ_x > max_x) targ_x = max_x; + if (targ_x < 1) targ_x = 1; + if (targ_y > max_y) targ_y = max_y; + if (targ_y < 1) targ_y = 1; + + targ_x *= game_x; + targ_y *= game_y; + break; + } + case 0: // no constraints + { + const int usex_y = round_nearest(game_y * targ_p / game_p * targ_x / game_x); + if (usex_y <= targ_y) + targ_y = usex_y; + else + targ_x = round_nearest(game_x * game_p / targ_p * targ_y / game_y); + break; + } + } // switch + } // if aspect + else if ((target->layerconfig & LAYER_CONFIG_CONSTRAIN_WIDTH) && + targ_x > game_x) + targ_x = targ_x / game_x * game_x; + else if ((target->layerconfig & LAYER_CONFIG_CONSTRAIN_HEIGHT) && + targ_y > game_y) + targ_y = targ_y / game_y * game_y; + // targ_x, targ_y contains computed size of this screen + *scalex = targ_x / (bounds.x1 - bounds.x0); + *scaley = targ_y / (bounds.y1 - bounds.y0); + // offset so that all screens are centered + *offsx = (target->width - *scalex * (scrbounds.x1 + scrbounds.x0)) / 2; + *offsy = (target->height - *scaley * (scrbounds.y1 + scrbounds.y0)) / 2; + //logerror("result: %dx%d scale: %4.2f %4.2f offset: %4.2f %4.2f\n",targ_x, targ_y, *scalex, *scaley, *offsx, *offsy); +} /*------------------------------------------------- render_target_get_minimum_size - get the @@ -1649,7 +1793,6 @@ object_transform root_xform, ui_xform; int itemcount[ITEM_LAYER_MAX]; const int *layer_order; - INT32 viswidth, visheight; int layernum, listnum; /* remember the base values if this is the first frame */ @@ -1673,14 +1816,7 @@ /* free any previous primitives */ release_render_list(&target->primlist[listnum]); - /* compute the visible width/height */ - render_target_compute_visible_area(target, target->width, target->height, target->pixel_aspect, target->orientation, &viswidth, &visheight); - - /* create a root transform for the target */ - root_xform.xoffs = (target->width - viswidth) / 2; - root_xform.yoffs = (target->height - visheight) / 2; - root_xform.xscale = viswidth; - root_xform.yscale = visheight; + render_target_compute_scale(target, &root_xform.xscale, &root_xform.yscale, &root_xform.xoffs, &root_xform.yoffs); root_xform.color.r = root_xform.color.g = root_xform.color.b = root_xform.color.a = 1.0f; root_xform.orientation = target->orientation; diff -Nru mame107u2orig\src\render.h mame107u2\src\render.h --- mame107u2orig\src\render.h Sun Jul 30 16:28:48 2006 +++ mame107u2\src\render.h Sun Jul 30 16:35:36 2006 @@ -74,7 +74,11 @@ #define LAYER_CONFIG_ENABLE_OVERLAY 0x02 /* enable overlay layers */ #define LAYER_CONFIG_ENABLE_BEZEL 0x04 /* enable bezel layers */ #define LAYER_CONFIG_ZOOM_TO_SCREEN 0x08 /* zoom to screen area by default */ +#define LAYER_CONFIG_CONSTRAIN_WIDTH 0x10 /* constrain to integer stretch horizontally */ +#define LAYER_CONFIG_CONSTRAIN_HEIGHT 0x20 /* constrain to integer stretch vertically */ +#define LAYER_CONFIG_CONSTRAIN_BOTH (LAYER_CONFIG_CONSTRAIN_WIDTH|LAYER_CONFIG_CONSTRAIN_HEIGHT) +#define LAYER_CONFIG_CONSTRAIN_MASK LAYER_CONFIG_CONSTRAIN_BOTH /* texture formats */ #define TEXFORMAT_UNDEFINED 0 /* require a format to be specified */ diff -Nru mame107u2orig\src\uimenu.c mame107u2\src\uimenu.c --- mame107u2orig\src\uimenu.c Mon Aug 07 11:09:52 2006 +++ mame107u2\src\uimenu.c Mon Aug 07 11:08:51 2006 @@ -1147,8 +1147,21 @@ /* otherwise, draw the list of layouts */ else { + static const struct { const char* text; int flag; } artopts[] = { + { "Backdrops", LAYER_CONFIG_ENABLE_BACKDROP }, + { "Overlays", LAYER_CONFIG_ENABLE_OVERLAY }, + { "Bezels", LAYER_CONFIG_ENABLE_BEZEL }, + { "Crop to screen", LAYER_CONFIG_ZOOM_TO_SCREEN} + }; + static const char* const csopts[] = { + "none", "horiz", "vert", "full" + }; + static const struct { const char* text; int rot; } rotopts[] = { + { "0\xb0", ROT0 }, { "90\xb0", ROT90 }, { "180\xb0", ROT180 }, { "270\xb0", ROT270 } + }; render_target *target = targetlist[curtarget]; - int layermask; + int layermask = render_target_get_layer_config(target); + int ii; assert(target != NULL); /* add all the views */ @@ -1163,32 +1176,27 @@ } /* add an item to rotate */ - item_list[menu_items++].text = "Rotate View"; + for (ii = 0; ii < sizeof(rotopts)/sizeof(rotopts[0]); ++ii) + if (render_target_get_orientation(target) == rotopts[ii].rot) + break; + assert(ii < sizeof(rotopts)/sizeof(rotopts[0])); - /* add an item to enable/disable backdrops */ - layermask = render_target_get_layer_config(target); - if (layermask & LAYER_CONFIG_ENABLE_BACKDROP) - item_list[menu_items++].text = "Hide Backdrops"; - else - item_list[menu_items++].text = "Show Backdrops"; - - /* add an item to enable/disable overlays */ - if (layermask & LAYER_CONFIG_ENABLE_OVERLAY) - item_list[menu_items++].text = "Hide Overlays"; - else - item_list[menu_items++].text = "Show Overlays"; - - /* add an item to enable/disable bezels */ - if (layermask & LAYER_CONFIG_ENABLE_BEZEL) - item_list[menu_items++].text = "Hide Bezels"; - else - item_list[menu_items++].text = "Show Bezels"; - - /* add an item to enable/disable cropping */ - if (layermask & LAYER_CONFIG_ZOOM_TO_SCREEN) - item_list[menu_items++].text = "Show Full Artwork"; - else - item_list[menu_items++].text = "Crop to Screen"; + item_list[menu_items].text = "Rotate"; + item_list[menu_items].subtext = rotopts[ii].text; + item_list[menu_items++].flags = MENU_FLAG_RIGHT_ARROW | MENU_FLAG_LEFT_ARROW; + // add artwork options + for (ii = 0; ii < sizeof(artopts)/sizeof(artopts[0]); ++ii) + { + item_list[menu_items].text = artopts[ii].text; + item_list[menu_items].subtext = (layermask & artopts[ii].flag) ? + ui_getstring(UI_on) : ui_getstring(UI_off); + ++menu_items; + } + // add cleanstretch options + ii = (layermask & LAYER_CONFIG_CONSTRAIN_MASK) / LAYER_CONFIG_CONSTRAIN_WIDTH; + item_list[menu_items].text = "Cleanstretch"; + item_list[menu_items].subtext = csopts[ii]; + item_list[menu_items++].flags = MENU_FLAG_RIGHT_ARROW | MENU_FLAG_LEFT_ARROW; /* add an item to return */ item_list[menu_items++].text = ui_getstring(UI_returntoprior); @@ -1204,44 +1212,65 @@ if (input_ui_pressed(IPT_UI_SELECT)) { /* rotate */ - if (selected == menu_items - 6) + if (selected == menu_items - 7) { render_target_set_orientation(target, orientation_add(ROT90, render_target_get_orientation(target))); if (target == render_get_ui_target()) render_container_set_orientation(render_container_get_ui(), orientation_add(ROT270, render_container_get_orientation(render_container_get_ui()))); } - - /* show/hide backdrops */ - else if (selected == menu_items - 5) + // Artwork options + else if (selected > (menu_items - 7) && selected < (menu_items - 2)) { - layermask ^= LAYER_CONFIG_ENABLE_BACKDROP; + layermask ^= artopts[selected - (menu_items - 6)].flag; render_target_set_layer_config(target, layermask); } + // cleanstretch + else if (selected == menu_items - 2) - /* show/hide overlays */ - else if (selected == menu_items - 4) { - layermask ^= LAYER_CONFIG_ENABLE_OVERLAY; + if (layermask & LAYER_CONFIG_CONSTRAIN_WIDTH) + layermask ^= LAYER_CONFIG_CONSTRAIN_BOTH; + else + layermask |= LAYER_CONFIG_CONSTRAIN_WIDTH; render_target_set_layer_config(target, layermask); } - - /* show/hide bezels */ - else if (selected == menu_items - 3) + /* else just set the selected view */ + else + render_target_set_view(target, selected); + } + else if (input_ui_pressed(IPT_UI_RIGHT)) + { + if (selected == menu_items - 7) { - layermask ^= LAYER_CONFIG_ENABLE_BEZEL; + render_target_set_orientation(target, orientation_add(ROT90, render_target_get_orientation(target))); + if (target == render_get_ui_target()) + render_container_set_orientation(render_container_get_ui(), orientation_add(ROT270, render_container_get_orientation(render_container_get_ui()))); + } + else if (selected == menu_items - 2) + { + if (layermask & LAYER_CONFIG_CONSTRAIN_WIDTH) + layermask ^= LAYER_CONFIG_CONSTRAIN_BOTH; + else + layermask |= LAYER_CONFIG_CONSTRAIN_WIDTH; render_target_set_layer_config(target, layermask); } - - /* crop/uncrop artwork */ + } + else if (input_ui_pressed(IPT_UI_LEFT)) + { + if (selected == menu_items - 7) + { + render_target_set_orientation(target, orientation_add(ROT270, render_target_get_orientation(target))); + if (target == render_get_ui_target()) + render_container_set_orientation(render_container_get_ui(), orientation_add(ROT90, render_container_get_orientation(render_container_get_ui()))); + } else if (selected == menu_items - 2) { - layermask ^= LAYER_CONFIG_ZOOM_TO_SCREEN; + if (layermask & LAYER_CONFIG_CONSTRAIN_WIDTH) + layermask ^= LAYER_CONFIG_CONSTRAIN_WIDTH; + else + layermask ^= LAYER_CONFIG_CONSTRAIN_BOTH; render_target_set_layer_config(target, layermask); } - - /* else just set the selected view */ - else - render_target_set_view(target, selected); } } diff -Nru mame107u2orig\src\windows\config.c mame107u2\src\windows\config.c --- mame107u2orig\src\windows\config.c Sun Jul 30 16:09:00 2006 +++ mame107u2\src\windows\config.c Sun Jul 30 21:27:17 2006 @@ -206,6 +206,7 @@ { "pause_brightness", "0.65", 0, "amount to scale the screen brightness when paused" }, { "waitvsync", "0", OPTION_BOOLEAN, "enable waiting for the start of VBLANK before flipping screens; reduces tearing effects" }, { "syncrefresh", "0", OPTION_BOOLEAN, "enable using the start of VBLANK for throttling instead of the game time" }, + { "cleanstretch;cs", "none", 0, "force integer stretch 'horizontal', 'vertical', 'full' or 'none'" }, // video rotation options { NULL, NULL, OPTION_HEADER, "VIDEO ROTATION OPTIONS" }, @@ -384,6 +385,18 @@ // parse vector.ini for vector games if (drv.video_attributes & VIDEO_TYPE_VECTOR) parse_ini_file("vector.ini"); + else if (drv.screen[1].tag == NULL) // single screen + { /* load inifile XxYO.ini e.g. 320x240H.ini, 224x288V.ini */ + int dx = drv.screen[0].defstate.visarea.max_x - drv.screen[0].defstate.visarea.min_x + 1; + int dy = drv.screen[0].defstate.visarea.max_y - drv.screen[0].defstate.visarea.min_y + 1; + int orientation = 0; // horizontal + if (driver->flags & ORIENTATION_SWAP_XY) + { + int tmp = dx; dx = dy; dy = tmp; orientation = 1; + } + sprintf(buffer, "%dx%d%c.ini", dx, dy, orientation ? 'V' : 'H'); + parse_ini_file(buffer); + } // then parse sourcefile.ini parse_ini_file(extract_base_name(driver->source_file, buffer, ARRAY_LENGTH(buffer))); diff -Nru mame107u2orig\src\windows\video.c mame107u2\src\windows\video.c --- mame107u2orig\src\windows\video.c Mon Aug 07 11:09:51 2006 +++ mame107u2\src\windows\video.c Mon Aug 07 11:08:51 2006 @@ -850,7 +850,26 @@ if (!options_get_bool("use_bezels", TRUE)) video_config.layerconfig &= ~LAYER_CONFIG_ENABLE_BEZEL; if (!options_get_bool("artwork", TRUE)) video_config.layerconfig = 0; if (options_get_bool("artwork_crop", TRUE)) video_config.layerconfig |= LAYER_CONFIG_ZOOM_TO_SCREEN; - + stemp = options_get_string("cleanstretch", TRUE); + if (stemp[0] != '\0') + { + static const struct { const char* name; unsigned flag; } csopts[] = { + { "none", 0 }, + { "horizontal", LAYER_CONFIG_CONSTRAIN_WIDTH }, + { "vertical", LAYER_CONFIG_CONSTRAIN_HEIGHT }, + { "full", LAYER_CONFIG_CONSTRAIN_BOTH } + }; + int ii; + for (ii = 0; ii < sizeof(csopts)/sizeof(csopts[0]); ++ii) + if (strstr(csopts[ii].name, stemp) == csopts[ii].name) + { + video_config.layerconfig |= csopts[ii].flag; + break; + } + if (ii == sizeof(csopts)/sizeof(csopts[0])) + fprintf(stderr, "Invalid cleanstretch value %s\n", stemp); + + } // per-window options: extract the data get_resolution("resolution0", &video_config.window[0], TRUE); get_resolution("resolution1", &video_config.window[1], TRUE);