mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-29 06:39:19 +00:00
Reimplement map screenshots.
They will remain broken until display.cpp switches over to using textures in stead of surfaces to render.
This commit is contained in:
parent
743a1b5655
commit
d39a6fe619
@ -71,6 +71,7 @@
|
||||
|
||||
static lg::log_domain log_display("display");
|
||||
#define ERR_DP LOG_STREAM(err, log_display)
|
||||
#define WRN_DP LOG_STREAM(warn, log_display)
|
||||
#define LOG_DP LOG_STREAM(info, log_display)
|
||||
#define DBG_DP LOG_STREAM(debug, log_display)
|
||||
|
||||
@ -229,7 +230,6 @@ display::display(const display_context* dc,
|
||||
, fps_handle_(0)
|
||||
, invalidated_hexes_(0)
|
||||
, drawn_hexes_(0)
|
||||
, map_screenshot_surf_(nullptr)
|
||||
, redraw_observers_()
|
||||
, draw_coordinates_(false)
|
||||
, draw_terrain_codes_(false)
|
||||
@ -781,43 +781,46 @@ map_location display::minimap_location_on(int x, int y)
|
||||
surface display::screenshot(bool map_screenshot)
|
||||
{
|
||||
if (!map_screenshot) {
|
||||
LOG_DP << "taking ordinary screenshot" << std::endl;
|
||||
return screen_.read_pixels();
|
||||
} else {
|
||||
if (get_map().empty()) {
|
||||
ERR_DP << "No map loaded, cannot create a map screenshot.\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SDL_Rect area = max_map_area();
|
||||
map_screenshot_surf_ = surface(area.w, area.h);
|
||||
|
||||
if (map_screenshot_surf_ == nullptr) {
|
||||
// Memory problem ?
|
||||
ERR_DP << "Could not create screenshot surface, try zooming out.\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// back up the current map view position and move to top-left
|
||||
int old_xpos = xpos_;
|
||||
int old_ypos = ypos_;
|
||||
xpos_ = 0;
|
||||
ypos_ = 0;
|
||||
|
||||
// we reroute render output to the screenshot surface and invalidate all
|
||||
map_screenshot_= true;
|
||||
invalidateAll_ = true;
|
||||
DBG_DP << "draw() with map_screenshot\n";
|
||||
draw(true,true);
|
||||
|
||||
// restore normal rendering
|
||||
map_screenshot_= false;
|
||||
xpos_ = old_xpos;
|
||||
ypos_ = old_ypos;
|
||||
|
||||
// Clear map_screenshot_surf_ and return a new surface that contains the same data
|
||||
surface surf(std::move(map_screenshot_surf_));
|
||||
return surf;
|
||||
}
|
||||
|
||||
if (get_map().empty()) {
|
||||
ERR_DP << "No map loaded, cannot create a map screenshot.\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// back up the current map view position and move to top-left
|
||||
int old_xpos = xpos_;
|
||||
int old_ypos = ypos_;
|
||||
xpos_ = 0;
|
||||
ypos_ = 0;
|
||||
|
||||
// Reroute render output to a separate texture until the end of scope.
|
||||
SDL_Rect area = max_map_area();
|
||||
if (area.w > 1 << 16 || area.h > 1 << 16) {
|
||||
WRN_DP << "Excessively large map screenshot area" << std::endl;
|
||||
}
|
||||
LOG_DP << "creating " << area.w << " by " << area.h
|
||||
<< " texture for map screenshot" << std::endl;
|
||||
texture output_texture(area.w, area.h, SDL_TEXTUREACCESS_TARGET);
|
||||
auto target_setter = video().set_render_target(output_texture);
|
||||
auto clipper = video().set_clip(area);
|
||||
|
||||
map_screenshot_ = true;
|
||||
invalidateAll_ = true;
|
||||
|
||||
DBG_DP << "draw() call for map screenshot\n";
|
||||
draw(true, true);
|
||||
|
||||
map_screenshot_ = false;
|
||||
|
||||
// Restore map viewport position
|
||||
xpos_ = old_xpos;
|
||||
ypos_ = old_ypos;
|
||||
|
||||
// Read rendered pixels back as an SDL surface.
|
||||
return video().read_pixels();
|
||||
}
|
||||
|
||||
std::shared_ptr<gui::button> display::find_action_button(const std::string& id)
|
||||
|
@ -1034,8 +1034,6 @@ private:
|
||||
int invalidated_hexes_;
|
||||
int drawn_hexes_;
|
||||
|
||||
surface map_screenshot_surf_;
|
||||
|
||||
std::vector<std::function<void(display&)>> redraw_observers_;
|
||||
|
||||
/** Debug flag - overlay x,y coords on tiles */
|
||||
|
@ -24,36 +24,9 @@
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
* Sets the renderer output target to the specified texture.
|
||||
*/
|
||||
class render_target_setter
|
||||
{
|
||||
public:
|
||||
explicit render_target_setter(texture& t)
|
||||
: renderer_(CVideo::get_singleton().get_renderer())
|
||||
, last_target_(nullptr)
|
||||
{
|
||||
if(renderer_) {
|
||||
// Validate we can render to this texture.
|
||||
assert(t.get_info().access == SDL_TEXTUREACCESS_TARGET);
|
||||
|
||||
last_target_ = SDL_GetRenderTarget(renderer_);
|
||||
SDL_SetRenderTarget(renderer_, t);
|
||||
}
|
||||
}
|
||||
|
||||
~render_target_setter()
|
||||
{
|
||||
if(renderer_) {
|
||||
SDL_SetRenderTarget(renderer_, last_target_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
SDL_Texture* last_target_; // TODO: use the texture wrapper?
|
||||
};
|
||||
// The render_target_setter class has been moved to CVideo.
|
||||
// To obtain one, use CVideo::set_render_target().
|
||||
//class render_target_setter
|
||||
|
||||
using sdl_rect_getter = void (*)(SDL_Renderer*, SDL_Rect*);
|
||||
using sdl_rect_setter = int (*)(SDL_Renderer*, const SDL_Rect*);
|
||||
|
@ -500,6 +500,28 @@ void CVideo::delay(unsigned int milliseconds)
|
||||
}
|
||||
}
|
||||
|
||||
CVideo::render_target_setter CVideo::set_render_target(const texture& t)
|
||||
{
|
||||
return CVideo::render_target_setter(*this, t);
|
||||
}
|
||||
|
||||
void CVideo::force_render_target(SDL_Texture* t)
|
||||
{
|
||||
SDL_SetRenderTarget(get_renderer(), t);
|
||||
|
||||
// The scale factor gets reset when the render target changes,
|
||||
// so make sure it gets set back appropriately.
|
||||
if (t == nullptr || t == render_texture_) {
|
||||
// TODO: highdpi - sort out who owns this
|
||||
window->set_logical_size(get_width(), get_height());
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Texture* CVideo::get_render_target()
|
||||
{
|
||||
return SDL_GetRenderTarget(get_renderer());
|
||||
}
|
||||
|
||||
// TODO: highdpi - separate drawing interface should also handle clipping
|
||||
|
||||
CVideo::clip_setter CVideo::set_clip(const SDL_Rect& clip)
|
||||
@ -510,7 +532,11 @@ CVideo::clip_setter CVideo::set_clip(const SDL_Rect& clip)
|
||||
void CVideo::force_clip(const SDL_Rect& clip)
|
||||
{
|
||||
// Set the clipping area both on the drawing surface,
|
||||
SDL_SetClipRect(drawingSurface, &clip);
|
||||
if (clip == sdl::empty_rect) {
|
||||
SDL_SetClipRect(drawingSurface, nullptr);
|
||||
} else {
|
||||
SDL_SetClipRect(drawingSurface, &clip);
|
||||
}
|
||||
// and on the render target.
|
||||
if (SDL_RenderSetClipRect(get_renderer(), &clip)) {
|
||||
throw error("Failed to set render clip rect");
|
||||
@ -519,13 +545,13 @@ void CVideo::force_clip(const SDL_Rect& clip)
|
||||
|
||||
SDL_Rect CVideo::get_clip() const
|
||||
{
|
||||
if (!drawingSurface) {
|
||||
return sdl::empty_rect;
|
||||
}
|
||||
SDL_Rect clip;
|
||||
SDL_RenderGetClipRect(*window, &clip);
|
||||
|
||||
SDL_Rect r_draw;
|
||||
SDL_GetClipRect(drawingSurface, &r_draw);
|
||||
return r_draw;
|
||||
if (clip == sdl::empty_rect) {
|
||||
return draw_area();
|
||||
}
|
||||
return clip;
|
||||
}
|
||||
|
||||
SDL_Rect CVideo::clip_to_draw_area(const SDL_Rect* r) const
|
||||
|
@ -18,9 +18,11 @@
|
||||
#include "events.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "lua_jailbreak_exception.hpp"
|
||||
#include "sdl/texture.hpp"
|
||||
|
||||
#include <SDL2/SDL_render.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
class surface;
|
||||
@ -372,6 +374,8 @@ public:
|
||||
|
||||
void lock_flips(bool);
|
||||
|
||||
/***** ***** ***** ***** State management ***** ***** ****** *****/
|
||||
|
||||
/** A class to manage automatic restoration of the clipping region.
|
||||
*
|
||||
* While this can be constructed on its own, it is usually easier to
|
||||
@ -421,6 +425,67 @@ public:
|
||||
/** Get the current clipping area, in draw coordinates. */
|
||||
SDL_Rect get_clip() const;
|
||||
|
||||
/** A class to manage automatic restoration of the render target.
|
||||
*
|
||||
* While this can be constructed on its own, it is usually easier to
|
||||
* use the CVideo::set_render_target() member function.
|
||||
*/
|
||||
class render_target_setter
|
||||
{
|
||||
public:
|
||||
explicit render_target_setter(CVideo& video, const texture& t)
|
||||
: video_(video), last_target_(nullptr)
|
||||
{
|
||||
// Validate we can render to this texture.
|
||||
assert(t.get_info().access == SDL_TEXTUREACCESS_TARGET);
|
||||
|
||||
last_target_ = video_.get_render_target();
|
||||
video_.force_render_target(t);
|
||||
}
|
||||
|
||||
~render_target_setter()
|
||||
{
|
||||
video_.force_render_target(last_target_);
|
||||
}
|
||||
|
||||
private:
|
||||
CVideo& video_;
|
||||
SDL_Texture* last_target_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the given texture as the active render target.
|
||||
*
|
||||
* All draw calls will draw to this texture until the returned object
|
||||
* goes out of scope. Do not retain the render_target_setter longer
|
||||
* than necessary.
|
||||
*
|
||||
* The provided texture must have been created with the
|
||||
* SDL_TEXTUREACCESS_TARGET access mode.
|
||||
*
|
||||
* @param t The new render target. This must be a texture created
|
||||
* with SDL_TEXTUREACCESS_TARGET.
|
||||
* @returns A render_target_setter object. When this object is
|
||||
* destroyed the render target will be restored to
|
||||
* whatever it was before this call.
|
||||
*/
|
||||
render_target_setter set_render_target(const texture& t);
|
||||
|
||||
/**
|
||||
* Set the render target, without any provided way of setting it back.
|
||||
*
|
||||
* @param t The new render target. This must be a texture created
|
||||
* with SDL_TEXTUREACCESS_TARGET, or NULL to indicate
|
||||
* the underlying window.
|
||||
*/
|
||||
void force_render_target(SDL_Texture* t);
|
||||
|
||||
/** Get the current render target.
|
||||
*
|
||||
* Returns NULL if the render target is the underlying window.
|
||||
*/
|
||||
SDL_Texture* get_render_target();
|
||||
|
||||
/***** ***** ***** ***** Help string functions ***** ***** ****** *****/
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user