GUI2/Canvas: refactor surface use out of image rendering
The only real reason to keep using a surface was in order to have resize mode manipulations. I've now added texture-only handling methods (the tiling one was borrowed from display.cpp's draw_background function).
This commit is contained in:
parent
01d78cbb7f
commit
61dcb43ee6
2 changed files with 60 additions and 87 deletions
|
@ -1019,7 +1019,6 @@ image_shape::image_shape(const config& cfg, wfl::action_function_symbol_table& f
|
|||
, y_(cfg["y"])
|
||||
, w_(cfg["w"])
|
||||
, h_(cfg["h"])
|
||||
, src_clip_()
|
||||
, image_()
|
||||
, image_name_(cfg["name"])
|
||||
, resize_mode_(get_resize_mode(cfg["resize_mode"]))
|
||||
|
@ -1061,23 +1060,21 @@ void image_shape::draw(
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The locator might return a different surface for every call so we can't
|
||||
* cache the output, also not if no formula is used.
|
||||
*/
|
||||
image_.assign(make_neutral_surface(image::get_image(image::locator(name))));
|
||||
image_ = image::get_texture(name);
|
||||
|
||||
if(!image_) {
|
||||
ERR_GUI_D << "Image: '" << name << "' not found and won't be drawn." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(image_);
|
||||
src_clip_ = {0, 0, image_->w, image_->h};
|
||||
//
|
||||
// Calculate dimensions and set WFL variables.
|
||||
//
|
||||
const texture::info info = image_.get_info();
|
||||
|
||||
wfl::map_formula_callable local_variables(variables);
|
||||
local_variables.add("image_original_width", wfl::variant(image_->w));
|
||||
local_variables.add("image_original_height", wfl::variant(image_->h));
|
||||
local_variables.add("image_original_width", wfl::variant(info.w));
|
||||
local_variables.add("image_original_height", wfl::variant(info.h));
|
||||
|
||||
unsigned w = w_(local_variables);
|
||||
dimension_validation(w, name, "w");
|
||||
|
@ -1085,8 +1082,8 @@ void image_shape::draw(
|
|||
unsigned h = h_(local_variables);
|
||||
dimension_validation(h, name, "h");
|
||||
|
||||
local_variables.add("image_width", wfl::variant(w ? w : image_->w));
|
||||
local_variables.add("image_height", wfl::variant(h ? h : image_->h));
|
||||
local_variables.add("image_width", wfl::variant(w ? w : info.w));
|
||||
local_variables.add("image_height", wfl::variant(h ? h : info.h));
|
||||
|
||||
const unsigned clip_x = x_(local_variables);
|
||||
dimension_validation(clip_x, name, "x");
|
||||
|
@ -1100,82 +1097,58 @@ void image_shape::draw(
|
|||
// Execute the provided actions for this context.
|
||||
wfl::variant(variables.fake_ptr()).execute_variant(actions_formula_.evaluate(local_variables));
|
||||
|
||||
// Copy the data to local variables to avoid overwriting the originals.
|
||||
SDL_Rect dst_clip = sdl::create_rect(clip_x, clip_y, 0, 0);
|
||||
surface surf(nullptr);
|
||||
|
||||
// Test whether we need to scale and do the scaling if needed.
|
||||
if ((w == 0) && (h == 0)) {
|
||||
surf = image_;
|
||||
}
|
||||
else { // assert((w != 0) || (h != 0))
|
||||
if(w == 0 && resize_mode_ == stretch) {
|
||||
DBG_GUI_D << "Image: vertical stretch from " << image_->w << ','
|
||||
<< image_->h << " to a height of " << h << ".\n";
|
||||
|
||||
// Textures are automatically scaled to size.
|
||||
w = image_->w;
|
||||
}
|
||||
else if(h == 0 && resize_mode_ == stretch) {
|
||||
DBG_GUI_D << "Image: horizontal stretch from " << image_->w
|
||||
<< ',' << image_->h << " to a width of " << w
|
||||
<< ".\n";
|
||||
|
||||
// Textures are automatically scaled to size.
|
||||
h = image_->h;
|
||||
}
|
||||
else {
|
||||
if(w == 0) {
|
||||
w = image_->w;
|
||||
}
|
||||
if(h == 0) {
|
||||
h = image_->h;
|
||||
}
|
||||
if(resize_mode_ == tile) {
|
||||
DBG_GUI_D << "Image: tiling from " << image_->w << ','
|
||||
<< image_->h << " to " << w << ',' << h << ".\n";
|
||||
|
||||
// TODO: convert to texture handling.
|
||||
surf = tile_surface(image_, w, h, false);
|
||||
} else if(resize_mode_ == tile_center) {
|
||||
DBG_GUI_D << "Image: tiling centrally from " << image_->w << ','
|
||||
<< image_->h << " to " << w << ',' << h << ".\n";
|
||||
|
||||
// TODO: convert to texture handling.
|
||||
surf = tile_surface(image_, w, h, true);
|
||||
} else {
|
||||
if(resize_mode_ == stretch) {
|
||||
ERR_GUI_D << "Image: failed to stretch image, "
|
||||
"fall back to scaling.\n";
|
||||
}
|
||||
|
||||
DBG_GUI_D << "Image: scaling from " << image_->w << ','
|
||||
<< image_->h << " to " << w << ',' << h << ".\n";
|
||||
|
||||
// Textures are automatically scaled to size.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!surf) {
|
||||
surf = image_;
|
||||
}
|
||||
//
|
||||
// Copy image texture to canvas texture (which should be the current rendering target)/
|
||||
//
|
||||
CVideo& video = CVideo::get_singleton();
|
||||
|
||||
// Flip on the vertical axis - ie, a horizontal flip.
|
||||
const bool mirror = vertical_mirror_(local_variables);
|
||||
|
||||
dst_clip.w = w ? w : surf->w;
|
||||
dst_clip.h = h ? h : surf->h;
|
||||
SDL_Rect dst_clip = sdl::create_rect(clip_x, clip_y, 0, 0);
|
||||
|
||||
/* NOTE: we cannot use SDL_UpdateTexture to copy the surface pixel data directly to the canvas texture
|
||||
* since no alpha blending occurs; values (even pure alpha) totally overwrite the underlying pixel data.
|
||||
*
|
||||
* To work around that, we create a texture from the surface and copy it to the renderer. This cleanly
|
||||
* copies the surface to the canvas texture with the appropriate alpha blending.
|
||||
*/
|
||||
texture txt(surf);
|
||||
const unsigned int dst_w = w ? w : info.w;
|
||||
const unsigned int dst_h = h ? h : info.h;
|
||||
|
||||
CVideo::get_singleton().render_copy(txt, nullptr, &dst_clip, mirror, false);
|
||||
// TODO: remove stretch mode
|
||||
switch(resize_mode_) {
|
||||
case scale:
|
||||
case stretch: {
|
||||
DBG_GUI_D << "Image: scaling from " << info.w << ',' << info.h << " to " << w << ',' << h << std::endl;
|
||||
|
||||
dst_clip.w = dst_w;
|
||||
dst_clip.h = dst_h;
|
||||
|
||||
video.render_copy(image_, nullptr, &dst_clip, mirror, false);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: move this to a more general place.
|
||||
case tile: {
|
||||
DBG_GUI_D << "Image: tiling from " << info.w << ',' << info.h << " to " << w << ',' << h << std::endl;
|
||||
|
||||
const unsigned int w_count = static_cast<int>(std::ceil(static_cast<double>(dst_w) / static_cast<double>(info.w)));
|
||||
const unsigned int h_count = static_cast<int>(std::ceil(static_cast<double>(dst_h) / static_cast<double>(info.h)));
|
||||
|
||||
for(unsigned int xi = 0, current_x = dst_clip.x; xi < w_count; ++xi, current_x += info.w) {
|
||||
for(unsigned int iy = 0, current_y = dst_clip.y; iy < h_count; ++iy, current_y += info.h) {
|
||||
SDL_Rect area = sdl::create_rect(current_x, current_y, info.w, info.h);
|
||||
video.render_copy(image_, nullptr, &area, mirror, false);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case tile_center: {
|
||||
DBG_GUI_D << "Image: tiling centrally from " << info.w << ',' << info.h << " to " << w << ',' << h << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO: text description
|
||||
ERR_GUI_D << "Unknown resize mode option: " << resize_mode_ << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
image_shape::resize_mode image_shape::get_resize_mode(const std::string& resize_mode)
|
||||
|
|
|
@ -204,11 +204,11 @@ private:
|
|||
w_, /**< The width of the image. */
|
||||
h_; /**< The height of the image. */
|
||||
|
||||
/** Contains the size of the image. */
|
||||
SDL_Rect src_clip_;
|
||||
|
||||
/** The image is cached in this surface. */
|
||||
surface image_;
|
||||
/**
|
||||
* The image texture. Since formulas may return different values each draw cycle, this is reassigned
|
||||
* each time, so this is mostly here to avoid constantly allocating a new textures.
|
||||
*/
|
||||
texture image_;
|
||||
|
||||
/**
|
||||
* Name of the image.
|
||||
|
|
Loading…
Add table
Reference in a new issue