grafX2/sdlscreen.c
Yves Rizoud e5f948076b New: Picture effects screen, resizes / mirrors / rotates image (Issue 73)
New: Distort brush (Issue 34)
New: Pixel scaler "Triple" for 3x3 zoom (Issue 147)
New: Pixel scaler "Quadruple" for 4x4 zoom (Issue 151)
New: Pixel scaler "Wide2" for 4x2 zoom (Issue 148)
New: Pixel scaler "Tall2" for 2x4 zoom (Issue 149)
Fix of very old bug: Resizing the image didn't mark the image 'modified since last save'

git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@763 416bcca6-2ee7-4201-b75f-2eb2f807beb1
2009-05-02 16:44:06 +00:00

236 lines
6.0 KiB
C

/* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2008 Yves Rizoud
Copyright 2008 Franck Charlet
Copyright 2007 Adrien Destugues
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
Grafx2 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
Grafx2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grafx2; if not, see <http://www.gnu.org/licenses/> or
write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include <SDL.h>
#include "global.h"
#include "sdlscreen.h"
#include "errors.h"
#include "misc.h"
// Update method that does a large number of small rectangles, aiming
// for a minimum number of total pixels updated.
#define UPDATE_METHOD_MULTI_RECTANGLE 1
// Intermediate update method, does only one update with the smallest
// rectangle that includes all modified pixels.
#define UPDATE_METHOD_CUMULATED 2
// Total screen update, for platforms that impose a Vsync on each SDL update.
#define UPDATE_METHOD_FULL_PAGE 3
// UPDATE_METHOD can be set from makefile, otherwise it's selected here
// depending on the platform :
#ifndef UPDATE_METHOD
#if defined(__macosx__) || defined(__FreeBSD__)
#define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE
#else
#define UPDATE_METHOD UPDATE_METHOD_CUMULATED
#endif
#endif
/// Sets the new screen/window dimensions.
void Set_mode_SDL(int *width, int *height, int fullscreen)
{
Screen_SDL=SDL_SetVideoMode(*width,*height,8,(fullscreen?SDL_FULLSCREEN:0)|SDL_RESIZABLE);
if(Screen_SDL != NULL)
{
// Check the mode we got, in case it was different from the one we requested.
if (Screen_SDL->w != *width || Screen_SDL->h != *height)
{
DEBUG("Error: Got a different video mode than the requested one!",0);
*width = Screen_SDL->w;
*height = Screen_SDL->h;
}
Screen_pixels=Screen_SDL->pixels;
}
else
DEBUG("Error: Unable to change video mode!",0);
SDL_ShowCursor(0); // Hide the SDL mouse cursor, we use our own
}
#if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED)
short Min_X=0;
short Min_Y=0;
short Max_X=10000;
short Max_Y=10000;
#endif
#if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE)
int update_is_required=0;
#endif
void Flush_update(void)
{
#if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE)
// Do a full screen update
if (update_is_required)
{
SDL_UpdateRect(Screen_SDL, 0, 0, 0, 0);
update_is_required=0;
}
#endif
#if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED)
if (Min_X>=Max_X || Min_Y>=Max_Y)
{
; // Nothing to do
}
else
{
if (Min_X<0)
Min_X=0;
if (Min_Y<0)
Min_Y=0;
SDL_UpdateRect(Screen_SDL, Min_X*Pixel_width, Min_Y*Pixel_height, Min(Screen_width-Min_X, Max_X-Min_X)*Pixel_width, Min(Screen_height-Min_Y, Max_Y-Min_Y)*Pixel_height);
Min_X=Min_Y=10000;
Max_X=Max_Y=0;
}
#endif
}
void Update_rect(short x, short y, unsigned short width, unsigned short height)
{
#if (UPDATE_METHOD == UPDATE_METHOD_MULTI_RECTANGLE)
SDL_UpdateRect(Screen_SDL, x*Pixel_width, y*Pixel_height, width*Pixel_width, height*Pixel_height);
#endif
#if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED)
if (width==0 || height==0)
{
Min_X=Min_Y=0;
Max_X=Max_Y=10000;
}
else
{
if (x < Min_X)
Min_X = x;
if (y < Min_Y)
Min_Y = y;
if (x+width>Max_X)
Max_X=x+width;
if (y+height>Max_Y)
Max_Y=y+height;
}
#endif
#if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE)
update_is_required=1;
#endif
}
// Converts a SDL_Surface (indexed colors or RGB) into an array of bytes
// (indexed colors).
// If dest is NULL, it's allocated by malloc(). Otherwise, be sure to
// pass a buffer of the right dimensions.
byte * Surface_to_bytefield(SDL_Surface *source, byte * dest)
{
byte *src;
byte *dest_ptr;
int y;
int remainder;
// Support seulement des images 256 couleurs
if (source->format->BytesPerPixel != 1)
return NULL;
if (source->w & 3)
remainder=4-(source->w&3);
else
remainder=0;
if (dest==NULL)
dest=(byte *)malloc(source->w*source->h);
dest_ptr=dest;
src=(byte *)(source->pixels);
for(y=0; y < source->h; y++)
{
memcpy(dest_ptr, src,source->w);
dest_ptr += source->w;
src += source->w + remainder;
}
return dest;
}
/// Gets the RGB 24-bit color currently associated with a palette index.
SDL_Color Color_to_SDL_color(byte index)
{
SDL_Color color;
color.r = Main_palette[index].R;
color.g = Main_palette[index].G;
color.b = Main_palette[index].B;
color.unused = 255;
return color;
}
// Reads a pixel in a SDL surface.
// Warning, this is only suitable for 8-bit surfaces.
byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y)
{
return ((byte *)(bmp->pixels))[(y*bmp->pitch+x)];
}
void Clear_screen(byte color)
{
memset(Screen_SDL->pixels,color,Screen_SDL->pitch*Screen_SDL->h);
Update_rect(0,0,0,0);
}
void Clear_border(byte color)
{
int width;
int height;
// This function can be called before the graphics mode is set.
// Nothing to do then.
if (!Screen_SDL)
return;
width = Screen_SDL->w - Screen_width*Pixel_width;
height = Screen_SDL->h - Screen_height*Pixel_height;
if (width)
{
SDL_Rect r;
r.x=Screen_SDL->w - width;
r.y=0;
r.h=Screen_SDL->h;
r.w=width;
SDL_FillRect(Screen_SDL,&r,color);
SDL_UpdateRect(Screen_SDL, r.x, r.y, r.w, r.h);
}
if (height)
{
SDL_Rect r;
r.x=0;
r.y=Screen_SDL->h - height;
r.h=height;
r.w=Screen_SDL->w - height;
SDL_FillRect(Screen_SDL,&r,color);
SDL_UpdateRect(Screen_SDL, r.x, r.y, r.w, r.h);
}
}