/*====================================================
                      ARTemis
                   (version 1.3)
             FM-TOWNS 用ペイントツール

                 by 松内 良介 1994
====================================================*/
#if 0
	pic.c : 「画像」

	pic_init
	
	pic_new(wid,ht)
	pic_destroy(pic)
	pic_dup(pic)

	static void pic_updatePoint(PIC* pic,int x,int y)
	static void pic_updateRect(PIC* pic, int x,int y,int wid,int ht)

	pic_setPixelXy(pic,x,y,pixel)	１ピクセルの色を設定
	pic_getPixelXy(pic,x,y,pixel)	１ピクセルの色を取得
void pic_grayPset(PIC* pic,int x,int y,int gray,PIXEL *pixel);
void pic_psetpen(PIC *pic,int x,int y,Pen pen,PIXEL *pixel);
void pic_grayhline(PIC *pic,int x1,int x2,int y,int gray,PIXEL *pixel);
void pic_clear(PIC *pic, PIXEL *pixel);
void pic_kosuriStart(PIC* pic,int x,int y,char* graypat,int wid,int ht);
void pic_kosuriDrag(PIC* pic,int x,int y,int r);

	void pic_copy(PIC* picSrc, FRAME* frSrc, PIC* picDest, POINT* ptDest);
	void pic_copyarea(PIC* picSrc, AREA areaSrc, PIC* picDest, POINT* ptDest);
	void pic_paint(PIC *pic, int x,int y, PIXEL* pix);
	void pic_blot(PIC *pic,int x,int y,PIXEL* pix,int branch,int depth)
	void pic_diffusePen(PIC* pic,int x,int y,Pen pen);
	void pic_sandPen(PIC* pic,int x,int y,Pen pen);
	void pic_polygon(PIC* pic,POINT* points,int nPoint,PIXEL* pix);
	void pic_fillarea(PIC* pic,AREA area,PIXEL* pix);

	pic_beginUpDate(pic)		更新領域のクリア
	pic_endUpDate(pic,frame)	更新終了；更新領域の取得

	pic_loadTIFF_
	pic_saveTIFF_
	pic_getRectImage(pic,buf,frame)
	void pic_getScrBitMap(PIC* pic,SCRBITMAP bm,int ofsx,int ofsy, FRAME *fr);
		// 画像内の fr の領域を bm の ofsx, ofsy に転送する

	pixel_setRgb(pixel, r,g,b)
	pixel_getRgb(pixel, r,g,b)
#endif

#define	MODULE_PIC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <memory.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <egb.h>

#include "art.h"
#include "pic.h"
#include "subgrp.h"
#include "guisub.h"
#include "pensel.h"

static char* tempBuf = NULL;

			static uint _31_255[] =
				{  0,8,16,25, 33,41,49,58, 66,74,82,90, 99,107,115,123,
				   132,140,148,156, 165,173,181,189, 197,206,214,222, 
				   230,239,247,255};

int		pic_init(void)
{
	return 0;
}

void	pic_close(void)
{
}

PIC		*pic_new(int pixelsize, int wid,int ht)
{
	PIC *pic;
	if ((pic = TL_calloc(1, sizeof(PIC))) == NULL)
		return NULL;
	if ((pic->buf = TL_calloc(1,wid*ht*pixelsize/8)) == NULL)
		{ TL_free(pic);  return NULL; }
	memset(pic->buf, 0xff, wid*ht*pixelsize/8);
	pic->wid  = wid;
	pic->ht = ht;
	pic->pixelsize = pixelsize;
	return pic;
}

PIC* pic_dup(PIC* pic)
{
	PIC* newpic;
	if ((newpic = TL_calloc(1,sizeof(PIC))) == NULL)
		return NULL;
	if ((newpic->buf = TL_calloc(1,pic->pixelsize*pic->wid*pic->ht/8)) == NULL)
		{ TL_free(newpic);  return NULL; }
	memcpy(newpic->buf, pic->buf, pic->wid*pic->ht*pic->pixelsize/8);
	newpic->wid = pic->wid;
	newpic->ht = pic->ht;
	newpic->pixelsize = pic->pixelsize;
	return newpic;
}

void	pic_destroy(PIC *pic)
{
	TL_free(pic->buf);
	TL_free(pic);
}

/*--------------------------------------------------------*/
/*                   PIC更新情報の更新                    */
/*--------------------------------------------------------*/

static void pic_updatePoint(PIC* pic,int x,int y)
{
	if (pic->update.lupx < 0)
	{
		pic->update.lupx = pic->update.rdwx = x;
		pic->update.lupy = pic->update.rdwy = y;
	}
	else
	{
		if (x < pic->update.lupx)
			pic->update.lupx = x;
		else if (pic->update.rdwx < x)
			pic->update.rdwx = x;
		if (y < pic->update.lupy)
			pic->update.lupy = y;
		else if (pic->update.rdwy < y)
			pic->update.rdwy = y;
	}
}

