/** * \brief Creates a hardware texture from the software surface. * * Also converts the software surface to a preferred format if necessary. */ void Surface::create_texture_from_surface() { SDL_Renderer* main_renderer = Video::get_renderer(); if (main_renderer != nullptr) { Debug::check_assertion(internal_surface != nullptr, "Missing software surface to create texture from"); // Create the texture. internal_texture = SDL_Texture_UniquePtr( SDL_CreateTexture( main_renderer, Video::get_pixel_format()->format, SDL_TEXTUREACCESS_STATIC, internal_surface->w, internal_surface->h ) ); SDL_SetTextureBlendMode(internal_texture.get(), get_sdl_blend_mode()); // Copy the pixels of the software surface to the GPU texture. SDL_UpdateTexture(internal_texture.get(), nullptr, internal_surface->pixels, internal_surface->pitch); SDL_GetSurfaceAlphaMod(internal_surface.get(), &opacity); } }
SDL_Surface *image_sdl_set_alpha(SDL_Surface *src, uint8_t alpha) { int ret; SDL_Surface *surf; Uint8 swap; assert(src); surf = image_sdl_create((uint32_t)src->w, (uint32_t)src->h, color_transparent); if(surf == NULL) { sg_log_err("image_create returns null."); return NULL; } SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_NONE); ret = SDL_GetSurfaceAlphaMod(src, &swap); if(ret != 0) { sg_log_err("SDL_GetSurfaceAlphaMod failure."); return NULL; } SDL_SetSurfaceAlphaMod(src, alpha); /* Set new alpha degree. */ SDL_BlitSurface(src, NULL, surf, NULL); SDL_SetSurfaceAlphaMod(src, swap); /* Reset to original alpha degree. */ return surf; }
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 hardware texture from the software surface. * * Also converts the software surface to a preferred format if necessary. */ void Surface::create_texture_from_surface() { SDL_Renderer* main_renderer = Video::get_renderer(); if (main_renderer != NULL) { Debug::check_assertion(internal_surface != NULL, "Missing software surface to create texture from"); // Make sure the software surface has the same format as the texture. // This is because SDL_UpdateTexture does not have a format parameter // for performance reasons. convert_software_surface(); // Create the texture. internal_texture = SDL_CreateTexture( main_renderer, Video::get_pixel_format()->format, SDL_TEXTUREACCESS_STATIC, internal_surface->w, internal_surface->h ); SDL_SetTextureBlendMode(internal_texture, SDL_BLENDMODE_BLEND); // Copy the pixels of the software surface to the GPU texture. SDL_UpdateTexture(internal_texture, NULL, internal_surface->pixels, internal_surface->pitch); SDL_GetSurfaceAlphaMod(internal_surface, &internal_opacity); } }
void MoveSprite(SDL_Surface * screen, SDL_Surface * light) { SDL_Rect updates[2]; Uint8 alpha; /* Erase the sprite if it was visible */ if (sprite_visible) { updates[0] = position; SDL_BlitSurface(backing, NULL, screen, &updates[0]); } else { updates[0].x = 0; updates[0].y = 0; updates[0].w = 0; updates[0].h = 0; sprite_visible = 1; } /* Since the sprite is off the screen, we can do other drawing without being overwritten by the saved area behind the sprite. */ if (light != NULL) { int x, y; SDL_GetMouseState(&x, &y); FlashLight(screen, light, x, y); } /* Move the sprite, bounce at the wall */ position.x += x_vel; if ((position.x < 0) || (position.x >= screen->w)) { x_vel = -x_vel; position.x += x_vel; } position.y += y_vel; if ((position.y < 0) || (position.y >= screen->h)) { y_vel = -y_vel; position.y += y_vel; } /* Update transparency (fade in and out) */ SDL_GetSurfaceAlphaMod(sprite, &alpha); if (((int) alpha + alpha_vel) < 0) { alpha_vel = -alpha_vel; } else if (((int) alpha + alpha_vel) > 255) { alpha_vel = -alpha_vel; } SDL_SetAlpha(sprite, SDL_SRCALPHA, (Uint8) (alpha + alpha_vel)); /* Save the area behind the sprite */ updates[1] = position; SDL_BlitSurface(screen, &updates[1], backing, NULL); /* Blit the sprite onto the screen */ updates[1] = position; SDL_BlitSurface(sprite, NULL, screen, &updates[1]); /* Make it so! */ SDL_UpdateRects(screen, 2, updates); }
Uint8 Surface::getAlphaMod(void) { Uint8 alpha = 255; if(SDL_GetSurfaceAlphaMod(sdlSurface, &alpha) == 0) { Logger::Error(SDL_GetError()); } return alpha; }
int inline Surface::getAlphaMod(State & state, SDL_Surface * surface){ Uint8 alpha; if (SDL_GetSurfaceAlphaMod(surface, &alpha) == 0){ state.stack->push<int>(alpha); return 1; } else{ return 0; } }
static mrb_value mrb_sdl2_video_surface_get_alpha_mod(mrb_state *mrb, mrb_value self) { uint8_t alpha; SDL_Surface *s = mrb_sdl2_video_surface_get_ptr(mrb, self); if (0 != SDL_GetSurfaceAlphaMod(s, &alpha)) { mruby_sdl2_raise_error(mrb); } return mrb_fixnum_value(alpha); }
/** * \brief Returns the SDL_Surface corresponding to the requested file. * * The returned SDL_Surface has to be manually deleted. * * \param file_name Name of the image file to load, relative to the base directory specified. * \param base_directory The base directory to use. * \return The SDL_Surface. */ SDL_Surface* Surface::get_surface_from_file( const std::string& file_name, ImageDirectory base_directory) { 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; if (!QuestFiles::data_file_exists(prefixed_file_name, language_specific)) { // File not found. return nullptr; } const std::string& buffer = QuestFiles::data_file_read(prefixed_file_name, language_specific); SDL_RWops* rw = SDL_RWFromMem(const_cast<char*>(buffer.data()), (int) buffer.size()); SDL_Surface* software_surface = IMG_Load_RW(rw, 0); SDL_RWclose(rw); Debug::check_assertion(software_surface != nullptr, std::string("Cannot load image '") + prefixed_file_name + "'"); SDL_PixelFormat* pixel_format = Video::get_pixel_format(); if (software_surface->format->format == pixel_format->format) { return software_surface; } // Convert to the preferred pixel format. uint8_t opacity; SDL_GetSurfaceAlphaMod(software_surface, &opacity); SDL_Surface* converted_surface = SDL_ConvertSurface( software_surface, pixel_format, 0 ); Debug::check_assertion(converted_surface != nullptr, "Failed to convert software surface"); SDL_FreeSurface(software_surface); SDL_SetSurfaceAlphaMod(converted_surface, opacity); // Re-apply the alpha. SDL_SetSurfaceBlendMode(converted_surface, SDL_BLENDMODE_BLEND); return converted_surface; }
uint8 Image::alpha ( void ) const { uint8 alpha; if ( SDL_GetSurfaceAlphaMod ( this->image(), &alpha ) != 0 ) { NOM_LOG_ERR ( NOM, SDL_GetError() ); return Color4i::ALPHA_OPAQUE; } return alpha; }
u32 Surface::alpha(void) const { #if SDL_VERSION_ATLEAST(2, 0, 0) if(isValid()) { u8 alpha = 0; SDL_GetSurfaceAlphaMod(surface, &alpha); return alpha; } return 0; #else return isValid() ? surface->format->alpha : 0; #endif }
u8 Surface::alpha(void) const { if(isValid()) { #if SDL_VERSION_ATLEAST(1, 3, 0) u8 alpha = 0; SDL_GetSurfaceAlphaMod(surface, &alpha); return alpha; #else return surface->format->alpha; #endif } return 0; }
/** * \brief Converts the software surface to the preferred pixel format * (32-bit with alpha channel). */ void Surface::convert_software_surface() { Debug::check_assertion(internal_surface != NULL, "Missing software surface to convert"); SDL_PixelFormat* pixel_format = Video::get_pixel_format(); if (internal_surface->format->format != pixel_format->format) { // Convert to the preferred pixel format. uint8_t opacity; SDL_GetSurfaceAlphaMod(internal_surface, &opacity); SDL_Surface* converted_surface = SDL_ConvertSurface( internal_surface, pixel_format, 0 ); Debug::check_assertion(converted_surface != NULL, "Failed to convert software surface"); SDL_FreeSurface(internal_surface); internal_surface = converted_surface; SDL_SetSurfaceAlphaMod(internal_surface, opacity); // Re-apply the alpha. } }
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; }
int loadFonts() { TTF_Font *font = NULL; SDL_Surface *fontSurface = NULL; SDL_Surface *tmp = NULL; Uint32 saved_flags; Uint8 saved_alpha; static SDL_Color fontColour = {255,255,255}; char letter[2]; int i; char *p; letter[1] = 0; p = findFile(va("%s/%s", MISCDIR, video.fontFile)); if (!p) { conAdd(LERR, "Could not open font"); return 0; } font = TTF_OpenFont(p, video.fontSize); if (!font) { conAdd(LERR, "Could not open %s", p); return 0; } TTF_SetFontStyle(font, TTF_STYLE_NORMAL); #ifdef TTF_HINTING_NORMAL TTF_SetFontHinting(font, TTF_HINTING_NORMAL); #endif memset(fonts, 0, sizeof(fonts)); fontHeight = 0; for (i = 32; i < 128; i++) { letter[0] = i; fontSurface = TTF_RenderText_Blended(font, letter, fontColour); if (!fontSurface) { #ifdef WIN32 MessageBox(NULL, TTF_GetError(), "gravit: font engine error", MB_OK); #else printf("%s\n", TTF_GetError()); #endif TTF_CloseFont(font); return 0; } fonts[i].ow = fontSurface->w; fonts[i].oh = fontSurface->h; if (fonts[i].oh > fontHeight) fontHeight = (float)fonts[i].oh; fonts[i].w = gfxPowerOfTwo(fonts[i].ow); fonts[i].h = gfxPowerOfTwo(fonts[i].oh); if (fonts[i].w > fonts[i].h) fonts[i].h = fonts[i].w; if (fonts[i].h > fonts[i].w) fonts[i].w = fonts[i].h; tmp = SDL_CreateRGBSurface(SDL_SWSURFACE, fonts[i].w, fonts[i].h, 32, #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks depend on byteorder */ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); #endif if (!tmp) { TTF_CloseFont(font); SDL_FreeSurface(fontSurface); return 0; } /* Save the alpha blending attributes */ saved_flags = fontSurface->flags & (SDL_SRCALPHA|SDL_RLEACCELOK); #if SDL_VERSION_ATLEAST(1, 3, 0) SDL_GetSurfaceAlphaMod(fontSurface, &saved_alpha); SDL_SetSurfaceAlphaMod(fontSurface, 0xFF); #else saved_alpha = fontSurface->format->alpha; if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { SDL_SetAlpha(fontSurface, 0, 0); } #endif /* copy to texture surface */ if (SDL_BlitSurface(fontSurface, NULL, tmp, NULL)) { TTF_CloseFont(font); SDL_FreeSurface(tmp); SDL_FreeSurface(fontSurface); return 0; } glGenTextures(1, &fonts[i].id); glCheck(); glBindTexture(GL_TEXTURE_2D, fonts[i].id); glCheck(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fonts[i].w, fonts[i].h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmp->pixels); glCheck(); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glCheck(); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glCheck(); SDL_FreeSurface(tmp); SDL_FreeSurface(fontSurface); } TTF_CloseFont(font); return 1; }
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; }
static int setup_test(int argc, char **argv) { const char *dumpfile = NULL; SDL_Surface *bmp = NULL; Uint32 dstbpp = 32; Uint32 dstrmask = 0x00FF0000; Uint32 dstgmask = 0x0000FF00; Uint32 dstbmask = 0x000000FF; Uint32 dstamask = 0x00000000; Uint32 dstflags = 0; int dstw = 640; int dsth = 480; Uint32 srcbpp = 32; Uint32 srcrmask = 0x00FF0000; Uint32 srcgmask = 0x0000FF00; Uint32 srcbmask = 0x000000FF; Uint32 srcamask = 0x00000000; Uint32 srcflags = 0; int srcw = 640; int srch = 480; Uint32 origsrcalphaflags = 0; Uint32 origdstalphaflags = 0; Uint32 srcalphaflags = 0; Uint32 dstalphaflags = 0; Uint8 origsrcalpha = 255; Uint8 origdstalpha = 255; Uint8 srcalpha = 255; Uint8 dstalpha = 255; int screenSurface = 0; int i = 0; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (strcmp(arg, "--dstbpp") == 0) dstbpp = atoi(argv[++i]); else if (strcmp(arg, "--dstrmask") == 0) dstrmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--dstgmask") == 0) dstgmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--dstbmask") == 0) dstbmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--dstamask") == 0) dstamask = atoi_hex(argv[++i]); else if (strcmp(arg, "--dstwidth") == 0) dstw = atoi(argv[++i]); else if (strcmp(arg, "--dstheight") == 0) dsth = atoi(argv[++i]); else if (strcmp(arg, "--dsthwsurface") == 0) dstflags |= SDL_HWSURFACE; else if (strcmp(arg, "--srcbpp") == 0) srcbpp = atoi(argv[++i]); else if (strcmp(arg, "--srcrmask") == 0) srcrmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--srcgmask") == 0) srcgmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--srcbmask") == 0) srcbmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--srcamask") == 0) srcamask = atoi_hex(argv[++i]); else if (strcmp(arg, "--srcwidth") == 0) srcw = atoi(argv[++i]); else if (strcmp(arg, "--srcheight") == 0) srch = atoi(argv[++i]); else if (strcmp(arg, "--srchwsurface") == 0) srcflags |= SDL_HWSURFACE; else if (strcmp(arg, "--seconds") == 0) testSeconds = atoi(argv[++i]); else if (strcmp(arg, "--screen") == 0) screenSurface = 1; else if (strcmp(arg, "--dumpfile") == 0) dumpfile = argv[++i]; /* !!! FIXME: set colorkey. */ else if (0) { /* !!! FIXME: we handle some commandlines elsewhere now */ fprintf(stderr, "Unknown commandline option: %s\n", arg); return (0); } } if (SDL_Init(SDL_INIT_VIDEO) == -1) { fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); return (0); } bmp = SDL_LoadBMP("sample.bmp"); if (bmp == NULL) { fprintf(stderr, "SDL_LoadBMP failed: %s\n", SDL_GetError()); SDL_Quit(); return (0); } if ((dstflags & SDL_HWSURFACE) == 0) dstflags |= SDL_SWSURFACE; if ((srcflags & SDL_HWSURFACE) == 0) srcflags |= SDL_SWSURFACE; if (screenSurface) dest = SDL_SetVideoMode(dstw, dsth, dstbpp, dstflags); else { dest = SDL_CreateRGBSurface(dstflags, dstw, dsth, dstbpp, dstrmask, dstgmask, dstbmask, dstamask); } if (dest == NULL) { fprintf(stderr, "dest surface creation failed: %s\n", SDL_GetError()); SDL_Quit(); return (0); } src = SDL_CreateRGBSurface(srcflags, srcw, srch, srcbpp, srcrmask, srcgmask, srcbmask, srcamask); if (src == NULL) { fprintf(stderr, "src surface creation failed: %s\n", SDL_GetError()); SDL_Quit(); return (0); } /* handle alpha settings... */ srcalphaflags = (src->flags & SDL_SRCALPHA) | (src->flags & SDL_RLEACCEL); dstalphaflags = (dest->flags & SDL_SRCALPHA) | (dest->flags & SDL_RLEACCEL); origsrcalphaflags = srcalphaflags; origdstalphaflags = dstalphaflags; SDL_GetSurfaceAlphaMod(src, &srcalpha); SDL_GetSurfaceAlphaMod(dest, &dstalpha); origsrcalpha = srcalpha; origdstalpha = dstalpha; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (strcmp(arg, "--srcalpha") == 0) srcalpha = atoi(argv[++i]); else if (strcmp(arg, "--dstalpha") == 0) dstalpha = atoi(argv[++i]); else if (strcmp(arg, "--srcsrcalpha") == 0) srcalphaflags |= SDL_SRCALPHA; else if (strcmp(arg, "--srcnosrcalpha") == 0) srcalphaflags &= ~SDL_SRCALPHA; else if (strcmp(arg, "--srcrleaccel") == 0) srcalphaflags |= SDL_RLEACCEL; else if (strcmp(arg, "--srcnorleaccel") == 0) srcalphaflags &= ~SDL_RLEACCEL; else if (strcmp(arg, "--dstsrcalpha") == 0) dstalphaflags |= SDL_SRCALPHA; else if (strcmp(arg, "--dstnosrcalpha") == 0) dstalphaflags &= ~SDL_SRCALPHA; else if (strcmp(arg, "--dstrleaccel") == 0) dstalphaflags |= SDL_RLEACCEL; else if (strcmp(arg, "--dstnorleaccel") == 0) dstalphaflags &= ~SDL_RLEACCEL; } if ((dstalphaflags != origdstalphaflags) || (origdstalpha != dstalpha)) SDL_SetAlpha(dest, dstalphaflags, dstalpha); if ((srcalphaflags != origsrcalphaflags) || (origsrcalpha != srcalpha)) SDL_SetAlpha(src, srcalphaflags, srcalpha); /* set some sane defaults so we can see if the blit code is broken... */ SDL_FillRect(dest, NULL, SDL_MapRGB(dest->format, 0, 0, 0)); SDL_FillRect(src, NULL, SDL_MapRGB(src->format, 0, 0, 0)); blitCentered(src, bmp); SDL_FreeSurface(bmp); if (dumpfile) SDL_SaveBMP(src, dumpfile); /* make sure initial convert is sane. */ output_details(); 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 *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; }
/** * \brief Renders the internal texture if any, and all subsurfaces that are * drawn onto it. * \param renderer The renderer where to draw. * \param src_rect The subrectangle of the texture to draw. * \param dst_xy The position where to draw on the renderer. * The width and height of this rectangle are ignored. * \param clip_rect A portion of the renderer where to restrict the drawing. * \param opacity The opacity of the parent surface. * \param subsurfaces The subsurfaces drawn onto this texture. They will be * renderered recursively. */ void Surface::render( SDL_Renderer* renderer, const Rectangle& src_rect, const Rectangle& dst_xy, const Rectangle& clip_rect, uint8_t opacity, const std::vector<SubSurfaceNode*>& subsurfaces) { const uint8_t current_opacity = std::min(internal_opacity, opacity); // Accelerate the internal software surface. if (internal_surface != NULL) { if (internal_texture == NULL) { create_texture_from_surface(); } // If the software surface has changed, update the hardware texture. else if ( (software_destination || !Video::is_acceleration_enabled()) && !is_rendered) { convert_software_surface(); SDL_UpdateTexture( internal_texture, NULL, internal_surface->pixels, internal_surface->pitch ); SDL_GetSurfaceAlphaMod(internal_surface, &internal_opacity); } } // Draw the internal color as background color. if (internal_color != NULL) { int r, g, b, a; internal_color->get_components(r, g, b, a); SDL_SetRenderDrawColor(renderer, r, g, b, std::min((uint8_t) a, current_opacity)); //SDL_RenderSetClipRect(renderer, clip_rect.get_internal_rect()); SDL_RenderFillRect(renderer, clip_rect.get_internal_rect()); } // Draw the internal texture. if (internal_texture != NULL) { SDL_SetTextureAlphaMod(internal_texture, current_opacity); //SDL_RenderSetClipRect(renderer, clip_rect.get_internal_rect()); SDL_RenderCopy( renderer, internal_texture, src_rect.get_internal_rect(), dst_xy.get_internal_rect() ); } // The surface is renderered. Now draw all subtextures. std::vector<SubSurfaceNode*>::const_iterator it; const std::vector<SubSurfaceNode*>::const_iterator end = subsurfaces.end(); for (it = subsurfaces.begin(); it != end; ++it) { SubSurfaceNode* subsurface = *it; // subsurface has to be drawn on this surface // Calculate absolute destination subrectangle position on screen. Rectangle subsurface_dst_rect( dst_xy.get_x() + subsurface->dst_rect.get_x() - src_rect.get_x(), dst_xy.get_y() + subsurface->dst_rect.get_y() - src_rect.get_y(), subsurface->src_rect.get_width(), subsurface->src_rect.get_height() ); // Set the intersection of the subsurface destination and this surface's clip as clipping rectangle. Rectangle superimposed_clip_rect; if (SDL_IntersectRect(subsurface_dst_rect.get_internal_rect(), clip_rect.get_internal_rect(), superimposed_clip_rect.get_internal_rect())) { // If there is an intersection, render the subsurface. subsurface->src_surface->render( renderer, subsurface->src_rect, subsurface_dst_rect, superimposed_clip_rect, current_opacity, subsurface->subsurfaces ); } } is_rendered = true; }
GLuint SDL_GL_LoadTexture(SDL_Surface * surface, GLfloat * texcoord) { GLuint texture; int w, h; SDL_Surface *image; SDL_Rect area; Uint32 saved_flags; Uint8 saved_alpha; /* Use the surface width and height expanded to powers of 2 */ w = power_of_two(surface->w); h = power_of_two(surface->h); texcoord[0] = 0.0f; /* Min X */ texcoord[1] = 0.0f; /* Min Y */ texcoord[2] = (GLfloat) surface->w / w; /* Max X */ texcoord[3] = (GLfloat) surface->h / h; /* Max Y */ image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF #endif ); if (image == NULL) { return 0; } /* Save the alpha blending attributes */ saved_flags = surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK); SDL_GetSurfaceAlphaMod(surface, &saved_alpha); if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA) { SDL_SetAlpha(surface, 0, 0); } /* Copy the surface into the GL texture image */ area.x = 0; area.y = 0; area.w = surface->w; area.h = surface->h; SDL_BlitSurface(surface, &area, image, &area); /* Restore the alpha blending attributes */ if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA) { SDL_SetAlpha(surface, saved_flags, saved_alpha); } /* Create an OpenGL texture for the image */ glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); SDL_FreeSurface(image); /* No longer needed */ return texture; }
/** * \brief Renders the internal texture if any, and all subsurfaces that are * drawn onto it. * \param renderer The renderer where to draw. * \param src_rect The subrectangle of the texture to draw. * \param dst_rect The position where to draw on the renderer. * \param clip_rect A portion of the renderer where to restrict the drawing. * \param opacity The opacity of the parent surface. * \param subsurfaces The subsurfaces drawn onto this texture. They will be * renderered recursively. */ void Surface::render( SDL_Renderer* renderer, const Rectangle& src_rect, const Rectangle& dst_rect, const Rectangle& clip_rect, uint8_t opacity, const std::vector<SubSurfaceNodePtr>& subsurfaces ) { //FIXME SDL_RenderSetClipRect is buggy for now, but should be fixed soon. // It means that software and hardware surface doesn't have the exact same behavior for now. // Uncomment the two lines using it when https://bugzilla.libsdl.org/show_bug.cgi?id=2336 will be solved. // Accelerate the internal software surface. if (internal_surface != nullptr) { if (internal_texture == nullptr) { create_texture_from_surface(); } // If the software surface has changed, update the hardware texture. else if ( (software_destination || !Video::is_acceleration_enabled()) && !is_rendered) { SDL_UpdateTexture( internal_texture.get(), nullptr, internal_surface->pixels, internal_surface->pitch ); SDL_GetSurfaceAlphaMod(internal_surface.get(), &this->opacity); } } const uint8_t current_opacity = std::min(this->opacity, opacity); // Draw the internal color as background color. if (internal_color != nullptr) { uint8_t r, g, b, a; internal_color->get_components(r, g, b, a); SDL_SetRenderDrawColor(renderer, r, g, b, std::min((uint8_t) a, current_opacity)); //SDL_RenderSetClipRect(renderer, clip_rect.get_internal_rect()); SDL_RenderFillRect(renderer, clip_rect.get_internal_rect()); } // Draw the internal texture. if (internal_texture != nullptr) { SDL_SetTextureAlphaMod(internal_texture.get(), current_opacity); //SDL_RenderSetClipRect(renderer, clip_rect.get_internal_rect()); SDL_RenderCopy( renderer, internal_texture.get(), src_rect.get_internal_rect(), dst_rect.get_internal_rect() ); } // The surface is rendered. Now draw all subtextures. for (const SubSurfaceNodePtr& subsurface: subsurfaces) { // subsurface has to be drawn on this surface // Calculate absolute destination subrectangle position on screen. Rectangle subsurface_dst_rect( dst_rect.get_xy() + subsurface->dst_rect.get_xy() - src_rect.get_xy(), subsurface->src_rect.get_size() ); // Set the intersection of the subsurface destination and this surface's clip as clipping rectangle. Rectangle superimposed_clip_rect; if (SDL_IntersectRect(subsurface_dst_rect.get_internal_rect(), clip_rect.get_internal_rect(), superimposed_clip_rect.get_internal_rect())) { // If there is an intersection, render the subsurface. subsurface->src_surface->render( renderer, subsurface->src_rect, subsurface_dst_rect, superimposed_clip_rect, current_opacity, subsurface->subsurfaces ); } } is_rendered = true; }
int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){ png_structp png_ptr; png_infop info_ptr; SDL_PixelFormat *fmt=NULL; SDL_Surface *tempsurf=NULL; int ret,funky_format; unsigned int i; Uint8 used_alpha, temp_alpha = 0; 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;(signed int)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 (surf->flags&SDL_SRCCOLORKEY) { Uint32 colorkey = 0; #if SDL_VERSION_ATLEAST(1, 3, 0) SDL_GetColorKey(surf, &colorkey); #else colorkey = fmt->colorkey + 1; #endif palette_alpha=(Uint8 *)malloc((colorkey+1)*sizeof(Uint8)); if (!palette_alpha) { SDL_SetError("Couldn't create memory for palette transparency"); goto savedone; } memset(palette_alpha, 0, (colorkey+1)*sizeof(Uint8)); palette_alpha[colorkey]=0; png_set_tRNS(png_ptr,info_ptr,palette_alpha,(colorkey+1),NULL); } }else{ /* Truecolor */ 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); } png_write_info(png_ptr, info_ptr); if (fmt->BitsPerPixel==8) { /* Paletted */ for(i=0;(signed int)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 SDL_BYTEORDER == SDL_BIG_ENDIAN tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); #else tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); #endif if(!tempsurf){ SDL_SetError("Couldn't allocate temp surface"); goto savedone; } if(surf->flags&SDL_SRCALPHA){ #if SDL_VERSION_ATLEAST(1, 3, 0) SDL_GetSurfaceAlphaMod(surf, &temp_alpha); #else temp_alpha=fmt->alpha; #endif used_alpha=1; SDL_SetAlpha(surf,0,255); /* Set for an opaque blit */ }else{ used_alpha=0; } if(SDL_BlitSurface(surf,NULL,tempsurf,NULL)!=0){ SDL_SetError("Couldn't blit surface to temp surface"); SDL_FreeSurface(tempsurf); goto savedone; } if (used_alpha) { SDL_SetAlpha(surf,SDL_SRCALPHA,(Uint8)temp_alpha); /* Restore alpha settings*/ } for(i=0;(signed int)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;(signed int)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; }