diff -r a4be1e781020 -r dd30bf36ec45 include/SDL_render.h --- a/include/SDL_render.h dom ene 22 23:51:46 2012 -0500 +++ b/include/SDL_render.h lun ene 23 11:45:15 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 srcquad A pointer to the source quad, or NULL for the entire + * texture. + * \param dstquad A pointer to the destination quad, 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 center of rotation (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 dd30bf36ec45 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 lun ene 23 11:45:15 2012 -0300 @@ -1231,6 +1233,47 @@ &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; + + 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; + } + } + + if (texture->native) { + texture = texture->native; + } + + return renderer->RenderCopyEx(renderer, texture, &real_srcrect, + dstrect, angle, center, flip); +} + int SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, void * pixels, int pitch) diff -r a4be1e781020 -r dd30bf36ec45 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 lun ene 23 11:45:15 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 dd30bf36ec45 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 lun ene 23 11:45:15 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,143 @@ 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; + } + + if (center != NULL) { + centerx = (float)center->x; + centery = (float)center->y; + } + else { + // Center in the middle of the rectangle + centerx = (float) dstrect->w / 2.0; + centery = (float) dstrect->h / 2.0; + } + + + 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 dd30bf36ec45 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 lun ene 23 11:45:15 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 dd30bf36ec45 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 lun ene 23 11:45:15 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,104 @@ } 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); + } + + + if (center != NULL) { + centerx = (GLfloat)center->x; + centery = (GLfloat)center->y; + } + else { + // Center in the middle of the rectangle + centerx = (GLfloat) dstrect->w / 2.0; + centery = (GLfloat) dstrect->h / 2.0; + } + + 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 dd30bf36ec45 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 lun ene 23 11:45:15 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,103 @@ 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); + + if (center != NULL) { + centerx = (GLfloat)center->x; + centery = (GLfloat)center->y; + } else { + // Center in the middle of the rectangle + centerx = (GLfloat) dstrect->w / 2.0; + centery = (GLfloat) dstrect->h / 2.0; + } + // 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 dd30bf36ec45 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 lun ene 23 11:45:15 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,183 @@ /* 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 */ + if (center != NULL) { + 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); + + } + else { + // Center in the middle of the rectangle + translate[0] = translate[2] = translate[4] = translate[6] = (GLfloat) (dstrect->w / 2.0 + dstrect->x); + translate[1] = translate[3] = translate[5] = translate[7] = (GLfloat) (dstrect->h / 2.0 + 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 +1462,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 +1487,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 +1698,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 dd30bf36ec45 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 lun ene 23 11:45:15 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; \ } \ ";