static void pic_updateRect(PIC* pic, int x,int y,int wid,int ht)
{
  // 内容変更領域を更新
	int left,top,right,bottom;
	left = _max(0,x);
	right = _min(pic->wid-1,x+wid-1);
	top = _max(0,y);
	bottom = _min(pic->ht-1,y+ht-1);
	if (pic->update.X < 0)
	{
		pic->update.X = left;
		pic->update.X2 = right;
		pic->update.Y = top;
		pic->update.Y2 = bottom;
	}
	else
	{
		#define R	(pic->update)
		R.X = _min(R.X, left);
		R.X2 = _max(R.X2, right);
		R.Y = _min(R.Y, top);
		R.Y2 = _max(R.Y2, bottom);
		#undef R
	}
}

/*--------------------------------------------------------*/
/*                ピクセルの色の設定・取得                */
/*--------------------------------------------------------*/

void	pic_setPixelXy(PIC *pic, int x, int y, PIXEL *pixel)
/* １ピクセルの色を設定 */
{
	if (x < 0 || pic->wid<=x || y < 0 || pic->ht<=y)
		return;
	if (pic->pixelsize == 16)
		*(unsigned short*)&pic->buf[(pic->wid * y + x) * 2] = CODE32K(*pixel);
	else
	{
		char *p = PICADDR(pic,x,y);
		uint col = CODE16M(*pixel);
		SETBYTE3(p,col);
	}
	pic_updatePoint(pic, x,y);
}

void pic_grayPset(PIC* pic,int x,int y,int gray,PIXEL* pixel)
{
	if (x < 0 || pic->wid<=x || y < 0 || pic->ht<=y)
		return;
	if (pic->pixelsize == 16)
	{
		ushort* p = (ushort*)PICADDR(pic,x,y);
		int col = CODE32K(*pixel);
		int sr,sg,sb,dr,dg,db;
		GETRGB31(*p, dr,dg,db);
		GETRGB31(col, sr,sg,sb);
		dr = (dr * (255-gray) + sr * gray) / 255;
		dg = (dg * (255-gray) + sg * gray) / 255;
		db = (db * (255-gray) + sb * gray) / 255;
		SETRGB31(*p, dr,dg,db);
	}
	else
	{
		char* p = PICADDR(pic,x,y);
		int sr,sg,sb,dr,dg,db;
		sr=pixel->r,sg=pixel->g,sb=pixel->b;
		dr=p[0],dg=p[1],db=p[2];
		dr = (dr * (255-gray) + sr * gray) / 255;
		dg = (dg * (255-gray) + sg * gray) / 255;
		db = (db * (255-gray) + sb * gray) / 255;
		p[0]=dr,p[1]=dg,p[2]=db;
	}
	pic_updatePoint(pic, x,y);
}

void	pic_getPixelXy(PIC *pic, int x, int y, PIXEL *pixel)
/* １ピクセルの色を取得 */
{
	if (x < 0 || pic->wid<=x || y < 0 || pic->ht<=y)
		return;
	if (pic->pixelsize == 16)
	{
		int col = *(unsigned short*)&pic->buf[(pic->wid * y + x) * 2];
		int r,g,b;
		GETRGB31(col,r,g,b);
		pixel->r = _31_255[r];
		pixel->g = _31_255[g];
		pixel->b = _31_255[b];
	}
	else
	{
		char *p = PICADDR(pic,x,y);
		pixel->r = p[0];
		pixel->g = p[1];
		pixel->b = p[2];
	}
}

/*--------------------------------------------------------*/
/*                     濃度分布の描画                     */
/*--------------------------------------------------------*/

void pic_psetpen(PIC *pic,int x,int y,Pen pen,PIXEL *pixel)
{
	uint mix = pensel_getmix();
	x -= pen->ofsx;
	y -= pen->ofsy;
	for (int i=0; i<pen->ht; i++)
	{
		int dy = y + i;
		if (dy < 0 || pic->ht <= dy)
			continue;
		char *penp = pen->buf + pen->wid * i;
		if (pic->pixelsize == 16)
		{
			char *dp = PICADDR(pic,x,dy);
			int col = CODE32K(*pixel);
			int sr,sg,sb,dr,dg,db;
			GETRGB31(col,sr,sg,sb);
			for (int j=0; j<pen->wid; j++,dp+=2,penp++)
			{
				if (*penp == 0 || x+j < 0 || pic->wid <= x+j)
					continue;
				uint mr = (mix * (*penp) + 127) / 255;
				GETRGB31(WORD(dp),dr,dg,db);
				dr = (dr * (255-mr) + sr * (uint)mr + 127)/255;
				dg = (dg * (255-mr) + sg * (uint)mr + 127)/255;
				db = (db * (255-mr) + sb * (uint)mr + 127)/255;
				SETRGB31(WORD(dp),dr,dg,db);
			}
		}
		else
		{
			char *dp = PICADDR(pic,x,dy);
			int sr,sg,sb,dr,dg,db;
			sr=pixel->r,sg=pixel->g,sb=pixel->b;
			for (int j=0; j<pen->wid; j++,dp+=3,penp++)
			{
				if (*penp == 0 || x+j < 0 || pic->wid <= x+j)
					continue;
				uint mr = (mix * (*penp) + 127) / 255;
				dr=dp[0],dg=dp[1],db=dp[2];
				dr = (dr * (255-mr) + sr * (uint)mr + 127)/255;
				dg = (dg * (255-mr) + sg * (uint)mr + 127)/255;
				db = (db * (255-mr) + sb * (uint)mr + 127)/255;
				dp[0]=dr,dp[1]=dg,dp[2]=db;
			}
		}
	}
	pic_updateRect(pic,x,y,pen->wid,pen->ht);
}

