Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add SDL_RenderTextureAffine #11353

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions include/SDL3/SDL_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -2087,6 +2087,36 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTextureRotated(SDL_Renderer *renderer
double angle, const SDL_FPoint *center,
SDL_FlipMode flip);

/**
* Copy a portion of the source texture to the current rendering target, with
* affine transform, at subpixel precision.
*
* \param renderer the renderer which should copy parts of a texture.
* \param texture the source texture.
* \param srcrect a pointer to the source rectangle, or NULL for the entire
* texture.
* \param origin a pointer to a point indicating where the top-left corner of
srcrect should be mapped to, or NULL for the rendering
target's origin.
* \param right a pointer to a point indicating where the top-right corner of
srcrect should be mapped to, or NULL for the rendering
target's top-right corner.
* \param down a pointer to a point indicating where the bottom-left corner
of srcrect should be mapped to, or NULL for the rendering
target's bottom-left corner.
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
* \threadsafety You may only call this function from the main thread.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_RenderTexture
*/
extern SDL_DECLSPEC bool SDLCALL SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_FRect *srcrect, const SDL_FPoint *origin,
const SDL_FPoint *right, const SDL_FPoint *down);

/**
* Tile a portion of the texture to the current rendering target at subpixel
* precision.
Expand Down
117 changes: 117 additions & 0 deletions src/render/SDL_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -3919,6 +3919,123 @@ bool SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_F
return SDL_RenderTextureInternal(renderer, texture, &real_srcrect, &real_dstrect);
}

bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_FRect *srcrect, const SDL_FPoint *origin, const SDL_FPoint *right, const SDL_FPoint *down)
{
SDL_FRect real_srcrect;
SDL_FRect real_dstrect;
bool result;

CHECK_RENDERER_MAGIC(renderer, false);
CHECK_TEXTURE_MAGIC(texture, false);

if (renderer != texture->renderer) {
return SDL_SetError("Texture was not created with this renderer");
}
if (!renderer->QueueCopyEx && !renderer->QueueGeometry) {
return SDL_SetError("Renderer does not support RenderCopyEx");
}

#if DONT_DRAW_WHILE_HIDDEN
// Don't draw while we're hidden
if (renderer->hidden) {
return true;
}
#endif

real_srcrect.x = 0.0f;
real_srcrect.y = 0.0f;
real_srcrect.w = (float)texture->w;
real_srcrect.h = (float)texture->h;
if (srcrect) {
if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect)) {
return true;
}
}

GetRenderViewportSize(renderer, &real_dstrect);

if (texture->native) {
texture = texture->native;
}

texture->last_command_generation = renderer->render_command_generation;

const float scale_x = renderer->view->current_scale.x;
const float scale_y = renderer->view->current_scale.y;

{
float xy[8];
const int xy_stride = 2 * sizeof(float);
float uv[8];
const int uv_stride = 2 * sizeof(float);
const int num_vertices = 4;
const int *indices = rect_index_order;
const int num_indices = 6;
const int size_indices = 4;

float minu = real_srcrect.x / texture->w;
float minv = real_srcrect.y / texture->h;
float maxu = (real_srcrect.x + real_srcrect.w) / texture->w;
float maxv = (real_srcrect.y + real_srcrect.h) / texture->h;

uv[0] = minu;
uv[1] = minv;
uv[2] = maxu;
uv[3] = minv;
uv[4] = maxu;
uv[5] = maxv;
uv[6] = minu;
uv[7] = maxv;

// (minx, miny)
if (origin) {
xy[0] = origin->x;
xy[1] = origin->y;
} else {
xy[0] = real_dstrect.x;
xy[1] = real_dstrect.y;
}

// (maxx, miny)
if (right) {
xy[2] = right->x;
xy[3] = right->y;
} else {
xy[2] = real_dstrect.x + real_dstrect.w;
xy[3] = real_dstrect.y;
}

// (minx, maxy)
if (down) {
xy[6] = down->x;
xy[7] = down->y;
} else {
xy[6] = real_dstrect.x;
xy[7] = real_dstrect.y + real_dstrect.h;
}

// (maxx, maxy)
if (origin || right || down) {
xy[4] = xy[2] + xy[6] - xy[0];
xy[5] = xy[3] + xy[7] - xy[1];
} else {
xy[4] = real_dstrect.x + real_dstrect.w;
xy[5] = real_dstrect.y + real_dstrect.h;
}

result = QueueCmdGeometry(
renderer, texture,
xy, xy_stride,
&texture->color, 0 /* color_stride */,
uv, uv_stride,
num_vertices, indices, num_indices, size_indices,
scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP
);
}
return result;
}

bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_FRect *srcrect, const SDL_FRect *dstrect,
const double angle, const SDL_FPoint *center, const SDL_FlipMode flip)
Expand Down
Loading