diff -r a4be1e781020 -r 65560856a220 include/SDL_render.h --- a/include/SDL_render.h dom ene 22 23:51:46 2012 -0500 +++ b/include/SDL_render.h mié ene 25 13:26:16 2012 -0300 @@ -105,6 +105,16 @@ } 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 */ struct SDL_Renderer; @@ -599,6 +609,27 @@ 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. diff -r a4be1e781020 -r 65560856a220 src/render/SDL_render.c --- a/src/render/SDL_render.c dom ene 22 23:51:46 2012 -0500 +++ b/src/render/SDL_render.c mié ene 25 13:26:16 2012 -0300 @@ -1231,6 +1233,62 @@ &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) diff -r a4be1e781020 -r 65560856a220 src/render/SDL_sysrender.h --- a/src/render/SDL_sysrender.h dom ene 22 23:51:46 2012 -0500 +++ b/src/render/SDL_sysrender.h mié ene 25 13:26:16 2012 -0300 @@ -88,6 +88,9 @@ 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); diff -r a4be1e781020 -r 65560856a220 src/render/direct3d/SDL_render_d3d.c --- a/src/render/direct3d/SDL_render_d3d.c dom ene 22 23:51:46 2012 -0500 +++ b/src/render/direct3d/SDL_render_d3d.c mié ene 25 13:26:16 2012 -0300 @@ -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 #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 @@ 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 @@ D3DTEXTUREFILTERTYPE scaleMode; IDirect3DSurface9 *defaultRenderTarget; IDirect3DSurface9 *currentRenderTarget; + void* d3dxDLL; + ID3DXMatrixStack *matrixStack; } D3D_RenderData; typedef struct @@ -347,6 +437,8 @@ 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 @@ SDL_UnloadObject(data->d3dDLL); data->d3dDLL = NULL; } + + for (d3dxVersion=50;d3dxVersion>0;d3dxVersion--) { + sprintf(d3dxDLLFile, "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->matrixStack) { + if (data->d3dxDLL) SDL_UnloadObject(data->d3dxDLL); + } } - if (!data->d3d) { + + + + if (!data->d3d || !data->matrixStack) { SDL_free(renderer); SDL_free(data); SDL_SetError("Unable to create Direct3D interface"); @@ -395,6 +507,7 @@ 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 @@ 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) diff -r a4be1e781020 -r 65560856a220 src/render/opengl/SDL_glfuncs.h --- a/src/render/opengl/SDL_glfuncs.h dom ene 22 23:51:46 2012 -0500 +++ b/src/render/opengl/SDL_glfuncs.h mié ene 25 13:26:16 2012 -0300 @@ -279,14 +279,14 @@ 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 @@ (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 @@ 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)) diff -r a4be1e781020 -r 65560856a220 src/render/opengl/SDL_render_gl.c --- a/src/render/opengl/SDL_render_gl.c dom ene 22 23:51:46 2012 -0500 +++ b/src/render/opengl/SDL_render_gl.c mié ene 25 13:26:16 2012 -0300 @@ -65,6 +65,9 @@ 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 @@ 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; @@ -1019,6 +1023,96 @@ } 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) { diff -r a4be1e781020 -r 65560856a220 src/render/opengles/SDL_render_gles.c --- a/src/render/opengles/SDL_render_gles.c dom ene 22 23:51:46 2012 -0500 +++ b/src/render/opengles/SDL_render_gles.c mié ene 25 13:26:16 2012 -0300 @@ -71,6 +71,9 @@ 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); @@ -303,6 +306,7 @@ 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; @@ -951,6 +955,98 @@ 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) { diff -r a4be1e781020 -r 65560856a220 src/render/opengles2/SDL_render_gles2.c --- a/src/render/opengles2/SDL_render_gles2.c dom ene 22 23:51:46 2012 -0500 +++ b/src/render/opengles2/SDL_render_gles2.c mié ene 25 13:26:16 2012 -0300 @@ -112,7 +112,9 @@ 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 @@ -626,6 +628,8 @@ 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) @@ -938,6 +942,9 @@ 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); @@ -1239,6 +1246,175 @@ /* 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); + } + 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); @@ -1278,6 +1454,19 @@ 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; @@ -1290,6 +1479,8 @@ 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"); @@ -1499,6 +1690,7 @@ 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; diff -r a4be1e781020 -r 65560856a220 src/render/opengles2/SDL_shaders_gles2.c --- a/src/render/opengles2/SDL_shaders_gles2.c dom ene 22 23:51:46 2012 -0500 +++ b/src/render/opengles2/SDL_shaders_gles2.c mié ene 25 13:26:16 2012 -0300 @@ -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; \ } \ "; diff -r a4be1e781020 -r 65560856a220 src/render/software/SDL_render_sw.c --- a/src/render/software/SDL_render_sw.c dom ene 22 23:51:46 2012 -0500 +++ b/src/render/software/SDL_render_sw.c mié ene 25 13:26:16 2012 -0300 @@ -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 @@ 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 @@ 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,100 @@ } 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) { + SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect); + _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) { diff -r a4be1e781020 -r 65560856a220 src/render/software/SDL_rotate.c --- /dev/null jue ene 01 00:00:00 1970 +0000 +++ b/src/render/software/SDL_rotate.c mié ene 25 13:26:16 2012 -0300 @@ -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 +#endif + +#include +#include + +#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 = sin(radangle); + *cangle = 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) + ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1); + dstheighthalf = MAX((int) + ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), 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 + */ + 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); +} + diff -r a4be1e781020 -r 65560856a220 src/render/software/SDL_rotate.h --- /dev/null jue ene 01 00:00:00 1970 +0000 +++ b/src/render/software/SDL_rotate.h mié ene 25 13:26:16 2012 -0300 @@ -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); \ No newline at end of file