/*--------------------------------------------------------*/
/*                     水平直線の描画                     */
/*--------------------------------------------------------*/

void pic_grayhline(PIC *pic,int x1,int x2,int y,int gray,PIXEL *pixel)
{
	if (x1 >= x2)
		SWAP_INT(x1,x2)
	if (y < 0 || pic->ht <= y)
		return;
	x1 = _max(0,x1);
	x2 = _min(pic->wid-1,x2);
	if (x2 < x1)
		return;
	if (pic->pixelsize == 16)
	{
		char *dp = PICADDR(pic,x1,y);
		ushort col = CODE32K(*pixel);
		if (gray >= 255)
		{
			for (int i=x1; i<=x2; i++,dp+=2)
				WORD(dp) = col;
		}
		else if (gray > 0)
		{
			int sr,sg,sb,dr,dg,db;
			int igray = 255 - gray;
			GETRGB31(col, sr,sg,sb);
			for (int i=x1; i<=x2; i++,dp+=2)
			{
				GETRGB31(WORD(dp), dr,dg,db);
				dr = (dr * igray + sr * gray + 128) / 255;
				dg = (dg * igray + sg * gray + 128) / 255;
				db = (db * igray + sb * gray + 128) / 255;
				SETRGB31(WORD(dp), dr,dg,db);
			}
		}
	}
	else if (pic->pixelsize == 24)
	{
		char *dp = PICADDR(pic,x1,y);
		if (gray >= 255)
		{
			for (int i=x1; i<=x2; i++,dp+=3)
				dp[0]=pixel->r,dp[1]=pixel->g,dp[2]=pixel->b;
		}
		else if (gray > 0)
		{
			int sr,sg,sb,dr,dg,db;
			sr=pixel->r,sg=pixel->g,sb=pixel->b;
			int igray = 255 - gray;
			for (int i=x1; i<=x2; i++,dp+=3)
			{
				dr=dp[0],dg=dp[1],db=dp[2];
				dr = (dr * igray + sr * (uint)gray + 127)/255;
				dg = (dg * igray + sg * (uint)gray + 127)/255;
				db = (db * igray + sb * (uint)gray + 127)/255;
				dp[0]=dr,dp[1]=dg,dp[2]=db;
			}
		}
	}
	pic_updateRect(pic,x1,y,x2-x1+1,1);
}

/*--------------------------------------------------------*/
/*                         クリア                         */
/*--------------------------------------------------------*/

void	pic_clear(PIC *pic, PIXEL *pixel)
{
	int i;
	for (i = 0; i < pic->ht; i++)
		pic_grayhline(pic, 0, pic->wid-1, i, 255, pixel);
}

/*--------------------------------------------------------*/
/*                       こすり処理                       */
/*--------------------------------------------------------*/

char *kosuri_graypat;
int kosuri_x, kosuri_y;
int kosuri_wid,kosuri_ht;

void pic_kosuriStart(PIC* pic,int x,int y,char* graypat,int wid,int ht)
// x,y : ペンの左上端の PIC 座標
// graypat : ペンの濃度デ−タ
// wid,ht : ペンの大きさ
{
	kosuri_graypat = graypat;
	kosuri_x = x;
	kosuri_y = y;
	kosuri_wid = wid;
	kosuri_ht = ht;
	if (tempBuf != NULL)
		TL_free(tempBuf);
	tempBuf = TL_calloc(1,pic->pixelsize*kosuri_wid*kosuri_ht/8);
}

