Initial refactor for main-screen accelerated rendering

This commit is contained in:
Charles Dang 2017-06-12 08:11:58 +11:00
parent 8dc661db40
commit d2087a14c4
13 changed files with 497 additions and 386 deletions

View file

@ -50,6 +50,8 @@
#include "whiteboard/manager.hpp"
#include "show_dialog.hpp"
#include "gui/dialogs/loading_screen.hpp"
#include "sdl/render_utils.hpp"
#include "sdl/texture.hpp"
#include <SDL_image.h>
@ -255,6 +257,13 @@ display::display(const display_context * dc, std::weak_ptr<wb::manager> wb, repo
create_buttons();
}
rebuild_all();
assert(builder_);
//builder_->rebuild_cache_all();
invalidate_all();
//invalidate_locations_in_rect(map_area());
}
display::~display()
@ -352,24 +361,27 @@ void display::init_flags_for_side_internal(size_t n, const std::string& side_col
}
}
surface display::get_flag(const map_location& loc)
texture display::get_flag(const map_location& loc)
{
if(!get_map().is_village(loc)) {
return surface(nullptr);
return texture(nullptr);
}
for (const team& t : dc_->teams()) {
if (t.owns_village(loc) && (!fogged(loc) || !dc_->get_team(viewing_side()).is_enemy(t.side())))
{
for(const team& t : dc_->teams()) {
if(t.owns_village(loc) && (!fogged(loc) || !dc_->get_team(viewing_side()).is_enemy(t.side()))) {
auto& flag = flags_[t.side() - 1];
flag.update_last_draw_time();
const image::locator &image_flag = animate_map_ ?
flag.get_current_frame() : flag.get_first_frame();
return image::get_image(image_flag, image::TOD_COLORED);
// TODO: move this if-animated check to a helper function.
const image::locator& image_flag = animate_map_
? flag.get_current_frame()
: flag.get_first_frame();
return image::get_texture(image_flag); // TODO: ToD coloring
}
}
return surface(nullptr);
return texture(nullptr);
}
void display::set_team(size_t teamindex, bool show_everything)
@ -665,7 +677,7 @@ const display::rect_of_hexes display::hexes_under_rect(const SDL_Rect& r) const
if (r.w<=0 || r.h<=0) {
// empty rect, return dummy values giving begin=end
res.left = 0;
res.right = -1; // end is right+1
res.right = -1; // end is right + 1
res.top[0] = 0;
res.top[1] = 0;
res.bottom[0] = 0;
@ -674,29 +686,33 @@ const display::rect_of_hexes display::hexes_under_rect(const SDL_Rect& r) const
}
SDL_Rect map_rect = map_area();
// translate rect coordinates from screen-based to map_area-based
int x = xpos_ - map_rect.x + r.x;
int y = ypos_ - map_rect.y + r.y;
// we use the "double" type to avoid important rounding error (size of an hex!)
// we will also need to use std::floor to avoid bad rounding at border (negative values)
double tile_width = hex_width();
double tile_size = hex_size();
double border = theme_.border().size;
// we minus "0.(3)", for horizontal imbrication.
// reason is: two adjacent hexes each overlap 1/4 of their width, so for
// grid calculation 3/4 of tile width is used, which by default gives
// 18/54=0.(3). Note that, while tile_width is zoom dependent, 0.(3) is not.
res.left = static_cast<int>(std::floor(-border + x / tile_width - 0.3333333));
// we remove 1 pixel of the rectangle dimensions
// (the rounded division take one pixel more than needed)
res.right = static_cast<int>(std::floor(-border + (x + r.w-1) / tile_width));
res.right = static_cast<int>(std::floor(-border + (x + r.w - 1) / tile_width));
// for odd x, we must shift up one half-hex. Since x will vary along the edge,
// we store here the y values for even and odd x, respectively
res.top[0] = static_cast<int>(std::floor(-border + y / tile_size));
res.top[1] = static_cast<int>(std::floor(-border + y / tile_size - 0.5));
res.bottom[0] = static_cast<int>(std::floor(-border + (y + r.h-1) / tile_size));
res.bottom[1] = static_cast<int>(std::floor(-border + (y + r.h-1) / tile_size - 0.5));
res.bottom[0] = static_cast<int>(std::floor(-border + (y + r.h - 1) / tile_size));
res.bottom[1] = static_cast<int>(std::floor(-border + (y + r.h - 1) / tile_size - 0.5));
// TODO: in some rare cases (1/16), a corner of the big rect is on a tile
// (the 72x72 rectangle containing the hex) but not on the hex itself
@ -1030,19 +1046,20 @@ std::vector<surface> display::get_fog_shroud_images(const map_location& loc, ima
void display::get_terrain_images(const map_location &loc,
const std::string& timeid,
TERRAIN_TYPE terrain_type)
{
TERRAIN_TYPE terrain_type){
terrain_image_vector_.clear();
terrain_builder::TERRAIN_TYPE builder_terrain_type =
(terrain_type == FOREGROUND ?
terrain_builder::FOREGROUND : terrain_builder::BACKGROUND);
terrain_builder::TERRAIN_TYPE builder_terrain_type = terrain_type == FOREGROUND
? terrain_builder::FOREGROUND
: terrain_builder::BACKGROUND;
const terrain_builder::imagelist* const terrains = builder_->get_terrain_at(loc,
timeid, builder_terrain_type);
assert(builder_);
const terrain_builder::imagelist* const terrains = builder_->get_terrain_at(loc, timeid, builder_terrain_type);
//assert(terrains);
image::light_string lt;
#if 0
const time_of_day& tod = get_time_of_day(loc);
//get all the light transitions
@ -1145,23 +1162,28 @@ void display::get_terrain_images(const map_location &loc,
lt = image::get_light_string(-1, col.r, col.g, col.b);
}
}
#endif
if(terrains != nullptr) {
// assert(terrains);
// Cache the offmap name.
// Since it is themeable it can change,
// so don't make it static.
const std::string off_map_name = "terrain/" + theme_.border().tile_image;
for(const auto& terrain : *terrains) {
const image::locator &image = animate_map_ ?
terrain.get_current_frame() : terrain.get_first_frame();
const image::locator &image = animate_map_
? terrain.get_current_frame()
: terrain.get_first_frame();
// We prevent ToD coloring and brightening of off-map tiles,
// We need to test for the tile to be rendered and
// not the location, since the transitions are rendered
// over the offmap-terrain and these need a ToD coloring.
surface surf;
const bool off_map = (image.get_filename() == off_map_name || image.get_modifications().find("NO_TOD_SHIFT()") != std::string::npos);
texture tex = image::get_texture(image);
//assert(tex);
//const bool off_map = (image.get_filename() == off_map_name || image.get_modifications().find("NO_TOD_SHIFT()") != std::string::npos);
#if 0
if(off_map) {
surf = image::get_image(image, image::SCALED_TO_HEX);
} else if(lt.empty()) {
@ -1170,26 +1192,61 @@ void display::get_terrain_images(const map_location &loc,
surf = image::get_lighted_image(image, lt, image::SCALED_TO_HEX);
}
if (!surf.null()) {
terrain_image_vector_.push_back(std::move(surf));
if (!tex.null()) {
terrain_image_vector_.push_back(std::move(tex));
}
}
}
}
void display::drawing_buffer_add(const drawing_buffer::drawing_layer layer,
const map_location& loc, int x, int y, const surface& surf,
const map_location& loc, int x, int y, const texture& tex,
const SDL_Rect &clip)
{
drawing_buffer_.add_item(layer, loc, x, y, surf, clip);
//drawing_buffer_.add_item(layer, loc, x, y, tex, clip);
}
void display::drawing_buffer_add(const drawing_buffer::drawing_layer layer,
const map_location& loc, int x, int y,
const std::vector<surface> &surf,
const std::vector<texture>& tex,
const SDL_Rect &clip)
{
drawing_buffer_.add_item(layer, loc, x, y, surf, clip);
//std::cerr << "adding texture vec to buffer" << std::endl;
//std::vector<texture> v = tex;
//if(v.empty()) {
// std::cerr << "vec empty"<< std::endl;
//}
//drawing_buffer_.add_item(layer, loc, x, y, v, clip);
}
void display::drawing_buffer_add(const drawing_buffer::drawing_layer layer,
const map_location& loc, int x, int y, const surface& surf,
const SDL_Rect &clip)
{
if(!surf) {
return;
}
//drawing_buffer_.add_item(layer, loc, x, y, texture(surf), clip);
}
void display::drawing_buffer_add(const drawing_buffer::drawing_layer layer,
const map_location& loc, int x, int y,
const std::vector<surface>& surf,
const SDL_Rect &clip)
{
//std::vector<texture> res;
//for(const auto& s : surf) {
// if(!s) {
// continue;
// }
// res.emplace_back(s);
//}
//drawing_buffer_.add_item(layer, loc, x, y, res, clip);
}
void display::toggle_benchmark()
@ -1213,7 +1270,7 @@ void display::flip()
font::draw_floating_labels(frameBuffer);
events::raise_volatile_draw_event();
video().render_screen();
//video().render_screen();
events::raise_volatile_undraw_event();
font::undraw_floating_labels(frameBuffer);
@ -1281,7 +1338,7 @@ static void draw_panel(CVideo &video, const theme::panel& panel, std::vector<std
//log_scope("draw panel");
DBG_DP << "drawing panel " << panel.get_id() << "\n";
surface surf(image::get_image(panel.image()));
texture tex(image::get_texture(panel.image()));
const SDL_Rect screen = video.screen_area();
SDL_Rect& loc = panel.location(screen);
@ -1289,11 +1346,9 @@ static void draw_panel(CVideo &video, const theme::panel& panel, std::vector<std
DBG_DP << "panel location: x=" << loc.x << ", y=" << loc.y
<< ", w=" << loc.w << ", h=" << loc.h << "\n";
if(!surf.null()) {
if(surf->w != loc.w || surf->h != loc.h) {
surf.assign(tile_surface(surf,loc.w,loc.h));
}
video.blit_surface(loc.x, loc.y, surf);
if(!tex.null()) {
// TODO: should probably tile this as before.
video.render_copy(tex, nullptr, &loc);
}
}
@ -1344,7 +1399,7 @@ void display::draw_all_panels()
* The minimap is also a panel, force it to update its contents.
* This is required when the size of the minimap has been modified.
*/
recalculate_minimap();
//recalculate_minimap();
for(const auto& panel : theme_.panels()) {
draw_panel(video(), panel, menu_buttons_);
@ -1357,7 +1412,7 @@ void display::draw_all_panels()
render_buttons();
}
static void draw_background(surface screen, const SDL_Rect& area, const std::string& image)
static void draw_background(const SDL_Rect& area, const std::string& image)
{
// No background image, just fill in black.
if(image.empty()) {
@ -1365,23 +1420,14 @@ static void draw_background(surface screen, const SDL_Rect& area, const std::str
return;
}
const surface background(image::get_image(image));
const texture background(image::get_texture(image));
if(background.null()) {
return;
}
const unsigned int width = background->w;
const unsigned int height = background->h;
const unsigned int w_count = static_cast<int>(std::ceil(static_cast<double>(area.w) / static_cast<double>(width)));
const unsigned int h_count = static_cast<int>(std::ceil(static_cast<double>(area.h) / static_cast<double>(height)));
for(unsigned int w = 0, w_off = area.x; w < w_count; ++w, w_off += width) {
for(unsigned int h = 0, h_off = area.y; h < h_count; ++h, h_off += height) {
SDL_Rect clip = sdl::create_rect(w_off, h_off, 0, 0);
sdl_blit(background, nullptr, screen, &clip);
}
}
// TODO: should probably tile this as before.
SDL_Rect a = area;
CVideo::get_singleton().render_copy(background, nullptr, &a);
}
void display::draw_text_in_hex(const map_location& loc,
@ -1532,7 +1578,7 @@ void display::draw_init()
const surface& screen = get_screen_surface();
clip_rect_setter set_clip_rect(screen, &clip_rect);
SDL_FillRect(screen, &clip_rect, 0x00000000);
draw_background(screen, clip_rect, theme_.border().background_image);
draw_background(clip_rect, theme_.border().background_image);
redraw_background_ = false;
// Force a full map redraw
@ -1824,10 +1870,10 @@ bool display::scroll(int xmove, int ymove, bool force)
// This is a workaround for a SDL2 bug when blitting on overlapping surfaces. The bug
// only strikes during scrolling, but will then duplicate textures across the entire map.
surface screen_copy = make_neutral_surface(screen);
//surface screen_copy = make_neutral_surface(screen);
SDL_SetSurfaceBlendMode(screen_copy, SDL_BLENDMODE_NONE);
SDL_BlitSurface(screen_copy, &srcrect, screen, &dstrect);
//SDL_SetSurfaceBlendMode(screen_copy, SDL_BLENDMODE_NONE);
//SDL_BlitSurface(screen_copy, &srcrect, screen, &dstrect);
}
if(diff_y != 0) {
@ -2263,6 +2309,7 @@ void display::set_idle_anim_rate(int rate)
void display::redraw_everything()
{
std::cerr << "calling redraw everything" << std::endl;
if(screen_.update_locked())
return;
@ -2331,7 +2378,10 @@ void display::draw(bool update) {
}
void display::draw(bool update,bool force) {
void display::draw(bool update,bool force)
{
return;
// log_scope("display::draw");
if (screen_.update_locked()) {
@ -2365,6 +2415,7 @@ void display::draw(bool update,bool force) {
* draw_invalidated() also invalidates the halos, so also needs to be
* ran if invalidated_.empty() == true.
*/
//drawing_buffer_.set_clip_rect(map_area());
if(!invalidated_.empty() || preferences::show_haloes()) {
draw_invalidated();
invalidated_.clear();
@ -2400,7 +2451,7 @@ void display::draw_invalidated() {
SDL_Rect clip_rect = get_clip_rect();
surface& screen = get_screen_surface();
clip_rect_setter set_clip_rect(screen, &clip_rect);
for (const map_location& loc : invalidated_) {
for (const map_location& loc : get_visible_hexes()) {
int xpos = get_location_x(loc);
int ypos = get_location_y(loc);
@ -2432,6 +2483,31 @@ void display::draw_invalidated() {
}
static bool populated = false;
void display::populate_terrain_cache()
{
if(populated) {
return;
}
//SDL_Rect clip_rect = get_clip_rect();
// surface& screen = get_screen_surface();
//clip_rect_setter set_clip_rect(screen, &clip_rect);
for (const map_location& loc : get_visible_hexes()) {
//int xpos = get_location_x(loc);
//int ypos = get_location_y(loc);
//const bool on_map = get_map().on_board(loc);
//SDL_Rect hex_rect = sdl::create_rect(xpos, ypos, zoom_, zoom_);
//if(!sdl::rects_overlap(hex_rect,clip_rect)) {
// continue;
//}
draw_hex(loc);
//drawn_hexes_+=1;
}
populated= true;
}
void display::draw_hex(const map_location& loc) {
int xpos = get_location_x(loc);
int ypos = get_location_y(loc);
@ -2442,7 +2518,7 @@ void display::draw_hex(const map_location& loc) {
int num_images_fg = 0;
int num_images_bg = 0;
if(!shrouded(loc)) {
//if(!shrouded(loc)) {
// unshrouded terrain (the normal case)
get_terrain_images(loc, tod.id, BACKGROUND); // updates terrain_image_vector_
drawing_buffer_add(drawing_buffer::LAYER_TERRAIN_BG, loc, xpos, ypos, terrain_image_vector_);
@ -2456,14 +2532,17 @@ void display::draw_hex(const map_location& loc) {
if(grid_) {
static const image::locator grid_top(game_config::images::grid_top);
drawing_buffer_add(drawing_buffer::LAYER_GRID_TOP, loc, xpos, ypos,
image::get_image(grid_top, image::TOD_COLORED));
image::get_texture(grid_top));
static const image::locator grid_bottom(game_config::images::grid_bottom);
drawing_buffer_add(drawing_buffer::LAYER_GRID_BOTTOM, loc, xpos, ypos,
image::get_image(grid_bottom, image::TOD_COLORED));
image::get_texture(grid_bottom));
}
drawing_buffer_add(LAYER_TERRAIN_BG, loc, xpos, ypos, get_flag(loc));
}
// village-control flags.
//drawing_buffer_add(drawing_buffer::LAYER_TERRAIN_BG, loc, xpos, ypos, get_flag(loc));
//}
#if 0
if(!shrouded(loc)) {
typedef overlay_map::const_iterator Itor;
std::pair<Itor,Itor> overlays = overlays_->equal_range(loc);
@ -2488,11 +2567,6 @@ void display::draw_hex(const map_location& loc) {
}
}
if(!shrouded(loc)) {
// village-control flags.
drawing_buffer_add(LAYER_TERRAIN_BG, loc, xpos, ypos, get_flag(loc));
}
// Draw the time-of-day mask on top of the terrain in the hex.
// tod may differ from tod if hex is illuminated.
const std::string& tod_hex_mask = tod.image_mask;
@ -2596,7 +2670,12 @@ void display::draw_hex(const map_location& loc) {
drawing_buffer_add(drawing_buffer::LAYER_UNIT_DEFAULT, loc, xpos, ypos,
image::get_image("terrain/foreground.png", image_type));
}
#endif
}
void display::draw_hex_cursor(const map_location& /*loc*/)
{
/** DO NOTHING */
}
image::TYPE display::get_image_type(const map_location& /*loc*/) {
@ -3117,27 +3196,115 @@ void display::process_reachmap_changes()
reach_map_changed_ = false;
}
void display::handle_window_event(const SDL_Event& event) {
if (event.type == SDL_WINDOWEVENT) {
switch (event.window.event) {
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_RESTORED:
case SDL_WINDOWEVENT_EXPOSED:
dirty_ = true;
break;
}
}
// TODO: decide whether to move this to CVideo.
// Also maybe a better name and/or additional functionality.
void display::render_texture_original_size(const texture& tex, const int x_pos, const int y_pos)
{
texture::info info = tex.get_info();
SDL_Rect dst {x_pos, y_pos, info.w, info.h};
screen_.render_copy(tex, nullptr, &dst);
}
void display::handle_event(const SDL_Event& event) {
if (gui2::dialogs::loading_screen::displaying()) {
void display::draw_gamemap()
{
SDL_Rect area = map_area();
render_clip_rect_setter setter(&area);
// TODO: ToD coloring
invalidate_animations();
unit_drawer drawer = unit_drawer(*this);
for(const map_location& loc : get_visible_hexes()) {
int xpos = get_location_x(loc);
int ypos = get_location_y(loc);
image::TYPE image_type = get_image_type(loc);
const bool on_map = get_map().on_board(loc);
const time_of_day& tod = get_time_of_day(loc);
// TODO:
//if(shrouded(loc))) {
// return;
//}
//
// Background terrains
//
get_terrain_images(loc, tod.id, image_type, FOREGROUND);
for(const texture& t : terrain_image_vector_) {
render_texture_original_size(t, xpos, ypos);
}
//
// Village flags
//
texture flag = get_flag(loc);
if(flag) {
render_texture_original_size(flag, xpos, ypos);
}
//
// Units
//
auto u_it = dc_->units().find(loc);
auto request = exclusive_unit_draw_requests_.find(loc);
if(u_it != dc_->units().end() && (request == exclusive_unit_draw_requests_.end() || request->second == u_it->id())) {
drawer.redraw_unit(*u_it);
}
//
// Foreground terrains
//
get_terrain_images(loc, tod.id, image_type, BACKGROUND);
for(const texture& t : terrain_image_vector_) {
render_texture_original_size(t, xpos, ypos);
}
}
}
void display::draw_new()
{
const SDL_Rect area = map_outside_area();
draw_background(area, theme_.border().background_image);
draw_gamemap();
draw_all_panels();
draw_minimap();
}
void display::handle_window_event(const SDL_Event& event)
{
if(event.type == SDL_WINDOWEVENT) {
switch(event.window.event) {
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_RESTORED:
case SDL_WINDOWEVENT_EXPOSED:
dirty_ = true;
break;
}
}
}
void display::handle_event(const SDL_Event& event)
{
if(gui2::dialogs::loading_screen::displaying()) {
return;
}
if (event.type == DRAW_ALL_EVENT) {
draw();
switch(event.type) {
case DRAW_EVENT:
case DRAW_ALL_EVENT:
draw_new();
break;
default:
break;
}
}

View file

@ -91,6 +91,8 @@ public:
const gamemap& get_map() const { return dc_->map(); }
void populate_terrain_cache();
const std::vector<team>& get_teams() const {return dc_->teams();}
/** The playing team is the team whose turn it is. */
@ -578,6 +580,8 @@ public:
void draw(bool update, bool force);
void draw_new();
map_labels& labels();
const map_labels& labels() const;
@ -643,6 +647,10 @@ public:
{
reports_object_ = &reports_object;
}
// TODO: decide whether to move this to CVideo.
void render_texture_original_size(const texture& tex, const int x_pos, const int y_pos);
private:
void init_flags_for_side_internal(size_t side, const std::string& side_color);
@ -698,6 +706,8 @@ protected:
*/
virtual void draw_hex(const map_location& loc);
virtual void draw_hex_cursor(const map_location& loc);
/**
* @returns the image type to be used for the passed hex
*/
@ -709,6 +719,8 @@ protected:
*/
virtual void draw_sidebar() {}
void draw_gamemap();
void draw_minimap();
enum TERRAIN_TYPE { BACKGROUND, FOREGROUND};
@ -792,65 +804,16 @@ protected:
private:
// This surface must be freed by the caller
surface get_flag(const map_location& loc);
texture get_flag(const map_location& loc);
/** Animated flags for each team */
std::vector<animated<image::locator>> flags_;
// This vector is a class member to avoid repeated memory allocations in get_terrain_images(),
// which turned out to be a significant bottleneck while profiling.
std::vector<surface> terrain_image_vector_;
std::vector<texture> terrain_image_vector_;
public:
/**
* The layers to render something on. This value should never be stored
* it's the internal drawing order and adding removing and reordering
* the layers should be safe.
* If needed in WML use the name and map that to the enum value.
*/
enum drawing_layer {
LAYER_TERRAIN_BG, /**<
* Layer for the terrain drawn behind the
* unit.
*/
LAYER_GRID_TOP, /**< Top half part of grid image */
LAYER_MOUSEOVER_OVERLAY, /**< Mouseover overlay used by editor*/
LAYER_FOOTSTEPS, /**< Footsteps showing path from unit to mouse */
LAYER_MOUSEOVER_TOP, /**< Top half of image following the mouse */
LAYER_UNIT_FIRST, /**< Reserve layers to be selected for WML. */
LAYER_UNIT_BG = LAYER_UNIT_FIRST+10, /**< Used for the ellipse behind the unit. */
LAYER_UNIT_DEFAULT=LAYER_UNIT_FIRST+40,/**<default layer for drawing units */
LAYER_TERRAIN_FG = LAYER_UNIT_FIRST+50, /**<
* Layer for the terrain drawn in front of
* the unit.
*/
LAYER_GRID_BOTTOM, /**<
* Used for the bottom half part of grid image.
* Should be under moving units, to avoid masking south move.
*/
LAYER_UNIT_MOVE_DEFAULT=LAYER_UNIT_FIRST+60/**<default layer for drawing moving units */,
LAYER_UNIT_FG = LAYER_UNIT_FIRST+80, /**<
* Used for the ellipse in front of the
* unit.
*/
LAYER_UNIT_MISSILE_DEFAULT = LAYER_UNIT_FIRST+90, /**< default layer for missile frames*/
LAYER_UNIT_LAST=LAYER_UNIT_FIRST+100,
LAYER_REACHMAP, /**< "black stripes" on unreachable hexes. */
LAYER_MOUSEOVER_BOTTOM, /**< Bottom half of image following the mouse */
LAYER_FOG_SHROUD, /**< Fog and shroud. */
LAYER_ARROWS, /**< Arrows from the arrows framework. Used for planned moves display. */
LAYER_ACTIONS_NUMBERING, /**< Move numbering for the whiteboard. */
LAYER_SELECTED_HEX, /**< Image on the selected unit */
LAYER_ATTACK_INDICATOR, /**< Layer which holds the attack indicator. */
LAYER_UNIT_BAR, /**<
* Unit bars and overlays are drawn on this
* layer (for testing here).
*/
LAYER_MOVE_INFO, /**< Movement info (defense%, etc...). */
LAYER_LINGER_OVERLAY, /**< The overlay used for the linger mode. */
LAYER_BORDER, /**< The border of the map. */
};
/**
* Draw an image at a certain location.
@ -885,6 +848,11 @@ protected:
drawing_buffer drawing_buffer_;
public:
drawing_buffer& get_drawing_buffer()
{
return drawing_buffer_;
}
/**
* Add an item to the drawing buffer. You need to update screen on affected area
*
@ -892,13 +860,22 @@ public:
* @param loc The hex the image belongs to, needed for the
* drawing order.
*/
void drawing_buffer_add(const drawing_buffer::drawing_layer layer,
const map_location& loc, int x, int y, const texture& tex,
const SDL_Rect &clip = SDL_Rect());
void drawing_buffer_add(const drawing_buffer::drawing_layer layer,
const map_location& loc, int x, int y,
const std::vector<texture>& tex,
const SDL_Rect &clip = SDL_Rect());
void drawing_buffer_add(const drawing_buffer::drawing_layer layer,
const map_location& loc, int x, int y, const surface& surf,
const SDL_Rect &clip = SDL_Rect());
void drawing_buffer_add(const drawing_buffer::drawing_layer layer,
const map_location& loc, int x, int y,
const std::vector<surface> &surf,
const std::vector<surface>& surf,
const SDL_Rect &clip = SDL_Rect());
protected:

View file

@ -84,13 +84,13 @@ void editor_display::draw_hex(const map_location& loc)
if (map().on_board_with_border(loc)) {
if (map().in_selection(loc)) {
drawing_buffer_add(drawing_buffer::LAYER_FOG_SHROUD, loc, xpos, ypos,
image::get_image("editor/selection-overlay.png", image::TOD_COLORED));
image::get_texture("editor/selection-overlay.png"));
}
if (brush_locations_.find(loc) != brush_locations_.end()) {
static const image::locator brush(game_config::images::editor_brush);
drawing_buffer_add(drawing_buffer::LAYER_SELECTED_HEX, loc, xpos, ypos,
image::get_image(brush, image::SCALED_TO_HEX));
image::get_texture(brush));
}
}
}

View file

@ -252,7 +252,7 @@ void minimap::impl_draw_background(int x_offset, int y_offset)
SDL_Rect dst {0, 0, surf->w, surf->h};
texture txt(surf);
CVideo::get_singleton().copy_to_screen(txt, nullptr, &dst);
CVideo::get_singleton().render_copy(txt, nullptr, &dst);
}
}

View file

@ -242,7 +242,7 @@ LEVEL_RESULT playsingle_controller::play_scenario(const config& level)
}
// FIXME
gui2::dialogs::game_ui::display(gui_->video());
//gui2::dialogs::game_ui::display(gui_->video());
gui_->labels().read(level);

View file

@ -2399,7 +2399,7 @@ void draw_centered_on_background(surface surf, const SDL_Rect& rect, const color
r.h = surf->h;
texture tex(surf);
CVideo::get_singleton().copy_to_screen(tex, nullptr, &r);
CVideo::get_singleton().render_copy(tex, nullptr, &r);
}
}

View file

@ -14,43 +14,43 @@
#include "units/drawer.hpp"
#include "color.hpp"
#include "display.hpp"
#include "display_context.hpp"
#include "formatter.hpp"
#include "preferences/game.hpp"
#include "halo.hpp"
#include "map/map.hpp"
#include "map/location.hpp"
#include "color.hpp"
#include "sdl/surface.hpp"
#include "map/map.hpp"
#include "preferences/game.hpp"
#include "sdl/rect.hpp"
#include "sdl/texture.hpp"
#include "team.hpp"
#include "units/unit.hpp"
#include "units/animation.hpp"
#include "units/animation_component.hpp"
#include "units/frame.hpp"
#include "units/unit.hpp"
// Map of different energy bar surfaces and their dimensions.
static std::map<surface, SDL_Rect> energy_bar_rects;
unit_drawer::unit_drawer(display & thedisp) :
disp(thedisp),
dc(disp.get_disp_context()),
map(dc.map()),
teams(dc.teams()),
halo_man(thedisp.get_halo_manager()),
viewing_team(disp.viewing_team()),
playing_team(disp.playing_team()),
viewing_team_ref(teams[viewing_team]),
playing_team_ref(teams[playing_team]),
is_blindfolded(disp.is_blindfolded()),
show_everything(disp.show_everything()),
sel_hex(disp.selected_hex()),
mouse_hex(disp.mouseover_hex()),
zoom_factor(disp.get_zoom_factor()),
hex_size(disp.hex_size()),
hex_size_by_2(disp.hex_size()/2)
{}
unit_drawer::unit_drawer(display& thedisp)
: disp(thedisp)
, dc(disp.get_disp_context())
, map(dc.map())
, teams(dc.teams())
, halo_man(thedisp.get_halo_manager())
, viewing_team(disp.viewing_team())
, playing_team(disp.playing_team())
, viewing_team_ref(teams[viewing_team])
, playing_team_ref(teams[playing_team])
, is_blindfolded(disp.is_blindfolded())
, show_everything(disp.show_everything())
, sel_hex(disp.selected_hex())
, mouse_hex(disp.mouseover_hex())
, zoom_factor(disp.get_zoom_factor())
, hex_size(disp.hex_size())
, hex_size_by_2(disp.hex_size() / 2)
{
}
// NOTE: surfaces were scaled to zoom
void unit_drawer::redraw_unit (const unit & u) const
{
unit_animation_component & ac = u.anim_comp();
@ -60,7 +60,9 @@ void unit_drawer::redraw_unit (const unit & u) const
bool hidden = u.get_hidden();
bool is_flying = u.is_flying();
map_location::DIRECTION facing = u.facing();
int hitpoints = u.hitpoints();
int max_hitpoints = u.max_hitpoints();
int movement_left = u.movement_left();
@ -74,60 +76,70 @@ void unit_drawer::redraw_unit (const unit & u) const
bool emit_zoc = u.emits_zoc();
color_t hp_color=u.hp_color();
color_t xp_color=u.xp_color();
color_t hp_color = u.hp_color();
color_t xp_color = u.xp_color();
std::string ellipse=u.image_ellipse();
if ( hidden || is_blindfolded || !u.is_visible_to_team(viewing_team_ref, dc, show_everything) )
{
if(hidden || is_blindfolded || !u.is_visible_to_team(viewing_team_ref, dc, show_everything)) {
ac.clear_haloes();
if(ac.anim_) {
ac.anim_->update_last_draw_time();
}
return;
}
if (!ac.anim_) {
if(!ac.anim_) {
ac.set_standing();
if (!ac.anim_) return;
if(!ac.anim_) {
return;
}
}
if(ac.refreshing_) {
return;
}
if (ac.refreshing_) return;
ac.refreshing_ = true;
ac.anim_->update_last_draw_time();
frame_parameters params;
const t_translation::terrain_code terrain = map.get_terrain(loc);
const terrain_type& terrain_info = map.get_terrain_info(terrain);
// do not set to 0 so we can distinguish the flying from the "not on submerge terrain"
frame_parameters params;
// Do not set to 0 so we can distinguish the flying from the "not on submerge terrain"
// instead use -1.0 (as in "negative depth", it will be ignored by rendering)
params.submerge= is_flying ? -1.0 : terrain_info.unit_submerge();
if (u.invisible(loc, dc) &&
params.highlight_ratio > 0.6) {
if(u.invisible(loc, dc) && params.highlight_ratio > 0.6) {
params.highlight_ratio = 0.6;
}
if (loc == sel_hex && params.highlight_ratio == 1.0) {
if(loc == sel_hex && params.highlight_ratio == 1.0) {
params.highlight_ratio = 1.5;
}
int height_adjust = static_cast<int>(terrain_info.unit_height_adjust() * zoom_factor);
if (is_flying && height_adjust < 0) {
if(is_flying && height_adjust < 0) {
height_adjust = 0;
}
params.y -= height_adjust;
params.halo_y -= height_adjust;
int red = 0,green = 0,blue = 0,tints = 0;
double blend_ratio = 0;
// Add future colored states here
if(u.poisoned()) {
green += 255;
blend_ratio += 0.25;
tints += 1;
}
if(u.slowed()) {
red += 191;
green += 191;
@ -135,23 +147,24 @@ void unit_drawer::redraw_unit (const unit & u) const
blend_ratio += 0.25;
tints += 1;
}
if(tints > 0) {
params.blend_with = color_t((red/tints),(green/tints),(blue/tints));
params.blend_ratio = ((blend_ratio/tints));
params.blend_with = color_t((red / tints), (green / tints), (blue / tints));
params.blend_ratio = blend_ratio / tints;
}
//hackish : see unit_frame::merge_parameters
// we use image_mod on the primary image
// and halo_mod on secondary images and all haloes
// Hackish: see unit_frame::merge_parameters.
// We use image_mod on the primary image and halo_mod on secondary images and all haloes
params.image_mod = u.image_mods();
params.halo_mod = u.TC_image_mods();
params.image= u.default_anim_image();
params.image = u.default_anim_image();
if(u.incapacitated()) {
params.image_mod +="~GS()";
}
if(u.incapacitated()) params.image_mod +="~GS()";
params.primary_frame = true;
const frame_parameters adjusted_params = ac.anim_->get_current_params(params);
const map_location dst = loc.get_direction(facing);
@ -160,13 +173,14 @@ void unit_drawer::redraw_unit (const unit & u) const
const int xdst = disp.get_location_x(dst);
const int ydst = disp.get_location_y(dst);
const int x = static_cast<int>(adjusted_params.offset * xdst + (1.0-adjusted_params.offset) * xsrc) + hex_size_by_2;
const int y = static_cast<int>(adjusted_params.offset * ydst + (1.0-adjusted_params.offset) * ysrc) + hex_size_by_2;
const int x = static_cast<int>(adjusted_params.offset * xdst + (1.0 - adjusted_params.offset) * xsrc) + hex_size_by_2;
const int y = static_cast<int>(adjusted_params.offset * ydst + (1.0 - adjusted_params.offset) * ysrc) + hex_size_by_2;
bool has_halo = ac.unit_halo_ && ac.unit_halo_->valid();
if(!has_halo && !u.image_halo().empty()) {
ac.unit_halo_ = halo_man.add(x, y - height_adjust, u.image_halo()+u.TC_image_mods(), map_location(-1, -1));
}
if(has_halo && u.image_halo().empty()) {
halo_man.remove(ac.unit_halo_);
ac.unit_halo_.reset();
@ -176,24 +190,26 @@ void unit_drawer::redraw_unit (const unit & u) const
// We draw bars only if wanted, visible on the map view
bool draw_bars = ac.draw_bars_ ;
if (draw_bars) {
SDL_Rect unit_rect {xsrc, ysrc +adjusted_params.y, hex_size, hex_size};
if(draw_bars) {
SDL_Rect unit_rect {xsrc, ysrc + adjusted_params.y, hex_size, hex_size};
draw_bars = sdl::rects_overlap(unit_rect, disp.map_outside_area());
}
surface ellipse_front(nullptr);
surface ellipse_back(nullptr);
texture ellipse_front(nullptr);
texture ellipse_back(nullptr);
int ellipse_floating = 0;
// Always show the ellipse for selected units
// Always show the ellipse for selected units.
if(draw_bars && (preferences::show_side_colors() || sel_hex == loc)) {
if(adjusted_params.submerge > 0.0) {
// The division by 2 seems to have no real meaning,
// It just works fine with the current center of ellipse
// and prevent a too large adjust if submerge = 1.0
// The division by 2 seems to have no real meaning. It just works fine with the current center
// of the ellipse and prevents an overadjustment if submerge == 1.0.
ellipse_floating = static_cast<int>(adjusted_params.submerge * hex_size_by_2);
}
if(ellipse.empty()){
ellipse="misc/ellipse";
if(ellipse.empty()) {
ellipse = "misc/ellipse";
}
if(ellipse != "none") {
@ -203,129 +219,151 @@ void unit_drawer::redraw_unit (const unit & u) const
const std::string selected = sel_hex == loc ? "selected-" : "";
const std::string tc = team::get_side_color_id(side);
const std::string ellipse_top = formatter() << ellipse << "-" << leader << nozoc << selected << "top.png~RC(ellipse_red>" << tc << ")";
const std::string ellipse_bot = formatter() << ellipse << "-" << leader << nozoc << selected << "bottom.png~RC(ellipse_red>" << tc << ")";
const std::string ellipse_top = formatter() <<
ellipse << "-" << leader << nozoc << selected << "top.png~RC(ellipse_red>" << tc << ")";
const std::string ellipse_bot = formatter() <<
ellipse << "-" << leader << nozoc << selected << "bottom.png~RC(ellipse_red>" << tc << ")";
// Load the ellipse parts recolored to match team color
ellipse_back.assign(image::get_image(image::locator(ellipse_top), image::SCALED_TO_ZOOM));
ellipse_front.assign(image::get_image(image::locator(ellipse_bot), image::SCALED_TO_ZOOM));
ellipse_back = image::get_texture(image::locator(ellipse_top) /*, image::SCALED_TO_ZOOM)*/);
ellipse_front = image::get_texture(image::locator(ellipse_bot) /*, image::SCALED_TO_ZOOM)*/);
}
}
if (ellipse_back != nullptr) {
if(ellipse_back != nullptr) {
//disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BG, loc,
disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_FIRST, loc,
xsrc, ysrc +adjusted_params.y-ellipse_floating, ellipse_back);
//disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_FIRST, loc,
// xsrc, ysrc +adjusted_params.y-ellipse_floating, ellipse_back);
disp.render_texture_original_size(ellipse_back, xsrc, ysrc + adjusted_params.y - ellipse_floating);
}
if (ellipse_front != nullptr) {
if(ellipse_front != nullptr) {
//disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_FG, loc,
disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_FIRST, loc,
xsrc, ysrc +adjusted_params.y-ellipse_floating, ellipse_front);
//disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_FIRST, loc,
// xsrc, ysrc +adjusted_params.y-ellipse_floating, ellipse_front);
disp.render_texture_original_size(ellipse_front, xsrc, ysrc + adjusted_params.y - ellipse_floating);
}
if(draw_bars) {
const image::locator* orb_img = nullptr;
const texture unit_img = image::get_texture(u.default_anim_image());
const texture::info unit_img_info = unit_img.get_info();
const auto& type_cfg = u.type().get_cfg();
const auto& cfg_offset_x = type_cfg["bar_offset_x"];
const auto& cfg_offset_y = type_cfg["bar_offset_y"];
int xoff;
int yoff;
if(cfg_offset_x.empty() && cfg_offset_y.empty()) {
const surface unit_img = image::get_image(u.default_anim_image(), image::SCALED_TO_ZOOM);
xoff = unit_img.null() ? 0 : (hex_size - unit_img->w)/2;
yoff = unit_img.null() ? 0 : (hex_size - unit_img->h)/2;
}
else {
} else {
xoff = cfg_offset_x.to_int();
yoff = cfg_offset_y.to_int();
}
/*static*/ const image::locator partmoved_orb(game_config::images::orb + "~RC(magenta>" +
preferences::partial_color() + ")" );
/*static*/ const image::locator moved_orb(game_config::images::orb + "~RC(magenta>" +
preferences::moved_color() + ")" );
/*static*/ const image::locator ally_orb(game_config::images::orb + "~RC(magenta>" +
preferences::allied_color() + ")" );
/*static*/ const image::locator enemy_orb(game_config::images::orb + "~RC(magenta>" +
preferences::enemy_color() + ")" );
/*static*/ const image::locator unmoved_orb(game_config::images::orb + "~RC(magenta>" +
preferences::unmoved_color() + ")" );
const image::locator partmoved_orb(
game_config::images::orb + "~RC(magenta>" + preferences::partial_color() + ")");
const image::locator moved_orb(
game_config::images::orb + "~RC(magenta>" + preferences::moved_color() + ")");
const image::locator ally_orb(
game_config::images::orb + "~RC(magenta>" + preferences::allied_color() + ")");
const image::locator enemy_orb(
game_config::images::orb + "~RC(magenta>" + preferences::enemy_color() + ")");
const image::locator unmoved_orb(
game_config::images::orb + "~RC(magenta>" + preferences::unmoved_color() + ")");
const std::string* energy_file = &game_config::images::energy;
const image::locator* orb_img = nullptr;
if(size_t(side) != viewing_team+1) {
if(disp.team_valid() &&
viewing_team_ref.is_enemy(side)) {
if (preferences::show_enemy_orb() && !u.incapacitated())
if(static_cast<size_t>(side) != viewing_team + 1) {
if(disp.team_valid() && viewing_team_ref.is_enemy(side)) {
if(preferences::show_enemy_orb() && !u.incapacitated()) {
orb_img = &enemy_orb;
else
orb_img = nullptr;
}
} else {
if (preferences::show_allied_orb())
if(preferences::show_allied_orb()) {
orb_img = &ally_orb;
else orb_img = nullptr;
}
}
} else {
if (preferences::show_moved_orb())
if(preferences::show_moved_orb()) {
orb_img = &moved_orb;
else orb_img = nullptr;
}
if(playing_team == viewing_team && !u.user_end_turn()) {
if (movement_left == total_movement) {
if (preferences::show_unmoved_orb())
if(movement_left == total_movement) {
if(preferences::show_unmoved_orb()) {
orb_img = &unmoved_orb;
else orb_img = nullptr;
} else if ( dc.unit_can_move(u) ) {
if (preferences::show_partial_orb())
}
} else if(dc.unit_can_move(u)) {
if(preferences::show_partial_orb()) {
orb_img = &partmoved_orb;
else orb_img = nullptr;
}
}
}
}
if (orb_img != nullptr) {
surface orb(image::get_image(*orb_img,image::SCALED_TO_ZOOM));
disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR,
loc, xsrc + xoff, ysrc + yoff + adjusted_params.y, orb);
if(orb_img != nullptr) {
texture orb(image::get_texture(*orb_img));
//disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR,
// loc, xsrc + xoff, ysrc + yoff + adjusted_params.y, orb);
disp.render_texture_original_size(orb, xsrc + xoff, ysrc + yoff + adjusted_params.y);
}
double unit_energy = 0.0;
if(max_hitpoints > 0) {
unit_energy = double(hitpoints)/double(max_hitpoints);
}
const int bar_shift = static_cast<int>(-5*zoom_factor);
const int hp_bar_height = static_cast<int>(max_hitpoints * u.hp_bar_scaling());
const fixed_t bar_alpha = (loc == mouse_hex || loc == sel_hex) ? ftofxp(1.0): ftofxp(0.8);
draw_bar(*energy_file, xsrc+xoff+bar_shift, ysrc+yoff+adjusted_params.y,
loc, hp_bar_height, unit_energy,hp_color, bar_alpha);
// HP bar
draw_bar(
xsrc + xoff + bar_shift,
ysrc + yoff + adjusted_params.y,
hp_bar_height, unit_energy, hp_color, bar_alpha
);
if(experience > 0 && can_advance) {
const double filled = double(experience)/double(max_experience);
const double filled = double(experience) / double(max_experience);
const int xp_bar_height = static_cast<int>(max_experience * u.xp_bar_scaling() / std::max<int>(u.level(),1));
draw_bar(*energy_file, xsrc+xoff, ysrc+yoff+adjusted_params.y,
loc, xp_bar_height, filled, xp_color, bar_alpha);
// XP bar
draw_bar(
xsrc + xoff,
ysrc + yoff + adjusted_params.y,
xp_bar_height, filled, xp_color, bar_alpha
);
}
if (can_recruit) {
surface crown(image::get_image(u.leader_crown(),image::SCALED_TO_ZOOM));
if(!crown.null()) {
if(can_recruit) {
texture crown(image::get_texture(u.leader_crown()));
if(crown != nullptr) {
//if(bar_alpha != ftofxp(1.0)) {
// crown = adjust_surface_alpha(crown, bar_alpha);
//}
disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR,
loc, xsrc+xoff, ysrc+yoff+adjusted_params.y, crown);
//disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR,
// loc, xsrc+xoff, ysrc+yoff+adjusted_params.y, crown);
disp.render_texture_original_size(crown, xsrc + xoff, ysrc + yoff + adjusted_params.y);
}
}
for(const std::string& ov : u.overlays()) {
const surface ov_img(image::get_image(ov, image::SCALED_TO_ZOOM));
const texture ov_img(image::get_texture(ov));
if(ov_img != nullptr) {
disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR,
loc, xsrc+xoff, ysrc+yoff+adjusted_params.y, ov_img);
//disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR,
// loc, xsrc+xoff, ysrc+yoff+adjusted_params.y, ov_img);
disp.render_texture_original_size(ov_img, xsrc + xoff, ysrc + yoff + adjusted_params.y);
}
}
}
@ -336,12 +374,15 @@ void unit_drawer::redraw_unit (const unit & u) const
const t_translation::terrain_code terrain_dst = map.get_terrain(dst);
const terrain_type& terrain_dst_info = map.get_terrain_info(terrain_dst);
int height_adjust_unit = static_cast<int>((terrain_info.unit_height_adjust() * (1.0 - adjusted_params.offset) +
terrain_dst_info.unit_height_adjust() * adjusted_params.offset) *
zoom_factor);
if (is_flying && height_adjust_unit < 0) {
int height_adjust_unit = static_cast<int>((
terrain_info.unit_height_adjust() * (1.0 - adjusted_params.offset) +
terrain_dst_info.unit_height_adjust() * adjusted_params.offset
) * zoom_factor);
if(is_flying && height_adjust_unit < 0) {
height_adjust_unit = 0;
}
params.y -= height_adjust_unit - height_adjust;
params.halo_y -= height_adjust_unit - height_adjust;
@ -349,118 +390,46 @@ void unit_drawer::redraw_unit (const unit & u) const
ac.refreshing_ = false;
}
void unit_drawer::draw_bar(const std::string& image, int xpos, int ypos,
const map_location& loc, size_t height, double filled,
const color_t& col, fixed_t alpha) const
void unit_drawer::draw_bar(int xpos, int ypos, size_t height, double filled, color_t col, fixed_t alpha) const
{
filled = utils::clamp<double>(filled, 0.0, 1.0);
height = static_cast<size_t>(height * zoom_factor);
filled = std::min<double>(std::max<double>(filled,0.0),1.0);
height = static_cast<size_t>(height*zoom_factor);
const size_t unfilled = static_cast<size_t>(height * (1.0 - filled));
surface surf(image::get_image(image,image::SCALED_TO_HEX));
// Magic width number
static unsigned int bar_width = 4;
// We use UNSCALED because scaling (and bilinear interpolation)
// is bad for calculate_energy_bar.
// But we will do a geometric scaling later.
surface bar_surf(image::get_image(image));
if(surf == nullptr || bar_surf == nullptr) {
return;
}
static const color_t bar_color_bg {0, 0, 0 , 80};
static const color_t bar_color_border {213, 213, 213, 200};
// calculate_energy_bar returns incorrect results if the surface colors
// have changed (for example, due to bilinear interpolation)
const SDL_Rect& unscaled_bar_loc = calculate_energy_bar(bar_surf);
// Override the filled area's color's alpha.
col.a = alpha;
SDL_Rect bar_loc;
if (surf->w == bar_surf->w && surf->h == bar_surf->h)
bar_loc = unscaled_bar_loc;
else {
const fixed_t xratio = fxpdiv(surf->w,bar_surf->w);
const fixed_t yratio = fxpdiv(surf->h,bar_surf->h);
const SDL_Rect scaled_bar_loc {
fxptoi(unscaled_bar_loc. x * xratio)
, fxptoi(unscaled_bar_loc. y * yratio + 127)
, fxptoi(unscaled_bar_loc. w * xratio + 255)
, fxptoi(unscaled_bar_loc. h * yratio + 255)
};
bar_loc = scaled_bar_loc;
}
// Bar dimensions.
// Note about the magic x, y additions: we used to use an image for the bar instead of drawing
// it procedurally. Its x,y position within the file was 19,13, so we offset the origin by that
// much to make it line up with the crowns as before. Should probably compensate for this better
// in the future.
SDL_Rect bar_rect;
bar_rect.x = xpos + 19;
bar_rect.y = ypos + 13;
bar_rect.w = bar_width;
bar_rect.h = height;
if(height > static_cast<size_t>(bar_loc.h)) {
height = bar_loc.h;
}
// Filled area dimensions.
SDL_Rect fill_rect;
fill_rect.x = bar_rect.x + unfilled;
fill_rect.y = bar_rect.y;
fill_rect.w = bar_rect.w;
fill_rect.h = bar_rect.h - unfilled;
//if(alpha != ftofxp(1.0)) {
// surf.assign(adjust_surface_alpha(surf,alpha));
// if(surf == nullptr) {
// return;
// }
//}
// Tinted background.
sdl::fill_rectangle(bar_rect, bar_color_bg);
const size_t skip_rows = bar_loc.h - height;
// Filled area.
sdl::fill_rectangle(fill_rect, col);
SDL_Rect top {0, 0, surf->w, bar_loc.y};
SDL_Rect bot = sdl::create_rect(0, bar_loc.y + skip_rows, surf->w, 0);
bot.h = surf->w - bot.y;
disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR, loc, xpos, ypos, surf, top);
disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR, loc, xpos, ypos + top.h, surf, bot);
size_t unfilled = static_cast<size_t>(height * (1.0 - filled));
if(unfilled < height && alpha >= ftofxp(0.3)) {
const uint8_t r_alpha = std::min<unsigned>(unsigned(fxpmult(alpha,255)),255);
surface filled_surf = create_compatible_surface(bar_surf, bar_loc.w, height - unfilled);
SDL_Rect filled_area = sdl::create_rect(0, 0, bar_loc.w, height-unfilled);
sdl::fill_surface_rect(filled_surf,&filled_area,SDL_MapRGBA(bar_surf->format,col.r,col.g,col.b, r_alpha));
disp.drawing_buffer_add(drawing_buffer::LAYER_UNIT_BAR, loc, xpos + bar_loc.x, ypos + bar_loc.y + unfilled, filled_surf);
}
}
struct is_energy_color {
bool operator()(uint32_t color) const { return (color&0xFF000000) > 0x10000000 &&
(color&0x00FF0000) < 0x00100000 &&
(color&0x0000FF00) < 0x00001000 &&
(color&0x000000FF) < 0x00000010; }
};
const SDL_Rect& unit_drawer::calculate_energy_bar(surface surf) const
{
const std::map<surface,SDL_Rect>::const_iterator i = energy_bar_rects.find(surf);
if(i != energy_bar_rects.end()) {
return i->second;
}
int first_row = -1, last_row = -1, first_col = -1, last_col = -1;
surface image(make_neutral_surface(surf));
const_surface_lock image_lock(image);
const uint32_t* const begin = image_lock.pixels();
for(int y = 0; y != image->h; ++y) {
const uint32_t* const i1 = begin + image->w*y;
const uint32_t* const i2 = i1 + image->w;
const uint32_t* const itor = std::find_if(i1,i2,is_energy_color());
const int count = std::count_if(itor,i2,is_energy_color());
if(itor != i2) {
if(first_row == -1) {
first_row = y;
}
first_col = itor - i1;
last_col = first_col + count;
last_row = y;
}
}
const SDL_Rect res {
first_col
, first_row
, last_col-first_col
, last_row+1-first_row
};
energy_bar_rects.emplace(surf, res);
return calculate_energy_bar(surf);
// Bar outline.
sdl::draw_rectangle(bar_rect, bar_color_border);
}

View file

@ -70,14 +70,5 @@ public:
private:
/** draw a health/xp bar of a unit */
void draw_bar(const std::string& image, int xpos, int ypos,
const map_location& loc, size_t height, double filled,
const color_t& col, fixed_t alpha) const;
/**
* Finds the start and end rows on the energy bar image.
*
* White pixels are substituted for the color of the energy.
*/
const SDL_Rect& calculate_energy_bar(surface surf) const;
void draw_bar(int xpos, int ypos, size_t height, double filled, color_t col, fixed_t alpha) const;
};

View file

@ -513,9 +513,9 @@ void unit_frame::redraw(const int frame_time, bool on_start_time, bool in_scope_
image_loc = image::locator(current_data.image, current_data.image_mod);
}
surface image;
texture image;
if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
image=image::get_image(image_loc, image::SCALED_TO_ZOOM);
image = image::get_texture(image_loc /*, image::SCALED_TO_ZOOM*/);
}
const int d2 = display::get_singleton()->hex_size() / 2;
@ -536,8 +536,10 @@ void unit_frame::redraw(const int frame_time, bool on_start_time, bool in_scope_
if(!current_data.auto_hflip) { facing_west = false; }
if(!current_data.auto_vflip) { facing_north = true; }
int my_x = x + current_data.x - image->w / 2;
int my_y = y + current_data.y - image->h / 2;
const texture::info info = image.get_info();
int my_x = x + current_data.x - info.w / 2;
int my_y = y + current_data.y - info.h / 2;
if(facing_west) {
my_x -= current_data.directional_x;
@ -551,11 +553,14 @@ void unit_frame::redraw(const int frame_time, bool on_start_time, bool in_scope_
my_y -= current_data.directional_y;
}
display::get_singleton()->render_texture_original_size(image, my_x, my_y);
#if 0
display::get_singleton()->render_image(my_x, my_y,
static_cast<drawing_buffer::drawing_layer>(drawing_buffer::LAYER_UNIT_FIRST + current_data.drawing_layer),
src, image, facing_west, false,
ftofxp(current_data.highlight_ratio), current_data.blend_with ? *current_data.blend_with : color_t(),
current_data.blend_ratio, current_data.submerge, !facing_north);
#endif
}
halo_id.reset();

View file

@ -169,7 +169,7 @@ void CVideo::blit_surface(int x, int y, surface surf, SDL_Rect* srcrect, SDL_Rec
render_clip_rect_setter crs(clip_rect);
SDL_Rect dst {x, y, surf->w, surf->h};
copy_to_screen(txt, srcrect, &dst);
render_copy(txt, srcrect, &dst);
}
void CVideo::make_fake()
@ -345,7 +345,7 @@ void CVideo::render_screen()
}
}
void CVideo::copy_to_screen(texture& txt, SDL_Rect* src_rect, SDL_Rect* dst_rect)
void CVideo::render_copy(const texture& txt, SDL_Rect* src_rect, SDL_Rect* dst_rect)
{
if(window) {
SDL_RenderCopy(*window, txt, src_rect, dst_rect);;

View file

@ -18,6 +18,8 @@
#include "exceptions.hpp"
#include "lua_jailbreak_exception.hpp"
#include <SDL_render.h>
#include <memory>
class surface;
@ -171,7 +173,7 @@ public:
/** Renders the screen. Should normally not be called directly! */
void render_screen();
void copy_to_screen(texture& txt, SDL_Rect* src_rect = nullptr, SDL_Rect* dst_rect = nullptr);
void render_copy(const texture& txt, SDL_Rect* src_rect = nullptr, SDL_Rect* dst_rect = nullptr);
/**
* Updates and ensures the framebuffer surface is valid.

View file

@ -204,7 +204,7 @@ void attack::draw_hex(const map_location& hex)
int ypos = display::get_singleton()->get_location_y(get_dest_hex());
display::get_singleton()->drawing_buffer_add(layer, get_dest_hex(), xpos, ypos,
image::get_image("whiteboard/attack-indicator-src-" + direction_text + ".png", image::SCALED_TO_HEX));
image::get_image("whiteboard/attack-indicator-src-" + direction_text + ".png"));
}
else if (hex == target_hex_) //add symbol to defender hex
{
@ -212,7 +212,7 @@ void attack::draw_hex(const map_location& hex)
int ypos = display::get_singleton()->get_location_y(target_hex_);
display::get_singleton()->drawing_buffer_add(layer, target_hex_, xpos, ypos,
image::get_image("whiteboard/attack-indicator-dst-" + direction_text + ".png", image::SCALED_TO_HEX));
image::get_texture("whiteboard/attack-indicator-dst-" + direction_text + ".png"));
}
}
}

View file

@ -143,7 +143,7 @@ void suppose_dead::draw_hex(const map_location& hex)
int xpos = display::get_singleton()->get_location_x(loc_);
int ypos = display::get_singleton()->get_location_y(loc_);
display::get_singleton()->drawing_buffer_add(layer, loc_, xpos, ypos,
image::get_image("whiteboard/suppose_dead.png", image::SCALED_TO_HEX));
image::get_texture("whiteboard/suppose_dead.png"));
}
}