/** * \brief Creates a surface from the specified image file name. * * An assertion error occurs if the file cannot be loaded. * * \param file_name Name of the image file to load, relative to the base directory specified. * \param base_directory The base directory to use. */ Surface::Surface(const std::string& file_name, ImageDirectory base_directory): Drawable(), internal_surface(NULL), owns_internal_surface(true), with_colorkey(false), colorkey(0) { std::string prefix = ""; bool language_specific = false; if (base_directory == DIR_SPRITES) { prefix = "sprites/"; } else if (base_directory == DIR_LANGUAGE) { language_specific = true; prefix = "images/"; } std::string prefixed_file_name = prefix + file_name; size_t size; char* buffer; FileTools::data_file_open_buffer(prefixed_file_name, &buffer, &size, language_specific); SDL_RWops* rw = SDL_RWFromMem(buffer, int(size)); this->internal_surface = IMG_Load_RW(rw, 0); FileTools::data_file_close_buffer(buffer); SDL_RWclose(rw); Debug::check_assertion(internal_surface != NULL, StringConcat() << "Cannot load image '" << prefixed_file_name << "'"); with_colorkey = SDL_GetColorKey(internal_surface, &colorkey) == 0; }
SDL_Surface* Blitter::create_surface_from_format(SDL_Surface* surface, int w, int h) { SDL_Surface* new_surface = SDL_CreateRGBSurface(0, w, h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask); Uint8 alpha; if (SDL_GetSurfaceAlphaMod(surface, &alpha) == 0) SDL_SetSurfaceAlphaMod(new_surface, alpha); SDL_BlendMode blend_mode; if (SDL_GetSurfaceBlendMode(surface, &blend_mode) == 0) SDL_SetSurfaceBlendMode(new_surface, blend_mode); Uint8 r, g, b; if (SDL_GetSurfaceColorMod(surface, &r, &g, &b) == 0) SDL_SetSurfaceColorMod(new_surface, r, g, b); if (surface->format->palette) SDL_SetSurfacePalette(new_surface, surface->format->palette); Uint32 colorkey; if (SDL_GetColorKey(surface, &colorkey) == 0) SDL_SetColorKey(new_surface, SDL_TRUE, colorkey); return new_surface; }
/** * \brief Creates a surface form the specified SDL surface. * * This constructor must be used only by lowlevel classes that manipulate directly * SDL dependent surfaces. * * \param internal_surface The internal surface data. It won't be copied. * It must remain valid during the lifetime of this surface. * The destructor will not free it. */ Surface::Surface(SDL_Surface* internal_surface): Drawable(), internal_surface(internal_surface), owns_internal_surface(false), with_colorkey(false), colorkey(0) { with_colorkey = SDL_GetColorKey(internal_surface, &colorkey) == 0; }
int inline Surface::getColorKey(State & state, SDL_Surface * surface){ Uint32 colorKey; if (SDL_GetColorKey(surface, &colorKey) == 0){ state.stack->push<int>(colorKey); return 1; } else{ return 0; } }
static mrb_value mrb_sdl2_video_surface_get_color_key(mrb_state *mrb, mrb_value self) { uint32_t key; SDL_Surface *s = mrb_sdl2_video_surface_get_ptr(mrb, self); if (0 != SDL_GetColorKey(s, &key)) { mruby_sdl2_raise_error(mrb); } return mrb_fixnum_value(key); }
/** Write out the PLTE (and possibly tRNS) chunk to the png. This will create the * palette data to set in the PLTE chunk and set it, and if the colorkey is set * for the surface an appropriate tRNS chunk is generated. * * \param png_ptr A pointer to the png write structure. * \param info_ptr A pointer to the png info structure. * \param surf The surface that is being written to the png. * \return -1 on error, 0 if the palette chunk was written without problems. */ static int write_palette_chunk(png_structp png_ptr, png_infop info_ptr, SDL_Surface *surf) { png_colorp palette; Uint8 *alphas; int slot; SDL_PixelFormat *fmt = surf -> format; SDL_Color *sourcepal = fmt -> palette -> colors; // Write the image header first... png_set_IHDR(png_ptr, info_ptr, surf -> w, surf -> h, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // now sort out the palette if(!(palette = (png_colorp)malloc(fmt -> palette -> ncolors * sizeof(png_color)))) { SDL_SetError("Unable to create memory for palette storage"); return -1; } // Copy the palette over. Can't just use a straight // memcpy as sdl palettes have pad bytes. for(slot = 0; slot < fmt -> palette -> ncolors; ++slot) { memcpy(&palette[slot], &sourcepal[slot], 3); } // Set it... png_set_PLTE(png_ptr, info_ptr, palette, fmt -> palette -> ncolors); // Done with the palette now free(palette); Uint32 colorkey; int ck = SDL_GetColorKey(surf, &colorkey); // If we have a colour key, we need to set up the alphas for each palette colour if(ck == 0) { // According the the PNG spec (section 4.2.1.1) we only need enough entries // to store transparencies up to the transparent pixel. if(!(alphas = (Uint8 *)malloc((colorkey + 1) * sizeof(Uint8)))) { SDL_SetError("Unable to create memory for transparency storage"); return -1; } // Set all of the alpha values to full memset(alphas, 255, (colorkey + 1) * sizeof(Uint8)); // And handle the transparent pixel alphas[colorkey] = 0; // Write the chunk, and then we're done with the transparencies png_set_tRNS(png_ptr, info_ptr, alphas, colorkey + 1, NULL); free(alphas); } return 0; }
/*! \brief Returns colorkey info for a surface */ Uint32 _colorkey(SDL_Surface *src) { Uint32 key = 0; #if (SDL_MINOR_VERSION == 3) SDL_GetColorKey(src, &key); #else if (src) { key = src->format->colorkey; } #endif return key; }
u32 Surface::GetColorKey(void) const { #if SDL_VERSION_ATLEAST(2, 0, 0) if(isValid() && ! amask()) { u32 res = 0; SDL_GetColorKey(surface, &res); return res; } return 0; #else return isValid() && (surface->flags & SDL_SRCCOLORKEY) ? surface->format->colorkey : 0; #endif }
const Color4i Image::colorkey ( void ) const { SDL_Surface* buffer = this->image(); uint32 transparent_color = 0; Color4i key; if ( SDL_GetColorKey ( this->image(), &transparent_color ) != 0 ) { NOM_LOG_ERR ( NOM, SDL_GetError() ); return key; // NULL (-1) } return nom::pixel ( transparent_color, buffer->format ); // SDL_helper function }
u32 Surface::GetColorKey(void) const { if(isValid()) { #if SDL_VERSION_ATLEAST(1, 3, 0) u32 res = 0; SDL_GetColorKey(surface, &res); return res; #else return (surface->flags & SDL_SRCCOLORKEY) ? surface->format->colorkey : 0; #endif } return 0; }
/** * \brief Returns whether a pixel is transparent. * * A pixel is transparent if it corresponds to the colorkey * or if its alpha channel is equal to 0. * * \param index The index of the pixel to test. * \return \c true if the pixel is transparent. */ bool Surface::is_pixel_transparent(int index) const { uint32_t pixel = get_pixel(index); uint32_t colorkey; bool with_colorkey = SDL_GetColorKey(internal_surface.get(), &colorkey) == 0; if (with_colorkey && pixel == colorkey) { // The pixel has the transparency color. return true; } if (internal_surface->format->Amask != 0 // There exists an alpha channel. && (pixel & internal_surface->format->Amask) == 0 // The pixel is fully transparent. ) { return true; } return false; }
void blitMaskedSprite(SDL_Surface *dst, SDL_Surface *src, Uint32 color) { if(SDL_MUSTLOCK(dst)) SDL_LockSurface(dst); if(SDL_MUSTLOCK(src)) SDL_LockSurface(src); const int bytePPdst = dst->format->BytesPerPixel; const int pitchdst = dst->pitch; const int bytePPsrc = src->format->BytesPerPixel; const int pitchsrc = src->pitch; Uint32 colorkey; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GetColorKey(dst, &colorkey); #else colorkey = dst->format->colorkey; #endif for(int y=0;y<dst->h;y++) { for(int x=0;x<dst->w;x++) { Uint8 r,g,b,a; r = g = b = a = 255; byte *srcPtr = (byte*)src->pixels; srcPtr += (pitchsrc*y+x*bytePPsrc); if(colorkey == *srcPtr) { Uint32 newValue = SDL_MapRGBA(dst->format, r, g, b, a); byte *dstPtr = (byte*)dst->pixels; dstPtr += (pitchdst*y+x*bytePPdst); memcpy( dstPtr, &newValue, bytePPdst ); } } } if(SDL_MUSTLOCK(src)) SDL_UnlockSurface(src); if(SDL_MUSTLOCK(dst)) SDL_UnlockSurface(dst); }
void CBSurfaceSDL::GenAlphaMask(SDL_Surface *surface) { delete[] m_AlphaMask; m_AlphaMask = NULL; if (!surface) return; SDL_LockSurface(surface); bool hasColorKey; Uint32 colorKey; Uint8 ckRed, ckGreen, ckBlue; if (SDL_GetColorKey(surface, &colorKey) == 0) { hasColorKey = true; SDL_GetRGB(colorKey, surface->format, &ckRed, &ckGreen, &ckBlue); } else hasColorKey = false; m_AlphaMask = new byte[surface->w * surface->h]; bool hasTransparency = false; for (int y = 0; y < surface->h; y++) { for (int x = 0; x < surface->w; x++) { Uint32 pixel = GetPixel(surface, x, y); Uint8 r, g, b, a; SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a); if (hasColorKey && r == ckRed && g == ckGreen && b == ckBlue) a = 0; m_AlphaMask[y * surface->w + x] = a; if (a < 255) hasTransparency = true; } } SDL_UnlockSurface(surface); if (!hasTransparency) { delete[] m_AlphaMask; m_AlphaMask = NULL; } }
SDL_Surface* Blitter::scale_surface(SDL_Surface* surface, int width, int height) { int i; int j; unsigned char *pixels; unsigned char *new_pixels; int x; int bpp; int new_pitch; SDL_Surface* new_surface; bpp = surface->format->BytesPerPixel; if (bpp == 1) { SDL_Palette* pal = SDL_AllocPalette(256); Uint32 ckey; int useckey = 0; useckey = SDL_GetColorKey(surface, &ckey) == 0; new_surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0); SDL_LockSurface(surface); SDL_LockSurface(new_surface); pixels = static_cast<unsigned char*>(surface->pixels); new_pixels = static_cast<unsigned char*>(new_surface->pixels); new_pitch = new_surface->pitch; memcpy(pal->colors, surface->format->palette->colors, sizeof(SDL_Color) * 256); for (i = 0; i < height; ++i) { x = i * new_pitch; for (j = 0; j < width; ++j) { new_pixels[x] = pixels[(i * surface->h / height) * surface->pitch + j * surface->w / width]; ++x; } } SDL_UnlockSurface(surface); SDL_UnlockSurface(new_surface); SDL_SetSurfacePalette(new_surface, pal); if (useckey) { SDL_SetColorKey(new_surface, SDL_TRUE, ckey); SDL_SetSurfaceRLE(new_surface, SDL_TRUE); } } else { int ix, iy; float fx, fy, fz; unsigned char *p1, *p2, *p3, *p4; new_surface = SDL_CreateRGBSurface(0, width, height, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask); SDL_LockSurface(surface); SDL_LockSurface(new_surface); pixels = static_cast<unsigned char*>(surface->pixels); new_pixels = static_cast<unsigned char*>(new_surface->pixels); new_pitch = new_surface->pitch; for (i = 0; i < height; ++i) { x = i * new_pitch; fy = static_cast<float>(i) * static_cast<float>(surface->h) / static_cast<float>(height); iy = static_cast<int>(fy); fy -= static_cast<float>(iy); for (j = 0; j < width; ++j) { fx = static_cast<float>(j) * static_cast<float>(surface->w) / static_cast<float>(width); ix = static_cast<int>(fx); fx -= static_cast<float>(ix); fz = (fx + fy) / 2; p1 = &pixels[iy * surface->pitch + ix * bpp]; p2 = (iy != surface->h - 1) ? &pixels[(iy + 1) * surface->pitch + ix * bpp] : p1; p3 = (ix != surface->w - 1) ? &pixels[iy * surface->pitch + (ix + 1) * bpp] : p1; p4 = (iy != surface->h - 1 && ix != surface->w - 1) ? &pixels[(iy + 1) * surface->pitch + (ix + 1) * bpp] : p1; new_pixels[x + 0] = static_cast<unsigned char>( (static_cast<float>(p1[0]) * (1 - fy) + static_cast<float>(p2[0]) * fy + static_cast<float>(p1[0]) * (1 - fx) + static_cast<float>(p3[0]) * fx + static_cast<float>(p1[0]) * (1 - fz) + static_cast<float>(p4[0]) * fz) / 3.0 + .5); new_pixels[x + 1] = static_cast<unsigned char>( (static_cast<float>(p1[1]) * (1 - fy) + static_cast<float>(p2[1]) * fy + static_cast<float>(p1[1]) * (1 - fx) + static_cast<float>(p3[1]) * fx + static_cast<float>(p1[1]) * (1 - fz) + static_cast<float>(p4[1]) * fz) / 3.0 + .5); new_pixels[x + 2] = static_cast<unsigned char>( (static_cast<float>(p1[2]) * (1 - fy) + static_cast<float>(p2[2]) * fy + static_cast<float>(p1[2]) * (1 - fx) + static_cast<float>(p3[2]) * fx + static_cast<float>(p1[2]) * (1 - fz) + static_cast<float>(p4[2]) * fz) / 3.0 + .5); if (bpp == 4) { new_pixels[x + 3] = static_cast<unsigned char>( (static_cast<float>(p1[3]) * (1 - fy) + static_cast<float>(p2[3]) * fy + static_cast<float>(p1[3]) * (1 - fx) + static_cast<float>(p3[3]) * fx + static_cast<float>(p1[3]) * (1 - fz) + static_cast<float>(p4[3]) * fz) / 3.0 + .5); } x += bpp; } } SDL_UnlockSurface(surface); SDL_UnlockSurface(new_surface); } return new_surface; }
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; }
SDL_Texture * SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface) { const SDL_PixelFormat *fmt; SDL_bool needAlpha; Uint32 i; Uint32 format; SDL_Texture *texture; CHECK_RENDERER_MAGIC(renderer, NULL); if (!surface) { SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface"); return NULL; } /* See what the best texture format is */ fmt = surface->format; if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) { needAlpha = SDL_TRUE; } else { needAlpha = SDL_FALSE; } format = renderer->info.texture_formats[0]; for (i = 0; i < renderer->info.num_texture_formats; ++i) { if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) && SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) { format = renderer->info.texture_formats[i]; break; } } texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC, surface->w, surface->h); if (!texture) { return NULL; } if (format == surface->format->format) { if (SDL_MUSTLOCK(surface)) { SDL_LockSurface(surface); SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); SDL_UnlockSurface(surface); } else { SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); } } else { SDL_PixelFormat *dst_fmt; SDL_Surface *temp = NULL; /* Set up a destination surface for the texture update */ dst_fmt = SDL_AllocFormat(format); temp = SDL_ConvertSurface(surface, dst_fmt, 0); SDL_FreeFormat(dst_fmt); if (temp) { SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch); SDL_FreeSurface(temp); } else { SDL_DestroyTexture(texture); return NULL; } } { Uint8 r, g, b, a; SDL_BlendMode blendMode; SDL_GetSurfaceColorMod(surface, &r, &g, &b); SDL_SetTextureColorMod(texture, r, g, b); SDL_GetSurfaceAlphaMod(surface, &a); SDL_SetTextureAlphaMod(texture, a); if (SDL_GetColorKey(surface, NULL) == 0) { /* We converted to a texture with alpha format */ SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); } else { SDL_GetSurfaceBlendMode(surface, &blendMode); SDL_SetTextureBlendMode(texture, blendMode); } } return texture; }
int main(int argc, char *argv[]) { int w = 5, h = 5; SDL_Window *window; SDL_Renderer *renderer; SDL_Surface *background; SDL_Rect bg_rect = { 0, 0, 12, 12 }; SDL_Surface *surface; SDL_Rect tgt_rect = { 0, 0, 5, 5 }; Uint32 pf; SDL_Surface *new_surface; SDL_Rect tgt_rect2 = { 6, 0, 5, 5 }; SDL_Texture *bg_tex; Uint32 first_pixel; Uint8 r,g,b,a; Uint32 colour_key; int waiting; SDL_Init(SDL_INIT_VIDEO); window = SDL_CreateWindow("Color key conversion test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 100, 100, 0); renderer = SDL_CreateRenderer(window, -1, 0); SDL_RenderSetScale(renderer, 8, 8); // create green background surface background = SDL_CreateRGBSurface(0, 12, 12, 32, 0,0,0,0); SDL_FillRect(background, &bg_rect, SDL_MapRGB(background->format, 100,200,100)); // create 16-bit surface surface = SDL_CreateRGBSurfaceFrom(pixel_data, w, h, 16, w*2, 0x0000f800,0x000007e0,0x0000001f,0); SDL_SetColorKey(surface, SDL_TRUE, 0xB54A); // blit original surface to left hand side of background SDL_BlitSurface(surface, NULL, background, &tgt_rect); // convert surface to 32-bit (suitable for window) pf = SDL_GetWindowPixelFormat(window); new_surface = SDL_ConvertSurfaceFormat(surface, pf, 0); // blit converted surface to right hand side SDL_BlitSurface(new_surface, NULL, background, &tgt_rect2); // show everything bg_tex = SDL_CreateTextureFromSurface(renderer, background); SDL_RenderCopy(renderer, bg_tex, NULL, &bg_rect); SDL_RenderPresent(renderer); // print value of first pixel first_pixel = ((Uint32 *) new_surface->pixels)[0]; SDL_GetRGBA(first_pixel, new_surface->format, &r,&g,&b,&a); printf("First pixel = %08x (%d,%d,%d alpha %d)\n", first_pixel, r,g,b,a); // print value of colour key SDL_GetColorKey(new_surface, &colour_key); SDL_GetRGB(colour_key, new_surface->format, &r,&g,&b); printf("colour key = %08x (%d,%d,%d)\n", colour_key, r,g,b); waiting = 1; while (waiting) { SDL_Event evt; SDL_WaitEvent(&evt); if (evt.type == SDL_QUIT) waiting = 0; } SDL_FreeSurface(new_surface); SDL_FreeSurface(surface); SDL_DestroyTexture(bg_tex); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
/* Saves an SDL surface to a png file. * TODO: support screen formats. */ int sdl_surface_savepng(SDL_Surface * surf, const char * filename) { png_bytep * rows = NULL; png_colorp pale = NULL; FILE * fout = NULL; png_structp png = NULL; png_infop info = NULL; int colortype; int i = 0; Uint8 * tran = NULL; SDL_PixelFormat * fmt = NULL; SDL_Surface * temp = NULL; if (!surf) { return save_fail("Surface was NULL."); } if (!filename) { return save_fail("Filename was NULL."); } rows = gymalloc(sizeof(png_bytep)*surf->h); if (!rows) { return save_fail("Out of memory."); } for (i = 0; i < surf->h; i++) { rows[i] = ((Uint8 *)surf->pixels) + i*surf->pitch; } /* Create palette and transparency table if needed. */ fmt = surf->format; if (fmt->palette) { pale = malloc(fmt->palette->ncolors * sizeof(png_color)); if (!pale) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Out of memory in saving palette."); } for (i = 0; i < fmt->palette->ncolors; i++) { pale[i].red = fmt->palette->colors[i].r; pale[i].green = fmt->palette->colors[i].g; pale[i].blue = fmt->palette->colors[i].b; } if (surf->flags & SDL_SRCCOLORKEY) { Uint32 colorkey = 0; SDL_GetColorKey(surf, &colorkey); tran = malloc(fmt->palette->ncolors * sizeof(Uint8)); if(!tran) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Out of memory in saving palette transparency."); } for (i = 0; i < fmt->palette->ncolors; i++) { tran[i] = (((unsigned)i) == colorkey) ? 255 : 0; } } } fout = fopen(filename, "wb"); if(!fout) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Couldn't open file for writing."); } png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Couldn't create png_structp"); } info = png_create_info_struct(png); if (!info) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Couldn't create png_infop"); } /* libpng rudely uses longjump to terminate on errors. This in turns causes warning of pissbli clobered variables. Could it suck more? */ if (setjmp(png->jmpbuf)) { /* This give a warning, but it seems to be unavoidable. */ savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Error writing png file."); } /* Set file pointer. */ png_init_io(png, fout); colortype = sdl_surface_pngcolortype(surf); png_set_IHDR(png, info, surf->w, surf->h, 8, colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Write palette if needed. */ if(pale) { png_set_PLTE(png, info, pale, fmt->palette->ncolors); } /* Write transparency table if needed. */ if (tran) { png_set_tRNS(png, info, tran, fmt->palette->ncolors, NULL); } /* Write the image. */ png_write_info(png, info); png_set_packing(png); if(SDL_MUSTLOCK(surf)) { SDL_LockSurface(surf); } png_write_image(png, rows); if(SDL_MUSTLOCK(surf)) { SDL_UnlockSurface(surf); } png_write_end(png, info); /* Clean up. */ savepng_done(rows, fout, png, info, temp, pale, tran); return 0; }
void GroundMap::put_alpha_surface(Surface provider, Surface sprovider, int x_pos, int y_pos, int real_x_arg, int real_y_arg) { if (sprovider.get_surface()->format->BitsPerPixel != 8 && sprovider.get_surface()->format->BitsPerPixel != 24 && sprovider.get_surface()->format->BitsPerPixel != 32) { log_error("Image has wrong color depth: %1%", static_cast<int>(sprovider.get_surface()->format->BitsPerPixel)); return; } int swidth = sprovider.get_width(); int twidth = provider.get_width(); int spitch = sprovider.get_pitch(); int tpitch = provider.get_pitch(); int start_x = std::max(0, -x_pos); int start_y = std::max(0, -y_pos); int end_x = std::min(swidth, twidth - x_pos); int end_y = std::min(sprovider.get_height(), provider.get_height() - y_pos); if (end_x - start_x <= 0 || end_y - start_y <= 0) return; provider.lock(); sprovider.lock(); Uint8* target_buf = static_cast<Uint8*>(provider.get_data()); Uint8* source_buf = static_cast<Uint8*>(sprovider.get_data()); Uint32 colorkey; if (sprovider.get_surface()->format->BitsPerPixel == 32) { for (int y = start_y; y < end_y; ++y) { Uint8* tptr = target_buf + tpitch*(y+y_pos) + 4*(x_pos + start_x); Uint8* sptr = source_buf + spitch*y + 4*start_x; for (int x = start_x; x < end_x; ++x) { if (sptr[3] == 255 && colmap->getpixel(real_x_arg+x, real_y_arg+y) != Groundtype::GP_SOLID) { tptr[3] = 0; } tptr += 4; sptr += 4; } } } else if (SDL_GetColorKey(sprovider.get_surface(), &colorkey) == 0) { for (int y = start_y; y < end_y; ++y) { Uint8* tptr = target_buf + tpitch*(y+y_pos) + 4*(x_pos + start_x); Uint8* sptr = source_buf + spitch*y + start_x; for (int x = start_x; x < end_x; ++x) { if (*sptr != colorkey && colmap->getpixel(real_x_arg+x, real_y_arg+y) != Groundtype::GP_SOLID) { tptr[3] = 0; } tptr += 4; sptr += 1; } } } else { // opaque source surface, so we can use the same code for 24bpp and indexed for (int y = start_y; y < end_y; ++y) { Uint8* tptr = target_buf + tpitch*(y+y_pos) + 4*(x_pos + start_x); for (int x = start_x; x < end_x; ++x) { if (colmap->getpixel(real_x_arg+x, real_y_arg+y) != Groundtype::GP_SOLID) { tptr[3] = 0; } tptr += 4; } } } sprovider.unlock(); provider.unlock(); }
int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){ #ifdef IMPLEMENT_SAVE_PNG png_structp png_ptr; png_infop info_ptr; SDL_PixelFormat *fmt=NULL; SDL_Surface *tempsurf=NULL; int ret,funky_format; unsigned int i; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_BlendMode temp_blend; bool used_blend = false; #else Uint8 temp_alpha; bool used_alpha = false; #endif png_colorp palette; Uint8 *palette_alpha=NULL; png_byte **row_pointers=NULL; png_ptr=NULL;info_ptr=NULL;palette=NULL;ret=-1; funky_format=0; if( !src || !surf) { goto savedone; /* Nothing to do. */ } row_pointers=(png_byte **)malloc(surf->h * sizeof(png_byte*)); if (!row_pointers) { SDL_SetError("Couldn't allocate memory for rowpointers"); goto savedone; } png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (!png_ptr){ SDL_SetError("Couldn't allocate memory for PNG file"); goto savedone; } info_ptr= png_create_info_struct(png_ptr); if (!info_ptr){ SDL_SetError("Couldn't allocate image information for PNG file"); goto savedone; } /* setup custom writer functions */ png_set_write_fn(png_ptr,(voidp)src,png_write_data,NULL); if (setjmp(png_jmpbuf(png_ptr))){ SDL_SetError("Unknown error writing PNG"); goto savedone; } if(compression>Z_BEST_COMPRESSION) compression=Z_BEST_COMPRESSION; if(compression == Z_NO_COMPRESSION) // No compression { png_set_filter(png_ptr,0,PNG_FILTER_NONE); png_set_compression_level(png_ptr,Z_NO_COMPRESSION); } else if(compression<0) // Default compression png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION); else png_set_compression_level(png_ptr,compression); fmt=surf->format; if(fmt->BitsPerPixel==8){ /* Paletted */ png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); palette=(png_colorp) malloc(fmt->palette->ncolors * sizeof(png_color)); if (!palette) { SDL_SetError("Couldn't create memory for palette"); goto savedone; } for (i=0;i<fmt->palette->ncolors;i++) { palette[i].red=fmt->palette->colors[i].r; palette[i].green=fmt->palette->colors[i].g; palette[i].blue=fmt->palette->colors[i].b; } png_set_PLTE(png_ptr,info_ptr,palette,fmt->palette->ncolors); #if SDL_VERSION_ATLEAST(2, 0, 0) Uint32 colorkey; if (SDL_GetColorKey(surf, &colorkey) == 0) { #else if (surf->flags&SDL_SRCCOLORKEY) { Uint32 colorkey = fmt->colorkey; #endif palette_alpha=(Uint8 *)malloc((colorkey+1)*sizeof(Uint8)); if (!palette_alpha) { SDL_SetError("Couldn't create memory for palette transparency"); goto savedone; } /* FIXME: memset? */ for (i=0;i<(colorkey+1);i++) { palette_alpha[i]=255; } palette_alpha[colorkey]=0; png_set_tRNS(png_ptr,info_ptr,palette_alpha,colorkey+1,NULL); } }else{ /* Truecolor */ if (fmt->Amask) { png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } else { png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } } png_write_info(png_ptr, info_ptr); if (fmt->BitsPerPixel==8) { /* Paletted */ for(i=0;i<surf->h;i++){ row_pointers[i]= ((png_byte*)surf->pixels) + i*surf->pitch; } if(SDL_MUSTLOCK(surf)){ SDL_LockSurface(surf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(surf)){ SDL_UnlockSurface(surf); } }else{ /* Truecolor */ if(fmt->BytesPerPixel==3){ if(fmt->Amask){ /* check for 24 bit with alpha */ funky_format=1; }else{ /* Check for RGB/BGR/GBR/RBG/etc surfaces.*/ #if SDL_BYTEORDER == SDL_BIG_ENDIAN if(fmt->Rmask!=0xFF0000 || fmt->Gmask!=0x00FF00 || fmt->Bmask!=0x0000FF){ #else if(fmt->Rmask!=0x0000FF || fmt->Gmask!=0x00FF00 || fmt->Bmask!=0xFF0000){ #endif funky_format=1; } } }else if (fmt->BytesPerPixel==4){ if (!fmt->Amask) { /* check for 32bit but no alpha */ funky_format=1; }else{ /* Check for ARGB/ABGR/GBAR/RABG/etc surfaces.*/ #if SDL_BYTEORDER == SDL_BIG_ENDIAN if(fmt->Rmask!=0xFF000000 || fmt->Gmask!=0x00FF0000 || fmt->Bmask!=0x0000FF00 || fmt->Amask!=0x000000FF){ #else if(fmt->Rmask!=0x000000FF || fmt->Gmask!=0x0000FF00 || fmt->Bmask!=0x00FF0000 || fmt->Amask!=0xFF000000){ #endif funky_format=1; } } }else{ /* 555 or 565 16 bit color */ funky_format=1; } if (funky_format) { /* Allocate non-funky format, and copy pixeldata in*/ if(fmt->Amask){ #if SDL_VERSION_ATLEAST(2, 0, 0) tempsurf = SDL_CreateRGBSurface(0, surf->w, surf->h, 24, SURFACE_MASK_WITH_ALPHA); #else tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24, SURFACE_MASK_WITH_ALPHA); #endif }else{ #if SDL_VERSION_ATLEAST(2, 0, 0) tempsurf = SDL_CreateRGBSurface(0, surf->w, surf->h, 24, SURFACE_MASK_WITHOUT_ALPHA); #else tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24, SURFACE_MASK_WITHOUT_ALPHA); #endif } if(!tempsurf){ SDL_SetError("Couldn't allocate temp surface"); goto savedone; } #if SDL_VERSION_ATLEAST(2, 0, 0) if(SDL_GetSurfaceBlendMode(surf, &temp_blend) == 0){ used_blend = true; SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE); } #else if(surf->flags&SDL_SRCALPHA) { temp_alpha = fmt->alpha; used_alpha = true; SDL_SetAlpha(surf,0,255); /* Set for an opaque blit */ } #endif if(SDL_BlitSurface(surf, NULL, tempsurf, NULL)!=0){ SDL_SetError("Couldn't blit surface to temp surface"); SDL_FreeSurface(tempsurf); goto savedone; } #if SDL_VERSION_ATLEAST(2, 0, 0) if (used_blend) { SDL_SetSurfaceBlendMode(surf, temp_blend); /* Restore blend settings*/ } #else if(used_alpha) { SDL_SetAlpha(surf, SDL_SRCALPHA, (Uint8)temp_alpha); /* Restore alpha settings*/ } #endif for(i=0;i<tempsurf->h;i++){ row_pointers[i]= ((png_byte*)tempsurf->pixels) + i*tempsurf->pitch; } if(SDL_MUSTLOCK(tempsurf)){ SDL_LockSurface(tempsurf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(tempsurf)){ SDL_UnlockSurface(tempsurf); } SDL_FreeSurface(tempsurf); } else { for(i=0;i<surf->h;i++){ row_pointers[i]= ((png_byte*)surf->pixels) + i*surf->pitch; } if(SDL_MUSTLOCK(surf)){ SDL_LockSurface(surf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(surf)){ SDL_UnlockSurface(surf); } } } png_write_end(png_ptr, NULL); ret=0; /* got here, so nothing went wrong. YAY! */ savedone: /* clean up and return */ png_destroy_write_struct(&png_ptr,&info_ptr); if (palette) { free(palette); } if (palette_alpha) { free(palette_alpha); } if (row_pointers) { free(row_pointers); } return ret; #else return -1; #endif }