void pic_kosuriDrag(PIC* pic,int x,int y,int r)
// x,y : ペンの左上端の PIC 座標
// r : こすり強さ (0〜255)
{
	if (tempBuf == NULL)
		return;
	int i,j;
  // 前のペンの位置の色を tempBuf に格納
	char *p = kosuri_graypat;
	for (i=0; i<kosuri_ht; i++)
	{
		if (kosuri_y+i < 0)
			continue;
		else if (kosuri_y+i >= pic->ht)
			break;
		char *ptrpic;
		ptrpic = pic->buf + PICOFFSET(pic,kosuri_x,kosuri_y+i);
		char *ptrbuf;
		ptrbuf = tempBuf + (kosuri_wid*i) * pic->pixelsize/8;
		if (pic->pixelsize == 16)
		{
			for (j=0; j<kosuri_wid; j++,p++,ptrpic+=2,ptrbuf+=2)
			{
				if (kosuri_x+j < 0)
					continue;
				else if (kosuri_x+j >= pic->wid)
					break;
				if (*p == 0)
					continue;
				WORD(ptrbuf) = WORD(ptrpic);
			}
		}
		else
		{
			for (j=0; j<kosuri_wid; j++,p++,ptrpic+=3,ptrbuf+=3)
			{
				if (kosuri_x+j < 0)
					continue;
				else if (kosuri_x+j >= pic->wid)
					break;
				if (*p == 0)
					continue;
				WORD(ptrbuf) = WORD(ptrpic);
				BYTE(ptrbuf+2) = BYTE(ptrpic+2);
			}
		}
	}
  // 新しいペンの位置と色をまぜあわせる
	p = kosuri_graypat;
	for (i=0; i<kosuri_ht; i++)
	{
		if (y+i < 0)
			continue;
		else if (y+i >= pic->ht)
			break;
		char *ptrpic;
		ptrpic = pic->buf + PICOFFSET(pic,x,y+i);
		char *ptrbuf;
		ptrbuf = tempBuf + (kosuri_wid*i) * pic->pixelsize/8;
		if (pic->pixelsize == 16)
		{
			for (j=0; j<kosuri_wid; j++,p++,ptrpic+=2,ptrbuf+=2)
			{
				if (x+j < 0)
					continue;
				else if (x+j >= pic->wid)
					break;
				if (*p == 0)
					continue;
				unsigned int sc,dc, sr,sg,sb,dr,dg,db,tr,tg,tb;
				sc = WORD(ptrbuf);
				dc = WORD(ptrpic);
				sr=(sc>>5)&31,sg=(sc>>10)&31,sb=sc&31;
				dr=(dc>>5)&31,dg=(dc>>10)&31,db=dc&31;
				tr = (sr*r+dr*(255-r)+127)/255;
				tg = (sg*r+dg*(255-r)+127)/255;
				tb = (sb*r+db*(255-r)+127)/255;
				WORD(ptrpic) = (tg<<10)|(tr<<5)|tb;
				tr = (sr*(255-r)+dr*r+127)/255;
				tg = (sg*(255-r)+dg*r+127)/255;
				tb = (sb*(255-r)+db*r+127)/255;
				WORD(ptrbuf) = (tg<<10)|(tr<<5)|tb;
			}
		}
		else
		{
			for (j=0; j<kosuri_wid; j++,p++,ptrpic+=3,ptrbuf+=3)
			{
				if (x+j < 0)
					continue;
				else if (x+j >= pic->wid)
					break;
				if (*p == 0)
					continue;
				unsigned int sr,sg,sb,dr,dg,db,tr,tg,tb;
				sr=ptrbuf[0],sg=ptrbuf[1],sb=ptrbuf[2];
				dr=ptrpic[0],dg=ptrpic[1],db=ptrpic[2];
				tr = (sr*r+dr*(255-r)+127)/255;
				tg = (sg*r+dg*(255-r)+127)/255;
				tb = (sb*r+db*(255-r)+127)/255;
				ptrpic[0]=tr,ptrpic[1]=tg,ptrpic[2]=tb;
				tr = (sr*(255-r)+dr*r+127)/255;
				tg = (sg*(255-r)+dg*r+127)/255;
				tb = (sb*(255-r)+db*r+127)/255;
				ptrbuf[0]=tr,ptrbuf[1]=tg,ptrbuf[2]=tb;
			}
		}
	}
	pic_updateRect(pic, x,y,kosuri_wid,kosuri_ht);
  // 次のこすりドラッグ
	kosuri_x = x;
	kosuri_y = y;
}

/*--------------------------------------------------------*/
/*                      ペン先ぼかし                      */
/*--------------------------------------------------------*/

void pic_diffusePen(PIC* pic,int x,int y,Pen pen)
{
	int picxbytes = pic->wid * pic->pixelsize / 8;
	int picy = y - pen->ofsy;
	for (int i=0; i<pen->ht; i++,picy++)
	{
		if (picy < 0 || pic->ht <= picy)
			continue;
		int picx = x - pen->ofsx;
		char* penp = pen->buf + PENOFFSET(pen,0,i);
		char* picp = pic->buf + PICOFFSET(pic,picx,picy);
		if (pic->pixelsize == 16)
		{
			for (int j=0; j<pen->wid; j++,picx++,penp++,picp+=2)
			{
				if (*penp == 0 || picx < 0 || pic->wid <= picx)
					continue;
				#define DIF 6
				uint r,g,b;
				uint sum,rsum,gsum,bsum;  sum=rsum=gsum=bsum=0;
				GETRGB31(WORD(picp),r,g,b);
				rsum+=r*DIF;  gsum+=g*DIF;  bsum+=b*DIF;  sum+=DIF;
				if (picy-1 >= 0)
				  { GETRGB31(WORD(picp-picxbytes),r,g,b);
				    rsum+=r,gsum+=g,bsum+=b,sum++; }
				if (picy+1 < pic->ht)
				  { GETRGB31(WORD(picp+picxbytes),r,g,b);
				    rsum+=r,gsum+=g,bsum+=b,sum++; }
				if (picx-1 >= 0)
				  { GETRGB31(WORD(picp-2),r,g,b);
				    rsum+=r,gsum+=g,bsum+=b,sum++; }
				if (picx+1 < pic->wid)
				  { GETRGB31(WORD(picp+2),r,g,b);
				    rsum+=r,gsum+=g,bsum+=b,sum++; }
				rsum = (rsum+sum/2) / sum;
				gsum = (gsum+sum/2) / sum;
				bsum = (bsum+sum/2) / sum;
				SETRGB31(WORD(picp),rsum,gsum,bsum);
				#undef DIF
			}
		}
		else
		{
			for (int j=0; j<pen->wid; j++,picx++,penp++,picp+=3)
			{
				if (*penp == 0 || picx < 0 || pic->wid <= picx)
					continue;
				#define DIF 6
				uint r,g,b;
				uint sum,rsum,gsum,bsum;  sum=rsum=gsum=bsum=0;
				r=picp[0],g=picp[1],b=picp[2];
				rsum+=r*DIF;  gsum+=g*DIF;  bsum+=b*DIF;  sum+=DIF;
				if (picy-1 >= 0)
				  { GET3BYTE(picp-picxbytes,r,g,b);
				    rsum+=r,gsum+=g,bsum+=b,sum++; }
				if (picy+1 < pic->ht)
				  { GET3BYTE(picp+picxbytes,r,g,b);
				    rsum+=r,gsum+=g,bsum+=b,sum++; }
				if (picx-1 >= 0)
				  { GET3BYTE(picp-3,r,g,b);
				    rsum+=r,gsum+=g,bsum+=b,sum++; }
				if (picx+1 < pic->wid)
				  { GET3BYTE(picp+3,r,g,b);
				    rsum+=r,gsum+=g,bsum+=b,sum++; }
				rsum = (rsum+sum/2) / sum;
				gsum = (gsum+sum/2) / sum;
				bsum = (bsum+sum/2) / sum;
				picp[0]=rsum,picp[1]=gsum,picp[2]=bsum;
				#undef DIF
			}
		}
	}
	pic_updateRect(pic, x-pen->ofsx, y-pen->ofsy, pen->wid, pen->ht);
}

