kobodl/graphics/region.c
Ville Lindholm dbc223eb84
Initial commit
Import existing source tree; original VCS history is no longer available.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 16:35:31 +03:00

214 lines
4.2 KiB
C

/*(LGPL)
----------------------------------------------------------------------
region.c - Graphics Engine
----------------------------------------------------------------------
* Copyright (C) 2007 David Olofson
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This program 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "region.h"
#include <stdlib.h>
static struct
{
RGN_region *region;
int x, y;
SDL_Surface *target;
} s;
static Uint32 gp1(SDL_Surface *surface, int x, int y)
{
return *((Uint8 *)surface->pixels + y * surface->pitch + x);
}
static Uint32 gp2(SDL_Surface *surface, int x, int y)
{
return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
}
static Uint32 gp3(SDL_Surface *surface, int x, int y)
{
int bpp = surface->format->BytesPerPixel;
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
#else
return p[0] | p[1] << 8 | p[2] << 16;
#endif
}
static Uint32 gp4(SDL_Surface *surface, int x, int y)
{
return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
}
RGN_region *RGN_ScanMask(SDL_Surface *src, Uint32 key)
{
RGN_region *rgn = (RGN_region *)calloc(1, sizeof(RGN_region));
Uint32 (*gp)(SDL_Surface *surface, int x, int y);
int x, y;
if(!rgn)
return NULL;
rgn->rows = src->h;
rgn->spans = (Uint16 **)calloc(1, sizeof(Uint16 *) * src->h);
if(!rgn->spans)
{
RGN_FreeRegion(rgn);
return NULL;
}
switch(src->format->BytesPerPixel)
{
case 1:
gp = gp1;
break;
case 2:
gp = gp2;
break;
case 3:
gp = gp3;
break;
case 4:
gp = gp4;
break;
default:
RGN_FreeRegion(rgn);
return NULL;
}
SDL_LockSurface(src);
for(y = 0; y < src->h; ++y)
{
int i = 0;
int drawing = 0;
Uint16 *sp = (Uint16 *)malloc(sizeof(Uint16) * 2 * (src->w + 1));
if(!sp)
{
SDL_UnlockSurface(src);
RGN_FreeRegion(rgn);
return NULL;
}
for(x = 0; x < src->w; ++x)
{
int nd = (gp(src, x, y) == key);
if(nd != drawing)
{
sp[i++] = x;
drawing = nd;
}
}
if(drawing)
sp[i++] = src->w;
sp[i++] = 0;
sp[i++] = 0;
rgn->spans[y] = (Uint16 *)realloc(sp, sizeof(Uint16) * i);
if(!rgn->spans[y])
rgn->spans[y] = sp;
}
SDL_UnlockSurface(src);
return rgn;
}
void RGN_FreeRegion(RGN_region *rgn)
{
if(!rgn)
return;
if(rgn->spans)
{
int i;
for(i = rgn->rows - 1; i >= 0; --i)
free(rgn->spans[i]);
free(rgn->spans);
}
free(rgn);
}
void RGN_Target(SDL_Surface *tgt)
{
s.target = tgt;
}
void RGN_SetRegion(RGN_region *rgn, int xpos, int ypos)
{
s.region = rgn;
s.x = xpos;
s.y = ypos;
}
int RGN_Blit(SDL_Surface *src, SDL_Rect *sr, int x, int y)
{
// FIXME: Clipping is only half done here...
int yy0, yy, yy1;
int sxmin, sxmax, symin, symax;
SDL_Rect sr2;
if(!s.region)
{
SDL_Rect dr;
dr.x = x;
dr.y = y;
return SDL_BlitSurface(src, sr, s.target, &dr);
}
if(sr)
{
sxmin = sr->x;
symin = sr->y;
sxmax = sxmin + sr->w;
symax = symin + sr->h;
}
else
{
sxmin = 0;
symin = 0;
sxmax = src->w;
symax = src->h;
}
yy0 = s.y;
if(yy0 >= y + (symax - symin))
return 0;
if(yy0 < y)
yy0 = y;
yy1 = s.y + s.region->rows;
if(y >= yy1)
return 0;
if(yy1 > y + (symax - symin))
yy1 = y + (symax - symin);
sr2.h = 1;
for(yy = yy0; yy < yy1; ++yy)
{
SDL_Rect dr;
Uint16 *spans = s.region->spans[yy - s.y];
sr2.y = symin + y - yy0;
dr.y = yy;
for( ; spans[0] && spans[1] ; spans += 2)
{
int x0 = s.x + spans[0];
int x1 = s.x + spans[1];
dr.x = x0;
sr2.x = sxmin + x0 - x;
sr2.w = x1 - x0;
SDL_BlitSurface(src, &sr2, s.target, &dr);
}
}
return 0;
}