static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Surface *src = (SDL_Surface *) texture->driverdata; SDL_Rect final_rect; if (!surface) { return -1; } if (renderer->viewport.x || renderer->viewport.y) { final_rect.x = (int)(renderer->viewport.x + dstrect->x); final_rect.y = (int)(renderer->viewport.y + dstrect->y); } else { final_rect.x = (int)dstrect->x; final_rect.y = (int)dstrect->y; } final_rect.w = (int)dstrect->w; final_rect.h = (int)dstrect->h; if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) { return SDL_BlitSurface(src, srcrect, surface, &final_rect); } else { /* If scaling is ever done, permanently disable RLE (which doesn't support scaling) * to avoid potentially frequent RLE encoding/decoding. */ SDL_SetSurfaceRLE(surface, 0); return SDL_BlitScaled(src, srcrect, surface, &final_rect); } }
static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, void * pixels, int pitch) { SDL_Surface *surface = SW_ActivateRenderer(renderer); Uint32 src_format; void *src_pixels; if (!surface) { return -1; } if (rect->x < 0 || rect->x+rect->w > surface->w || rect->y < 0 || rect->y+rect->h > surface->h) { SDL_SetError("Tried to read outside of surface bounds"); return -1; } src_format = SDL_MasksToPixelFormatEnum( surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask); src_pixels = (void*)((Uint8 *) surface->pixels + rect->y * surface->pitch + rect->x * surface->format->BytesPerPixel); return SDL_ConvertPixels(rect->w, rect->h, src_format, src_pixels, surface->pitch, format, pixels, pitch); }
static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, void * pixels, int pitch) { SDL_Surface *surface = SW_ActivateRenderer(renderer); Uint32 src_format; void *src_pixels; if (!surface) { return -1; } /* NOTE: The rect is already adjusted according to the viewport by * SDL_RenderReadPixels. */ if (rect->x < 0 || rect->x+rect->w > surface->w || rect->y < 0 || rect->y+rect->h > surface->h) { return SDL_SetError("Tried to read outside of surface bounds"); } src_format = surface->format->format; src_pixels = (void*)((Uint8 *) surface->pixels + rect->y * surface->pitch + rect->x * surface->format->BytesPerPixel); return SDL_ConvertPixels(rect->w, rect->h, src_format, src_pixels, surface->pitch, format, pixels, pitch); }
static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Surface *src = (SDL_Surface *) texture->driverdata; SDL_Rect final_rect; if (!surface) { return -1; } if (renderer->viewport.x || renderer->viewport.y) { final_rect.x = (int)(renderer->viewport.x + dstrect->x); final_rect.y = (int)(renderer->viewport.y + dstrect->y); } else { final_rect.x = (int)dstrect->x; final_rect.y = (int)dstrect->y; } final_rect.w = (int)dstrect->w; final_rect.h = (int)dstrect->h; if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) { return SDL_BlitSurface(src, srcrect, surface, &final_rect); } else { return SDL_BlitScaled(src, srcrect, surface, &final_rect); } }
static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, void * pixels, int pitch) { SDL_Surface *surface = SW_ActivateRenderer(renderer); Uint32 src_format; void *src_pixels; SDL_Rect final_rect; if (!surface) { return -1; } if (renderer->viewport.x || renderer->viewport.y) { final_rect.x = renderer->viewport.x + rect->x; final_rect.y = renderer->viewport.y + rect->y; final_rect.w = rect->w; final_rect.h = rect->h; rect = &final_rect; } if (rect->x < 0 || rect->x+rect->w > surface->w || rect->y < 0 || rect->y+rect->h > surface->h) { return SDL_SetError("Tried to read outside of surface bounds"); } src_format = surface->format->format; src_pixels = (void*)((Uint8 *) surface->pixels + rect->y * surface->pitch + rect->x * surface->format->BytesPerPixel); return SDL_ConvertPixels(rect->w, rect->h, src_format, src_pixels, surface->pitch, format, pixels, pitch); }
SDL_Renderer * SW_CreateRendererForSurface(SDL_Surface * surface) { SDL_Renderer *renderer; SW_RenderData *data; if (!surface) { SDL_SetError("Can't create renderer for NULL surface"); return NULL; } renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); if (!renderer) { SDL_OutOfMemory(); return NULL; } data = (SW_RenderData *) SDL_calloc(1, sizeof(*data)); if (!data) { SW_DestroyRenderer(renderer); SDL_OutOfMemory(); return NULL; } data->surface = surface; data->window = surface; renderer->WindowEvent = SW_WindowEvent; renderer->GetOutputSize = SW_GetOutputSize; renderer->CreateTexture = SW_CreateTexture; renderer->SetTextureColorMod = SW_SetTextureColorMod; renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod; renderer->SetTextureBlendMode = SW_SetTextureBlendMode; renderer->UpdateTexture = SW_UpdateTexture; renderer->LockTexture = SW_LockTexture; renderer->UnlockTexture = SW_UnlockTexture; renderer->SetRenderTarget = SW_SetRenderTarget; renderer->UpdateViewport = SW_UpdateViewport; renderer->UpdateClipRect = SW_UpdateClipRect; renderer->RenderClear = SW_RenderClear; renderer->RenderDrawPoints = SW_RenderDrawPoints; 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; renderer->DestroyRenderer = SW_DestroyRenderer; renderer->info = SW_RenderDriver.info; renderer->driverdata = data; SW_ActivateRenderer(renderer); return renderer; }
SDL_Renderer * SW_CreateRendererForSurface(SDL_Surface * surface) { SDL_Renderer *renderer; SW_RenderData *data; if (!surface) { SDL_SetError("Can't create renderer for NULL surface"); return NULL; } renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); if (!renderer) { SDL_OutOfMemory(); return NULL; } data = (SW_RenderData *) SDL_calloc(1, sizeof(*data)); if (!data) { SW_DestroyRenderer(renderer); SDL_OutOfMemory(); return NULL; } data->surface = surface; data->window = surface; renderer->WindowEvent = SW_WindowEvent; renderer->GetOutputSize = SW_GetOutputSize; renderer->CreateTexture = SW_CreateTexture; renderer->UpdateTexture = SW_UpdateTexture; renderer->LockTexture = SW_LockTexture; renderer->UnlockTexture = SW_UnlockTexture; renderer->SetRenderTarget = SW_SetRenderTarget; renderer->QueueSetViewport = SW_QueueSetViewport; renderer->QueueSetDrawColor = SW_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ renderer->QueueDrawPoints = SW_QueueDrawPoints; renderer->QueueDrawLines = SW_QueueDrawPoints; /* lines and points queue vertices the same way. */ renderer->QueueFillRects = SW_QueueFillRects; renderer->QueueCopy = SW_QueueCopy; renderer->QueueCopyEx = SW_QueueCopyEx; renderer->RunCommandQueue = SW_RunCommandQueue; renderer->RenderReadPixels = SW_RenderReadPixels; renderer->RenderPresent = SW_RenderPresent; renderer->DestroyTexture = SW_DestroyTexture; renderer->DestroyRenderer = SW_DestroyRenderer; renderer->info = SW_RenderDriver.info; renderer->driverdata = data; SW_ActivateRenderer(renderer); return renderer; }
static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Surface *src = (SDL_Surface *) texture->driverdata; SDL_Rect final_rect = *dstrect; if (!surface) { return -1; } return SDL_BlitSurface(src, srcrect, surface, &final_rect); }
static int SW_DisplayModeChanged(SDL_Renderer * renderer) { SW_RenderData *data = (SW_RenderData *) renderer->driverdata; if (data->renderer && data->renderer->DisplayModeChanged) { if (data->renderer->DisplayModeChanged(data->renderer) < 0) { return -1; } } /* Rebind the context to the window area */ data->updateSize = SDL_TRUE; return SW_ActivateRenderer(renderer); }
static int SW_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Rect *final_rects; int i, status; if (!surface) { return -1; } final_rects = SDL_stack_alloc(SDL_Rect, count); if (!final_rects) { return SDL_OutOfMemory(); } if (renderer->viewport.x || renderer->viewport.y) { int x = renderer->viewport.x; int y = renderer->viewport.y; for (i = 0; i < count; ++i) { final_rects[i].x = (int)(x + rects[i].x); final_rects[i].y = (int)(y + rects[i].y); final_rects[i].w = SDL_max((int)rects[i].w, 1); final_rects[i].h = SDL_max((int)rects[i].h, 1); } } else { for (i = 0; i < count; ++i) { final_rects[i].x = (int)rects[i].x; final_rects[i].y = (int)rects[i].y; final_rects[i].w = SDL_max((int)rects[i].w, 1); final_rects[i].h = SDL_max((int)rects[i].h, 1); } } if (renderer->blendMode == SDL_BLENDMODE_NONE) { Uint32 color = SDL_MapRGBA(surface->format, renderer->r, renderer->g, renderer->b, renderer->a); status = SDL_FillRects(surface, final_rects, count, color); } else { status = SDL_BlendFillRects(surface, final_rects, count, renderer->blendMode, renderer->r, renderer->g, renderer->b, renderer->a); } SDL_stack_free(final_rects); return status; }
static int SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points, int count) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Point *final_points; int i, status; if (!surface) { return -1; } final_points = SDL_stack_alloc(SDL_Point, count); if (!final_points) { return SDL_OutOfMemory(); } if (renderer->viewport.x || renderer->viewport.y) { int x = renderer->viewport.x; int y = renderer->viewport.y; for (i = 0; i < count; ++i) { final_points[i].x = (int)(x + points[i].x); final_points[i].y = (int)(y + points[i].y); } } else { for (i = 0; i < count; ++i) { final_points[i].x = (int)points[i].x; final_points[i].y = (int)points[i].y; } } /* Draw the lines! */ if (renderer->blendMode == SDL_BLENDMODE_NONE) { Uint32 color = SDL_MapRGBA(surface->format, renderer->r, renderer->g, renderer->b, renderer->a); status = SDL_DrawLines(surface, final_points, count, color); } else { status = SDL_BlendLines(surface, final_points, count, renderer->blendMode, renderer->r, renderer->g, renderer->b, renderer->a); } SDL_stack_free(final_points); return status; }
static int SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) { SDL_Surface *surface = SW_ActivateRenderer(renderer); if (surface) { if (w) { *w = surface->w; } if (h) { *h = surface->h; } return 0; } else { SDL_SetError("Software renderer doesn't have an output surface"); return -1; } }
static int SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, int count) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Point *temp = NULL; int status; if (!surface) { return -1; } if (renderer->viewport.x || renderer->viewport.y) { int i; int x = renderer->viewport.x; int y = renderer->viewport.y; temp = SDL_stack_alloc(SDL_Point, count); for (i = 0; i < count; ++i) { temp[i].x = x + points[i].x; temp[i].y = y + points[i].y; } points = temp; } /* Draw the lines! */ if (renderer->blendMode == SDL_BLENDMODE_NONE) { Uint32 color = SDL_MapRGBA(surface->format, renderer->r, renderer->g, renderer->b, renderer->a); status = SDL_DrawLines(surface, points, count, color); } else { status = SDL_BlendLines(surface, points, count, renderer->blendMode, renderer->r, renderer->g, renderer->b, renderer->a); } if (temp) { SDL_stack_free(temp); } return status; }
static int SW_RenderClear(SDL_Renderer * renderer) { SDL_Surface *surface = SW_ActivateRenderer(renderer); Uint32 color; SDL_Rect clip_rect; if (!surface) { return -1; } color = SDL_MapRGBA(surface->format, renderer->r, renderer->g, renderer->b, renderer->a); /* By definition the clear ignores the clip rect */ clip_rect = surface->clip_rect; SDL_SetClipRect(surface, NULL); SDL_FillRect(surface, NULL, color); SDL_SetClipRect(surface, &clip_rect); return 0; }
static int SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count) { SDL_Surface *surface = SW_ActivateRenderer(renderer); if (!surface) { return -1; } if (renderer->blendMode == SDL_BLENDMODE_NONE) { Uint32 color = SDL_MapRGBA(surface->format, renderer->r, renderer->g, renderer->b, renderer->a); return SDL_FillRects(surface, rects, count, color); } else { return SDL_BlendFillRects(surface, rects, count, renderer->blendMode, renderer->r, renderer->g, renderer->b, renderer->a); } }
static int SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, int count) { SDL_Surface *surface = SW_ActivateRenderer(renderer); if (!surface) { return -1; } /* Draw the lines! */ if (renderer->blendMode == SDL_BLENDMODE_NONE) { Uint32 color = SDL_MapRGBA(surface->format, renderer->r, renderer->g, renderer->b, renderer->a); return SDL_DrawLines(surface, points, count, color); } else { return SDL_BlendLines(surface, points, count, renderer->blendMode, renderer->r, renderer->g, renderer->b, renderer->a); } }
static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect, const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Surface *src = (SDL_Surface *) texture->driverdata; SDL_Rect final_rect, tmp_rect; SDL_Surface *surface_rotated, *surface_scaled; 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 = (int)(renderer->viewport.x + dstrect->x); final_rect.y = (int)(renderer->viewport.y + dstrect->y); } else { final_rect.x = (int)dstrect->x; final_rect.y = (int)dstrect->y; } final_rect.w = (int)dstrect->w; final_rect.h = (int)dstrect->h; 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 ); if (surface_scaled) { SDL_GetColorKey(src, &colorkey); SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey); tmp_rect = final_rect; tmp_rect.x = 0; tmp_rect.y = 0; retval = SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect); if (!retval) { SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle); surface_rotated = SDLgfx_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 + (int)center->x; abscentery = final_rect.y + (int)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_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect, const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Surface *src = (SDL_Surface *) texture->driverdata; SDL_Rect final_rect, tmp_rect; SDL_Surface *surface_rotated, *surface_scaled; 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 = (int)(renderer->viewport.x + dstrect->x); final_rect.y = (int)(renderer->viewport.y + dstrect->y); } else { final_rect.x = (int)dstrect->x; final_rect.y = (int)dstrect->y; } final_rect.w = (int)dstrect->w; final_rect.h = (int)dstrect->h; /* SDLgfx_rotateSurface doesn't accept a source rectangle, so crop and scale if we need to */ tmp_rect = final_rect; tmp_rect.x = 0; tmp_rect.y = 0; if (srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0) { surface_scaled = src; /* but if we don't need to, just use the original */ retval = 0; } else { SDL_Surface *blit_src = src; Uint32 colorkey; SDL_BlendMode blendMode; Uint8 alphaMod, r, g, b; SDL_bool cloneSource = SDL_FALSE; 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 ); if (!surface_scaled) { return -1; } /* copy the color key, alpha mod, blend mode, and color mod so the scaled surface behaves like the source */ if (SDL_GetColorKey(src, &colorkey) == 0) { SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey); cloneSource = SDL_TRUE; } SDL_GetSurfaceAlphaMod(src, &alphaMod); /* these will be copied to surface_scaled below if necessary */ SDL_GetSurfaceBlendMode(src, &blendMode); SDL_GetSurfaceColorMod(src, &r, &g, &b); /* now we need to blit the src into surface_scaled. since we want to copy the colors from the source to * surface_scaled rather than blend them, etc. we'll need to disable the blend mode, alpha mod, etc. * but we don't want to modify src (in case it's being used on other threads), so we'll need to clone it * before changing the blend options */ cloneSource |= blendMode != SDL_BLENDMODE_NONE || (alphaMod & r & g & b) != 255; if (cloneSource) { blit_src = SDL_ConvertSurface(src, src->format, src->flags); /* clone src */ if (!blit_src) { SDL_FreeSurface(surface_scaled); return -1; } SDL_SetSurfaceAlphaMod(blit_src, 255); /* disable all blending options in blit_src */ SDL_SetSurfaceBlendMode(blit_src, SDL_BLENDMODE_NONE); SDL_SetColorKey(blit_src, 0, 0); SDL_SetSurfaceColorMod(blit_src, 255, 255, 255); SDL_SetSurfaceRLE(blit_src, 0); /* don't RLE encode a surface we'll only use once */ SDL_SetSurfaceAlphaMod(surface_scaled, alphaMod); /* copy blending options to surface_scaled */ SDL_SetSurfaceBlendMode(surface_scaled, blendMode); SDL_SetSurfaceColorMod(surface_scaled, r, g, b); } retval = SDL_BlitScaled(blit_src, srcrect, surface_scaled, &tmp_rect); if (blit_src != src) { SDL_FreeSurface(blit_src); } } if (!retval) { SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, &dstwidth, &dstheight, &cangle, &sangle); surface_rotated = SDLgfx_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 + (int)center->x; abscentery = final_rect.y + (int)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_rotated); } } if (surface_scaled != src) { SDL_FreeSurface(surface_scaled); } return retval; }
static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect, const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip) { SDL_Surface *surface = SW_ActivateRenderer(renderer); SDL_Surface *src = (SDL_Surface *) texture->driverdata; SDL_Rect final_rect, tmp_rect; SDL_Surface *src_clone, *src_rotated, *src_scaled; SDL_Surface *mask = NULL, *mask_rotated = NULL; int retval = 0, dstwidth, dstheight, abscenterx, abscentery; double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y; SDL_BlendMode blendmode; Uint8 alphaMod, rMod, gMod, bMod; int applyModulation = SDL_FALSE; int blitRequired = SDL_FALSE; int isOpaque = SDL_FALSE; if (!surface) { return -1; } if (renderer->viewport.x || renderer->viewport.y) { final_rect.x = (int)(renderer->viewport.x + dstrect->x); final_rect.y = (int)(renderer->viewport.y + dstrect->y); } else { final_rect.x = (int)dstrect->x; final_rect.y = (int)dstrect->y; } final_rect.w = (int)dstrect->w; final_rect.h = (int)dstrect->h; tmp_rect = final_rect; tmp_rect.x = 0; tmp_rect.y = 0; /* It is possible to encounter an RLE encoded surface here and locking it is * necessary because this code is going to access the pixel buffer directly. */ if (SDL_MUSTLOCK(src)) { SDL_LockSurface(src); } /* Clone the source surface but use its pixel buffer directly. * The original source surface must be treated as read-only. */ src_clone = SDL_CreateRGBSurfaceFrom(src->pixels, src->w, src->h, src->format->BitsPerPixel, src->pitch, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask); if (src_clone == NULL) { if (SDL_MUSTLOCK(src)) { SDL_UnlockSurface(src); } return -1; } SDL_GetSurfaceBlendMode(src, &blendmode); SDL_GetSurfaceAlphaMod(src, &alphaMod); SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod); /* SDLgfx_rotateSurface only accepts 32-bit surfaces with a 8888 layout. Everything else has to be converted. */ if (src->format->BitsPerPixel != 32 || SDL_PIXELLAYOUT(src->format->format) != SDL_PACKEDLAYOUT_8888 || !src->format->Amask) { blitRequired = SDL_TRUE; } /* If scaling and cropping is necessary, it has to be taken care of before the rotation. */ if (!(srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0)) { blitRequired = SDL_TRUE; } /* The color and alpha modulation has to be applied before the rotation when using the NONE and MOD blend modes. */ if ((blendmode == SDL_BLENDMODE_NONE || blendmode == SDL_BLENDMODE_MOD) && (alphaMod & rMod & gMod & bMod) != 255) { applyModulation = SDL_TRUE; SDL_SetSurfaceAlphaMod(src_clone, alphaMod); SDL_SetSurfaceColorMod(src_clone, rMod, gMod, bMod); } /* Opaque surfaces are much easier to handle with the NONE blend mode. */ if (blendmode == SDL_BLENDMODE_NONE && !src->format->Amask && alphaMod == 255) { isOpaque = SDL_TRUE; } /* The NONE blend mode requires a mask for non-opaque surfaces. This mask will be used * to clear the pixels in the destination surface. The other steps are explained below. */ if (blendmode == SDL_BLENDMODE_NONE && !isOpaque) { mask = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); if (mask == NULL) { retval = -1; } else { SDL_SetSurfaceBlendMode(mask, SDL_BLENDMODE_MOD); } } /* Create a new surface should there be a format mismatch or if scaling, cropping, * or modulation is required. It's possible to use the source surface directly otherwise. */ if (!retval && (blitRequired || applyModulation)) { SDL_Rect scale_rect = tmp_rect; src_scaled = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); if (src_scaled == NULL) { retval = -1; } else { SDL_SetSurfaceBlendMode(src_clone, SDL_BLENDMODE_NONE); retval = SDL_BlitScaled(src_clone, srcrect, src_scaled, &scale_rect); SDL_FreeSurface(src_clone); src_clone = src_scaled; src_scaled = NULL; } } /* SDLgfx_rotateSurface is going to make decisions depending on the blend mode. */ SDL_SetSurfaceBlendMode(src_clone, blendmode); if (!retval) { SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, &dstwidth, &dstheight, &cangle, &sangle); src_rotated = SDLgfx_rotateSurface(src_clone, angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle); if (src_rotated == NULL) { retval = -1; } if (!retval && mask != NULL) { /* The mask needed for the NONE blend mode gets rotated with the same parameters. */ mask_rotated = SDLgfx_rotateSurface(mask, angle, dstwidth/2, dstheight/2, SDL_FALSE, 0, 0, dstwidth, dstheight, cangle, sangle); if (mask_rotated == NULL) { retval = -1; } } if (!retval) { /* 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 + (int)center->x; abscentery = final_rect.y + (int)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; /* The NONE blend mode needs some special care with non-opaque surfaces. * Other blend modes or opaque surfaces can be blitted directly. */ if (blendmode != SDL_BLENDMODE_NONE || isOpaque) { if (applyModulation == SDL_FALSE) { /* If the modulation wasn't already applied, make it happen now. */ SDL_SetSurfaceAlphaMod(src_rotated, alphaMod); SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod); } retval = SDL_BlitSurface(src_rotated, NULL, surface, &tmp_rect); } else { /* The NONE blend mode requires three steps to get the pixels onto the destination surface. * First, the area where the rotated pixels will be blitted to get set to zero. * This is accomplished by simply blitting a mask with the NONE blend mode. * The colorkey set by the rotate function will discard the correct pixels. */ SDL_Rect mask_rect = tmp_rect; SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE); retval = SDL_BlitSurface(mask_rotated, NULL, surface, &mask_rect); if (!retval) { /* The next step copies the alpha value. This is done with the BLEND blend mode and * by modulating the source colors with 0. Since the destination is all zeros, this * will effectively set the destination alpha to the source alpha. */ SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0); mask_rect = tmp_rect; retval = SDL_BlitSurface(src_rotated, NULL, surface, &mask_rect); if (!retval) { /* The last step gets the color values in place. The ADD blend mode simply adds them to * the destination (where the color values are all zero). However, because the ADD blend * mode modulates the colors with the alpha channel, a surface without an alpha mask needs * to be created. This makes all source pixels opaque and the colors get copied correctly. */ SDL_Surface *src_rotated_rgb; src_rotated_rgb = SDL_CreateRGBSurfaceFrom(src_rotated->pixels, src_rotated->w, src_rotated->h, src_rotated->format->BitsPerPixel, src_rotated->pitch, src_rotated->format->Rmask, src_rotated->format->Gmask, src_rotated->format->Bmask, 0); if (src_rotated_rgb == NULL) { retval = -1; } else { SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD); retval = SDL_BlitSurface(src_rotated_rgb, NULL, surface, &tmp_rect); SDL_FreeSurface(src_rotated_rgb); } } } SDL_FreeSurface(mask_rotated); } if (src_rotated != NULL) { SDL_FreeSurface(src_rotated); } } } if (SDL_MUSTLOCK(src)) { SDL_UnlockSurface(src); } if (mask != NULL) { SDL_FreeSurface(mask); } if (src_clone != NULL) { SDL_FreeSurface(src_clone); } return retval; }
static int SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) { SW_RenderData *data = (SW_RenderData *) renderer->driverdata; SDL_Surface *surface = SW_ActivateRenderer(renderer); const SDL_Rect *viewport = NULL; const SDL_Rect *cliprect = NULL; if (!surface) { return -1; } while (cmd) { switch (cmd->command) { case SDL_RENDERCMD_SETDRAWCOLOR: { break; /* Not used in this backend. */ } case SDL_RENDERCMD_SETVIEWPORT: { viewport = &cmd->data.viewport.rect; SDL_SetClipRect(data->surface, viewport); break; } case SDL_RENDERCMD_SETCLIPRECT: { SDL_assert(viewport != NULL); cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL; if (cliprect) { SDL_Rect clip_rect; clip_rect.x = cliprect->x + viewport->x; clip_rect.y = cliprect->y + viewport->y; clip_rect.w = cliprect->w; clip_rect.h = cliprect->h; SDL_IntersectRect(viewport, &clip_rect, &clip_rect); SDL_SetClipRect(surface, &clip_rect); } else { SDL_SetClipRect(surface, viewport); } break; } case SDL_RENDERCMD_CLEAR: { const Uint8 r = cmd->data.color.r; const Uint8 g = cmd->data.color.g; const Uint8 b = cmd->data.color.b; const Uint8 a = cmd->data.color.a; const SDL_Rect clip_rect = surface->clip_rect; /* By definition the clear ignores the clip rect */ SDL_SetClipRect(surface, NULL); SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, r, g, b, a)); SDL_SetClipRect(surface, &clip_rect); break; } case SDL_RENDERCMD_DRAW_POINTS: { const Uint8 r = cmd->data.draw.r; const Uint8 g = cmd->data.draw.g; const Uint8 b = cmd->data.draw.b; const Uint8 a = cmd->data.draw.a; const int count = (int) cmd->data.draw.count; const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first); const SDL_BlendMode blend = cmd->data.draw.blend; if (blend == SDL_BLENDMODE_NONE) { SDL_DrawPoints(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a)); } else { SDL_BlendPoints(surface, verts, count, blend, r, g, b, a); } break; } case SDL_RENDERCMD_DRAW_LINES: { const Uint8 r = cmd->data.draw.r; const Uint8 g = cmd->data.draw.g; const Uint8 b = cmd->data.draw.b; const Uint8 a = cmd->data.draw.a; const int count = (int) cmd->data.draw.count; const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first); const SDL_BlendMode blend = cmd->data.draw.blend; if (blend == SDL_BLENDMODE_NONE) { SDL_DrawLines(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a)); } else { SDL_BlendLines(surface, verts, count, blend, r, g, b, a); } break; } case SDL_RENDERCMD_FILL_RECTS: { const Uint8 r = cmd->data.draw.r; const Uint8 g = cmd->data.draw.g; const Uint8 b = cmd->data.draw.b; const Uint8 a = cmd->data.draw.a; const int count = (int) cmd->data.draw.count; const SDL_Rect *verts = (SDL_Rect *) (((Uint8 *) vertices) + cmd->data.draw.first); const SDL_BlendMode blend = cmd->data.draw.blend; if (blend == SDL_BLENDMODE_NONE) { SDL_FillRects(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a)); } else { SDL_BlendFillRects(surface, verts, count, blend, r, g, b, a); } break; } case SDL_RENDERCMD_COPY: { SDL_Rect *verts = (SDL_Rect *) (((Uint8 *) vertices) + cmd->data.draw.first); const SDL_Rect *srcrect = verts; SDL_Rect *dstrect = verts + 1; SDL_Texture *texture = cmd->data.draw.texture; SDL_Surface *src = (SDL_Surface *) texture->driverdata; PrepTextureForCopy(cmd); if ( srcrect->w == dstrect->w && srcrect->h == dstrect->h ) { SDL_BlitSurface(src, srcrect, surface, dstrect); } else { /* If scaling is ever done, permanently disable RLE (which doesn't support scaling) * to avoid potentially frequent RLE encoding/decoding. */ SDL_SetSurfaceRLE(surface, 0); SDL_BlitScaled(src, srcrect, surface, dstrect); } break; } case SDL_RENDERCMD_COPY_EX: { const CopyExData *copydata = (CopyExData *) (((Uint8 *) vertices) + cmd->data.draw.first); PrepTextureForCopy(cmd); SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, ©data->srcrect, ©data->dstrect, copydata->angle, ©data->center, copydata->flip); break; } case SDL_RENDERCMD_NO_OP: break; } cmd = cmd->next; } return 0; }