void pic_sandPen(PIC* pic,int x,int y,Pen pen)
{
	int picxbytes = pic->wid * pic->pixelsize / 8;
	int picy = y - pen->ofsy;
	for (int i=0; i<pen->ht; i++,picy++)
	{
		if (picy < 0 || pic->ht <= picy)
			continue;
		int picx = x - pen->ofsx;
		char* penp = pen->buf + PENOFFSET(pen,0,i);
		char* picp = pic->buf + PICOFFSET(pic,picx,picy);
		if (pic->pixelsize == 16)
		{
			for (int j=0; j<pen->wid; j++,picx++,penp++,picp+=2)
			{
				if (*penp == 0 || picx < 0 || pic->wid <= picx)
					continue;
				#define DIF 6
				int r,g,b;
				GETRGB31(WORD(picp),r,g,b);
				r = _min(31,_max(0, r + rand() % 3 - 1));
				g = _min(31,_max(0, g + rand() % 3 - 1));
				b = _min(31,_max(0, b + rand() % 3 - 1));
				SETRGB31(WORD(picp),r,g,b);
				#undef DIF
			}
		}
		else
		{
			for (int j=0; j<pen->wid; j++,picx++,penp++,picp+=3)
			{
				if (*penp == 0 || picx < 0 || pic->wid <= picx)
					continue;
				int r,g,b;
				r=picp[0],g=picp[1],b=picp[2];
				r = _min(255,_max(0, r + (rand() % 13 - 6)));
				g = _min(255,_max(0, g + (rand() % 13 - 6)));
				b = _min(255,_max(0, b + (rand() % 13 - 6)));
				picp[0]=r,picp[1]=g,picp[2]=b;
			}
		}
	}
	pic_updateRect(pic, x-pen->ofsx, y-pen->ofsy, pen->wid, pen->ht);
}

/*--------------------------------------------------------*/
/*                    更新の開始・終了                    */
/*--------------------------------------------------------*/

void	pic_beginUpDate(PIC *pic)
{
	pic->update.lupx = -1;
}

void	pic_endUpDate(PIC *pic, FRAME *frame)
{
	pic->update.WID = pic->update.X2 - pic->update.X + 1;
	pic->update.HT  = pic->update.Y2 - pic->update.Y + 1;
	*frame = pic->update;
}

	static PIC *_pic;
	static TIFFINFO tiffinfo;

	static int putimage(char *buf, int ofsy, int ht)
	{
		for (int i=0; i<ht; i++)
		{
			if (ofsy+i >= _pic->ht)
				break;
			char *dp = _pic->buf + PICOFFSET(_pic, 0, ofsy+i);
			char *sp = buf + (tiffinfo.wid*tiffinfo.pixelsize/8)*i;
			int wid = _min(_pic->wid, tiffinfo.wid);
			int t = wid * _pic->pixelsize / 8;
			memcpy(dp, sp, t);
		}
		return 0;
	}

	static int getimage(char *buf,int ofsy,int ht)
	{
		for (int i=0; i<ht; i++)
		{
			if (ofsy+i >= _pic->ht)
				break;
			char *dp = buf + (tiffinfo.wid*tiffinfo.pixelsize/8)*i;
			char *sp = _pic->buf + PICOFFSET(_pic, 0, ofsy+i);
			int wid = _min(_pic->wid, tiffinfo.wid);
			int t = wid * _pic->pixelsize / 8;
			memcpy(dp, sp, t);
		}
		return 0;
	}

