/*
* Copyright (c) 2005-2007 Hypertriton, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "tileset.h"
#include "tileview.h"
#include "fill.h"
#include "icons.h"
const AG_Version rgFillVer = { 0, 0, };
const RG_FeatureOps rgFillOps = {
"fill",
sizeof(struct rg_fill_feature),
N_("Fill tile with solid color/pattern."),
FEATURE_AUTOREDRAW,
RG_FillInit,
RG_FillLoad,
RG_FillSave,
NULL, /* destroy */
RG_FillApply,
RG_FillMenu,
RG_FillToolbar,
RG_FillEdit
};
void
RG_FillInit(void *p, RG_Tileset *ts, int flags)
{
struct rg_fill_feature *f = p;
AG_FeatureInit(f, ts, flags, &rgFillOps);
f->type = FILL_SOLID;
f->alpha = 255;
f->f_gradient.c1 = AG_MapRGB(ts->fmt, 0,0,0);
f->f_gradient.c2 = AG_MapRGB(ts->fmt, 0,0,0);
}
int
RG_FillLoad(void *p, AG_DataSource *buf)
{
struct rg_fill_feature *f = p;
RG_Tileset *ts = RG_FEATURE(f)->ts;
if (AG_ReadVersion(buf, "RG_Feature:RG_Fill", &rgFillVer, NULL) == -1)
return (-1);
f->type = (enum rg_fill_type)AG_ReadUint8(buf);
switch (f->type) {
case FILL_SOLID:
f->f_solid.c = AG_ReadColor(buf, ts->fmt);
break;
case FILL_HGRADIENT:
case FILL_VGRADIENT:
case FILL_CGRADIENT:
f->f_gradient.c1 = AG_ReadColor(buf, ts->fmt);
f->f_gradient.c2 = AG_ReadColor(buf, ts->fmt);
break;
case FILL_PATTERN:
f->f_pattern.texid = (int)AG_ReadUint32(buf);
f->f_pattern.tex_xoffs = (int)AG_ReadUint32(buf);
f->f_pattern.tex_yoffs = (int)AG_ReadUint32(buf);
break;
}
return (0);
}
void
RG_FillSave(void *p, AG_DataSource *buf)
{
struct rg_fill_feature *f = p;
RG_Tileset *ts = RG_FEATURE(f)->ts;
AG_WriteVersion(buf, "RG_Feature:RG_Fill", &rgFillVer);
AG_WriteUint8(buf, (Uint8)f->type);
switch (f->type) {
case FILL_SOLID:
AG_WriteColor(buf, ts->fmt, f->f_solid.c);
break;
case FILL_HGRADIENT:
case FILL_VGRADIENT:
case FILL_CGRADIENT:
AG_WriteColor(buf, ts->fmt, f->f_gradient.c1);
AG_WriteColor(buf, ts->fmt, f->f_gradient.c2);
break;
case FILL_PATTERN:
AG_WriteUint32(buf, (Uint32)f->f_pattern.texid);
AG_WriteUint32(buf, (Uint32)f->f_pattern.tex_xoffs);
AG_WriteUint32(buf, (Uint32)f->f_pattern.tex_yoffs);
break;
}
}
AG_Window *
RG_FillEdit(void *p, RG_Tileview *tv)
{
struct rg_fill_feature *f = p;
AG_Window *win;
AG_Box *box;
win = AG_WindowNew(0);
AG_WindowSetCaption(win, _("Fill/gradient"));
{
static const char *modes[] = {
N_("Solid"),
N_("Horizontal gradient"),
N_("Vertical gradient"),
N_("Circular gradient"),
N_("Pixmap pattern"),
NULL
};
AG_RadioNewUint(win, AG_RADIO_HFILL, modes, &f->type);
}
box = AG_BoxNew(win, AG_BOX_VERT, AG_BOX_HFILL|AG_BOX_VFILL);
{
AG_HSVPal *hsv1, *hsv2;
AG_Numerical *num;
AG_Notebook *nb;
AG_NotebookTab *ntab;
nb = AG_NotebookNew(box, AG_NOTEBOOK_HFILL|AG_NOTEBOOK_VFILL);
ntab = AG_NotebookAddTab(nb, _("Color A"), AG_BOX_VERT);
{
hsv1 = AG_HSVPalNew(ntab, AG_HSVPAL_EXPAND);
AG_BindPointer(hsv1, "pixel-format",
(void *)&tv->ts->fmt);
AG_BindUint32(hsv1, "pixel", &f->f_gradient.c1);
}
ntab = AG_NotebookAddTab(nb, _("Color B"), AG_BOX_VERT);
{
hsv2 = AG_HSVPalNew(ntab, AG_HSVPAL_EXPAND);
AG_BindPointer(hsv1, "pixel-format",
(void *)&tv->ts->fmt);
AG_BindUint32(hsv2, "pixel", &f->f_gradient.c2);
}
num = AG_NumericalNewUint8R(box, 0, NULL,
_("Overall alpha: "), &f->alpha, 0, 255);
AG_NumericalSetIncrement(num, 5);
}
return (win);
}
void
RG_FillApply(void *p, RG_Tile *t, int x, int y)
{
struct rg_fill_feature *fi = p;
AG_Surface *su = t->su;
Uint8 r1, g1, b1;
Uint8 r2, g2, b2;
AG_GetRGB(fi->f_gradient.c1, t->ts->fmt, &r1,&g1,&b1);
AG_GetRGB(fi->f_gradient.c2, t->ts->fmt, &r2,&g2,&b2);
switch (fi->type) {
case FILL_SOLID:
AG_GetRGB(fi->f_solid.c, t->ts->fmt, &r1, &g1, &b1);
AG_FillRect(su, NULL,
AG_MapRGBA(t->ts->fmt, r1,g1,b1, fi->alpha));
break;
case FILL_HGRADIENT:
{
int x, y;
AG_SurfaceLock(su);
for (y = 0; y < su->h; y++) {
Uint32 c;
Uint8 a = (Uint8)(su->h-y)*255/su->h;
c = AG_MapRGB(t->ts->fmt,
(((r1 - r2) * a) >> 8) + r2,
(((g1 - g2) * a) >> 8) + g2,
(((b1 - b2) * a) >> 8) + b2);
for (x = 0; x < su->w; x++) {
if (fi->alpha == 255) {
RG_PutPixel(t->su, x, y,
AG_MapRGB(t->su->format,
(((r1 - r2)*a) >> 8) + r2,
(((g1 - g2)*a) >> 8) + g2,
(((b1 - b2)*a) >> 8) + b2));
} else {
RG_BlendRGB(t->su, x, y,
RG_PRIM_OVERLAY_ALPHA,
(((r1 - r2)*a) >> 8) + r2,
(((g1 - g2)*a) >> 8) + g2,
(((b1 - b2)*a) >> 8) + b2,
fi->alpha);
}
}
}
AG_SurfaceUnlock(su);
}
break;
case FILL_VGRADIENT:
{
int x, y;
AG_SurfaceLock(su);
for (y = 0; y < su->h; y++) {
for (x = 0; x < su->w; x++) {
Uint8 a = (su->h-x)*255/su->h;
RG_BlendRGB(t->su, x, y,
RG_PRIM_OVERLAY_ALPHA,
(((r1 - r2) * a) >> 8) + r2,
(((g1 - g2) * a) >> 8) + g2,
(((b1 - b2) * a) >> 8) + b2,
fi->alpha);
}
}
AG_SurfaceUnlock(su);
}
break;
case FILL_CGRADIENT:
{
int i, r = MAX(su->w,su->h);
int x = su->w/2;
int y = su->h/2;
AG_SurfaceLock(su);
for (i = 0; i < r; i++) {
Uint8 a = (r-i)*255/r;
RG_ColorRGBA(t,
(((r1 - r2) * a) >> 8) + r2,
(((g1 - g2) * a) >> 8) + g2,
(((b1 - b2) * a) >> 8) + b2,
fi->alpha);
RG_Circle2(t, x, y, i);
}
AG_SurfaceUnlock(su);
}
break;
default:
break;
}
}
static void
InvertColors(AG_Event *event)
{
struct rg_fill_feature *fi = AG_PTR(1);
RG_Tileset *ts = RG_FEATURE(fi)->ts;
Uint8 r, g, b;
switch (fi->type) {
case FILL_SOLID:
AG_GetRGB(fi->f_solid.c, ts->fmt, &r,&g,&b);
r = 255 - r;
g = 255 - g;
b = 255 - b;
fi->f_solid.c = AG_MapRGB(ts->fmt, r,g,b);
break;
case FILL_HGRADIENT:
case FILL_VGRADIENT:
case FILL_CGRADIENT:
AG_GetRGB(fi->f_gradient.c1, ts->fmt, &r,&g,&b);
r = 255 - r;
g = 255 - g;
b = 255 - b;
fi->f_gradient.c1 = AG_MapRGB(ts->fmt, r,g,b);
AG_GetRGB(fi->f_gradient.c2, ts->fmt, &r,&g,&b);
r = 255 - r;
g = 255 - g;
b = 255 - b;
fi->f_gradient.c2 = AG_MapRGB(ts->fmt, r,g,b);
break;
default:
break;
}
}
static void
SwapGradientColors(AG_Event *event)
{
struct rg_fill_feature *fi = AG_PTR(1);
Uint32 cSave;
switch (fi->type) {
case FILL_HGRADIENT:
case FILL_VGRADIENT:
case FILL_CGRADIENT:
cSave = fi->f_gradient.c2;
fi->f_gradient.c2 = fi->f_gradient.c1;
fi->f_gradient.c1 = cSave;
break;
default:
break;
}
}
static void
set_type(AG_Event *event)
{
struct rg_fill_feature *fi = AG_PTR(1);
int type = AG_INT(2);
fi->type = type;
}
void
RG_FillMenu(void *p, AG_MenuItem *mi)
{
struct rg_fill_feature *fi = p;
AG_MenuItem *mi_fill;
mi_fill = AG_MenuAction(mi, _("Fill type"), rgIconFill.s, NULL, NULL);
{
AG_MenuAction(mi_fill, _("Solid fill"), rgIconFill.s,
set_type, "%p, %i", fi, FILL_SOLID);
AG_MenuAction(mi_fill, _("Horizontal gradient"), rgIconHGrad.s,
set_type, "%p, %i", fi, FILL_HGRADIENT);
AG_MenuAction(mi_fill, _("Vertical gradient"), rgIconVGrad.s,
set_type, "%p, %i", fi, FILL_VGRADIENT);
AG_MenuAction(mi_fill, _("Circular gradient"), rgIconCGrad.s,
set_type, "%p, %i", fi, FILL_CGRADIENT);
AG_MenuAction(mi_fill, _("Pattern"), rgIconTiling.s,
set_type, "%p, %i", fi, FILL_PATTERN);
}
AG_MenuSeparator(mi);
AG_MenuAction(mi, _("Swap gradient colors"), rgIconSwap.s,
SwapGradientColors, "%p", fi);
AG_MenuAction(mi, _("Invert colors"), rgIconInvert.s,
InvertColors, "%p", fi);
}
AG_Toolbar *
RG_FillToolbar(void *p, RG_Tileview *tv)
{
struct rg_fill_feature *fi = p;
AG_Toolbar *tbar;
tbar = AG_ToolbarNew(tv->tel_box, AG_TOOLBAR_VERT, 1, 0);
AG_ToolbarButtonIcon(tbar, rgIconSwap.s, 0,
SwapGradientColors, "%p", fi);
AG_ToolbarButtonIcon(tbar, rgIconInvert.s, 0,
InvertColors, "%p", fi);
return (tbar);
}