RenderCopyEx,rotation and flipping for all hardware/software backends (#1308)
This commit is contained in:
parent
5791b11bc4
commit
17bdcc6e8e
14 changed files with 1550 additions and 10 deletions
|
@ -104,6 +104,16 @@ typedef enum
|
|||
SDL_TEXTUREMODULATE_ALPHA = 0x00000002 /**< srcA = srcA * alpha */
|
||||
} SDL_TextureModulate;
|
||||
|
||||
/**
|
||||
* \brief Flip constants for SDL_RenderCopyEx
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SDL_FLIP_NONE = 0x00000000, /**< Do not flip */
|
||||
SDL_FLIP_HORIZONTAL = 0x00000001, /**< flip horizontally */
|
||||
SDL_FLIP_VERTICAL = 0x00000002 /**< flip vertically */
|
||||
} SDL_RendererFlip;
|
||||
|
||||
/**
|
||||
* \brief A structure representing rendering state
|
||||
*/
|
||||
|
@ -599,6 +609,27 @@ extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer,
|
|||
const SDL_Rect * srcrect,
|
||||
const SDL_Rect * dstrect);
|
||||
|
||||
/**
|
||||
* \brief Copy a portion of the source texture to the current rendering target, rotating it by angle around the given center
|
||||
*
|
||||
* \param texture The source texture.
|
||||
* \param srcrect A pointer to the source rectangle, or NULL for the entire
|
||||
* texture.
|
||||
* \param dstrect A pointer to the destination rectangle, or NULL for the
|
||||
* entire rendering target.
|
||||
* \param angle An angle in degrees that indicates the rotation that will be applied to dstrect
|
||||
* \param center A pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done aroud dstrect.w/2, dstrect.h/2)
|
||||
* \param flip A SFL_Flip value stating which flipping actions should be performed on the texture
|
||||
*
|
||||
* \return 0 on success, or -1 on error
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_RenderCopyEx(SDL_Renderer * renderer,
|
||||
SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect,
|
||||
const SDL_Rect * dstrect,
|
||||
const double angle,
|
||||
const SDL_Point *center,
|
||||
const SDL_RendererFlip flip);
|
||||
|
||||
/**
|
||||
* \brief Read pixels from the current rendering target.
|
||||
|
|
|
@ -1231,6 +1231,62 @@ SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
|||
&real_dstrect);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
|
||||
{
|
||||
SDL_Window *window;
|
||||
SDL_Rect real_srcrect, real_dstrect;
|
||||
SDL_Point real_center;
|
||||
|
||||
CHECK_RENDERER_MAGIC(renderer, -1);
|
||||
CHECK_TEXTURE_MAGIC(texture, -1);
|
||||
|
||||
if (renderer != texture->renderer) {
|
||||
SDL_SetError("Texture was not created with this renderer");
|
||||
return -1;
|
||||
}
|
||||
if (!renderer->RenderCopyEx) {
|
||||
SDL_SetError("Renderer does not support RenderCopyEx");
|
||||
return -1;
|
||||
}
|
||||
|
||||
window = renderer->window;
|
||||
|
||||
real_srcrect.x = 0;
|
||||
real_srcrect.y = 0;
|
||||
real_srcrect.w = texture->w;
|
||||
real_srcrect.h = texture->h;
|
||||
if (srcrect) {
|
||||
if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */
|
||||
if (dstrect) real_dstrect = *dstrect;
|
||||
else {
|
||||
real_srcrect.x = 0;
|
||||
real_srcrect.y = 0;
|
||||
real_srcrect.w = renderer->viewport.w;
|
||||
real_srcrect.h = renderer->viewport.h;
|
||||
}
|
||||
|
||||
if (texture->native) {
|
||||
texture = texture->native;
|
||||
}
|
||||
|
||||
if(center) real_center = *center;
|
||||
else {
|
||||
real_center.x = real_dstrect.w/2;
|
||||
real_center.y = real_dstrect.h/2;
|
||||
}
|
||||
|
||||
return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 format, void * pixels, int pitch)
|
||||
|
|
|
@ -88,6 +88,9 @@ struct SDL_Renderer
|
|||
int count);
|
||||
int (*RenderCopy) (SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect);
|
||||
int (*RenderCopyEx) (SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcquad, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point *center, const SDL_RendererFlip flip);
|
||||
int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 format, void * pixels, int pitch);
|
||||
void (*RenderPresent) (SDL_Renderer * renderer);
|
||||
|
|
|
@ -29,12 +29,97 @@
|
|||
#include "SDL_loadso.h"
|
||||
#include "SDL_syswm.h"
|
||||
#include "../SDL_sysrender.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#if SDL_VIDEO_RENDER_D3D
|
||||
#define D3D_DEBUG_INFO
|
||||
#include <d3d9.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef interface ID3DXMatrixStack *LPD3DXMATRIXSTACK;
|
||||
typedef struct _D3DMATRIX D3DXMATRIX, *LPD3DXMATRIX;
|
||||
typedef struct _D3DVECTOR D3DXVECTOR3, *LPD3DXVECTOR3;
|
||||
|
||||
DEFINE_GUID(IID_ID3DXMatrixStack,
|
||||
0xc7885ba7, 0xf990, 0x4fe7, 0x92, 0x2d, 0x85, 0x15, 0xe4, 0x77, 0xdd, 0x85);
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE ID3DXMatrixStack
|
||||
|
||||
DECLARE_INTERFACE_(ID3DXMatrixStack, IUnknown)
|
||||
{
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE;
|
||||
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG,Release)(THIS) PURE;
|
||||
STDMETHOD(Pop)(THIS) PURE;
|
||||
STDMETHOD(Push)(THIS) PURE;
|
||||
STDMETHOD(LoadIdentity)(THIS) PURE;
|
||||
STDMETHOD(LoadMatrix)(THIS_ CONST D3DXMATRIX* pM ) PURE;
|
||||
STDMETHOD(MultMatrix)(THIS_ CONST D3DXMATRIX* pM ) PURE;
|
||||
STDMETHOD(MultMatrixLocal)(THIS_ CONST D3DXMATRIX* pM ) PURE;
|
||||
STDMETHOD(RotateAxis)(THIS_ CONST D3DXVECTOR3* pV, FLOAT Angle) PURE;
|
||||
STDMETHOD(RotateAxisLocal)(THIS_ CONST D3DXVECTOR3* pV, FLOAT Angle) PURE;
|
||||
STDMETHOD(RotateYawPitchRoll)(THIS_ FLOAT Yaw, FLOAT Pitch, FLOAT Roll) PURE;
|
||||
STDMETHOD(RotateYawPitchRollLocal)(THIS_ FLOAT Yaw, FLOAT Pitch, FLOAT Roll) PURE;
|
||||
STDMETHOD(Scale)(THIS_ FLOAT x, FLOAT y, FLOAT z) PURE;
|
||||
STDMETHOD(ScaleLocal)(THIS_ FLOAT x, FLOAT y, FLOAT z) PURE;
|
||||
STDMETHOD(Translate)(THIS_ FLOAT x, FLOAT y, FLOAT z ) PURE;
|
||||
STDMETHOD(TranslateLocal)(THIS_ FLOAT x, FLOAT y, FLOAT z) PURE;
|
||||
STDMETHOD_(D3DXMATRIX*, GetTop)(THIS) PURE;
|
||||
};
|
||||
|
||||
#undef INTERFACE
|
||||
|
||||
#if !defined(__cplusplus) || defined(CINTERFACE)
|
||||
#define ID3DXMatrixStack_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
|
||||
#define ID3DXMatrixStack_AddRef(p) (p)->lpVtbl->AddRef(p)
|
||||
#define ID3DXMatrixStack_Release(p) (p)->lpVtbl->Release(p)
|
||||
#define ID3DXMatrixStack_Pop(p) (p)->lpVtbl->Pop(p)
|
||||
#define ID3DXMatrixStack_Push(p) (p)->lpVtbl->Push(p)
|
||||
#define ID3DXMatrixStack_LoadIdentity(p) (p)->lpVtbl->LoadIdentity(p)
|
||||
#define ID3DXMatrixStack_LoadMatrix(p,a) (p)->lpVtbl->LoadMatrix(p,a)
|
||||
#define ID3DXMatrixStack_MultMatrix(p,a) (p)->lpVtbl->MultMatrix(p,a)
|
||||
#define ID3DXMatrixStack_MultMatrixLocal(p,a) (p)->lpVtbl->MultMatrixLocal(p,a)
|
||||
#define ID3DXMatrixStack_RotateAxis(p,a,b) (p)->lpVtbl->RotateAxis(p,a,b)
|
||||
#define ID3DXMatrixStack_RotateAxisLocal(p,a,b) (p)->lpVtbl->RotateAxisLocal(p,a,b)
|
||||
#define ID3DXMatrixStack_RotateYawPitchRoll(p,a,b,c) (p)->lpVtbl->RotateYawPitchRoll(p,a,b,c)
|
||||
#define ID3DXMatrixStack_RotateYawPitchRollLocal(p,a,b,c) (p)->lpVtbl->RotateYawPitchRollLocal(p,a,b,c)
|
||||
#define ID3DXMatrixStack_Scale(p,a,b,c) (p)->lpVtbl->Scale(p,a,b,c)
|
||||
#define ID3DXMatrixStack_ScaleLocal(p,a,b,c) (p)->lpVtbl->ScaleLocal(p,a,b,c)
|
||||
#define ID3DXMatrixStack_Translate(p,a,b,c) (p)->lpVtbl->Translate(p,a,b,c)
|
||||
#define ID3DXMatrixStack_TranslateLocal(p,a,b,c) (p)->lpVtbl->TranslateLocal(p,a,b,c)
|
||||
#define ID3DXMatrixStack_GetTop(p) (p)->lpVtbl->GetTop(p)
|
||||
#else
|
||||
#define ID3DXMatrixStack_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
|
||||
#define ID3DXMatrixStack_AddRef(p) (p)->AddRef()
|
||||
#define ID3DXMatrixStack_Release(p) (p)->Release()
|
||||
#define ID3DXMatrixStack_Pop(p) (p)->Pop()
|
||||
#define ID3DXMatrixStack_Push(p) (p)->Push()
|
||||
#define ID3DXMatrixStack_LoadIdentity(p) (p)->LoadIdentity()
|
||||
#define ID3DXMatrixStack_LoadMatrix(p,a) (p)->LoadMatrix(a)
|
||||
#define ID3DXMatrixStack_MultMatrix(p,a) (p)->MultMatrix(a)
|
||||
#define ID3DXMatrixStack_MultMatrixLocal(p,a) (p)->MultMatrixLocal(a)
|
||||
#define ID3DXMatrixStack_RotateAxis(p,a,b) (p)->RotateAxis(a,b)
|
||||
#define ID3DXMatrixStack_RotateAxisLocal(p,a,b) (p)->RotateAxisLocal(a,b)
|
||||
#define ID3DXMatrixStack_RotateYawPitchRoll(p,a,b,c) (p)->RotateYawPitchRollLocal(a,b,c)
|
||||
#define ID3DXMatrixStack_Scale(p,a,b,c) (p)->Scale(a,b,c)
|
||||
#define ID3DXMatrixStack_ScaleLocal(p,a,b,c) (p)->ScaleLocal(a,b,c)
|
||||
#define ID3DXMatrixStack_Translate(p,a,b,c) (p)->Translate(a,b,c)
|
||||
#define ID3DXMatrixStack_TranslateLocal(p,a,b,c) (p)->TranslateLocal(a,b,c)
|
||||
#define ID3DXMatrixStack_GetTop(p) (p)->GetTop()
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HRESULT WINAPI D3DXCreateMatrixStack(DWORD flags, LPD3DXMATRIXSTACK* ppstack);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ASSEMBLE_SHADER
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ID3DXBuffer:
|
||||
|
@ -110,6 +195,9 @@ static int D3D_RenderFillRects(SDL_Renderer * renderer,
|
|||
const SDL_Rect * rects, int count);
|
||||
static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect);
|
||||
static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point * center, const SDL_RendererFlip flip);
|
||||
static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 format, void * pixels, int pitch);
|
||||
static void D3D_RenderPresent(SDL_Renderer * renderer);
|
||||
|
@ -141,6 +229,8 @@ typedef struct
|
|||
D3DTEXTUREFILTERTYPE scaleMode;
|
||||
IDirect3DSurface9 *defaultRenderTarget;
|
||||
IDirect3DSurface9 *currentRenderTarget;
|
||||
void* d3dxDLL;
|
||||
ID3DXMatrixStack *matrixStack;
|
||||
} D3D_RenderData;
|
||||
|
||||
typedef struct
|
||||
|
@ -347,6 +437,8 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
int w, h;
|
||||
SDL_DisplayMode fullscreen_mode;
|
||||
D3DMATRIX matrix;
|
||||
int d3dxVersion;
|
||||
char d3dxDLLFile[50];
|
||||
|
||||
renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
|
||||
if (!renderer) {
|
||||
|
@ -375,8 +467,28 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
SDL_UnloadObject(data->d3dDLL);
|
||||
data->d3dDLL = NULL;
|
||||
}
|
||||
|
||||
for (d3dxVersion=50;d3dxVersion>0;d3dxVersion--) {
|
||||
SDL_snprintf(d3dxDLLFile, 49, "D3DX9_%02d.dll", d3dxVersion);
|
||||
data->d3dxDLL = SDL_LoadObject(d3dxDLLFile);
|
||||
if (data->d3dxDLL) {
|
||||
HRESULT (WINAPI *D3DXCreateMatrixStack) (DWORD Flags, LPD3DXMATRIXSTACK* ppStack);
|
||||
D3DXCreateMatrixStack = (HRESULT (WINAPI *) (DWORD, LPD3DXMATRIXSTACK*)) SDL_LoadFunction(data->d3dxDLL, "D3DXCreateMatrixStack");
|
||||
if (D3DXCreateMatrixStack) {
|
||||
D3DXCreateMatrixStack(0, &data->matrixStack);
|
||||
break;
|
||||
}
|
||||
if (!data->d3d) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!data->matrixStack) {
|
||||
if (data->d3dxDLL) SDL_UnloadObject(data->d3dxDLL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!data->d3d || !data->matrixStack) {
|
||||
SDL_free(renderer);
|
||||
SDL_free(data);
|
||||
SDL_SetError("Unable to create Direct3D interface");
|
||||
|
@ -395,6 +507,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
renderer->RenderDrawLines = D3D_RenderDrawLines;
|
||||
renderer->RenderFillRects = D3D_RenderFillRects;
|
||||
renderer->RenderCopy = D3D_RenderCopy;
|
||||
renderer->RenderCopyEx = D3D_RenderCopyEx;
|
||||
renderer->RenderReadPixels = D3D_RenderReadPixels;
|
||||
renderer->RenderPresent = D3D_RenderPresent;
|
||||
renderer->DestroyTexture = D3D_DestroyTexture;
|
||||
|
@ -1126,6 +1239,135 @@ D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point * center, const SDL_RendererFlip flip)
|
||||
{
|
||||
D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
|
||||
D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
|
||||
LPDIRECT3DPIXELSHADER9 shader = NULL;
|
||||
float minx, miny, maxx, maxy;
|
||||
float minu, maxu, minv, maxv;
|
||||
float centerx, centery;
|
||||
DWORD color;
|
||||
Vertex vertices[4];
|
||||
HRESULT result;
|
||||
|
||||
if (D3D_ActivateRenderer(renderer) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
centerx = (float)center->x;
|
||||
centery = (float)center->y;
|
||||
|
||||
if (flip & SDL_FLIP_HORIZONTAL) {
|
||||
minx = (float) dstrect->w - centerx - 0.5f;
|
||||
maxx = (float) -centerx - 0.5f;
|
||||
}
|
||||
else {
|
||||
minx = (float) -centerx - 0.5f;
|
||||
maxx = (float) dstrect->w - centerx - 0.5f;
|
||||
}
|
||||
|
||||
if (flip & SDL_FLIP_VERTICAL) {
|
||||
miny = (float) dstrect->h - centery - 0.5f;
|
||||
maxy = (float) -centery - 0.5f;
|
||||
}
|
||||
else {
|
||||
miny = (float) -centery - 0.5f;
|
||||
maxy = (float) dstrect->h - centery - 0.5f;
|
||||
}
|
||||
|
||||
minu = (float) srcrect->x / texture->w;
|
||||
maxu = (float) (srcrect->x + srcrect->w) / texture->w;
|
||||
minv = (float) srcrect->y / texture->h;
|
||||
maxv = (float) (srcrect->y + srcrect->h) / texture->h;
|
||||
|
||||
color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
|
||||
|
||||
vertices[0].x = minx;
|
||||
vertices[0].y = miny;
|
||||
vertices[0].z = 0.0f;
|
||||
vertices[0].color = color;
|
||||
vertices[0].u = minu;
|
||||
vertices[0].v = minv;
|
||||
|
||||
vertices[1].x = maxx;
|
||||
vertices[1].y = miny;
|
||||
vertices[1].z = 0.0f;
|
||||
vertices[1].color = color;
|
||||
vertices[1].u = maxu;
|
||||
vertices[1].v = minv;
|
||||
|
||||
vertices[2].x = maxx;
|
||||
vertices[2].y = maxy;
|
||||
vertices[2].z = 0.0f;
|
||||
vertices[2].color = color;
|
||||
vertices[2].u = maxu;
|
||||
vertices[2].v = maxv;
|
||||
|
||||
vertices[3].x = minx;
|
||||
vertices[3].y = maxy;
|
||||
vertices[3].z = 0.0f;
|
||||
vertices[3].color = color;
|
||||
vertices[3].u = minu;
|
||||
vertices[3].v = maxv;
|
||||
|
||||
D3D_SetBlendMode(data, texture->blendMode);
|
||||
|
||||
// Rotate and translate
|
||||
ID3DXMatrixStack_Push(data->matrixStack);
|
||||
ID3DXMatrixStack_LoadIdentity(data->matrixStack);
|
||||
ID3DXMatrixStack_RotateYawPitchRoll(data->matrixStack, 0.0, 0.0, M_PI * (float) angle / 180.0f);
|
||||
ID3DXMatrixStack_Translate(data->matrixStack, (float)dstrect->x + centerx, (float)dstrect->y + centery, (float)0.0);
|
||||
IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)ID3DXMatrixStack_GetTop(data->matrixStack));
|
||||
|
||||
if (texturedata->scaleMode != data->scaleMode) {
|
||||
IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
|
||||
texturedata->scaleMode);
|
||||
IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
|
||||
texturedata->scaleMode);
|
||||
data->scaleMode = texturedata->scaleMode;
|
||||
}
|
||||
|
||||
result =
|
||||
IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
|
||||
texturedata->texture);
|
||||
if (FAILED(result)) {
|
||||
D3D_SetError("SetTexture()", result);
|
||||
return -1;
|
||||
}
|
||||
if (shader) {
|
||||
result = IDirect3DDevice9_SetPixelShader(data->device, shader);
|
||||
if (FAILED(result)) {
|
||||
D3D_SetError("SetShader()", result);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
result =
|
||||
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
|
||||
vertices, sizeof(*vertices));
|
||||
if (FAILED(result)) {
|
||||
D3D_SetError("DrawPrimitiveUP()", result);
|
||||
return -1;
|
||||
}
|
||||
if (shader) {
|
||||
result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
|
||||
if (FAILED(result)) {
|
||||
D3D_SetError("SetShader()", result);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ID3DXMatrixStack_Pop(data->matrixStack);
|
||||
ID3DXMatrixStack_Push(data->matrixStack);
|
||||
ID3DXMatrixStack_LoadIdentity(data->matrixStack);
|
||||
IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)ID3DXMatrixStack_GetTop(data->matrixStack));
|
||||
ID3DXMatrixStack_Pop(data->matrixStack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 format, void * pixels, int pitch)
|
||||
|
|
|
@ -279,14 +279,14 @@ SDL_PROC_UNUSED(void, glPolygonOffset, (GLfloat factor, GLfloat units))
|
|||
SDL_PROC_UNUSED(void, glPolygonStipple, (const GLubyte * mask))
|
||||
SDL_PROC_UNUSED(void, glPopAttrib, (void))
|
||||
SDL_PROC_UNUSED(void, glPopClientAttrib, (void))
|
||||
SDL_PROC_UNUSED(void, glPopMatrix, (void))
|
||||
SDL_PROC(void, glPopMatrix, (void))
|
||||
SDL_PROC_UNUSED(void, glPopName, (void))
|
||||
SDL_PROC_UNUSED(void, glPrioritizeTextures,
|
||||
(GLsizei n, const GLuint * textures,
|
||||
const GLclampf * priorities))
|
||||
SDL_PROC_UNUSED(void, glPushAttrib, (GLbitfield mask))
|
||||
SDL_PROC_UNUSED(void, glPushClientAttrib, (GLbitfield mask))
|
||||
SDL_PROC_UNUSED(void, glPushMatrix, (void))
|
||||
SDL_PROC(void, glPushMatrix, (void))
|
||||
SDL_PROC_UNUSED(void, glPushName, (GLuint name))
|
||||
SDL_PROC_UNUSED(void, glRasterPos2d, (GLdouble x, GLdouble y))
|
||||
SDL_PROC_UNUSED(void, glRasterPos2dv, (const GLdouble * v))
|
||||
|
@ -331,7 +331,7 @@ SDL_PROC_UNUSED(void, glRects,
|
|||
(GLshort x1, GLshort y1, GLshort x2, GLshort y2))
|
||||
SDL_PROC_UNUSED(void, glRectsv, (const GLshort * v1, const GLshort * v2))
|
||||
SDL_PROC_UNUSED(GLint, glRenderMode, (GLenum mode))
|
||||
SDL_PROC_UNUSED(void, glRotated,
|
||||
SDL_PROC(void, glRotated,
|
||||
(GLdouble angle, GLdouble x, GLdouble y, GLdouble z))
|
||||
SDL_PROC_UNUSED(void, glRotatef,
|
||||
(GLfloat angle, GLfloat x, GLfloat y, GLfloat z))
|
||||
|
@ -419,7 +419,7 @@ SDL_PROC(void, glTexSubImage2D,
|
|||
GLsizei width, GLsizei height, GLenum format, GLenum type,
|
||||
const GLvoid * pixels))
|
||||
SDL_PROC_UNUSED(void, glTranslated, (GLdouble x, GLdouble y, GLdouble z))
|
||||
SDL_PROC_UNUSED(void, glTranslatef, (GLfloat x, GLfloat y, GLfloat z))
|
||||
SDL_PROC(void, glTranslatef, (GLfloat x, GLfloat y, GLfloat z))
|
||||
SDL_PROC_UNUSED(void, glVertex2d, (GLdouble x, GLdouble y))
|
||||
SDL_PROC_UNUSED(void, glVertex2dv, (const GLdouble * v))
|
||||
SDL_PROC(void, glVertex2f, (GLfloat x, GLfloat y))
|
||||
|
|
|
@ -65,6 +65,9 @@ static int GL_RenderFillRects(SDL_Renderer * renderer,
|
|||
const SDL_Rect * rects, int count);
|
||||
static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect);
|
||||
static int GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point *center, const SDL_RendererFlip flip);
|
||||
static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 pixel_format, void * pixels, int pitch);
|
||||
static void GL_RenderPresent(SDL_Renderer * renderer);
|
||||
|
@ -314,6 +317,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
renderer->RenderDrawLines = GL_RenderDrawLines;
|
||||
renderer->RenderFillRects = GL_RenderFillRects;
|
||||
renderer->RenderCopy = GL_RenderCopy;
|
||||
renderer->RenderCopyEx = GL_RenderCopyEx;
|
||||
renderer->RenderReadPixels = GL_RenderReadPixels;
|
||||
renderer->RenderPresent = GL_RenderPresent;
|
||||
renderer->DestroyTexture = GL_DestroyTexture;
|
||||
|
@ -1018,6 +1022,96 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
|
||||
{
|
||||
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
|
||||
GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
|
||||
GLfloat minx, miny, maxx, maxy;
|
||||
GLfloat centerx, centery;
|
||||
GLfloat minu, maxu, minv, maxv;
|
||||
GL_ActivateRenderer(renderer);
|
||||
|
||||
data->glEnable(texturedata->type);
|
||||
if (texturedata->yuv) {
|
||||
data->glActiveTextureARB(GL_TEXTURE2_ARB);
|
||||
data->glBindTexture(texturedata->type, texturedata->vtexture);
|
||||
|
||||
data->glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
data->glBindTexture(texturedata->type, texturedata->utexture);
|
||||
|
||||
data->glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
}
|
||||
data->glBindTexture(texturedata->type, texturedata->texture);
|
||||
|
||||
if (texture->modMode) {
|
||||
GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
|
||||
} else {
|
||||
GL_SetColor(data, 255, 255, 255, 255);
|
||||
}
|
||||
|
||||
GL_SetBlendMode(data, texture->blendMode);
|
||||
|
||||
if (texturedata->yuv) {
|
||||
GL_SetShader(data, SHADER_YV12);
|
||||
} else {
|
||||
GL_SetShader(data, SHADER_RGB);
|
||||
}
|
||||
|
||||
centerx = (GLfloat)center->x;
|
||||
centery = (GLfloat)center->y;
|
||||
|
||||
if (flip & SDL_FLIP_HORIZONTAL) {
|
||||
minx = (GLfloat) dstrect->w - centerx;
|
||||
maxx = -centerx;
|
||||
}
|
||||
else {
|
||||
minx = -centerx;
|
||||
maxx = (GLfloat) dstrect->w - centerx;
|
||||
}
|
||||
|
||||
if (flip & SDL_FLIP_VERTICAL) {
|
||||
miny = (GLfloat) dstrect->h - centery;
|
||||
maxy = -centery;
|
||||
}
|
||||
else {
|
||||
miny = -centery;
|
||||
maxy = (GLfloat) dstrect->h - centery;
|
||||
}
|
||||
|
||||
minu = (GLfloat) srcrect->x / texture->w;
|
||||
minu *= texturedata->texw;
|
||||
maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
|
||||
maxu *= texturedata->texw;
|
||||
minv = (GLfloat) srcrect->y / texture->h;
|
||||
minv *= texturedata->texh;
|
||||
maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
|
||||
maxv *= texturedata->texh;
|
||||
|
||||
// Translate to flip, rotate, translate to position
|
||||
data->glPushMatrix();
|
||||
data->glTranslatef((GLfloat)dstrect->x + centerx, (GLfloat)dstrect->y + centery, (GLfloat)0.0);
|
||||
data->glRotated(angle, (GLdouble)0.0, (GLdouble)0.0, (GLdouble)1.0);
|
||||
|
||||
data->glBegin(GL_TRIANGLE_STRIP);
|
||||
data->glTexCoord2f(minu, minv);
|
||||
data->glVertex2f(minx, miny);
|
||||
data->glTexCoord2f(maxu, minv);
|
||||
data->glVertex2f(maxx, miny);
|
||||
data->glTexCoord2f(minu, maxv);
|
||||
data->glVertex2f(minx, maxy);
|
||||
data->glTexCoord2f(maxu, maxv);
|
||||
data->glVertex2f(maxx, maxy);
|
||||
data->glEnd();
|
||||
data->glPopMatrix();
|
||||
|
||||
data->glDisable(texturedata->type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 pixel_format, void * pixels, int pitch)
|
||||
|
|
|
@ -71,6 +71,9 @@ static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
|||
const SDL_Rect * dstrect);
|
||||
static int GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 pixel_format, void * pixels, int pitch);
|
||||
static int GLES_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point *center, const SDL_RendererFlip flip);
|
||||
static void GLES_RenderPresent(SDL_Renderer * renderer);
|
||||
static void GLES_DestroyTexture(SDL_Renderer * renderer,
|
||||
SDL_Texture * texture);
|
||||
|
@ -304,6 +307,7 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
renderer->RenderFillRects = GLES_RenderFillRects;
|
||||
renderer->RenderCopy = GLES_RenderCopy;
|
||||
renderer->RenderReadPixels = GLES_RenderReadPixels;
|
||||
renderer->RenderCopyEx = GLES_RenderCopyEx;
|
||||
renderer->RenderPresent = GLES_RenderPresent;
|
||||
renderer->DestroyTexture = GLES_DestroyTexture;
|
||||
renderer->DestroyRenderer = GLES_DestroyRenderer;
|
||||
|
@ -958,6 +962,98 @@ GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
|||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
GLES_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
|
||||
{
|
||||
|
||||
GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
|
||||
GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
|
||||
int minx, miny, maxx, maxy;
|
||||
GLfloat minu, maxu, minv, maxv;
|
||||
GLfloat centerx, centery;
|
||||
|
||||
GLES_ActivateRenderer(renderer);
|
||||
|
||||
data->glEnable(GL_TEXTURE_2D);
|
||||
|
||||
data->glBindTexture(texturedata->type, texturedata->texture);
|
||||
|
||||
if (texture->modMode) {
|
||||
GLES_SetColor(data, texture->r, texture->g, texture->b, texture->a);
|
||||
} else {
|
||||
GLES_SetColor(data, 255, 255, 255, 255);
|
||||
}
|
||||
|
||||
GLES_SetBlendMode(data, texture->blendMode);
|
||||
|
||||
GLES_SetTexCoords(data, SDL_TRUE);
|
||||
|
||||
centerx = (GLfloat)center->x;
|
||||
centery = (GLfloat)center->y;
|
||||
|
||||
// Rotate and translate
|
||||
data->glPushMatrix();
|
||||
data->glTranslatef((GLfloat)dstrect->x + centerx, (GLfloat)dstrect->y + centery, (GLfloat)0.0);
|
||||
data->glRotatef((GLfloat)angle, (GLfloat)0.0, (GLfloat)0.0, (GLfloat)1.0);
|
||||
|
||||
if (flip & SDL_FLIP_HORIZONTAL) {
|
||||
minx = (GLfloat) dstrect->w - centerx;
|
||||
maxx = -centerx;
|
||||
}
|
||||
else {
|
||||
minx = -centerx;
|
||||
maxx = dstrect->w - centerx;
|
||||
}
|
||||
|
||||
if (flip & SDL_FLIP_VERTICAL) {
|
||||
miny = dstrect->h - centery;
|
||||
maxy = -centery;
|
||||
}
|
||||
else {
|
||||
miny = -centery;
|
||||
maxy = dstrect->h - centery;
|
||||
}
|
||||
|
||||
minu = (GLfloat) srcrect->x / texture->w;
|
||||
minu *= texturedata->texw;
|
||||
maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
|
||||
maxu *= texturedata->texw;
|
||||
minv = (GLfloat) srcrect->y / texture->h;
|
||||
minv *= texturedata->texh;
|
||||
maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
|
||||
maxv *= texturedata->texh;
|
||||
|
||||
GLshort vertices[8];
|
||||
GLfloat texCoords[8];
|
||||
|
||||
vertices[0] = minx;
|
||||
vertices[1] = miny;
|
||||
vertices[2] = maxx;
|
||||
vertices[3] = miny;
|
||||
vertices[4] = minx;
|
||||
vertices[5] = maxy;
|
||||
vertices[6] = maxx;
|
||||
vertices[7] = maxy;
|
||||
|
||||
texCoords[0] = minu;
|
||||
texCoords[1] = minv;
|
||||
texCoords[2] = maxu;
|
||||
texCoords[3] = minv;
|
||||
texCoords[4] = minu;
|
||||
texCoords[5] = maxv;
|
||||
texCoords[6] = maxu;
|
||||
texCoords[7] = maxv;
|
||||
data->glVertexPointer(2, GL_SHORT, 0, vertices);
|
||||
data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
|
||||
data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
data->glPopMatrix();
|
||||
data->glDisable(GL_TEXTURE_2D);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
GLES_RenderPresent(SDL_Renderer * renderer)
|
||||
{
|
||||
|
|
|
@ -112,7 +112,9 @@ typedef struct GLES2_ProgramCache
|
|||
typedef enum
|
||||
{
|
||||
GLES2_ATTRIBUTE_POSITION = 0,
|
||||
GLES2_ATTRIBUTE_TEXCOORD = 1
|
||||
GLES2_ATTRIBUTE_TEXCOORD = 1,
|
||||
GLES2_ATTRIBUTE_ANGLE = 2,
|
||||
GLES2_ATTRIBUTE_CENTER = 3,
|
||||
} GLES2_Attribute;
|
||||
|
||||
typedef enum
|
||||
|
@ -628,6 +630,8 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
|
|||
rdata->glAttachShader(entry->id, fragment->id);
|
||||
rdata->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position");
|
||||
rdata->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
|
||||
rdata->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_ANGLE, "a_angle");
|
||||
rdata->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_CENTER, "a_center");
|
||||
rdata->glLinkProgram(entry->id);
|
||||
rdata->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
|
||||
if (rdata->glGetError() != GL_NO_ERROR || !linkSuccessful)
|
||||
|
@ -940,6 +944,9 @@ static int GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const
|
|||
const SDL_Rect *dstrect);
|
||||
static int GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 pixel_format, void * pixels, int pitch);
|
||||
static int GLES2_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point *center, const SDL_RendererFlip flip);
|
||||
static void GLES2_RenderPresent(SDL_Renderer *renderer);
|
||||
|
||||
|
||||
|
@ -1281,6 +1288,188 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s
|
|||
vertices[7] = (GLfloat)(dstrect->y + dstrect->h);
|
||||
}
|
||||
rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
texCoords[0] = srcrect->x / (GLfloat)texture->w;
|
||||
texCoords[1] = srcrect->y / (GLfloat)texture->h;
|
||||
texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
|
||||
texCoords[3] = srcrect->y / (GLfloat)texture->h;
|
||||
texCoords[4] = srcrect->x / (GLfloat)texture->w;
|
||||
texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
|
||||
texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
|
||||
texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
|
||||
rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
|
||||
rdata->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
if (rdata->glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
SDL_SetError("Failed to render texture");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
|
||||
const SDL_Rect *dstrect, const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
|
||||
{
|
||||
GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
|
||||
GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
|
||||
GLES2_ImageSource sourceType;
|
||||
SDL_BlendMode blendMode;
|
||||
GLfloat vertices[8];
|
||||
GLfloat texCoords[8];
|
||||
GLuint locTexture;
|
||||
GLuint locModulation;
|
||||
GLfloat translate[8];
|
||||
GLfloat fAngle[4];
|
||||
GLfloat tmp;
|
||||
|
||||
GLES2_ActivateRenderer(renderer);
|
||||
|
||||
rdata->glEnableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
|
||||
rdata->glEnableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
|
||||
fAngle[0] = fAngle[1] = fAngle[2] = fAngle[3] = (GLfloat)angle;
|
||||
/* Calculate the center of rotation */
|
||||
translate[0] = translate[2] = translate[4] = translate[6] = (GLfloat)(center->x + dstrect->x);
|
||||
translate[1] = translate[3] = translate[5] = translate[7] = (GLfloat)(center->y + dstrect->y);
|
||||
|
||||
/* Activate an appropriate shader and set the projection matrix */
|
||||
blendMode = texture->blendMode;
|
||||
if (renderer->target) {
|
||||
/* Check if we need to do color mapping between the source and render target textures */
|
||||
if (renderer->target->format != texture->format) {
|
||||
switch (texture->format)
|
||||
{
|
||||
case SDL_PIXELFORMAT_ABGR8888:
|
||||
switch (renderer->target->format)
|
||||
{
|
||||
case SDL_PIXELFORMAT_ARGB8888:
|
||||
case SDL_PIXELFORMAT_RGB888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_BGR888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ARGB8888:
|
||||
switch (renderer->target->format)
|
||||
{
|
||||
case SDL_PIXELFORMAT_ABGR8888:
|
||||
case SDL_PIXELFORMAT_BGR888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_RGB888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_PIXELFORMAT_BGR888:
|
||||
switch (renderer->target->format)
|
||||
{
|
||||
case SDL_PIXELFORMAT_ABGR8888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ARGB8888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_RGB888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_PIXELFORMAT_RGB888:
|
||||
switch (renderer->target->format)
|
||||
{
|
||||
case SDL_PIXELFORMAT_ABGR8888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ARGB8888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_BGR888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; // Texture formats match, use the non color mapping shader (even if the formats are not ABGR)
|
||||
}
|
||||
else {
|
||||
switch (texture->format)
|
||||
{
|
||||
case SDL_PIXELFORMAT_ABGR8888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ARGB8888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_BGR888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_RGB888:
|
||||
sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0)
|
||||
return -1;
|
||||
|
||||
/* Select the target texture */
|
||||
locTexture = rdata->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE];
|
||||
rdata->glGetError();
|
||||
rdata->glActiveTexture(GL_TEXTURE0);
|
||||
rdata->glBindTexture(tdata->texture_type, tdata->texture);
|
||||
rdata->glUniform1i(locTexture, 0);
|
||||
|
||||
/* Configure color modulation */
|
||||
locModulation = rdata->current_program->uniform_locations[GLES2_UNIFORM_MODULATION];
|
||||
rdata->glUniform4f(locModulation,
|
||||
texture->r * inv255f,
|
||||
texture->g * inv255f,
|
||||
texture->b * inv255f,
|
||||
texture->a * inv255f);
|
||||
|
||||
/* Configure texture blending */
|
||||
GLES2_SetBlendMode(rdata, blendMode);
|
||||
|
||||
GLES2_SetTexCoords(rdata, SDL_TRUE);
|
||||
|
||||
/* Emit the textured quad */
|
||||
if (renderer->target) {
|
||||
// Flip the texture vertically to compensate for the inversion it'll be subjected to later when it's rendered to the screen
|
||||
vertices[0] = (GLfloat)dstrect->x;
|
||||
vertices[1] = (GLfloat)renderer->viewport.h-dstrect->y;
|
||||
vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
|
||||
vertices[3] = (GLfloat)renderer->viewport.h-dstrect->y;
|
||||
vertices[4] = (GLfloat)dstrect->x;
|
||||
vertices[5] = (GLfloat)renderer->viewport.h-(dstrect->y + dstrect->h);
|
||||
vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
|
||||
vertices[7] = (GLfloat)renderer->viewport.h-(dstrect->y + dstrect->h);
|
||||
}
|
||||
else {
|
||||
vertices[0] = (GLfloat)dstrect->x;
|
||||
vertices[1] = (GLfloat)dstrect->y;
|
||||
vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
|
||||
vertices[3] = (GLfloat)dstrect->y;
|
||||
vertices[4] = (GLfloat)dstrect->x;
|
||||
vertices[5] = (GLfloat)(dstrect->y + dstrect->h);
|
||||
vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
|
||||
vertices[7] = (GLfloat)(dstrect->y + dstrect->h);
|
||||
}
|
||||
if (flip & SDL_FLIP_HORIZONTAL) {
|
||||
tmp = vertices[0];
|
||||
vertices[0] = vertices[4] = vertices[2];
|
||||
vertices[2] = vertices[6] = tmp;
|
||||
}
|
||||
if (flip & SDL_FLIP_VERTICAL) {
|
||||
tmp = vertices[1];
|
||||
vertices[1] = vertices[3] = vertices[5];
|
||||
vertices[5] = vertices[7] = tmp;
|
||||
}
|
||||
|
||||
rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle);
|
||||
rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, translate);
|
||||
rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
|
||||
texCoords[0] = srcrect->x / (GLfloat)texture->w;
|
||||
texCoords[1] = srcrect->y / (GLfloat)texture->h;
|
||||
|
@ -1292,6 +1481,8 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s
|
|||
texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
|
||||
rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
|
||||
rdata->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
rdata->glDisableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
|
||||
rdata->glDisableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
|
||||
if (rdata->glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
SDL_SetError("Failed to render texture");
|
||||
|
@ -1504,6 +1695,7 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
|
|||
renderer->RenderFillRects = &GLES2_RenderFillRects;
|
||||
renderer->RenderCopy = &GLES2_RenderCopy;
|
||||
renderer->RenderReadPixels = &GLES2_RenderReadPixels;
|
||||
renderer->RenderCopyEx = &GLES2_RenderCopyEx;
|
||||
renderer->RenderPresent = &GLES2_RenderPresent;
|
||||
renderer->DestroyTexture = &GLES2_DestroyTexture;
|
||||
renderer->DestroyRenderer = &GLES2_DestroyRenderer;
|
||||
|
|
|
@ -33,14 +33,21 @@
|
|||
|
||||
static const Uint8 GLES2_VertexSrc_Default_[] = " \
|
||||
uniform mat4 u_projection; \
|
||||
attribute vec4 a_position; \
|
||||
attribute vec2 a_position; \
|
||||
attribute vec2 a_texCoord; \
|
||||
attribute float a_angle; \
|
||||
attribute vec2 a_center; \
|
||||
varying vec2 v_texCoord; \
|
||||
\
|
||||
void main() \
|
||||
{ \
|
||||
float angle = radians(a_angle); \
|
||||
float c = cos(angle); \
|
||||
float s = sin(angle); \
|
||||
mat2 rotationMatrix = mat2(c, -s, s, c); \
|
||||
vec2 position = rotationMatrix * (a_position - a_center) + a_center; \
|
||||
v_texCoord = a_texCoord; \
|
||||
gl_Position = u_projection * a_position; \
|
||||
gl_Position = u_projection * vec4(position, 0.0, 1.0);\
|
||||
gl_PointSize = 1.0; \
|
||||
} \
|
||||
";
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "../SDL_sysrender.h"
|
||||
#include "SDL_render_sw_c.h"
|
||||
#include "SDL_hints.h"
|
||||
|
||||
#include "SDL_draw.h"
|
||||
#include "SDL_blendfillrect.h"
|
||||
|
@ -31,7 +32,7 @@
|
|||
#include "SDL_blendpoint.h"
|
||||
#include "SDL_drawline.h"
|
||||
#include "SDL_drawpoint.h"
|
||||
|
||||
#include "SDL_rotate.h"
|
||||
|
||||
/* SDL surface based renderer implementation */
|
||||
|
||||
|
@ -62,6 +63,9 @@ static int SW_RenderFillRects(SDL_Renderer * renderer,
|
|||
const SDL_Rect * rects, int count);
|
||||
static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect);
|
||||
static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point * center, const SDL_RendererFlip flip);
|
||||
static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 format, void * pixels, int pitch);
|
||||
static void SW_RenderPresent(SDL_Renderer * renderer);
|
||||
|
@ -152,6 +156,7 @@ SW_CreateRendererForSurface(SDL_Surface * surface)
|
|||
renderer->RenderDrawLines = SW_RenderDrawLines;
|
||||
renderer->RenderFillRects = SW_RenderFillRects;
|
||||
renderer->RenderCopy = SW_RenderCopy;
|
||||
renderer->RenderCopyEx = SW_RenderCopyEx;
|
||||
renderer->RenderReadPixels = SW_RenderReadPixels;
|
||||
renderer->RenderPresent = SW_RenderPresent;
|
||||
renderer->DestroyTexture = SW_DestroyTexture;
|
||||
|
@ -495,6 +500,102 @@ SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
GetScaleQuality(void)
|
||||
{
|
||||
const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
|
||||
|
||||
if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
|
||||
const double angle, const SDL_Point * center, const SDL_RendererFlip flip)
|
||||
{
|
||||
SDL_Surface *surface = SW_ActivateRenderer(renderer);
|
||||
SDL_Surface *src = (SDL_Surface *) texture->driverdata;
|
||||
SDL_Rect final_rect = *dstrect, tmp_rect;
|
||||
SDL_Surface *surface_rotated, *surface_scaled;
|
||||
SDL_Point final_rect_center;
|
||||
Uint32 colorkey;
|
||||
int retval, dstwidth, dstheight, abscenterx, abscentery;
|
||||
double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
|
||||
|
||||
if (!surface) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (renderer->viewport.x || renderer->viewport.y) {
|
||||
final_rect.x += renderer->viewport.x;
|
||||
final_rect.y += renderer->viewport.y;
|
||||
}
|
||||
|
||||
surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
|
||||
src->format->Rmask, src->format->Gmask,
|
||||
src->format->Bmask, src->format->Amask );
|
||||
SDL_GetColorKey(src, &colorkey);
|
||||
SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
|
||||
tmp_rect = final_rect;
|
||||
tmp_rect.x = 0;
|
||||
tmp_rect.y = 0;
|
||||
if (surface_scaled) {
|
||||
retval = SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect);
|
||||
if (!retval) {
|
||||
_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle);
|
||||
surface_rotated = _rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
|
||||
if(surface_rotated) {
|
||||
/* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
|
||||
abscenterx = final_rect.x + center->x;
|
||||
abscentery = final_rect.y + center->y;
|
||||
/* Compensate the angle inversion to match the behaviour of the other backends */
|
||||
sangle = -sangle;
|
||||
|
||||
/* Top Left */
|
||||
px = final_rect.x - abscenterx;
|
||||
py = final_rect.y - abscentery;
|
||||
p1x = px * cangle - py * sangle + abscenterx;
|
||||
p1y = px * sangle + py * cangle + abscentery;
|
||||
|
||||
/* Top Right */
|
||||
px = final_rect.x + final_rect.w - abscenterx;
|
||||
py = final_rect.y - abscentery;
|
||||
p2x = px * cangle - py * sangle + abscenterx;
|
||||
p2y = px * sangle + py * cangle + abscentery;
|
||||
|
||||
/* Bottom Left */
|
||||
px = final_rect.x - abscenterx;
|
||||
py = final_rect.y + final_rect.h - abscentery;
|
||||
p3x = px * cangle - py * sangle + abscenterx;
|
||||
p3y = px * sangle + py * cangle + abscentery;
|
||||
|
||||
/* Bottom Right */
|
||||
px = final_rect.x + final_rect.w - abscenterx;
|
||||
py = final_rect.y + final_rect.h - abscentery;
|
||||
p4x = px * cangle - py * sangle + abscenterx;
|
||||
p4y = px * sangle + py * cangle + abscentery;
|
||||
|
||||
tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
|
||||
tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
|
||||
tmp_rect.w = dstwidth;
|
||||
tmp_rect.h = dstheight;
|
||||
|
||||
retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
|
||||
SDL_FreeSurface(surface_scaled);
|
||||
SDL_FreeSurface(surface_rotated);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||
Uint32 format, void * pixels, int pitch)
|
||||
|
|
500
src/render/software/SDL_rotate.c
Normal file
500
src/render/software/SDL_rotate.c
Normal file
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
|
||||
SDL_rotate.c: rotates 32bit or 8bit surfaces
|
||||
|
||||
Shamelessly stolen from SDL_gfx by Andreas Schiffler. Original copyright follows:
|
||||
|
||||
Copyright (C) 2001-2011 Andreas Schiffler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
Andreas Schiffler -- aschiffler at ferzkopp dot net
|
||||
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_rotate.h"
|
||||
|
||||
/* ---- Internally used structures */
|
||||
|
||||
/*!
|
||||
\brief A 32 bit RGBA pixel.
|
||||
*/
|
||||
typedef struct tColorRGBA {
|
||||
Uint8 r;
|
||||
Uint8 g;
|
||||
Uint8 b;
|
||||
Uint8 a;
|
||||
} tColorRGBA;
|
||||
|
||||
/*!
|
||||
\brief A 8bit Y/palette pixel.
|
||||
*/
|
||||
typedef struct tColorY {
|
||||
Uint8 y;
|
||||
} tColorY;
|
||||
|
||||
/*!
|
||||
\brief Returns maximum of two numbers a and b.
|
||||
*/
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
/*!
|
||||
\brief Number of guard rows added to destination surfaces.
|
||||
|
||||
This is a simple but effective workaround for observed issues.
|
||||
These rows allocate extra memory and are then hidden from the surface.
|
||||
Rows are added to the end of destination surfaces when they are allocated.
|
||||
This catches any potential overflows which seem to happen with
|
||||
just the right src image dimensions and scale/rotation and can lead
|
||||
to a situation where the program can segfault.
|
||||
*/
|
||||
#define GUARD_ROWS (2)
|
||||
|
||||
/*!
|
||||
\brief Lower limit of absolute zoom factor or rotation degrees.
|
||||
*/
|
||||
#define VALUE_LIMIT 0.001
|
||||
|
||||
/*!
|
||||
\brief Returns colorkey info for a surface
|
||||
*/
|
||||
Uint32 _colorkey(SDL_Surface *src)
|
||||
{
|
||||
Uint32 key = 0;
|
||||
SDL_GetColorKey(src, &key);
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Internal target surface sizing function for rotations with trig result return.
|
||||
|
||||
\param width The source surface width.
|
||||
\param height The source surface height.
|
||||
\param angle The angle to rotate in degrees.
|
||||
\param dstwidth The calculated width of the destination surface.
|
||||
\param dstheight The calculated height of the destination surface.
|
||||
\param cangle The sine of the angle
|
||||
\param sangle The cosine of the angle
|
||||
|
||||
*/
|
||||
void _rotozoomSurfaceSizeTrig(int width, int height, double angle,
|
||||
int *dstwidth, int *dstheight,
|
||||
double *cangle, double *sangle)
|
||||
{
|
||||
double x, y, cx, cy, sx, sy;
|
||||
double radangle;
|
||||
int dstwidthhalf, dstheighthalf;
|
||||
|
||||
/*
|
||||
* Determine destination width and height by rotating a centered source box
|
||||
*/
|
||||
radangle = angle * (M_PI / 180.0);
|
||||
*sangle = SDL_sin(radangle);
|
||||
*cangle = SDL_cos(radangle);
|
||||
x = (double)(width / 2);
|
||||
y = (double)(height / 2);
|
||||
cx = *cangle * x;
|
||||
cy = *cangle * y;
|
||||
sx = *sangle * x;
|
||||
sy = *sangle * y;
|
||||
|
||||
dstwidthhalf = MAX((int)
|
||||
SDL_ceil(MAX(MAX(MAX(SDL_fabs(cx + sy), SDL_fabs(cx - sy)), SDL_fabs(-cx + sy)), SDL_fabs(-cx - sy))), 1);
|
||||
dstheighthalf = MAX((int)
|
||||
SDL_ceil(MAX(MAX(MAX(SDL_fabs(sx + cy), SDL_fabs(sx - cy)), SDL_fabs(-sx + cy)), SDL_fabs(-sx - cy))), 1);
|
||||
*dstwidth = 2 * dstwidthhalf;
|
||||
*dstheight = 2 * dstheighthalf;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Internal 32 bit rotozoomer with optional anti-aliasing.
|
||||
|
||||
Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
|
||||
parameters by scanning the destination surface and applying optionally anti-aliasing
|
||||
by bilinear interpolation.
|
||||
Assumes src and dst surfaces are of 32 bit depth.
|
||||
Assumes dst surface was allocated with the correct dimensions.
|
||||
|
||||
\param src Source surface.
|
||||
\param dst Destination surface.
|
||||
\param cx Horizontal center coordinate.
|
||||
\param cy Vertical center coordinate.
|
||||
\param isin Integer version of sine of angle.
|
||||
\param icos Integer version of cosine of angle.
|
||||
\param flipx Flag indicating horizontal mirroring should be applied.
|
||||
\param flipy Flag indicating vertical mirroring should be applied.
|
||||
\param smooth Flag indicating anti-aliasing should be used.
|
||||
*/
|
||||
void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
|
||||
{
|
||||
int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
|
||||
tColorRGBA c00, c01, c10, c11, cswap;
|
||||
tColorRGBA *pc, *sp;
|
||||
int gap;
|
||||
|
||||
/*
|
||||
* Variable setup
|
||||
*/
|
||||
xd = ((src->w - dst->w) << 15);
|
||||
yd = ((src->h - dst->h) << 15);
|
||||
ax = (cx << 16) - (icos * cx);
|
||||
ay = (cy << 16) - (isin * cx);
|
||||
sw = src->w - 1;
|
||||
sh = src->h - 1;
|
||||
pc = (tColorRGBA*) dst->pixels;
|
||||
gap = dst->pitch - dst->w * 4;
|
||||
|
||||
/*
|
||||
* Switch between interpolating and non-interpolating code
|
||||
*/
|
||||
if (smooth) {
|
||||
for (y = 0; y < dst->h; y++) {
|
||||
dy = cy - y;
|
||||
sdx = (ax + (isin * dy)) + xd;
|
||||
sdy = (ay - (icos * dy)) + yd;
|
||||
for (x = 0; x < dst->w; x++) {
|
||||
dx = (sdx >> 16);
|
||||
dy = (sdy >> 16);
|
||||
if (flipx) dx = sw - dx;
|
||||
if (flipy) dy = sh - dy;
|
||||
if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
|
||||
sp = (tColorRGBA *)src->pixels;;
|
||||
sp += ((src->pitch/4) * dy);
|
||||
sp += dx;
|
||||
c00 = *sp;
|
||||
sp += 1;
|
||||
c01 = *sp;
|
||||
sp += (src->pitch/4);
|
||||
c11 = *sp;
|
||||
sp -= 1;
|
||||
c10 = *sp;
|
||||
if (flipx) {
|
||||
cswap = c00; c00=c01; c01=cswap;
|
||||
cswap = c10; c10=c11; c11=cswap;
|
||||
}
|
||||
if (flipy) {
|
||||
cswap = c00; c00=c10; c10=cswap;
|
||||
cswap = c01; c01=c11; c11=cswap;
|
||||
}
|
||||
/*
|
||||
* Interpolate colors
|
||||
*/
|
||||
ex = (sdx & 0xffff);
|
||||
ey = (sdy & 0xffff);
|
||||
t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
|
||||
t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
|
||||
pc->r = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
|
||||
t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
|
||||
pc->g = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
|
||||
t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
|
||||
pc->b = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
|
||||
t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
|
||||
pc->a = (((t2 - t1) * ey) >> 16) + t1;
|
||||
}
|
||||
sdx += icos;
|
||||
sdy += isin;
|
||||
pc++;
|
||||
}
|
||||
pc = (tColorRGBA *) ((Uint8 *) pc + gap);
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < dst->h; y++) {
|
||||
dy = cy - y;
|
||||
sdx = (ax + (isin * dy)) + xd;
|
||||
sdy = (ay - (icos * dy)) + yd;
|
||||
for (x = 0; x < dst->w; x++) {
|
||||
dx = (short) (sdx >> 16);
|
||||
dy = (short) (sdy >> 16);
|
||||
if (flipx) dx = (src->w-1)-dx;
|
||||
if (flipy) dy = (src->h-1)-dy;
|
||||
if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
|
||||
sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
|
||||
sp += dx;
|
||||
*pc = *sp;
|
||||
}
|
||||
sdx += icos;
|
||||
sdy += isin;
|
||||
pc++;
|
||||
}
|
||||
pc = (tColorRGBA *) ((Uint8 *) pc + gap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
\brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
|
||||
|
||||
Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
|
||||
parameters by scanning the destination surface.
|
||||
Assumes src and dst surfaces are of 8 bit depth.
|
||||
Assumes dst surface was allocated with the correct dimensions.
|
||||
|
||||
\param src Source surface.
|
||||
\param dst Destination surface.
|
||||
\param cx Horizontal center coordinate.
|
||||
\param cy Vertical center coordinate.
|
||||
\param isin Integer version of sine of angle.
|
||||
\param icos Integer version of cosine of angle.
|
||||
\param flipx Flag indicating horizontal mirroring should be applied.
|
||||
\param flipy Flag indicating vertical mirroring should be applied.
|
||||
*/
|
||||
void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
|
||||
{
|
||||
int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
|
||||
tColorY *pc, *sp;
|
||||
int gap;
|
||||
|
||||
/*
|
||||
* Variable setup
|
||||
*/
|
||||
xd = ((src->w - dst->w) << 15);
|
||||
yd = ((src->h - dst->h) << 15);
|
||||
ax = (cx << 16) - (icos * cx);
|
||||
ay = (cy << 16) - (isin * cx);
|
||||
sw = src->w - 1;
|
||||
sh = src->h - 1;
|
||||
pc = (tColorY*) dst->pixels;
|
||||
gap = dst->pitch - dst->w;
|
||||
/*
|
||||
* Clear surface to colorkey
|
||||
*/
|
||||
SDL_memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
|
||||
/*
|
||||
* Iterate through destination surface
|
||||
*/
|
||||
for (y = 0; y < dst->h; y++) {
|
||||
dy = cy - y;
|
||||
sdx = (ax + (isin * dy)) + xd;
|
||||
sdy = (ay - (icos * dy)) + yd;
|
||||
for (x = 0; x < dst->w; x++) {
|
||||
dx = (short) (sdx >> 16);
|
||||
dy = (short) (sdy >> 16);
|
||||
if (flipx) dx = (src->w-1)-dx;
|
||||
if (flipy) dy = (src->h-1)-dy;
|
||||
if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
|
||||
sp = (tColorY *) (src->pixels);
|
||||
sp += (src->pitch * dy + dx);
|
||||
*pc = *sp;
|
||||
}
|
||||
sdx += icos;
|
||||
sdy += isin;
|
||||
pc++;
|
||||
}
|
||||
pc += gap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
\brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
|
||||
|
||||
Rotates a 32bit or 8bit 'src' surface to newly created 'dst' surface.
|
||||
'angle' is the rotation in degrees, 'centerx' and 'centery' the rotation center. If 'smooth' is set
|
||||
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
|
||||
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
|
||||
|
||||
\param src The surface to rotozoom.
|
||||
\param angle The angle to rotate in degrees.
|
||||
\param centerx The horizontal coordinate of the center of rotation
|
||||
\param zoomy The vertical coordinate of the center of rotation
|
||||
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
|
||||
\param flipx Set to 1 to flip the image horizontally
|
||||
\param flipy Set to 1 to flip the image vertically
|
||||
\param dstwidth The destination surface width
|
||||
\param dstheight The destination surface height
|
||||
\param cangle The angle cosine
|
||||
\param sangle The angle sine
|
||||
\return The new rotated surface.
|
||||
|
||||
*/
|
||||
|
||||
SDL_Surface *_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle)
|
||||
{
|
||||
SDL_Surface *rz_src;
|
||||
SDL_Surface *rz_dst;
|
||||
int is32bit;
|
||||
int i, src_converted;
|
||||
Uint8 r,g,b;
|
||||
Uint32 colorkey = 0;
|
||||
int colorKeyAvailable = 0;
|
||||
double sangleinv, cangleinv;
|
||||
|
||||
/*
|
||||
* Sanity check
|
||||
*/
|
||||
if (src == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (src->flags & SDL_TRUE/*SDL_SRCCOLORKEY*/)
|
||||
{
|
||||
colorkey = _colorkey(src);
|
||||
SDL_GetRGB(colorkey, src->format, &r, &g, &b);
|
||||
colorKeyAvailable = 1;
|
||||
}
|
||||
/*
|
||||
* Determine if source surface is 32bit or 8bit
|
||||
*/
|
||||
is32bit = (src->format->BitsPerPixel == 32);
|
||||
if ((is32bit) || (src->format->BitsPerPixel == 8)) {
|
||||
/*
|
||||
* Use source surface 'as is'
|
||||
*/
|
||||
rz_src = src;
|
||||
src_converted = 0;
|
||||
} else {
|
||||
/*
|
||||
* New source surface is 32bit with a defined RGBA ordering
|
||||
*/
|
||||
rz_src =
|
||||
SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
|
||||
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
|
||||
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
|
||||
#else
|
||||
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
|
||||
#endif
|
||||
);
|
||||
if(colorKeyAvailable)
|
||||
SDL_SetColorKey(src, 0, 0);
|
||||
|
||||
SDL_BlitSurface(src, NULL, rz_src, NULL);
|
||||
|
||||
if(colorKeyAvailable)
|
||||
SDL_SetColorKey(src, SDL_TRUE /*SDL_SRCCOLORKEY*/, colorkey);
|
||||
src_converted = 1;
|
||||
is32bit = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Determine target size */
|
||||
//_rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, &dstwidth, &dstheight, &cangle, &sangle);
|
||||
|
||||
/*
|
||||
* Calculate target factors from sin/cos and zoom
|
||||
*/
|
||||
sangleinv = sangle*65536.0;
|
||||
cangleinv = cangle*65536.0;
|
||||
|
||||
/*
|
||||
* Alloc space to completely contain the rotated surface
|
||||
*/
|
||||
rz_dst = NULL;
|
||||
if (is32bit) {
|
||||
/*
|
||||
* Target surface is 32bit with source RGBA/ABGR ordering
|
||||
*/
|
||||
rz_dst =
|
||||
SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
|
||||
rz_src->format->Rmask, rz_src->format->Gmask,
|
||||
rz_src->format->Bmask, rz_src->format->Amask);
|
||||
} else {
|
||||
/*
|
||||
* Target surface is 8bit
|
||||
*/
|
||||
rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Check target */
|
||||
if (rz_dst == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Adjust for guard rows */
|
||||
rz_dst->h = dstheight;
|
||||
|
||||
if (colorKeyAvailable == 1){
|
||||
colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
|
||||
|
||||
SDL_FillRect(rz_dst, NULL, colorkey );
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock source surface
|
||||
*/
|
||||
if (SDL_MUSTLOCK(rz_src)) {
|
||||
SDL_LockSurface(rz_src);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check which kind of surface we have
|
||||
*/
|
||||
if (is32bit) {
|
||||
/*
|
||||
* Call the 32bit transformation routine to do the rotation (using alpha)
|
||||
*/
|
||||
_transformSurfaceRGBA(rz_src, rz_dst, centerx, centery,
|
||||
(int) (sangleinv), (int) (cangleinv),
|
||||
flipx, flipy,
|
||||
smooth);
|
||||
/*
|
||||
* Turn on source-alpha support
|
||||
*/
|
||||
//SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
|
||||
SDL_SetColorKey(rz_dst, /*SDL_SRCCOLORKEY*/ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src));
|
||||
} else {
|
||||
/*
|
||||
* Copy palette and colorkey info
|
||||
*/
|
||||
for (i = 0; i < rz_src->format->palette->ncolors; i++) {
|
||||
rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
|
||||
}
|
||||
rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
|
||||
/*
|
||||
* Call the 8bit transformation routine to do the rotation
|
||||
*/
|
||||
transformSurfaceY(rz_src, rz_dst, centerx, centery,
|
||||
(int) (sangleinv), (int) (cangleinv),
|
||||
flipx, flipy);
|
||||
SDL_SetColorKey(rz_dst, /*SDL_SRCCOLORKEY*/ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src));
|
||||
}
|
||||
/*
|
||||
* Unlock source surface
|
||||
*/
|
||||
if (SDL_MUSTLOCK(rz_src)) {
|
||||
SDL_UnlockSurface(rz_src);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup temp surface
|
||||
*/
|
||||
if (src_converted) {
|
||||
SDL_FreeSurface(rz_src);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return destination surface
|
||||
*/
|
||||
return (rz_dst);
|
||||
}
|
||||
|
6
src/render/software/SDL_rotate.h
Normal file
6
src/render/software/SDL_rotate.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef MIN
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
extern SDL_Surface *_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle);
|
||||
extern void _rotozoomSurfaceSizeTrig(int width, int height, double angle, int *dstwidth, int *dstheight, double *cangle, double *sangle);
|
|
@ -45,6 +45,7 @@ TARGETS = \
|
|||
testver$(EXE) \
|
||||
testwm2$(EXE) \
|
||||
torturethread$(EXE) \
|
||||
testrendercopyex$(EXE) \
|
||||
|
||||
all: Makefile $(TARGETS)
|
||||
|
||||
|
@ -171,6 +172,9 @@ testwm2$(EXE): $(srcdir)/testwm2.c $(srcdir)/common.c
|
|||
torturethread$(EXE): $(srcdir)/torturethread.c
|
||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
||||
|
||||
testrendercopyex$(EXE): $(srcdir)/testrendercopyex.c $(srcdir)/common.c
|
||||
$(CC) -o $@ $(srcdir)/testrendercopyex.c $(srcdir)/common.c $(CFLAGS) $(LIBS) @MATHLIB@
|
||||
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
||||
|
||||
|
|
208
test/testrendercopyex.c
Normal file
208
test/testrendercopyex.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely.
|
||||
*/
|
||||
/* Simple program: Move N sprites around on the screen as fast as possible */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "SDL.h"
|
||||
#include "common.h"
|
||||
|
||||
#define WINDOW_WIDTH 640
|
||||
#define WINDOW_HEIGHT 480
|
||||
|
||||
static CommonState *state;
|
||||
|
||||
typedef struct {
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Texture *background;
|
||||
SDL_Texture *sprite;
|
||||
SDL_Rect sprite_rect;
|
||||
int scale_direction;
|
||||
} DrawState;
|
||||
|
||||
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
|
||||
static void
|
||||
quit(int rc)
|
||||
{
|
||||
CommonQuit(state);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
SDL_Texture *
|
||||
LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
|
||||
{
|
||||
SDL_Surface *temp;
|
||||
SDL_Texture *texture;
|
||||
|
||||
/* Load the sprite image */
|
||||
temp = SDL_LoadBMP(file);
|
||||
if (temp == NULL) {
|
||||
fprintf(stderr, "Couldn't load %s: %s", file, SDL_GetError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set transparent pixel as the pixel at (0,0) */
|
||||
if (transparent) {
|
||||
if (temp->format->palette) {
|
||||
SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
|
||||
} else {
|
||||
switch (temp->format->BitsPerPixel) {
|
||||
case 15:
|
||||
SDL_SetColorKey(temp, SDL_TRUE,
|
||||
(*(Uint16 *) temp->pixels) & 0x00007FFF);
|
||||
break;
|
||||
case 16:
|
||||
SDL_SetColorKey(temp, SDL_TRUE, *(Uint16 *) temp->pixels);
|
||||
break;
|
||||
case 24:
|
||||
SDL_SetColorKey(temp, SDL_TRUE,
|
||||
(*(Uint32 *) temp->pixels) & 0x00FFFFFF);
|
||||
break;
|
||||
case 32:
|
||||
SDL_SetColorKey(temp, SDL_TRUE, *(Uint32 *) temp->pixels);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create textures from the image */
|
||||
texture = SDL_CreateTextureFromSurface(renderer, temp);
|
||||
if (!texture) {
|
||||
fprintf(stderr, "Couldn't create texture: %s\n", SDL_GetError());
|
||||
SDL_FreeSurface(temp);
|
||||
return NULL;
|
||||
}
|
||||
SDL_FreeSurface(temp);
|
||||
|
||||
/* We're ready to roll. :) */
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
Draw(DrawState *s)
|
||||
{
|
||||
SDL_Rect viewport;
|
||||
SDL_Texture *target;
|
||||
SDL_Point *center=NULL;
|
||||
SDL_Point origin = {0,0};
|
||||
|
||||
SDL_RenderGetViewport(s->renderer, &viewport);
|
||||
|
||||
target = SDL_CreateTexture(s->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, viewport.w, viewport.h);
|
||||
SDL_SetRenderTarget(s->renderer, target);
|
||||
|
||||
/* Draw the background */
|
||||
SDL_RenderCopy(s->renderer, s->background, NULL, NULL);
|
||||
|
||||
/* Scale and draw the sprite */
|
||||
s->sprite_rect.w += s->scale_direction;
|
||||
s->sprite_rect.h += s->scale_direction;
|
||||
if (s->scale_direction > 0) {
|
||||
center = &origin;
|
||||
if (s->sprite_rect.w >= viewport.w || s->sprite_rect.h >= viewport.h) {
|
||||
s->scale_direction = -1;
|
||||
}
|
||||
} else {
|
||||
if (s->sprite_rect.w <= 1 || s->sprite_rect.h <= 1) {
|
||||
s->scale_direction = 1;
|
||||
}
|
||||
}
|
||||
s->sprite_rect.x = (viewport.w - s->sprite_rect.w) / 2;
|
||||
s->sprite_rect.y = (viewport.h - s->sprite_rect.h) / 2;
|
||||
|
||||
SDL_RenderCopyEx(s->renderer, s->sprite, NULL, &s->sprite_rect, (double)s->sprite_rect.w, center, s->scale_direction);
|
||||
|
||||
SDL_SetRenderTarget(s->renderer, NULL);
|
||||
SDL_RenderCopy(s->renderer, target, NULL, NULL);
|
||||
SDL_DestroyTexture(target);
|
||||
|
||||
/* Update the screen! */
|
||||
SDL_RenderPresent(s->renderer);
|
||||
//SDL_Delay(10);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
DrawState *drawstates;
|
||||
int i, done;
|
||||
SDL_Event event;
|
||||
int frames;
|
||||
Uint32 then, now;
|
||||
|
||||
/* Initialize test framework */
|
||||
state = CommonCreateState(argv, SDL_INIT_VIDEO);
|
||||
if (!state) {
|
||||
return 1;
|
||||
}
|
||||
for (i = 1; i < argc;) {
|
||||
int consumed;
|
||||
|
||||
consumed = CommonArg(state, i);
|
||||
if (consumed == 0) {
|
||||
fprintf(stderr, "Usage: %s %s\n", argv[0], CommonUsage(state));
|
||||
return 1;
|
||||
}
|
||||
i += consumed;
|
||||
}
|
||||
if (!CommonInit(state)) {
|
||||
quit(2);
|
||||
}
|
||||
|
||||
drawstates = SDL_stack_alloc(DrawState, state->num_windows);
|
||||
for (i = 0; i < state->num_windows; ++i) {
|
||||
DrawState *drawstate = &drawstates[i];
|
||||
|
||||
drawstate->window = state->windows[i];
|
||||
drawstate->renderer = state->renderers[i];
|
||||
drawstate->sprite = LoadTexture(drawstate->renderer, "icon.bmp", SDL_TRUE);
|
||||
drawstate->background = LoadTexture(drawstate->renderer, "sample.bmp", SDL_FALSE);
|
||||
if (!drawstate->sprite || !drawstate->background) {
|
||||
quit(2);
|
||||
}
|
||||
SDL_QueryTexture(drawstate->sprite, NULL, NULL,
|
||||
&drawstate->sprite_rect.w, &drawstate->sprite_rect.h);
|
||||
drawstate->scale_direction = 1;
|
||||
}
|
||||
|
||||
/* Main render loop */
|
||||
frames = 0;
|
||||
then = SDL_GetTicks();
|
||||
done = 0;
|
||||
while (!done) {
|
||||
/* Check for events */
|
||||
++frames;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
CommonEvent(state, &event, &done);
|
||||
}
|
||||
for (i = 0; i < state->num_windows; ++i) {
|
||||
Draw(&drawstates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print out some timing information */
|
||||
now = SDL_GetTicks();
|
||||
if (now > then) {
|
||||
double fps = ((double) frames * 1000) / (now - then);
|
||||
printf("%2.2f frames per second\n", fps);
|
||||
}
|
||||
|
||||
SDL_stack_free(drawstates);
|
||||
|
||||
quit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
Loading…
Add table
Add a link
Reference in a new issue