mirror of
https://github.com/libretro/same_cdi.git
synced 2026-11-07 12:37:58 -10:00
Update rendering.
This commit is contained in:
1 parent
45d64b0804
commit
27bfc22efd
5 files changed
+406
-243
No files matched your search
+231
-203
@@ -41,6 +41,7 @@
|
||||
|
||||
#include "corestr.h"
|
||||
#include "emuopts.h"
|
||||
#include "fileio.h"
|
||||
#include "rendfont.h"
|
||||
#include "rendlay.h"
|
||||
#include "rendutil.h"
|
||||
@@ -56,6 +57,7 @@
|
||||
#include "util/xmlfile.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
|
||||
|
||||
@@ -98,6 +100,20 @@ struct render_target::object_transform
|
||||
};
|
||||
|
||||
|
||||
struct render_target::hit_test
|
||||
{
|
||||
hit_test() noexcept
|
||||
: inbounds(0U, 0U)
|
||||
, hit(0U)
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<u64, u64> inbounds;
|
||||
u64 hit;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
@@ -300,7 +316,8 @@ render_texture::render_texture()
|
||||
m_curseq(0)
|
||||
{
|
||||
m_sbounds.set(0, -1, 0, -1);
|
||||
memset(m_scaled, 0, sizeof(m_scaled));
|
||||
for (auto &elem : m_scaled)
|
||||
elem.seqid = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -352,6 +369,7 @@ void render_texture::release()
|
||||
m_bitmap = nullptr;
|
||||
m_sbounds.set(0, -1, 0, -1);
|
||||
m_format = TEXFORMAT_ARGB32;
|
||||
m_scaler = nullptr;
|
||||
m_curseq = 0;
|
||||
}
|
||||
|
||||
@@ -430,6 +448,7 @@ void render_texture::get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo
|
||||
texinfo.base = m_bitmap->raw_pixptr(m_sbounds.top(), m_sbounds.left());
|
||||
texinfo.rowpixels = m_bitmap->rowpixels();
|
||||
texinfo.width = swidth;
|
||||
texinfo.width_margin = m_sbounds.left();
|
||||
texinfo.height = sheight;
|
||||
// palette will be set later
|
||||
texinfo.seqid = ++m_curseq;
|
||||
@@ -690,7 +709,7 @@ const rgb_t *render_container::bcg_lookup_table(int texformat, u32 &out_length,
|
||||
m_bcglookup.resize(palette->max_index());
|
||||
recompute_lookups();
|
||||
}
|
||||
assert (palette == &m_palclient->palette());
|
||||
assert(palette == &m_palclient->palette());
|
||||
out_length = palette->max_index();
|
||||
return &m_bcglookup[0];
|
||||
|
||||
@@ -880,19 +899,21 @@ render_container::user_settings::user_settings()
|
||||
// render_target - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
render_target::render_target(render_manager &manager, const internal_layout *layoutfile, u32 flags)
|
||||
: render_target(manager, layoutfile, flags, CONSTRUCTOR_IMPL)
|
||||
render_target::render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags)
|
||||
: render_target(manager, ui, layoutfile, flags, CONSTRUCTOR_IMPL)
|
||||
{
|
||||
}
|
||||
|
||||
render_target::render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags)
|
||||
: render_target(manager, layout, flags, CONSTRUCTOR_IMPL)
|
||||
render_target::render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags)
|
||||
: render_target(manager, ui, layout, flags, CONSTRUCTOR_IMPL)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T> render_target::render_target(render_manager &manager, T &&layout, u32 flags, constructor_impl_t)
|
||||
template <typename T>
|
||||
render_target::render_target(render_manager &manager, render_container *ui, T &&layout, u32 flags, constructor_impl_t)
|
||||
: m_next(nullptr)
|
||||
, m_manager(manager)
|
||||
, m_ui_container(ui)
|
||||
, m_curview(0U)
|
||||
, m_flags(flags)
|
||||
, m_listindex(0)
|
||||
@@ -1012,9 +1033,9 @@ void render_target::set_bounds(s32 width, s32 height, float pixel_aspect)
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_bounds.x0 = m_bounds.y0 = 0;
|
||||
m_bounds.x1 = (float)width;
|
||||
m_bounds.y1 = (float)height;
|
||||
m_pixel_aspect = pixel_aspect != 0.0? pixel_aspect : 1.0;
|
||||
m_bounds.x1 = float(width);
|
||||
m_bounds.y1 = float(height);
|
||||
m_pixel_aspect = pixel_aspect != 0.0F ? pixel_aspect : 1.0F;
|
||||
}
|
||||
|
||||
|
||||
@@ -1030,6 +1051,8 @@ void render_target::set_view(unsigned viewindex)
|
||||
m_curview = viewindex;
|
||||
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
|
||||
current_view().preload();
|
||||
m_clickable_items.clear();
|
||||
m_clickable_items.resize(current_view().interactive_items().size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,7 +1081,7 @@ void render_target::set_visibility_toggle(unsigned index, bool enable)
|
||||
m_views[m_curview].second |= u32(1) << index;
|
||||
else
|
||||
m_views[m_curview].second &= ~(u32(1) << index);
|
||||
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
|
||||
update_layer_config();
|
||||
current_view().preload();
|
||||
}
|
||||
|
||||
@@ -1070,28 +1093,29 @@ void render_target::set_visibility_toggle(unsigned index, bool enable)
|
||||
|
||||
unsigned render_target::configured_view(const char *viewname, int targetindex, int numtargets)
|
||||
{
|
||||
layout_view *view = nullptr;
|
||||
|
||||
// if it isn't "auto" or an empty string, try to match it as a view name prefix
|
||||
if (viewname && *viewname && strcmp(viewname, "auto"))
|
||||
{
|
||||
// scan for a matching view name
|
||||
size_t const viewlen = strlen(viewname);
|
||||
for (unsigned i = 0; !view && (m_views.size() > i); ++i)
|
||||
for (unsigned i = 0; m_views.size() > i; ++i)
|
||||
{
|
||||
if (!core_strnicmp(m_views[i].first.name().c_str(), viewname, viewlen))
|
||||
view = &m_views[i].first;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't have a match, default to the nth view
|
||||
std::vector<std::reference_wrapper<screen_device> > screens;
|
||||
for (screen_device &screen : screen_device_enumerator(m_manager.machine().root_device()))
|
||||
screens.push_back(screen);
|
||||
if (!view && !screens.empty())
|
||||
if (!screens.empty())
|
||||
{
|
||||
// if we have enough targets to be one per screen, assign in order
|
||||
if (numtargets >= screens.size())
|
||||
{
|
||||
// find the first view with this screen and this screen only
|
||||
layout_view *view = nullptr;
|
||||
screen_device const &screen = screens[index() % screens.size()];
|
||||
for (unsigned i = 0; !view && (m_views.size() > i); ++i)
|
||||
{
|
||||
@@ -1109,22 +1133,21 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i
|
||||
}
|
||||
}
|
||||
}
|
||||
if (view)
|
||||
return view_index(*view);
|
||||
}
|
||||
|
||||
// otherwise, find the first view that has all the screens
|
||||
if (!view)
|
||||
for (unsigned i = 0; m_views.size() > i; ++i)
|
||||
{
|
||||
for (unsigned i = 0; !view && (m_views.size() > i); ++i)
|
||||
{
|
||||
layout_view &curview = m_views[i].first;
|
||||
if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end())
|
||||
view = &curview;
|
||||
}
|
||||
layout_view &curview = m_views[i].first;
|
||||
if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end())
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure it's a valid view
|
||||
return view ? view_index(*view) : 0;
|
||||
// default to the first view
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1197,63 +1220,103 @@ void render_target::compute_visible_area(s32 target_width, s32 target_height, fl
|
||||
|
||||
// apply orientation if required
|
||||
if (target_orientation & ORIENTATION_SWAP_XY)
|
||||
src_aspect = 1.0 / src_aspect;
|
||||
src_aspect = 1.0f / src_aspect;
|
||||
|
||||
// get target aspect
|
||||
float target_aspect = (float)target_width / (float)target_height * target_pixel_aspect;
|
||||
// we need the ratio of target to source aspect
|
||||
float aspect_ratio = m_keepaspect ? (float)target_width / (float)target_height * target_pixel_aspect / src_aspect : 1.0f;
|
||||
|
||||
// first compute (a, b) scale factors to fit the screen
|
||||
float a = (float)target_width / src_width;
|
||||
float b = (float)target_height / src_height;
|
||||
|
||||
// apply automatic axial stretching if required
|
||||
int scale_mode = m_scale_mode;
|
||||
if (m_scale_mode == SCALE_FRACTIONAL_AUTO)
|
||||
if (scale_mode == SCALE_FRACTIONAL_AUTO)
|
||||
scale_mode = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY) ?
|
||||
SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X;
|
||||
|
||||
// determine the scaling method for each axis
|
||||
bool a_is_fract = (scale_mode == SCALE_FRACTIONAL_X || scale_mode == SCALE_FRACTIONAL);
|
||||
bool b_is_fract = (scale_mode == SCALE_FRACTIONAL_Y || scale_mode == SCALE_FRACTIONAL);
|
||||
|
||||
// check if we have user defined scale factors, if so use them instead, but only on integer axes
|
||||
int a_user = a_is_fract ? 0 : m_int_scale_x;
|
||||
int b_user = b_is_fract ? 0 : m_int_scale_y;
|
||||
|
||||
// we allow overscan either explicitely or if integer scale factors are forced by user
|
||||
bool int_overscan = m_int_overscan || (m_keepaspect && (a_user != 0 || b_user != 0));
|
||||
float a_max = std::max(a, (float)a_user);
|
||||
float b_max = std::max(b, (float)b_user);
|
||||
|
||||
|
||||
// get the usable bounding box considering the type of scaling for each axis
|
||||
float usable_aspect = (a_is_fract ? a : std::max(1.0f, floorf(a))) * src_width /
|
||||
((b_is_fract ? b : std::max(1.0f, floorf(b))) * src_height) * target_pixel_aspect;
|
||||
|
||||
// depending on the relative shape between target and source, let's define 'a' and 'b' so that:
|
||||
// * a is the leader axis (first to hit a boundary)
|
||||
// * b is the follower axis
|
||||
if (usable_aspect > src_aspect)
|
||||
{
|
||||
bool is_rotated = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY);
|
||||
scale_mode = is_rotated ? SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X;
|
||||
std::swap(a, b);
|
||||
std::swap(a_user, b_user);
|
||||
std::swap(a_is_fract, b_is_fract);
|
||||
std::swap(a_max, b_max);
|
||||
aspect_ratio = 1.0f / aspect_ratio;
|
||||
}
|
||||
|
||||
// first compute scale factors to fit the screen
|
||||
float xscale = (float)target_width / src_width;
|
||||
float yscale = (float)target_height / src_height;
|
||||
// now find an (a, b) pair that best fits our boundaries and scale options
|
||||
float a_best = 1.0f, b_best = 1.0f;
|
||||
float diff = 1000;
|
||||
|
||||
// apply aspect correction
|
||||
if (m_keepaspect)
|
||||
// fill (a0, a1) range
|
||||
float u = a_user == 0 ? a : (float)a_user;
|
||||
float a_range[] = {a_is_fract ? u : std::max(1.0f, floorf(u)), a_is_fract ? u : std::max(1.0f, roundf(u))};
|
||||
|
||||
for (float aa : a_range)
|
||||
{
|
||||
if (target_aspect > src_aspect)
|
||||
xscale *= src_aspect / target_aspect;
|
||||
else
|
||||
yscale *= target_aspect / src_aspect;
|
||||
}
|
||||
// apply aspect correction to 'b' axis if needed, considering resulting 'a' borders
|
||||
float ba = b * (m_keepaspect ? aspect_ratio * (aa / a) : 1.0f);
|
||||
|
||||
bool x_fits = render_round_nearest(xscale) * src_width <= target_width;
|
||||
bool y_fits = render_round_nearest(yscale) * src_height <= target_height;
|
||||
// fill (b0, b1) range
|
||||
float v = b_user == 0 ? ba : (float)b_user;
|
||||
float b_range[] = {b_is_fract ? v : std::max(1.0f, floorf(v)), b_is_fract ? v : std::max(1.0f, roundf(v))};
|
||||
|
||||
// compute integer scale factors
|
||||
float integer_x = std::max(1.0f, float(m_int_overscan || x_fits ? render_round_nearest(xscale) : floor(xscale)));
|
||||
float integer_y = std::max(1.0f, float(m_int_overscan || y_fits ? render_round_nearest(yscale) : floor(yscale)));
|
||||
for (float bb : b_range)
|
||||
{
|
||||
// we may need to propagate proportions back to 'a' axis
|
||||
float ab = aa;
|
||||
if (m_keepaspect && a_user == 0)
|
||||
{
|
||||
if (a_is_fract) ab *= (bb / ba);
|
||||
else if (b_user != 0) ab = std::max(1.0f, roundf(ab * (bb / ba)));
|
||||
}
|
||||
|
||||
// check if we have user defined scale factors, if so use them instead
|
||||
integer_x = m_int_scale_x > 0 ? m_int_scale_x : integer_x;
|
||||
integer_y = m_int_scale_y > 0 ? m_int_scale_y : integer_y;
|
||||
// if overscan isn't allowed, discard values that exceed the usable bounding box, except a minimum of 1.0f
|
||||
if (!int_overscan && ((ab > a_max && bb > 1.0f) || (bb > b_max && ab > 1.0f)))
|
||||
continue;
|
||||
|
||||
// now apply desired scale mode
|
||||
if (scale_mode == SCALE_FRACTIONAL_X)
|
||||
{
|
||||
if (m_keepaspect) xscale *= integer_y / yscale;
|
||||
yscale = integer_y;
|
||||
}
|
||||
else if (scale_mode == SCALE_FRACTIONAL_Y)
|
||||
{
|
||||
if (m_keepaspect) yscale *= integer_x / xscale;
|
||||
xscale = integer_x;
|
||||
}
|
||||
else
|
||||
{
|
||||
xscale = integer_x;
|
||||
yscale = integer_y;
|
||||
// score the result
|
||||
float new_diff = fabsf(aspect_ratio * (a / b) - (ab / bb));
|
||||
|
||||
if (new_diff <= diff)
|
||||
{
|
||||
diff = new_diff;
|
||||
a_best = ab;
|
||||
b_best = bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
a = a_best;
|
||||
b = b_best;
|
||||
|
||||
// restore orientation
|
||||
if (usable_aspect > src_aspect)
|
||||
std::swap(a, b);
|
||||
|
||||
// set the final width/height
|
||||
visible_width = render_round_nearest(src_width * xscale);
|
||||
visible_height = render_round_nearest(src_height * yscale);
|
||||
visible_width = render_round_nearest(src_width * a);
|
||||
visible_height = render_round_nearest(src_height * b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1411,8 +1474,8 @@ render_primitive_list &render_target::get_primitives()
|
||||
}
|
||||
}
|
||||
|
||||
// process the UI if we are the UI target
|
||||
if (is_ui_target())
|
||||
// process UI elements if applicable
|
||||
if (m_ui_container)
|
||||
{
|
||||
// compute the transform for the UI
|
||||
object_transform ui_xform;
|
||||
@@ -1425,7 +1488,7 @@ render_primitive_list &render_target::get_primitives()
|
||||
ui_xform.no_center = false;
|
||||
|
||||
// add UI elements
|
||||
add_container_primitives(list, root_xform, ui_xform, m_manager.ui_container(), BLENDMODE_ALPHA);
|
||||
add_container_primitives(list, root_xform, ui_xform, *m_ui_container, BLENDMODE_ALPHA);
|
||||
}
|
||||
|
||||
// optimize the list before handing it off
|
||||
@@ -1446,16 +1509,12 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
|
||||
std::pair<float, float> target_f(map_point_internal(target_x, target_y));
|
||||
|
||||
// explicitly check for the UI container
|
||||
if (&container == &m_manager.ui_container())
|
||||
if (&container == m_ui_container)
|
||||
{
|
||||
// this hit test went against the UI container
|
||||
if ((target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f))
|
||||
{
|
||||
// this point was successfully mapped
|
||||
container_x = float(target_x) / m_width;
|
||||
container_y = float(target_y) / m_height;
|
||||
return true;
|
||||
}
|
||||
container_x = float(target_x) / m_width;
|
||||
container_y = float(target_y) / m_height;
|
||||
return (target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1474,15 +1533,12 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
|
||||
[&container] (layout_view_item &item) { return &item.screen()->container() == &container; }));
|
||||
if (items.end() != found)
|
||||
{
|
||||
// point successfully mapped
|
||||
layout_view_item &item(*found);
|
||||
render_bounds const bounds(item.bounds());
|
||||
if (bounds.includes(target_f.first, target_f.second))
|
||||
{
|
||||
// point successfully mapped
|
||||
container_x = (target_f.first - bounds.x0) / bounds.width();
|
||||
container_y = (target_f.second - bounds.y0) / bounds.height();
|
||||
return true;
|
||||
}
|
||||
container_x = (target_f.first - bounds.x0) / bounds.width();
|
||||
container_y = (target_f.second - bounds.y0) / bounds.height();
|
||||
return bounds.includes(target_f.first, target_f.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1492,74 +1548,6 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// map_point_input - attempts to map a point on
|
||||
// the specified render_target to an input port
|
||||
// field, if possible
|
||||
//-------------------------------------------------
|
||||
|
||||
bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y)
|
||||
{
|
||||
std::pair<float, float> target_f(map_point_internal(target_x, target_y));
|
||||
if (m_orientation & ORIENTATION_FLIP_X)
|
||||
target_f.first = 1.0f - target_f.first;
|
||||
if (m_orientation & ORIENTATION_FLIP_Y)
|
||||
target_f.second = 1.0f - target_f.second;
|
||||
if (m_orientation & ORIENTATION_SWAP_XY)
|
||||
std::swap(target_f.first, target_f.second);
|
||||
|
||||
auto const &items(current_view().interactive_items());
|
||||
m_hit_test.resize(items.size() * 2);
|
||||
std::fill(m_hit_test.begin(), m_hit_test.end(), false);
|
||||
|
||||
for (auto const &edge : current_view().interactive_edges_x())
|
||||
{
|
||||
if ((edge.position() > target_f.first) || ((edge.position() == target_f.first) && edge.trailing()))
|
||||
break;
|
||||
else
|
||||
m_hit_test[edge.index()] = !edge.trailing();
|
||||
}
|
||||
|
||||
for (auto const &edge : current_view().interactive_edges_y())
|
||||
{
|
||||
if ((edge.position() > target_f.second) || ((edge.position() == target_f.second) && edge.trailing()))
|
||||
break;
|
||||
else
|
||||
m_hit_test[items.size() + edge.index()] = !edge.trailing();
|
||||
}
|
||||
|
||||
for (unsigned i = 0; items.size() > i; ++i)
|
||||
{
|
||||
if (m_hit_test[i] && m_hit_test[items.size() + i])
|
||||
{
|
||||
layout_view_item &item(items[i]);
|
||||
render_bounds const bounds(item.bounds());
|
||||
if (bounds.includes(target_f.first, target_f.second))
|
||||
{
|
||||
if (item.has_input())
|
||||
{
|
||||
// point successfully mapped
|
||||
std::tie(input_port, input_mask) = item.input_tag_and_mask();
|
||||
input_x = (target_f.first - bounds.x0) / bounds.width();
|
||||
input_y = (target_f.second - bounds.y0) / bounds.height();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default to point not mapped
|
||||
input_port = nullptr;
|
||||
input_mask = 0;
|
||||
input_x = input_y = -1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// invalidate_all - if any of our primitive lists
|
||||
// contain a reference to the given pointer,
|
||||
@@ -1589,7 +1577,7 @@ void render_target::resolve_tags()
|
||||
for (layout_file &file : m_filelist)
|
||||
file.resolve_tags();
|
||||
|
||||
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
|
||||
update_layer_config();
|
||||
current_view().preload();
|
||||
}
|
||||
|
||||
@@ -1602,6 +1590,8 @@ void render_target::resolve_tags()
|
||||
void render_target::update_layer_config()
|
||||
{
|
||||
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
|
||||
m_clickable_items.clear();
|
||||
m_clickable_items.resize(current_view().interactive_items().size());
|
||||
}
|
||||
|
||||
|
||||
@@ -1664,14 +1654,6 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
else
|
||||
m_external_artwork = true;
|
||||
|
||||
// if a default view has been specified, use that as a fallback
|
||||
bool have_default = false;
|
||||
if (system.default_layout)
|
||||
have_default |= load_layout_file(nullptr, *system.default_layout);
|
||||
m_manager.machine().config().apply_default_layouts(
|
||||
[this, &have_default] (device_t &dev, internal_layout const &layout)
|
||||
{ have_default |= load_layout_file(nullptr, layout, &dev); });
|
||||
|
||||
// try to load another file based on the parent driver name
|
||||
int cloneof = driver_list::clone(system);
|
||||
while (0 <= cloneof)
|
||||
@@ -1689,6 +1671,14 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
cloneof = driver_list::clone(parent);
|
||||
}
|
||||
|
||||
// if a default view has been specified, use that as a fallback
|
||||
bool have_default = false;
|
||||
if (system.default_layout)
|
||||
have_default |= load_layout_file(nullptr, *system.default_layout);
|
||||
m_manager.machine().config().apply_default_layouts(
|
||||
[this, &have_default] (device_t &dev, internal_layout const &layout)
|
||||
{ have_default |= load_layout_file(nullptr, layout, &dev); });
|
||||
|
||||
have_artwork |= m_external_artwork;
|
||||
|
||||
// Use fallback artwork if defined and no artwork has been found yet
|
||||
@@ -2076,11 +2066,10 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
|
||||
size_t decompressed = 0;
|
||||
do
|
||||
{
|
||||
size_t actual;
|
||||
std::error_condition const err = inflater->read(
|
||||
auto const [err, actual] = read(
|
||||
*inflater,
|
||||
&tempout[decompressed],
|
||||
layout_data.decompressed_size - decompressed,
|
||||
actual);
|
||||
layout_data.decompressed_size - decompressed);
|
||||
decompressed += actual;
|
||||
if (err)
|
||||
{
|
||||
@@ -2173,7 +2162,7 @@ bool render_target::load_layout_file(device_t &device, util::xml::data_node cons
|
||||
{
|
||||
m_filelist.emplace_back(device, rootnode, searchpath, dirname);
|
||||
}
|
||||
catch (emu_fatalerror &err)
|
||||
catch (emu_fatalerror const &err)
|
||||
{
|
||||
osd_printf_warning("%s\n", err.what());
|
||||
return false;
|
||||
@@ -2309,11 +2298,11 @@ void render_target::add_container_primitives(render_primitive_list &list, const
|
||||
// clip the primitive
|
||||
if (!m_transform_container && PRIMFLAG_GET_VECTOR(curitem.flags()))
|
||||
{
|
||||
clipped = render_clip_line(&prim->bounds, &root_cliprect);
|
||||
clipped = render_clip_line(prim->bounds, root_cliprect);
|
||||
}
|
||||
else
|
||||
{
|
||||
clipped = render_clip_line(&prim->bounds, &cliprect);
|
||||
clipped = render_clip_line(prim->bounds, cliprect);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2346,7 +2335,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
|
||||
prim->texcoords = oriented_texcoords[finalorient];
|
||||
|
||||
// apply clipping
|
||||
clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
|
||||
clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords);
|
||||
|
||||
// apply the final orientation from the quad flags and then build up the final flags
|
||||
prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK))
|
||||
@@ -2406,7 +2395,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
|
||||
prim->texcoords = oriented_texcoords[finalorient];
|
||||
|
||||
// apply clipping
|
||||
clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
|
||||
clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords);
|
||||
|
||||
// apply the final orientation from the quad flags and then build up the final flags
|
||||
prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK))
|
||||
@@ -2422,7 +2411,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
|
||||
| PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
|
||||
|
||||
// apply clipping
|
||||
clipped = render_clip_quad(&prim->bounds, &cliprect, nullptr);
|
||||
clipped = render_clip_quad(prim->bounds, cliprect, nullptr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2547,7 +2536,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob
|
||||
}
|
||||
|
||||
// add to the list or free if we're clipped out
|
||||
bool const clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
|
||||
bool const clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords);
|
||||
list.append_or_return(*prim, clipped);
|
||||
}
|
||||
}
|
||||
@@ -2577,6 +2566,25 @@ std::pair<float, float> render_target::map_point_internal(s32 target_x, s32 targ
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// map_point_layout - map point from screen
|
||||
// coordinates to layout coordinates
|
||||
//-------------------------------------------------
|
||||
|
||||
std::pair<float, float> render_target::map_point_layout(s32 target_x, s32 target_y)
|
||||
{
|
||||
using std::swap;
|
||||
std::pair<float, float> result(map_point_internal(target_x, target_y));
|
||||
if (m_orientation & ORIENTATION_FLIP_X)
|
||||
result.first = 1.0f - result.first;
|
||||
if (m_orientation & ORIENTATION_FLIP_Y)
|
||||
result.second = 1.0f - result.second;
|
||||
if (m_orientation & ORIENTATION_SWAP_XY)
|
||||
swap(result.first, result.second);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// view_name - return the name of the indexed
|
||||
// view, or nullptr if it doesn't exist
|
||||
@@ -2619,20 +2627,22 @@ void render_target::config_load(util::xml::data_node const *targetnode)
|
||||
if (!targetnode)
|
||||
return;
|
||||
|
||||
// TODO: consider option priority - command line should take precedence over CFG
|
||||
// not practical at the moment because view selection options are in the OSD layer
|
||||
|
||||
// find the view
|
||||
const char *viewname = targetnode->get_attribute_string("view", nullptr);
|
||||
if (viewname != nullptr)
|
||||
for (int viewnum = 0; viewnum < 1000; viewnum++)
|
||||
if (viewname)
|
||||
{
|
||||
for (unsigned viewnum = 0; m_views.size() > viewnum; viewnum++)
|
||||
{
|
||||
const char *testname = view_name(viewnum);
|
||||
if (testname == nullptr)
|
||||
break;
|
||||
if (!strcmp(viewname, testname))
|
||||
if (!strcmp(viewname, view_name(viewnum)))
|
||||
{
|
||||
set_view(viewnum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// modify the artwork config
|
||||
int const zoom = targetnode->get_attribute_int("zoom", -1);
|
||||
@@ -2654,12 +2664,11 @@ void render_target::config_load(util::xml::data_node const *targetnode)
|
||||
set_orientation(orientation_add(rotate, orientation()));
|
||||
|
||||
// apply the opposite orientation to the UI
|
||||
if (is_ui_target())
|
||||
if (m_ui_container)
|
||||
{
|
||||
render_container &ui_container = m_manager.ui_container();
|
||||
render_container::user_settings settings = ui_container.get_user_settings();
|
||||
render_container::user_settings settings = m_ui_container->get_user_settings();
|
||||
settings.m_orientation = orientation_add(orientation_reverse(rotate), settings.m_orientation);
|
||||
ui_container.set_user_settings(settings);
|
||||
m_ui_container->set_user_settings(settings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2699,6 +2708,8 @@ void render_target::config_load(util::xml::data_node const *targetnode)
|
||||
{
|
||||
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
|
||||
current_view().preload();
|
||||
m_clickable_items.clear();
|
||||
m_clickable_items.resize(current_view().interactive_items().size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3060,7 +3071,6 @@ render_manager::render_manager(running_machine &machine)
|
||||
, m_ui_target(nullptr)
|
||||
, m_live_textures(0)
|
||||
, m_texture_id(0)
|
||||
, m_ui_container(std::make_unique<render_container>(*this))
|
||||
{
|
||||
// register callbacks
|
||||
machine.configuration().config_register(
|
||||
@@ -3081,7 +3091,7 @@ render_manager::render_manager(running_machine &machine)
|
||||
render_manager::~render_manager()
|
||||
{
|
||||
// free all the containers since they may own textures
|
||||
m_ui_container.reset();
|
||||
m_ui_containers.clear();
|
||||
m_screen_container_list.clear();
|
||||
|
||||
// better not be any outstanding textures when we die
|
||||
@@ -3137,12 +3147,14 @@ float render_manager::max_update_rate() const
|
||||
|
||||
render_target *render_manager::target_alloc(const internal_layout *layoutfile, u32 flags)
|
||||
{
|
||||
return &m_targetlist.append(*new render_target(*this, layoutfile, flags));
|
||||
render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this);
|
||||
return &m_targetlist.append(*new render_target(*this, ui, layoutfile, flags));
|
||||
}
|
||||
|
||||
render_target *render_manager::target_alloc(util::xml::data_node const &layout, u32 flags)
|
||||
{
|
||||
return &m_targetlist.append(*new render_target(*this, layout, flags));
|
||||
render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this);
|
||||
return &m_targetlist.append(*new render_target(*this, ui, layout, flags));
|
||||
}
|
||||
|
||||
|
||||
@@ -3179,35 +3191,56 @@ render_target *render_manager::target_by_index(int index) const
|
||||
|
||||
float render_manager::ui_aspect(render_container *rc)
|
||||
{
|
||||
int orient;
|
||||
// work out if this is a UI container
|
||||
render_target *target = nullptr;
|
||||
if (!rc)
|
||||
{
|
||||
target = &ui_target();
|
||||
rc = target->ui_container();
|
||||
assert(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (render_target &t : m_targetlist)
|
||||
{
|
||||
if (t.ui_container() == rc)
|
||||
{
|
||||
target = &t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float aspect;
|
||||
|
||||
if (rc == m_ui_container.get() || rc == nullptr) {
|
||||
// ui container, aggregated multi-screen target
|
||||
if (target)
|
||||
{
|
||||
// UI container, aggregated multi-screen target
|
||||
|
||||
orient = orientation_add(m_ui_target->orientation(), m_ui_container->orientation());
|
||||
// based on the orientation of the target, compute height/width or width/height
|
||||
int const orient = orientation_add(target->orientation(), rc->orientation());
|
||||
if (!(orient & ORIENTATION_SWAP_XY))
|
||||
aspect = (float)m_ui_target->height() / (float)m_ui_target->width();
|
||||
aspect = float(target->height()) / float(target->width());
|
||||
else
|
||||
aspect = (float)m_ui_target->width() / (float)m_ui_target->height();
|
||||
aspect = float(target->width()) / float(target->height());
|
||||
|
||||
// if we have a valid pixel aspect, apply that and return
|
||||
if (m_ui_target->pixel_aspect() != 0.0f)
|
||||
if (target->pixel_aspect() != 0.0f)
|
||||
{
|
||||
float pixel_aspect = m_ui_target->pixel_aspect();
|
||||
float pixel_aspect = target->pixel_aspect();
|
||||
|
||||
if (orient & ORIENTATION_SWAP_XY)
|
||||
pixel_aspect = 1.0f / pixel_aspect;
|
||||
|
||||
return aspect /= pixel_aspect;
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// single screen container
|
||||
|
||||
orient = rc->orientation();
|
||||
// based on the orientation of the target, compute height/width or width/height
|
||||
int const orient = rc->orientation();
|
||||
if (!(orient & ORIENTATION_SWAP_XY))
|
||||
aspect = (float)rc->screen()->visible_area().height() / (float)rc->screen()->visible_area().width();
|
||||
else
|
||||
@@ -3215,12 +3248,7 @@ float render_manager::ui_aspect(render_container *rc)
|
||||
}
|
||||
|
||||
// clamp for extreme proportions
|
||||
if (aspect < 0.66f)
|
||||
aspect = 0.66f;
|
||||
if (aspect > 1.5f)
|
||||
aspect = 1.5f;
|
||||
|
||||
return aspect;
|
||||
return std::clamp(aspect, 0.66f, 1.5f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+31
-28
@@ -47,18 +47,12 @@
|
||||
#define MAME_EMU_RENDER_H
|
||||
|
||||
#include "rendertypes.h"
|
||||
#include "screen.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -164,6 +158,7 @@ struct render_texinfo
|
||||
void * base; // base of the data
|
||||
u32 rowpixels; // pixels per row
|
||||
u32 width; // width of the image
|
||||
u32 width_margin; // left margin of the scaled bounds, if applicable
|
||||
u32 height; // height of the image
|
||||
u32 seqid; // sequence ID
|
||||
u64 unique_id; // unique identifier to pass to osd
|
||||
@@ -346,7 +341,7 @@ private:
|
||||
void get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo, render_primitive_list &primlist, u32 flags = 0);
|
||||
const rgb_t *get_adjusted_palette(render_container &container, u32 &out_length);
|
||||
|
||||
static constexpr int MAX_TEXTURE_SCALES = 20;
|
||||
static constexpr int MAX_TEXTURE_SCALES = 100;
|
||||
|
||||
// a scaled_texture contains a single scaled entry for a texture
|
||||
struct scaled_texture
|
||||
@@ -498,14 +493,15 @@ class render_target
|
||||
friend class render_manager;
|
||||
|
||||
// construction/destruction
|
||||
render_target(render_manager &manager, const internal_layout *layoutfile = nullptr, u32 flags = 0);
|
||||
render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags = 0);
|
||||
render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags);
|
||||
render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags);
|
||||
~render_target();
|
||||
|
||||
public:
|
||||
// getters
|
||||
render_target *next() const { return m_next; }
|
||||
render_manager &manager() const { return m_manager; }
|
||||
render_container *ui_container() const { return m_ui_container; }
|
||||
u32 width() const { return m_width; }
|
||||
u32 height() const { return m_height; }
|
||||
float pixel_aspect() const { return m_pixel_aspect; }
|
||||
@@ -556,7 +552,6 @@ public:
|
||||
|
||||
// hit testing
|
||||
bool map_point_container(s32 target_x, s32 target_y, render_container &container, float &container_x, float &container_y);
|
||||
bool map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y);
|
||||
|
||||
// reference tracking
|
||||
void invalidate_all(void *refptr);
|
||||
@@ -565,15 +560,24 @@ public:
|
||||
void resolve_tags();
|
||||
|
||||
private:
|
||||
// constants
|
||||
static inline constexpr int NUM_PRIMLISTS = 3;
|
||||
static inline constexpr int MAX_CLEAR_EXTENTS = 1000;
|
||||
|
||||
using view_mask_pair = std::pair<layout_view &, u32>;
|
||||
using view_mask_vector = std::vector<view_mask_pair>;
|
||||
|
||||
// private classes declared in render.cpp
|
||||
struct object_transform;
|
||||
struct pointer_info;
|
||||
struct hit_test;
|
||||
|
||||
using pointer_info_vector = std::vector<pointer_info>;
|
||||
using hit_test_vector = std::vector<hit_test>;
|
||||
|
||||
// internal helpers
|
||||
enum constructor_impl_t { CONSTRUCTOR_IMPL };
|
||||
template <typename T> render_target(render_manager &manager, T&& layout, u32 flags, constructor_impl_t);
|
||||
template <typename T> render_target(render_manager &manager, render_container *ui, T&& layout, u32 flags, constructor_impl_t);
|
||||
void update_layer_config();
|
||||
void load_layout_files(const internal_layout *layoutfile, bool singlefile);
|
||||
void load_layout_files(util::xml::data_node const &rootnode, bool singlefile);
|
||||
@@ -584,6 +588,7 @@ private:
|
||||
void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode);
|
||||
void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item);
|
||||
std::pair<float, float> map_point_internal(s32 target_x, s32 target_y);
|
||||
std::pair<float, float> map_point_layout(s32 target_x, s32 target_y);
|
||||
|
||||
// config callbacks
|
||||
void config_load(util::xml::data_node const *targetnode);
|
||||
@@ -599,13 +604,10 @@ private:
|
||||
void add_clear_extents(render_primitive_list &list);
|
||||
void add_clear_and_optimize_primitive_list(render_primitive_list &list);
|
||||
|
||||
// constants
|
||||
static constexpr int NUM_PRIMLISTS = 3;
|
||||
static constexpr int MAX_CLEAR_EXTENTS = 1000;
|
||||
|
||||
// internal state
|
||||
render_target * m_next; // link to next target
|
||||
render_manager & m_manager; // reference to our owning manager
|
||||
render_container *const m_ui_container; // container for drawing UI elements
|
||||
std::list<layout_file> m_filelist; // list of layout files
|
||||
view_mask_vector m_views; // views we consider
|
||||
unsigned m_curview; // current view index
|
||||
@@ -624,7 +626,8 @@ private:
|
||||
float m_max_refresh; // maximum refresh rate, 0 or if none
|
||||
int m_orientation; // orientation
|
||||
render_layer_config m_layerconfig; // layer configuration
|
||||
std::vector<bool> m_hit_test; // used when mapping points to inputs
|
||||
pointer_info_vector m_pointers; // state of pointers over this target
|
||||
hit_test_vector m_clickable_items; // for tracking clicked elements
|
||||
layout_view * m_base_view; // the view at the time of first frame
|
||||
int m_base_orientation; // the orientation at the time of first frame
|
||||
render_layer_config m_base_layerconfig; // the layer configuration at the time of first frame
|
||||
@@ -671,7 +674,7 @@ public:
|
||||
float ui_aspect(render_container *rc = nullptr);
|
||||
|
||||
// UI containers
|
||||
render_container &ui_container() const { assert(m_ui_container != nullptr); return *m_ui_container; }
|
||||
render_container &ui_container() const { assert(ui_target().ui_container()); return *ui_target().ui_container(); }
|
||||
|
||||
// textures
|
||||
render_texture *texture_alloc(texture_scaler_func scaler = nullptr, void *param = nullptr);
|
||||
@@ -692,20 +695,20 @@ private:
|
||||
void config_save(config_type cfg_type, util::xml::data_node *parentnode);
|
||||
|
||||
// internal state
|
||||
running_machine & m_machine; // reference back to the machine
|
||||
running_machine & m_machine; // reference back to the machine
|
||||
|
||||
// array of live targets
|
||||
simple_list<render_target> m_targetlist; // list of targets
|
||||
render_target * m_ui_target; // current UI target
|
||||
simple_list<render_target> m_targetlist; // list of targets
|
||||
render_target * m_ui_target; // current UI target
|
||||
|
||||
// texture lists
|
||||
u32 m_live_textures; // number of live textures
|
||||
u64 m_texture_id; // rolling texture ID counter
|
||||
fixed_allocator<render_texture> m_texture_allocator;// texture allocator
|
||||
u32 m_live_textures; // number of live textures
|
||||
u64 m_texture_id; // rolling texture ID counter
|
||||
fixed_allocator<render_texture> m_texture_allocator; // texture allocator
|
||||
|
||||
// containers for the UI and for screens
|
||||
std::unique_ptr<render_container> m_ui_container; // UI container
|
||||
std::list<render_container> m_screen_container_list; // list of containers for the screen
|
||||
// containers for UI elements and for screens
|
||||
std::list<render_container> m_ui_containers; // containers for drawing UI elements
|
||||
std::list<render_container> m_screen_container_list; // list of containers for the screen
|
||||
};
|
||||
|
||||
#endif // MAME_EMU_RENDER_H
|
||||
@@ -20,6 +20,16 @@
|
||||
//**************************************************************************
|
||||
|
||||
|
||||
// texture formats
|
||||
enum texture_format
|
||||
{
|
||||
TEXFORMAT_UNDEFINED = 0, // require a format to be specified
|
||||
TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha
|
||||
TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB
|
||||
TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB
|
||||
TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence
|
||||
};
|
||||
|
||||
// blending modes
|
||||
enum
|
||||
{
|
||||
|
||||
+11
-8
@@ -15,8 +15,11 @@
|
||||
|
||||
#include "rendertypes.h"
|
||||
|
||||
#include "utilfwd.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
|
||||
/* ----- image formats ----- */
|
||||
@@ -39,14 +42,14 @@ enum ru_imgformat
|
||||
|
||||
/* ----- render utilities ----- */
|
||||
|
||||
void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false);
|
||||
bool render_clip_line(render_bounds *bounds, const render_bounds *clip);
|
||||
bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords);
|
||||
void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1);
|
||||
void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file);
|
||||
void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file);
|
||||
bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false);
|
||||
ru_imgformat render_detect_image(util::random_read &file);
|
||||
void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false) noexcept;
|
||||
bool render_clip_line(render_bounds &bounds, const render_bounds &clip);
|
||||
bool render_clip_quad(render_bounds &bounds, const render_bounds &clip, render_quad_texuv *texcoords);
|
||||
std::pair<render_bounds, render_bounds> render_line_to_quad(const render_bounds &bounds, float width, float length_extension);
|
||||
void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) noexcept;
|
||||
void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) noexcept;
|
||||
bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false) noexcept;
|
||||
ru_imgformat render_detect_image(util::random_read &file) noexcept;
|
||||
|
||||
|
||||
|
||||
|
||||
+123
-4
@@ -19,6 +19,8 @@
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
|
||||
// FIXME: make a proper place for OSD forward declarations
|
||||
@@ -56,7 +58,7 @@ public:
|
||||
/// \param [out] actual Number of bytes actually read. Will always
|
||||
/// be less than or equal to the requested length.
|
||||
/// \return An error condition if reading stopped due to an error.
|
||||
virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
|
||||
virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -100,7 +102,7 @@ public:
|
||||
/// \param [out] actual Number of bytes actually written. Will
|
||||
/// always be less than or equal to the requested length.
|
||||
/// \return An error condition if writing stopped due to an error.
|
||||
virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
|
||||
virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -184,7 +186,7 @@ public:
|
||||
/// be less than or equal to the requested length.
|
||||
/// \return An error condition if seeking failed or reading stopped
|
||||
/// due to an error.
|
||||
virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
|
||||
virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -214,7 +216,7 @@ public:
|
||||
/// always be less than or equal to the requested length.
|
||||
/// \return An error condition if seeking failed or writing stopped
|
||||
/// due to an error.
|
||||
virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
|
||||
virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -229,6 +231,123 @@ public:
|
||||
using ptr = std::unique_ptr<random_read_write>;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Read from the current position in the stream
|
||||
///
|
||||
/// Reads up to the specified number of bytes from the stream into the
|
||||
/// supplied buffer, continuing if interrupted by asynchronous signals.
|
||||
/// May read less than the requested number of bytes if the end of the
|
||||
/// stream is reached or an error occurs. If the stream supports
|
||||
/// seeking, reading starts at the current position in the stream, and
|
||||
/// the current position is incremented by the number of bytes read.
|
||||
/// The operation may not be atomic if it is interrupted before the
|
||||
/// requested number of bytes is read.
|
||||
/// \param [in] stream The stream to read from.
|
||||
/// \param [out] buffer Destination buffer. Must be large enough to
|
||||
/// hold the requested number of bytes.
|
||||
/// \param [in] length Maximum number of bytes to read.
|
||||
/// \return A pair containing an error condition if reading stopped due
|
||||
/// to an error, and the actual number of bytes read.
|
||||
std::pair<std::error_condition, std::size_t> read(read_stream &stream, void *buffer, std::size_t length) noexcept;
|
||||
|
||||
/// \brief Allocate memory and read from the current position in the
|
||||
/// stream
|
||||
///
|
||||
/// Allocates the specified number of bytes and then reads up to that
|
||||
/// number of bytes from the stream into the newly allocated buffer,
|
||||
/// continuing if interrupted by asynchronous signals. May read less
|
||||
/// than the requested number of bytes if the end of the stream is
|
||||
/// reached or an error occurs. If the stream supports seeking,
|
||||
/// reading starts at the current position in the stream, and the
|
||||
/// current position is incremented by the number of bytes read. The
|
||||
/// operation may not be atomic if it is interrupted before the
|
||||
/// requested number of bytes is read. No data will be read if
|
||||
/// allocation fails.
|
||||
/// \param [in] stream The stream to read from.
|
||||
/// hold the requested number of bytes.
|
||||
/// \param [in] length Maximum number of bytes to read.
|
||||
/// \return A tuple containing an error condition if allocation failed
|
||||
/// or reading stopped due to an error, the allocated buffer, and the
|
||||
/// actual number of bytes read.
|
||||
std::tuple<std::error_condition, std::unique_ptr<std::uint8_t []>, std::size_t> read(read_stream &stream, std::size_t length) noexcept;
|
||||
|
||||
/// \brief Read from the specified position
|
||||
///
|
||||
/// Reads up to the specified number of bytes from the stream into the
|
||||
/// supplied buffer, continuing if interrupted by asynchronous signals.
|
||||
/// May read less than the requested number of bytes if the end of the
|
||||
/// stream is reached or an error occurs. If seeking is supported,
|
||||
/// reading starts at the specified position and the current position is
|
||||
/// unaffected. The operation may not be atomic if it is interrupted
|
||||
/// before the requested number of bytes is read.
|
||||
/// \param [in] stream The stream to read from.
|
||||
/// \param [in] offset The position to start reading from, specified as
|
||||
/// a number of bytes from the beginning of the stream.
|
||||
/// \param [out] buffer Destination buffer. Must be large enough to
|
||||
/// hold the requested number of bytes.
|
||||
/// \param [in] length Maximum number of bytes to read.
|
||||
/// \return A pair containing an error condition if reading stopped due
|
||||
/// to an error, and the actual number of bytes read.
|
||||
std::pair<std::error_condition, std::size_t> read_at(random_read &stream, std::uint64_t offset, void *buffer, std::size_t length) noexcept;
|
||||
|
||||
/// \brief Allocate memory and read from the specified position
|
||||
///
|
||||
/// Allocates the specified number of bytes and then reads up to that
|
||||
/// number of bytes from the stream into the newly allocated buffer,
|
||||
/// continuing if interrupted by asynchronous signals. May read less
|
||||
/// than the requested number of bytes if the end of the stream is
|
||||
/// reached or an error occurs. If seeking is supported, reading
|
||||
/// starts at the specified position and the current position is
|
||||
/// unaffected. The operation may not be atomic if it is interrupted
|
||||
/// before the requested number of bytes is read. No data will be read
|
||||
/// if allocation fails.
|
||||
/// \param [in] stream The stream to read from.
|
||||
/// \param [in] offset The position to start reading from, specified as
|
||||
/// a number of bytes from the beginning of the stream.
|
||||
/// \param [out] buffer Destination buffer. Must be large enough to
|
||||
/// hold the requested number of bytes.
|
||||
/// \param [in] length Maximum number of bytes to read.
|
||||
/// \return A tuple containing an error condition if allocation failed
|
||||
/// or reading stopped due to an error, the allocated buffer, and the
|
||||
/// actual number of bytes read.
|
||||
std::tuple<std::error_condition, std::unique_ptr<std::uint8_t []>, std::size_t> read_at(random_read &stream, std::uint64_t offset, std::size_t length) noexcept;
|
||||
|
||||
/// \brief Write at the current position in the stream
|
||||
///
|
||||
/// Writes up to the specified number of bytes from the supplied
|
||||
/// buffer to the stream, continuing if interrupted by asynchronous
|
||||
/// signals. May write less than the requested number of bytes if an
|
||||
/// error occurs. If the stream supports seeking, writing starts at the
|
||||
/// current position in the stream, and the current position is
|
||||
/// incremented by the number of bytes written. The operation may not
|
||||
/// be atomic if it is interrupted before the requested number of bytes
|
||||
/// is written.
|
||||
/// \param [in] stream The stream to write to.
|
||||
/// \param [in] buffer Buffer containing the data to write. Must
|
||||
/// contain at least the specified number of bytes.
|
||||
/// \param [in] length Number of bytes to write.
|
||||
/// \return A pair containing an error condition if writing stopped due
|
||||
/// to an error, and the actual number of bytes written.
|
||||
std::pair<std::error_condition, std::size_t> write(write_stream &stream, void const *buffer, std::size_t length) noexcept;
|
||||
|
||||
/// \brief Write at specified position
|
||||
///
|
||||
/// Writes up to the specified number of bytes from the supplied buffer,
|
||||
/// continuing if interrupted by asynchronous signals. If seeking is
|
||||
/// supported, writing starts at the specified position and the current
|
||||
/// position is unaffected. May write less than the requested number
|
||||
/// of bytes if an error occurs. The operation may not be atomic if it
|
||||
/// is interrupted before the requested number of bytes is written.
|
||||
/// \param [in] stream The stream to write to.
|
||||
/// \param [in] offset The position to start writing at, specified as a
|
||||
/// number of bytes from the beginning of the stream.
|
||||
/// \param [in] buffer Buffer containing the data to write. Must
|
||||
/// contain at least the specified number of bytes.
|
||||
/// \param [in] length Number of bytes to write.
|
||||
/// \return A pair containing an error condition if writing stopped due
|
||||
/// to an error, and the actual number of bytes written.
|
||||
std::pair<std::error_condition, std::size_t> write_at(random_write &stream, std::uint64_t offset, void const *buffer, std::size_t length) noexcept;
|
||||
|
||||
/// \}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user