int pic_loadTIFF_(PIC *pic, char *fname)
/* PIC構造体内に TIFF ファイルの画像をロードする */
{
	_pic = pic;
	int ret;
	if ((ret = RM_getTIFFinfo(fname, &tiffinfo)) != NOERR)
		return ret;
	ret = RM_loadTIFF(fname, putimage, (int(*)())0);
	return ret;
}

int pic_saveTIFF_(PIC *pic, char *fname)
{
	_pic = pic;
	tiffinfo.wid = pic->wid;
	tiffinfo.ht = pic->ht;
	tiffinfo.pixelsize = pic->pixelsize;
	int ret;
	ret = RM_saveTIFF(fname, pic->pixelsize, pic->wid, pic->ht, TRUE,
					  getimage, (int(*)())0);
	return ret;
}

void pic_getScrBitMap(PIC* pic,SCRBITMAP bm, int ofsx, int ofsy, FRAME *_fr,
                      int zoom)
	// 画像内の fr(x,y,wid,ht) の領域を bm の ofsx, ofsy に転送する
	// 画面イメージへの変換を行う
{
	int i;
	FRAME fr;
	fr = *_fr;
	if (ofsx < 0)
		fr.X+=(-ofsx)/zoom, fr.WID-=(-ofsx)/zoom, ofsx=0;
	if (ofsy < 0)
		fr.Y+=(-ofsy)/zoom, fr.HT-=(-ofsy)/zoom, ofsy=0;
	if (fr.WID <= 0 && fr.HT <= 0)
		return;
	int wid = _min(fr.WID, pic->wid - fr.X,
	          (bm->wid - ofsx + zoom-1) / zoom);
		// ↑実際の転送ドット数
	if (wid <= 0)
		return;
	int dcnt = _min(zoom, bm->wid - ofsx - (wid-1)*zoom);
		// ↑SCRBITMAP側の右端のピクセルの横幅
	int dxbytes = bm->wid * bm->pixelsize / 8;
		// ↑SCRBITMAPの横バイト数
	int dxcnt = (wid-1)*zoom + dcnt;
		// ↑SCRBITMAP側の転送領域の横ピクセル数
	for (i=0; i<fr.HT; i++)
	{
		int dy = ofsy + zoom * i;
		int sy = fr.Y + i;
		if (sy < 0 || pic->ht <= sy)
			continue;
		if (dy < 0 || bm->ht <= dy)
			continue;
		if (wid == 0)
			break;
		char *dp = bm->buf + BMOFFSET(bm, ofsx, dy);
		char *dp0 = dp;
		char *sp = pic->buf + PICOFFSET(pic, fr.X, sy);
		if (zoom==1 && pic->pixelsize == 16 && bm->pixelsize == 16)
			memcpy(dp,sp,wid * 2);
		else if (pic->pixelsize == 16 && bm->pixelsize == 16)
		{
			int j;
			if (zoom == 2)
				for (j=0; j<wid-1; j++,sp+=2,dp+=4)
					WORD(dp)=WORD(dp+2)=WORD(sp);
			else if (zoom==3)
				for (j=0; j<wid-1; j++,sp+=2,dp+=6)
					WORD(dp)=WORD(dp+2)=WORD(dp+4)=WORD(sp);
			else if (zoom==4)
				for (j=0; j<wid-1; j++,sp+=2,dp+=8)
					WORD(dp)=WORD(dp+2)=WORD(dp+4)=WORD(dp+6)=WORD(sp);
			else if (zoom==5)
				for (j=0; j<wid-1; j++,sp+=2,dp+=10)
					WORD(dp)=WORD(dp+2)=WORD(dp+4)=WORD(dp+6)=
					WORD(dp+8)=WORD(sp);
			else if (zoom==6)
				for (j=0; j<wid-1; j++,sp+=2,dp+=12)
					WORD(dp)=WORD(dp+2)=WORD(dp+4)=WORD(dp+6)=
					WORD(dp+8)=WORD(dp+10)=WORD(sp);
			else if (zoom==7)
				for (j=0; j<wid-1; j++,sp+=2,dp+=14)
					WORD(dp)=WORD(dp+2)=WORD(dp+4)=WORD(dp+6)=
					WORD(dp+8)=WORD(dp+10)=WORD(dp+12)=WORD(sp);
			else if (zoom==8)
				for (j=0; j<wid-1; j++,sp+=2,dp+=16)
					WORD(dp)=WORD(dp+2)=WORD(dp+4)=WORD(dp+6)=
					WORD(dp+8)=WORD(dp+10)=WORD(dp+12)=WORD(dp+14)=WORD(sp);
			// SCRBITMAP 側の右端のドットだけ特別扱い
			for (j=0; j<dcnt; j++,dp+=2)
				WORD(dp)=WORD(sp);
		}
		else if (pic->pixelsize == 16 && bm->pixelsize == 24)
		{
			for (int j=0; j<wid-1; j++,sp+=2)
			{
				int r,g,b;
				GETRGB31(WORD(sp),r,g,b);
				r=_31_255[r]; g=_31_255[g], b=_31_255[b];
				for (int k=0; k<zoom; k++,dp+=3)
					dp[0]=r,dp[1]=g,dp[2]=b;
			}
			int r,g,b;
			GETRGB31(WORD(sp),r,g,b);
			r=_31_255[r]; g=_31_255[g], b=_31_255[b];
			for (int k=0; k<dcnt; k++,dp+=3)
				dp[0]=r,dp[1]=g,dp[2]=b;
		}
		else if (pic->pixelsize == 24 && bm->pixelsize == 16)
		{
			for (int j=0; j<wid-1; j++,sp+=3)
			{
				int r,g,b;
				r=sp[0],g=sp[1],b=sp[2];
				r>>=3,g>>=3,b>>=3;
				for (int k=0; k<zoom; k++,dp+=2)
					SETRGB31(WORD(dp), r,g,b);
			}
			int r,g,b;
			r=sp[0],g=sp[1],b=sp[2];
			r>>=3,g>>=3,b>>=3;
			for (int k=0; k<dcnt; k++,dp+=2)
				SETRGB31(WORD(dp), r,g,b);
		}
		else if (pic->pixelsize == 24 && bm->pixelsize == 24)
		{
			for (int j=0; j<wid-1; j++,sp+=3)
			{
				for (int k=0; k<zoom; k++,dp+=3)
					dp[0]=sp[0],dp[1]=sp[1],dp[2]=sp[2];
			}
			for (int k=0; k<dcnt; k++,dp+=3)
				dp[0]=sp[0],dp[1]=sp[1],dp[2]=sp[2];
		}
		// 縦方向にひきのばす
		int t = dxcnt * bm->pixelsize / 8;
		for (int j=1; j < zoom && dy+j < bm->ht; j++)
			memcpy(dp0+dxbytes*j, dp0, t);
	}
}

