video: Add functions for immediate rendering of surfaces and textures.
This commit is contained in:
parent
24f7d0d329
commit
581c6e6a93
3 changed files with 186 additions and 22 deletions
|
@ -343,6 +343,7 @@ scripting/plugins/context.cpp
|
|||
scripting/plugins/manager.cpp
|
||||
sdl/point.cpp
|
||||
sdl/input.cpp
|
||||
sdl/texture.cpp
|
||||
map_settings.cpp
|
||||
side_filter.cpp
|
||||
statistics.cpp
|
||||
|
|
122
src/video.cpp
122
src/video.cpp
|
@ -26,6 +26,7 @@
|
|||
#include "sdl/utils.hpp"
|
||||
#include "sdl/window.hpp"
|
||||
#include "sdl/input.hpp"
|
||||
#include "sdl/texture.hpp"
|
||||
|
||||
#ifdef TARGET_OS_OSX
|
||||
#include "desktop/apple_video.hpp"
|
||||
|
@ -164,13 +165,32 @@ void CVideo::video_event_handler::handle_window_event(const SDL_Event& event)
|
|||
}
|
||||
}
|
||||
|
||||
void CVideo::blit_surface(int x, int y, surface surf, SDL_Rect* srcrect, SDL_Rect* clip_rect)
|
||||
void CVideo::blit_surface(const surface& surf, SDL_Rect* dst)
|
||||
{
|
||||
sdl_blit(surf, nullptr, getDrawingSurface(), dst);
|
||||
render_low_res(dst);
|
||||
}
|
||||
|
||||
void CVideo::blit_surface(int x, int y, const surface& surf)
|
||||
{
|
||||
SDL_Rect dst{x, y, 0, 0};
|
||||
blit_surface(surf, &dst);
|
||||
}
|
||||
|
||||
void CVideo::blit_surface(int x, int y, const surface& surf, const SDL_Rect* srcrect, const SDL_Rect* clip_rect)
|
||||
{
|
||||
surface& target(getDrawingSurface());
|
||||
SDL_Rect dst{x, y, 0, 0};
|
||||
|
||||
const clip_rect_setter clip_setter(target, clip_rect, clip_rect != nullptr);
|
||||
sdl_blit(surf, srcrect, target, &dst);
|
||||
// dst gets updated by SDL_BlitSurface to reflect clipping etc.
|
||||
render_low_res(&dst);
|
||||
}
|
||||
|
||||
void CVideo::blit_texture(texture& tex, SDL_Rect* dst_rect, SDL_Rect* src_rect)
|
||||
{
|
||||
SDL_RenderCopy(*window.get(), tex, src_rect, dst_rect);
|
||||
}
|
||||
|
||||
void CVideo::make_fake()
|
||||
|
@ -276,6 +296,8 @@ void CVideo::update_framebuffer()
|
|||
drawingSurface->w,
|
||||
drawingSurface->h
|
||||
);
|
||||
// Always use alpha blending.
|
||||
SDL_SetTextureBlendMode(drawing_texture_, SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
|
||||
// Update sizes for input conversion.
|
||||
|
@ -402,6 +424,86 @@ void CVideo::delay(unsigned int milliseconds)
|
|||
}
|
||||
}
|
||||
|
||||
SDL_Rect CVideo::clip_to_draw_area(const SDL_Rect* r) const
|
||||
{
|
||||
if (r) {
|
||||
return sdl::intersect_rects(*r, draw_area());
|
||||
} else {
|
||||
return draw_area();
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Rect CVideo::to_output(const SDL_Rect& r) const
|
||||
{
|
||||
int s = output_size().x / get_width();
|
||||
return {s*r.x, s*r.y, s*r.w, s*r.h};
|
||||
}
|
||||
|
||||
void CVideo::render_low_res()
|
||||
{
|
||||
if (!drawingSurface) {
|
||||
throw game::error("trying to render with no drawingSurface");
|
||||
}
|
||||
if (!drawing_texture_) {
|
||||
throw game::error("trying to render with no drawing_texture_");
|
||||
}
|
||||
// Upload the drawing surface to the drawing texture.
|
||||
void* pixels_out; // somewhere we can write raw pixel data to
|
||||
int pitch; // the length of one row of pixels in bytes
|
||||
SDL_LockTexture(drawing_texture_, nullptr, &pixels_out, &pitch);
|
||||
if (pitch != drawingSurface->pitch) {
|
||||
// If these don't match we are not gonna have a good time.
|
||||
throw game::error("drawing surface and texture are incompatible");
|
||||
}
|
||||
// The pitch and pixel format should be the same,
|
||||
// so we can just copy the whole chunk of memory directly.
|
||||
size_t num_bytes = drawingSurface->h * pitch;
|
||||
memcpy(pixels_out, drawingSurface->pixels, num_bytes);
|
||||
SDL_UnlockTexture(drawing_texture_);
|
||||
|
||||
// Copy the whole drawing texture to the render target.
|
||||
SDL_RenderCopy(*window.get(), drawing_texture_, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void CVideo::render_low_res(SDL_Rect* src_rect)
|
||||
{
|
||||
if (!drawingSurface) {
|
||||
throw game::error("trying to render with no drawingSurface");
|
||||
}
|
||||
if (!drawing_texture_) {
|
||||
throw game::error("trying to render with no drawing_texture_");
|
||||
}
|
||||
|
||||
SDL_Rect r = clip_to_draw_area(src_rect);
|
||||
uint8_t bytes_per_pixel = SDL_BYTESPERPIXEL(drawingSurface->format->format);
|
||||
|
||||
// Upload the drawing surface to the drawing texture.
|
||||
void* pixels_out; // somewhere we can write raw pixel data to
|
||||
int pitch; // the length of one row of pixels in bytes
|
||||
SDL_LockTexture(drawing_texture_, &r, &pixels_out, &pitch);
|
||||
if (pitch != drawingSurface->pitch) {
|
||||
// If these don't match we are not gonna have a good time.
|
||||
throw game::error("drawing surface and texture are incompatible");
|
||||
}
|
||||
char* pixels_in = static_cast<char*>(drawingSurface->pixels);
|
||||
pixels_in += (r.x * bytes_per_pixel) + (r.y * pitch);
|
||||
size_t row_bytes = r.w * bytes_per_pixel;
|
||||
for (int y = 0; y < r.h; ++y) {
|
||||
size_t row_offset = y * pitch;
|
||||
memcpy(
|
||||
static_cast<char*>(pixels_out) + row_offset,
|
||||
pixels_in + row_offset,
|
||||
row_bytes
|
||||
);
|
||||
}
|
||||
SDL_UnlockTexture(drawing_texture_);
|
||||
|
||||
// Copy the drawing texture to the render target.
|
||||
// SDL will adapt the destination rect coordinates automatically
|
||||
// in high-dpi contexts, thanks to set_logical_size().
|
||||
SDL_RenderCopy(*window.get(), drawing_texture_, &r, &r);
|
||||
}
|
||||
|
||||
void CVideo::render_screen()
|
||||
{
|
||||
if(fake_screen_ || flip_locked_ > 0) {
|
||||
|
@ -409,25 +511,11 @@ void CVideo::render_screen()
|
|||
}
|
||||
|
||||
if (drawingSurface && drawing_texture_) {
|
||||
// Upload the drawing surface to the drawing texture.
|
||||
void* pixels_out; // somewhere we can write raw pixel data to
|
||||
int pitch; // the length of one row of pixels in bytes
|
||||
SDL_LockTexture(drawing_texture_, nullptr, &pixels_out, &pitch);
|
||||
if (pitch != drawingSurface->pitch) {
|
||||
// If these don't match we are not gonna have a good time.
|
||||
throw game::error("drawing surface and texture are incompatible");
|
||||
}
|
||||
size_t num_bytes = drawingSurface->h * pitch;
|
||||
memcpy(pixels_out, drawingSurface->pixels, num_bytes);
|
||||
SDL_UnlockTexture(drawing_texture_);
|
||||
|
||||
//SDL_UpdateTexture(drawing_texture_, nullptr, drawingSurface->pixels, drawingSurface->pitch);
|
||||
|
||||
// Copy the drawing texture to the render target.
|
||||
SDL_RenderCopy(*window.get(), drawing_texture_, nullptr, nullptr);
|
||||
render_low_res();
|
||||
}
|
||||
|
||||
if(window) {
|
||||
// TODO: rename this to "present"
|
||||
window->render();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <memory>
|
||||
|
||||
class surface;
|
||||
class texture;
|
||||
struct point;
|
||||
struct SDL_Texture;
|
||||
|
||||
|
@ -181,6 +182,20 @@ public:
|
|||
/** The current scale factor on High-DPI screens. */
|
||||
std::pair<float, float> get_dpi_scale_factor() const;
|
||||
|
||||
/**
|
||||
* Clip a rectangle to the drawing area.
|
||||
*
|
||||
* This does not change the original
|
||||
* @param r The SDL_Rect to clip.
|
||||
* @returns The new clipped SDL_Rect.
|
||||
*/
|
||||
SDL_Rect clip_to_draw_area(const SDL_Rect* r) const;
|
||||
|
||||
/**
|
||||
* Convert coordinates in draw space to coordinates in render space.
|
||||
*/
|
||||
SDL_Rect to_output(const SDL_Rect& draw_space_rect) const;
|
||||
|
||||
/**
|
||||
* Tests whether the given flags are currently set on the SDL window.
|
||||
*
|
||||
|
@ -210,17 +225,77 @@ public:
|
|||
/***** ***** ***** ***** Drawing functions ***** ***** ****** *****/
|
||||
|
||||
/**
|
||||
* Copies an area of a surface to the drawing surface.
|
||||
* Draws a surface at the given location.
|
||||
*
|
||||
* The w and h members of dst are ignored, but will be updated
|
||||
* to reflect the final draw extents including clipping.
|
||||
*
|
||||
* The surface will be rendered in game-native resolution,
|
||||
* and all coordinates are given in this context.
|
||||
*
|
||||
* @param surf The surface to draw.
|
||||
* @param dst Where to draw the surface. w and h are ignored, but will be updated to reflect the final draw extents including clipping.
|
||||
*/
|
||||
void blit_surface(const surface& surf, SDL_Rect* dst);
|
||||
|
||||
/**
|
||||
* Draws a surface at the given coordinates.
|
||||
*
|
||||
* The surface will be rendered in game-native resolution,
|
||||
* and all coordinates are given in this context.
|
||||
*
|
||||
* @param x The x coordinate at which to draw.
|
||||
* @param y The y coordinate at which to draw.
|
||||
* @param surf The surface to draw.
|
||||
* @param srcrect The area of the surface to draw. This defaults to nullptr,
|
||||
* which implies the entire thing.
|
||||
* @param clip_rect The clipping rect. If not null, the surface will only be drawn
|
||||
*/
|
||||
void blit_surface(int x, int y, const surface& surf);
|
||||
|
||||
/**
|
||||
* Draws an area of a surface at the given location.
|
||||
*
|
||||
* The surface will be rendered in game-native resolution,
|
||||
* and all coordinates are given in this context.
|
||||
*
|
||||
* @param x The x coordinate at which to draw.
|
||||
* @param y The y coordinate at which to draw.
|
||||
* @param surf The surface to draw.
|
||||
* @param srcrect The area of the surface to draw. If null, the entire surface is drawn.
|
||||
* @param clip_rect The clipping area. If not null, the surface will only be drawn
|
||||
* within the bounds of the given rectangle.
|
||||
*/
|
||||
void blit_surface(int x, int y, surface surf, SDL_Rect* srcrect = nullptr, SDL_Rect* clip_rect = nullptr);
|
||||
void blit_surface(int x, int y, const surface& surf, const SDL_Rect* srcrect, const SDL_Rect* clip_rect);
|
||||
|
||||
/**
|
||||
* Draws a texture, or part of a texture, at the given location.
|
||||
*
|
||||
* The portion of the texture to be drawn will be scaled to fill
|
||||
* the target rectangle.
|
||||
*
|
||||
* This version takes coordinates in game-native resolution,
|
||||
* which may be lower than the final output resolution in high-dpi
|
||||
* contexts or if pixel scaling is used. The texture will be copied
|
||||
* in high-resolution if possible.
|
||||
*
|
||||
* @param tex The texture to be copied / drawn.
|
||||
* @param dstrect The target location to copy the texture to,
|
||||
* in low-resolution game-native drawing coordinates.
|
||||
* If null, this fills the entire render target.
|
||||
* @param srcrect The portion of the texture to copy.
|
||||
* If null, this copies the entire texture.
|
||||
*/
|
||||
void blit_texture(texture& tex, SDL_Rect* dstrect = nullptr, SDL_Rect* srcrect = nullptr);
|
||||
|
||||
/**
|
||||
* Render a portion of the low-resolution drawing surface.
|
||||
*
|
||||
* @param src_rect The portion of the drawing surface to render, in draw-space coordinates. If null, the entire drawing surface is rendered.
|
||||
*/
|
||||
void render_low_res(SDL_Rect* src_rect);
|
||||
|
||||
/**
|
||||
* Render the entire low-resolution drawing surface.
|
||||
*/
|
||||
void render_low_res();
|
||||
|
||||
/** Renders the screen. Should normally not be called directly! */
|
||||
void render_screen();
|
||||
|
|
Loading…
Add table
Reference in a new issue