/*
* Copyright (C) 1997 and 1998 WIDE Project. 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.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
*/
/*
* $Id: background.c,v 1.14 2000/03/05 07:26:29 nishida Exp $
*/
#include <math.h>
#include "mgp.h"
/* background gradation */
#define G_PI 3.1415926535897932385
#define G_PI2 1.5707963267948966192
static void draw_gradation0 __P((int, int, int, int, int, int,
byte *, byte *, int, int, u_int));
static void g_rotate __P((byte *, struct ctrl_grad *, int, int));
/*
* generate gradation for single color plane.
* x: color plane
* y: axis for gradation
* z: extra axis
*/
static void
draw_gradation0(x1, x2, y1, y2, z1, z2, p1, p2, dpy, dpz, mask)
int x1, x2;
int y1, y2;
int z1, z2;
byte *p1, *p2;
int dpy, dpz; /* delta of p in x/y's direction */
u_int mask;
{
int s, step;
int dx, dy;
int z;
byte *p;
dx = abs(x2 - x1);
dy = abs(y2 - y1);
if (dx > dy) {
if (x1 > x2) {
step = (y1 > y2) ? 1 : -1;
s = x1; x1 = x2; x2 = s; /*swap*/
y1 = y2;
p = p2;
} else {
step = (y1 < y2) ? 1 : -1;
p = p1;
}
for (z = z1; z < z2; z++)
*(p + z * dpz) = x1 & mask;
s = dx >> 1;
while (++x1 <= x2) {
if ((s -= dy) < 0) {
s += dx;
y1 += step;
p += (dpy * step);
}
#ifdef DITHERED_BGRAD
for (z = z1; z < z2; z+=3){
*(p + z * dpz) = x1 * (30 + (y1 % 3)) / 32 & mask;
*(p + (z+1) * dpz) = x1 * (30 + ((y1 + 2) % 3)) / 32 & mask;
*(p + (z+2) * dpz) = x1 * (30 + ((y1 + 1) % 3)) / 32 & mask;
}
#else
for (z = z1; z < z2; z++)
*(p + z * dpz) = x1 & mask;
#endif
}
} else {
if (y1 > y2) {
step = (x1 > x2) ? 1 : -1;
s = y1; y1 = y2; y2 = s; /*swap*/
x1 = x2;
p = p2;
} else {
step = (x1 < x2) ? 1 : -1;
p = p1;
}
for (z = z1; z < z2; z++)
*(p + z * dpz) = x1 & mask;
s = dy >> 1;
while (++y1 <= y2) {
p += dpy; /*y always inc*/
if ((s -= dx) < 0) {
s += dy;
x1 += step;
}
#ifdef DITHERED_BGRAD
for (z = z1; z < z2; z+=3){
*(p + z * dpz) = x1 * (30 + (y1 % 3)) / 32 & mask;
*(p + (z+1) * dpz) = x1 * (30 + ((y1 + 2) % 3)) / 32 & mask;
*(p + (z+2) * dpz) = x1 * (30 + ((y1 + 1) % 3)) / 32 & mask;
}
#else
for (z = z1; z < z2; z++)
*(p + z * dpz) = x1 & mask;
#endif
}
}
}
byte *
draw_gradation(width, height, cg)
int width;
int height;
struct ctrl_grad *cg;
{
int bmask[8] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
byte *pic;
const u_int bits = 8;
int i, j;
int x1 = 0, x2 = 0;
int y1 = 0, y2 = 0, dpy = 0;
int z1 = 0, z2 = 0, dpz = 0;
byte *p1 = NULL, *p2 = NULL;
byte mask;
pic = (byte *)malloc(width * height * 3 * sizeof(byte));
if (!pic) {
fprintf(stderr,"couldn't alloc space for gradation image\n");
return NULL;
}
memset(pic, 0, width * height * 3 * sizeof(byte));
if (cg->ct_direction % 90) {
g_rotate(pic, cg, width, height);
return pic;
}
for (j = 0; j < 3; j++) { /*r, g, b*/
for (i = 0; i < cg->ct_g_colors - 1; i++) {
switch (j) {
case 0:
x1 = cg->colors[i]->r;
x2 = cg->colors[i + 1]->r;
break;
case 1:
x1 = cg->colors[i]->g;
x2 = cg->colors[i + 1]->g;
break;
case 2:
x1 = cg->colors[i]->b;
x2 = cg->colors[i + 1]->b;
break;
}
mask = bmask[bits - 1];
switch (cg->ct_direction) {
case 0:
y1 = ((height - 1) * i) / (cg->ct_g_colors - 1);
y2 = ((height - 1) * (i + 1))
/ (cg->ct_g_colors - 1);
p1 = pic + j + width * 3 * y1;
p2 = pic + j + width * 3 * y2;
z1 = 0;
z2 = width;
dpy = width * 3;
dpz = 3;
break;
case 90:
y1 = ((width - 1) * i) / (cg->ct_g_colors - 1);
y2 = ((width - 1) * (i + 1))
/ (cg->ct_g_colors - 1);
p1 = pic + j + 3 * y1;
p2 = pic + j + 3 * y2;
z1 = 0;
z2 = height;
dpy = 3;
dpz = width * 3;
break;
case 180:
y1 = ((height - 1) * (cg->ct_g_colors - i - 1))
/ (cg->ct_g_colors - 1);
y2 = ((height - 1) * (cg->ct_g_colors - i - 2))
/ (cg->ct_g_colors - 1);
p1 = pic + j + width * 3 * y1;
p2 = pic + j + width * 3 * y2;
z1 = 0;
z2 = width;
dpy = width * 3;
dpz = 3;
break;
case 270:
y1 = ((width - 1) * (cg->ct_g_colors - i - 1))
/ (cg->ct_g_colors - 1);
y2 = ((width - 1) * (cg->ct_g_colors - i - 2))
/ (cg->ct_g_colors - 1);
p1 = pic + j + 3 * y1;
p2 = pic + j + 3 * y2;
z1 = 0;
z2 = height;
dpy = 3;
dpz = width * 3;
break;
}
draw_gradation0(x1, x2, y1, y2, z1, z2, p1, p2,
dpy, dpz, mask);
}
}
return pic;
}
static double cost, sint;
static double cos2t, sin2t;
static double dcost, dsint;
/* rotate graphic */
static void
g_rotate(pic, cg, width, height)
byte *pic;
struct ctrl_grad * cg;
int width, height;
{
byte *pp;
double maxd, mind, del, d, rat, crat, cval;
double theta, dy, ey, td1, td2;
int x, y, cx, cy, r, g, b, bc, nc1;
int rot, mode;
struct g_color * c1;
struct g_color * c2;
rot = cg->ct_direction;
mode = cg->ct_mode;
cx = width/2; cy = height/2;
theta = (double) rot * G_PI / 180.0;
cost = cos(theta);
sint = sin(theta);
dsint = sint*sint;
dcost = cost*cost;
sin2t = sin(2*theta);
cos2t = cos(2*theta);
nc1 = cg->ct_g_colors - 1;
/* compute max/min distances */
if (rot > 0 && rot < 90) {
mind = cdist(0, 0, cx, cy, rot, mode);
maxd = cdist(width-1, height-1, cx, cy, rot, mode);
}
else if (rot >= 90 && rot < 180) {
mind = cdist(0, height-1, cx, cy, rot, mode);
maxd = cdist(width-1, 0, cx, cy, rot, mode);
}
else if (rot >= 180 && rot < 270) {
mind = cdist(width-1, height-1, cx, cy, rot, mode);
maxd = cdist(0, 0, cx, cy, rot, mode);
}
else {
mind = cdist(width-1, 0, cx, cy, rot, mode);
maxd = cdist(0, height-1, cx, cy, rot, mode);
}
del = maxd - mind; /* maximum distance */
/* loop start */
td1 = cx - cx*dcost;
td2 = cy + 0.5*cx*sin2t;
for (y = 0; y < height; y++) {
pp = pic + (y * width * 3);
dy = (cy-y)*0.5*sin2t + td1;
ey = (y-cy)*dsint + td2;
for (x = 0; x < width; x++) {
d = lcdist(x, y, cx, cy, rot, mode, dy, ey);
rat = (d - mind) / del;
if (rat < 0.0){
cval = bc = crat = 0.0;
} else if (rat > 1.0){
cval = bc = (double)nc1;
crat = 0.0;
} else {
cval = rat * nc1;
bc = floor(cval);
crat = cval - bc;
}
if (bc < nc1) {
c1 = (cg->colors)[bc];
c2 = (cg->colors)[bc+1];
r = c1->r + crat * ((c2->r) - (c1->r));
g = c1->g + crat * ((c2->g) - (c1->g));
b = c1->b + crat * ((c2->b) - (c1->b));
} else {
c1 = (cg->colors)[nc1];
r = c1->r; g = c1->g; b = c1->b;
}
*pp++ = (byte) r; *pp++ = (byte) g; *pp++ = (byte) b;
}
}
}
/* compute distance */
double cdist(x, y, cx, cy, rot, mode)
int x, y, cx, cy, rot, mode;
{
double x1, y1, x2, y2, x3, d ;
/* special case */
if (rot == 0) return (double) (y - cy);
if (rot == 90) return (double) (x - cx);
if (rot == 180) return (double) (cy - y);
if (rot == 270) return (double) (cx - x);
/* experimental routine for circle patern gradation */
if (mode == 1) {
d = sqrt((y-cy)*(y-cy)*cost + (x-cx)*(x-cx)*sint);
if (x + y - cy < 0) d = -d;
return d;
}
/* x1,y1 = original point */
x1 = (double) x; y1 = (double) y;
x2 = cx + (cy-y1)*0.5*sin2t - (cx-x1)*dcost;
y2 = cy - (cy-y1)*dsint + (cx-x1)*0.5*sin2t;
x3 = x1-x2;
d = sqrt(x3*x3 + (y1 - y2)*(y1 - y2));
if ((rot < 180 && x3<0) || (rot > 180 && x3>0)) d = -d;
return d;
}
double lcdist(x, y, cx, cy, rot, mode, dy, ey)
int x, y, cx, cy, rot, mode;
double dy,ey;
{
double x1, y1, x2, y2, x3, d ;
/* special case */
if (rot == 0) return (double) (y - cy);
if (rot == 90) return (double) (x - cx);
if (rot == 180) return (double) (cy - y);
if (rot == 270) return (double) (cx - x);
/* experimental routine for circle patern gradation */
if (mode == 1) {
d = sqrt((y-cy)*(y-cy)*cost + (x-cx)*(x-cx)*sint);
if (x + y - cy < 0) d = -d;
return d;
}
x1 = (double) x;
y1 = (double) y;
x2 = dy + x1*dcost;
y2 = ey - x1*0.5*sin2t;
x3 = x1-x2;
d = sqrt(x3*x3 + (y1 - y2)*(y1 - y2));
if ((rot < 180 && x3<0) || (rot > 180 && x3>0)) d = -d;
return d;
}
Image *
make_XImage(pic, width, height)
byte *pic;
unsigned int width, height;
{
Image *image;
int size;
#if USE_COLOR_DEPTH
byte *destptr;
unsigned int y, maxval;
#endif
size= height * width * 3;
/* make Image structure (stolen from image/new.c)*/
image= (Image *)lmalloc(sizeof(Image));
image->type= ITRUE;
image->title= strdup("");
image->rgb.used= image->rgb.size= 0;
image->width= width;
image->height= height;
image->depth= 24;
image->pixlen= 3;
image->data= pic;
#if USE_COLOR_DEPTH
#define PM_SCALE(a, b, c) (long)((a) * (c))/(b)
/* color depth (future use) */
maxval = 0xff;
destptr= image->data;
for (y= 0; y < size; y++) {
*destptr= PM_SCALE(*destptr, maxval, 0xff);
destptr++;
}
#endif
return(image);
}
syntax highlighted by Code2HTML, v. 0.9.1