/*--------------------------------------------------------*/
/*                       ピクセル値                       */
/*--------------------------------------------------------*/

void pixel_setRgb(PIXEL *pixel, int r, int g, int b)
{
	pixel->r = (r < 0 ? 0 : r > 255 ? 255 : r);
	pixel->g = (g < 0 ? 0 : g > 255 ? 255 : g);
	pixel->b = (b < 0 ? 0 : b > 255 ? 255 : b);
}

void pixel_getRgb(PIXEL *pixel, int *r, int *g, int *b)
{
	*r = pixel->r;
	*g = pixel->g;
	*b = pixel->b;
}

void pic_copy(PIC* picSrc, FRAME* frSrc, PIC* picDest, POINT* ptDest)
	// frSrc:(x,y,wid,ht)
	// update 管理を忘れないこと！
{
	int i;
	if (frSrc->Y >= ptDest->y)
	{
		for (i=0; i<frSrc->HT; i++)
		{
			int sy = frSrc->Y+i;
			int dy = ptDest->y+i;
			if (sy < 0 || dy < 0)
				continue;
			if (sy >= picSrc->ht || dy >= picDest->ht)
				break;
			char *sp = picSrc->buf + PICOFFSET(picSrc,frSrc->X,frSrc->Y+i);
			char *dp = picDest->buf + PICOFFSET(picDest,ptDest->x,ptDest->y+i);
			int wid = _max(0,_min(frSrc->WID,
			               picSrc->wid - frSrc->X,
			               picDest->wid - ptDest->x));
			if (wid == 0)
				break;
			if (picSrc->pixelsize == picDest->pixelsize)
				memcpy(dp, sp, wid * picSrc->pixelsize / 8);
			else if (picSrc->pixelsize == 16 && picDest->pixelsize == 24)
			{
				for (int j=0; j<wid; j++,dp+=3,sp+=2)
				  { int r,g,b;  GETRGB31(WORD(sp), r,g,b);
					dp[0]=_31_255[r],dp[1]=_31_255[g],dp[2]=_31_255[b]; }
			}
			else if (picSrc->pixelsize == 24 && picDest->pixelsize == 16)
			{
				for (int j=0; j<wid; j++,dp+=2,sp+=3)
					SETRGB31(WORD(dp),sp[0]>>3,sp[1]>>3,sp[2]>>3);
			}
		}
	}
	else
	{
		for (i=0; i<frSrc->HT; i++)
		{
			int sy = frSrc->Y+frSrc->HT-1-i;
			int dy = ptDest->y+frSrc->HT-1-i;
			if (sy < 0 || dy < 0)
				break;
			if (sy >= picSrc->ht || dy >= picDest->ht)
				continue;
			char *sp = picSrc->buf + PICOFFSET(picSrc,frSrc->X,frSrc->Y+i);
			char *dp = picDest->buf + PICOFFSET(picDest,ptDest->x,ptDest->y+i);
			int wid = _max(0,_min(frSrc->WID,
			               picSrc->wid - frSrc->X,
			               picDest->wid - ptDest->x));
			if (wid == 0)
				break;
			if (picSrc->pixelsize == picDest->pixelsize)
				memcpy(dp, sp, wid * picSrc->pixelsize / 8);
			else if (picSrc->pixelsize == 16 && picDest->pixelsize == 24)
			{
				for (int j=0; j<wid; j++,dp+=3,sp+=2)
				  { int r,g,b;  GETRGB31(WORD(sp), r,g,b);
					dp[0]=_31_255[r],dp[1]=_31_255[g],dp[2]=_31_255[b]; }
			}
			else if (picSrc->pixelsize == 24 && picDest->pixelsize == 16)
			{
				for (int j=0; j<wid; j++,dp+=2,sp+=3)
					SETRGB31(WORD(dp),sp[0]>>3,sp[1]>>3,sp[2]>>3);
			}
		}
	}
	pic_updateRect(picDest, ptDest->x, ptDest->y, frSrc->WID, frSrc->HT);
}

void pic_paint(PIC *pic, int x,int y, PIXEL* pix)
{
	PIXEL pixBack;
	#define ISBACK(pix)	\
		((pix).r==pixBack.r && (pix).g==pixBack.g && (pix).b==pixBack.b)
	pic_getPixelXy(pic,x,y,&pixBack);
	if (ISBACK(*pix))
		return;
	int mix = pensel_getmix();
	void hline(int x1,int x2,int y)
	{
		pic_grayhline(pic,x1,x2,y,mix,pix);
	}
	BOOL shouldPaint(int x,int y)
	{
		PIXEL pix;
		pic_getPixelXy(pic,x,y,&pix);
		if (ISBACK(pix))
			return TRUE;
		else
			return FALSE;
	}
	int srchleft(int x,int y)
	{
		int sx1;
		PIXEL pix;
		for (sx1=x; sx1 > 0; sx1--)
		{
			pic_getPixelXy(pic,sx1-1,y,&pix);
			if (!ISBACK(pix))
				break;
		}
		return sx1;
	}
	int srchright(int x,int y)
	{
		int sx2;
		PIXEL pix;
		for (sx2=x; sx2 < pic->wid-1; sx2++)
		{
			pic_getPixelXy(pic,sx2+1,y,&pix);
			if (!ISBACK(pix))
				break;
		}
		return sx2;
	}
	do_paint(x,y,pic->wid,pic->ht,hline,shouldPaint,srchleft,srchright);
}

void pic_blot(PIC *pic,int x,int y,int branch,int depth,PIXEL* pix)
{
	uint mix = pensel_getmix();
	void pset(int x,int y,int gray)
	{
		pic_grayPset(pic,x,y,(gray*mix+127)/255,pix);
	}
	do_blot(x,y,branch,depth,pset);
}

void pic_polygon(PIC* pic,POINT* points,int nPoint,PIXEL* pix)
{
	int mix = pensel_getmix();
	void hline(int x1,int x2,int y)
	{
		pic_grayhline(pic,x1,x2,y,mix,pix);
	}
	do_polygon(points,nPoint,hline);
}

void pic_copyarea(PIC* picSrc, AREA areaSrc, PIC* picDest, POINT* ptDest)
{
	void hline(int x1,int x2,int y)
	{
		char *sp = PICADDR(picSrc,x1,y);
		char *dp = PICADDR(picDest,
			ptDest->x + (x1 - areaSrc->x), ptDest->y + (y - areaSrc->y));
		int wid = _max(0,_min( x2-x1+1,
					   picSrc->wid - areaSrc->x,
					   picDest->wid - ptDest->x));
		if (wid == 0)
			return;
		if (picSrc->pixelsize == picDest->pixelsize)
			memcpy(dp, sp, wid * picSrc->pixelsize / 8);
		else if (picSrc->pixelsize == 16 && picDest->pixelsize == 24)
		{
			for (int j=0; j<wid; j++,dp+=3,sp+=2)
			  { int r,g,b;  GETRGB31(WORD(sp), r,g,b);
				dp[0]=_31_255[r],dp[1]=_31_255[g],dp[2]=_31_255[b]; }
		}
		else if (picSrc->pixelsize == 24 && picDest->pixelsize == 16)
		{
			for (int j=0; j<wid; j++,dp+=2,sp+=3)
				SETRGB31(WORD(dp),sp[0]>>3,sp[1]>>3,sp[2]>>3);
		}
	}
	if (areaSrc->y >= ptDest->y)
	{
		for (int i=0; i<areaSrc->ht; i++)
		{
			int sy = areaSrc->y + i;
			int dy = ptDest->y + i;
			if (sy < 0 || dy < 0)
				continue;
			if (sy >= picSrc->ht || dy >= picDest->ht)
				break;
			area_forEachSect(areaSrc,sy,hline);
		}
	}
	else
	{
		for (int i=0; i<areaSrc->ht; i++)
		{
			int sy = areaSrc->y + areaSrc->ht - 1 - i;
			int dy = ptDest->y + areaSrc->ht - 1 - i;
			if (sy < 0 || dy < 0)
				break;
			if (sy >= picSrc->ht || dy >= picDest->ht)
				continue;
			area_forEachSect(areaSrc,sy,hline);
		}
	}
	pic_updateRect(picDest, ptDest->x, ptDest->y, areaSrc->wid, areaSrc->ht);
}

void pic_fillarea(PIC* pic,AREA area,PIXEL* pix)
{
	int mix = pensel_getmix();
	void hline(int x1,int x2,int y)
	{
		pic_grayhline(pic,x1,x2,y,mix,pix);
	}
	for (int i=0; i<area->ht; i++)
	{
		int sy = area->y + i;
		if (sy < 0)
			continue;
		if (sy >= pic->ht)
			break;
		area_forEachSect(area, sy, hline);
	}
	pic_updateRect(pic, area->x, area->y, area->wid, area->ht);
}
