changeset 60:e16e13d8cd68

Replaced SATURATE -> ADD, implemented objComposite, corrected minor things
author Thibaut GIRKA <thib@sitedethib.com>
date Fri, 18 Dec 2009 20:41:38 +0100
parents 36d92d21300f
children bdd8a5ff8f46
files scn2k/scn2k_grp.cc scn2k/scn2k_grp.h scn2k/scn2k_grpimpl.cc window/picture.cc window/picture.h window/render.cc window/render.h
diffstat 7 files changed, 94 insertions(+), 114 deletions(-) [+]
line wrap: on
line diff
--- a/scn2k/scn2k_grp.cc
+++ b/scn2k/scn2k_grp.cc
@@ -168,7 +168,7 @@ void GrpObj::Update(void) {
 	}
 	if (picture == NULL) return;
 	if (attr & UPDATE_POS) {
-		if ( (attr & SATURATE) || zoom != -1) {
+		if (zoom != -1) {
 			int w=0, h=0;
 			GetSrcGeom(w,h);
 			picture->Move(_posx-w/2, _posy-h/2);
@@ -238,8 +238,8 @@ void GrpObj::UpdateSurface(void) {
 			picture->SetSurface(path.c_str(), 0, 0);
 			picture->SetSurfaceRect(Rect(0,0,width,height));
 		}
-		if (attr & SATURATE)
-			picture->SetSurfaceAttribute(PicBase::BLIT_SATURATE);
+		if (attr & BLIT_ADD)
+			picture->SetSurfaceAttribute(PicBase::BLIT_ADD);
 	} else if (gtype == MOJI) { // テキスト描画
 		if (print_moji.length() == 0) return;
 		UpdateMoji();
@@ -396,8 +396,7 @@ void GrpObj::CreateGan(Event::Container&
 		return;
 	}
 
-	picture->SetSurfaceAttribute(PicBase::BLIT_SATURATE);
-	attr = Attribute(attr | UPDATE_POS | SATURATE);
+	attr = Attribute(attr | UPDATE_POS);
 
 	const char* buf = data + 16;
 	buf += strlen(buf) + 1; // 画像ファイル名が入っている
@@ -631,7 +630,7 @@ Grp::Grp(Event::Container& _event, PicCo
 	RegisterCommand(1, 33, 100, "grpCopy", (CmdImpl) &Grp::impl_grpCopy);
 	RegisterCommand(1, 33, 1201, "recFill", (CmdImpl) &Grp::impl_recFill);
 	RegisterCommand(1, 33, 1100, "recCopy", (CmdImpl) &Grp::impl_recCopy);
-	RegisterCommand(1, 33, 1101, "recMaskCopy", NULL); //FIXME
+	RegisterCommand(1, 33, 1101, "recMaskCopy", NULL); //TODO: Same thing as recCopy, but using source's alpha
 	RegisterCommand(1, 33, 1600, "recAdd", (CmdImpl) &Grp::impl_recAdd);
 	RegisterCommand(1, 33, 406, "grpPan", (CmdImpl) &Grp::impl_grpPan);
 
@@ -734,7 +733,7 @@ Grp::Grp(Event::Container& _event, PicCo
 	RegisterCommand(1, 82, 1019, "objBgColB", NULL);
 	RegisterCommand(1, 81, 1020, "objColLevel", NULL);
 	RegisterCommand(1, 82, 1020, "objBgColLevel", NULL);
-	RegisterCommand(1, 81, 1021, "objComposite", NULL);//(CmdImpl) &Grp::impl_objComposite); //FIXME: May be broken
+	RegisterCommand(1, 81, 1021, "objComposite", (CmdImpl) &Grp::impl_objComposite); //FIXME: May be broken
 	RegisterCommand(1, 82, 1021, "objBgComposite", (CmdImpl) &Grp::impl_objComposite);
 	RegisterCommand(1, 81, 1024, "objSetText", (CmdImpl) &Grp::impl_objSetText);
 	RegisterCommand(1, 82, 1024, "objBgSetText", (CmdImpl) &Grp::impl_objSetText);
@@ -1553,22 +1552,17 @@ void Grp::Exec(Cmd& cmd) {
 	CommandHandler::Exec(cmd);
 
 	//TODO: ???
-	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x3c && cmd.cmd3 == 0) { // ??? : KANOGI : 画像オブジェクトの削除?
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 60 && cmd.cmd3 == 0) { // ??? : KANOGI : 画像オブジェクトの削除?
 		DeleteObjPic(cmd.args[0].value); // 旧ファイル名のsurfaceを削除
 		GrpObj& g = grpobj[cmd.args[0].value];
 		g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN);
 		cmd.clear();
 	}
 
-	//TODO: ???
-	if ( (cmd.cmd1 == 1 || cmd.cmd1 == 2) && cmd.cmd2 == 0x51) {
-		/*GrpObj& g = grpobj[cmd.args[0].value];
-		int attr;
-		GrpObjMap::iterator it;
-		for (it = g.children_obj.begin(); it != g.children_obj.end(); it++)
-			attr |= it->second.attr;
-		if (attr & GrpObj::UPDATE_ALL)
-			SetObjChanged(cmd.args[0].value);*/
+	// Refresh changed objects...
+	//FIXME: should may be go away?
+	//Seems it'll work only for objects in the foreground
+	if ( (cmd.cmd1 == 1 || cmd.cmd1 == 2) && cmd.cmd2 == 81) {
 		GrpObj* g;
 		if (cmd.cmd1 == 2)
 			g = GetGraphicObj(cmd.args[0].value, cmd.args[1].value);
--- a/scn2k/scn2k_grp.h
+++ b/scn2k/scn2k_grp.h
@@ -81,7 +81,7 @@ struct GrpObj {
 
 	vector<Rect> src_pos;
 	enum GrpType { FILLRECT = 1, FILE = 2, GAN = 3, MOJI = 4, DIGIT = 5} gtype;
-	enum Attribute { NONE=0, WIPEON=1, SATURATE=2, HIDDEN=4,
+	enum Attribute { NONE=0, WIPEON=1, BLIT_ADD=2, HIDDEN=4,
 		UPDATE_PICTURE = 16, UPDATE_POS = 32, UPDATE_ALPHA = 64, UPDATE_SNUM = 128, UPDATE_CLIP = 256, UPDATE_VISIBLE = 512,
 		UPDATE_ALL = (UPDATE_PICTURE | UPDATE_POS | UPDATE_ALPHA | UPDATE_SNUM | UPDATE_CLIP | UPDATE_VISIBLE),
 		ANM_PLAYSTART = 0x8000, ANM_PLAYING = 0x10000,
--- a/scn2k/scn2k_grpimpl.cc
+++ b/scn2k/scn2k_grpimpl.cc
@@ -155,6 +155,7 @@ void Grp::impl_recFill(Cmd& cmd) {
 }
 
 void Grp::impl_recCopy(Cmd& cmd) {
+	//TODO: Handle forms 0 and 1
 	int sx = cmd.args[0].value;
 	int sy = cmd.args[1].value;
 	int w = cmd.args[2].value;
@@ -172,7 +173,6 @@ void Grp::impl_recCopy(Cmd& cmd) {
 		// if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
 		cmd.cmd_type = CMD_SAVECMDGRP;
 	}
-
 	else if (cmd.cmd4 == 3) { // alpha ゃcopy
 		unsigned char alpha;
 		if (cmd.args[8].value < 0) alpha = 0;
@@ -191,7 +191,7 @@ void Grp::impl_recCopy(Cmd& cmd) {
 }
 
 void Grp::impl_recAdd(Cmd& cmd) {
-	if (cmd.cmd4 == 3) { // saturate mode  alpha 篁 copy
+	if (cmd.cmd4 == 3) { // add mode  alpha 篁 copy
 		int sx = cmd.args[0].value;
 		int sy = cmd.args[1].value;
 		int w = cmd.args[2].value;
@@ -205,15 +205,15 @@ void Grp::impl_recAdd(Cmd& cmd) {
 		if (cmd.args[8].value < 0) alpha = 0;
 		else if (cmd.args[8].value > 255) alpha = 255;
 		else alpha = cmd.args[8].value;
-		eprintf("copy surface w/ saturate %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+		eprintf("copy surface w/ add %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
 		if (src == dest) {
 			DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
 			src = WORKPDT;
 		}
 		if (alpha != 0) {
-			// saturate mode : screen (picture) 筝篏
+			// add mode : screen (picture) 筝篏
 			PicBase* screen_tmp = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
-			screen_tmp->SetSurface(Ssurface(src), 0, 0, PicBase::BLIT_SATURATE);
+			screen_tmp->SetSurface(Ssurface(src), 0, 0, PicBase::BLIT_ADD);
 			screen_tmp->SetSurfaceRect(rect);
 			screen_tmp->Move(dx, dy);
 			screen_tmp->SetSurfaceAlpha(&alpha, Rect(0,0,1,1));
@@ -348,7 +348,7 @@ void Grp::impl_createObj(Cmd& cmd) {
 		base_argc = 1;
 
 	if (cmd.cmd3 == 1000) { /* <ゃ荐絎 */
-		g->gtype = GrpObj::FILE; //FIXME: Strange thing in the main menu; that happens with objComposite
+		g->gtype = GrpObj::FILE;
 		string name = cmd.Str(cmd.args[base_argc + 1]);
 		if (name.find('?') != -1) {//TODO
 			//Used for shading, with DAT/tcdata.tcc or other filename provided by #TONECURVE_FILENAME
@@ -516,12 +516,11 @@ void Grp::impl_objColour(Cmd& cmd) {
 void Grp::impl_objComposite(Cmd& cmd) {//FIXME
 	int base_arg = 0;
 	GrpObj* g = GetGraphicObjVarMode(cmd, base_arg, (cmd.cmd2 == 0x51));
-
 	if (cmd.args[base_arg + 1].value == 1) {
-		g->attr = GrpObj::Attribute(g->attr | GrpObj::SATURATE);
+		g->attr = GrpObj::Attribute(g->attr | GrpObj::BLIT_ADD);
 		cmd.clear();
 	} else if (cmd.args[base_arg + 1].value == 0) {
-		g->attr = GrpObj::Attribute(g->attr & (~GrpObj::SATURATE));
+		g->attr = GrpObj::Attribute(g->attr & (~GrpObj::BLIT_ADD));
 		cmd.clear();
 	}
 	g->SetUpdate();
@@ -765,3 +764,4 @@ void Grp::impl_movPlay(Cmd& cmd) {
 		cmd.clear();
 	}
 }
+
--- a/window/picture.cc
+++ b/window/picture.cc
@@ -41,10 +41,9 @@
 
 using namespace std;
 
-int print_blit = 0;
 /* render.cc */
 void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect);
-void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
+void DSurfaceBlitAdd(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
 void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect);
 void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a=0xff); // クリア
 #if 0 /* DEBUG */
@@ -180,13 +179,9 @@ void PicBase::ExecReBlit(const Rect& rpo
 	Rect rpos = rpos_c;
 	Rect abs_r = QueryAbsPos(rpos);
 	Rect ppos = parent_pos(rpos);
-if(print_blit) fprintf(stderr,"back.");
 	if (parent) parent->BlitBack(z_pos, ppos);
-if(print_blit) fprintf(stderr,"self.");
 	if (!is_hidden_now) Blit(rpos);
-if(print_blit) fprintf(stderr,"front.");
 	if (parent) parent->BlitFront(z_pos, ppos);
-if(print_blit) fprintf(stderr,"end.");
 }
 
 void PicBase::ZMove(PicBase* move_to) {
@@ -324,7 +319,7 @@ void PicBase::SetSurfaceAlpha(const unsi
 void PicBase::SetSurfaceColorKey(int r, int g, int b) {
 	surface_alpha = 0;
 	surface_alpha_rect = Rect(0,0);
-	attribute &= ~(BLIT_SATURATE | BLIT_MULTIPLY);
+	attribute &= ~(BLIT_ADD | BLIT_MULTIPLY);
 	if (surface_own) {
 		int key = SDL_MapRGB( ((SDL_Surface*)surface_own)->format, r, g, b);
 		key |= 0xff000000;
@@ -402,7 +397,7 @@ void PicBase::SetSurface(Surface* new_su
 	if (surface_own != NULL && (attribute & SURFACE_FREE)) {
 		root->DeleteSurface(surface_own);
 	}
-	attribute &= ~(SURFACE_FREE | BLIT_SATURATE | BLIT_MULTIPLY | NO_PICTURE | SOLID);
+	attribute &= ~(SURFACE_FREE | BLIT_ADD | BLIT_MULTIPLY | NO_PICTURE | SOLID);
 	attribute |= new_attr;
 	surface_own = new_surface;
 	surface_x = x;
@@ -469,9 +464,9 @@ void PicBase::SetClipArea(const Rect& r)
 }
 
 void PicBase::SetSurfaceAttribute(int new_attribute) {
-	attribute &= ~(BLIT_SATURATE | BLIT_MULTIPLY);
-	attribute |= new_attribute & (BLIT_SATURATE | BLIT_MULTIPLY);
-	if (new_attribute & (BLIT_SATURATE | BLIT_MULTIPLY)) {
+	attribute &= ~(BLIT_ADD | BLIT_MULTIPLY);
+	attribute |= new_attribute & (BLIT_ADD | BLIT_MULTIPLY);
+	if (new_attribute & (BLIT_ADD | BLIT_MULTIPLY)) {
 		rel_solid_area = Rect(0,0);
 	}
 }
@@ -539,19 +534,16 @@ void PicContainer::BlitBack(iterator z, 
 		Rect cpos = child_pos(rpos, *z);
 		Rect apos = (*z)->QueryAbsPos(cpos);
 		Rect draw_rpos = (*z)->parent_pos(cpos);
-if(print_blit) fprintf(stderr,"cahce.");
 		root->BlitSurface(surface_back, draw_rpos, root->surface, apos);
 		goto self_redraw;
 	}
 parent_redraw:
 	if (parent) {
 		Rect ppos = parent_pos(rpos);
-if(print_blit) fprintf(stderr,"parent-back.");
 		parent->BlitBack(z_pos, ppos);
 	}
 	if (is_hidden_now) return;
 self_redraw:
-if(print_blit) fprintf(stderr,"back-self.");
 	BlitSelf(rpos); // 子は描画せず、自分だけ描画
 children_redraw:
 	for (; it != z; it++) {
@@ -564,10 +556,8 @@ children_redraw:
 }
 
 void PicContainer::BlitChildren(Rect rpos) {
-if (print_blit) fprintf(stderr,"bc.");
 	iterator end = children.end();
 	for (iterator it = children.begin(); it != end; it++) {
-if ( (*it)->is_hidden_now) if(print_blit) fprintf(stderr,"bch %p;",*it);
 		if ( (*it)->is_hidden_now) continue;
 		if ( (*it)->rel_pos.is_crossed(rpos)) {
 			Rect cpos = child_pos(rpos, *it);
@@ -601,7 +591,6 @@ void PicContainer::BlitSelf(Rect rpos) {
 	if (rpos.empty()) return;
 	Rect apos = QueryAbsPos(rpos);
 	// 必要に応じて保存、描画
-if(print_blit) fprintf(stderr,"self-back.");
 	if (attribute & CACHE_BACK) root->BlitSurface(root->surface, apos, surface_back, rpos);
 	if (! (attribute & NO_PICTURE)) {
 		rpos.rmove(surface_x, surface_y);
@@ -610,7 +599,6 @@ if(print_blit) fprintf(stderr,"self-back
 			clip.rmove(rpos.lx, rpos.ty);
 			rpos.intersect(clip);
 		}
-if(print_blit) fprintf(stderr,"self-blit.");
 		root->BlitSurface(surface_own, rpos, surface_alpha, surface_alpha_rect, root->surface, apos, attribute);
 	} else if (parent == NULL) { // 親がいないなら背景消去の責任をもつ
 		DSurfaceFill(root->surface, apos, 0, 0, 0);
@@ -894,14 +882,6 @@ void PicRoot::ExecUpdate(void) {
 	vector<UpdateItem>::iterator it;
 	vector<UpdateItem>::iterator end = update_rects.end();
 
-if(print_blit){
-	fprintf(stderr,"ExecUpdate Start: \n\t");
-	for (it=update_rects.begin(); it != end; it++) {
-		fprintf(stderr,"(%d,%d,%d,%d), ",it->apos.lx,it->apos.ty,it->apos.rx,it->apos.by);
-	}
-	fprintf(stderr,"\n");
-}
-
 	for (it=update_rects.begin(); it != end; it++) {
 		if (it->rpos.width() == 0) continue;
 
@@ -925,14 +905,6 @@ if(print_blit){
 		}
 	}
 
-if(print_blit){
-	fprintf(stderr,"->\t");
-	for (it=update_rects.begin(); it != end; it++) {
-		fprintf(stderr,"(%d,%d,%d,%d), ",it->apos.lx,it->apos.ty,it->apos.rx,it->apos.by);
-	}
-	fprintf(stderr,"\n");
-}
-
 	int num = update_rects.size();
 	SDL_Rect* r = new SDL_Rect[num];
 	Rect confine = Rect(0, 0, surface->w, surface->h);
@@ -942,10 +914,9 @@ if(print_blit){
 		UpdateItem& item = update_rects[i];
 		Rect& ur = item.apos;
 		if (ur.width() == 0) continue;
-if(print_blit)fprintf(stderr,"%p: %d,%d,%d,%d",item.pic, item.apos.lx, item.apos.ty, item.apos.rx, item.apos.by);
 
 		item.pic->ExecReBlit(item.rpos);
-if(print_blit)fprintf(stderr,"\n");
+
 		ur.intersect(confine);
 		r[n].x = ur.lx;
 		r[n].y = ur.ty;
@@ -954,7 +925,7 @@ if(print_blit)fprintf(stderr,"\n");
 		if (surface != hw_surface) SDL_BlitSurface(surface, &r[n], hw_surface, &r[n]);
 		n++;
 	}
-if(print_blit)fprintf(stderr,"\n");
+
 	SDL_UpdateRects(hw_surface, n, r);
 	delete[] r;
 	update_rects.clear();
@@ -1016,36 +987,36 @@ inline SDL_Rect SDLed(const Rect& rect) 
 #ifndef ALPHA_MAX
 #define ALPHA_MAX 255
 #endif
-void PicRoot::BlitSurface(Surface* src, const Rect& src_r, const unsigned char* alpha, const Rect& alpha_r, Surface* dest, const Rect& dest_r, int attribute) const {
-if (print_blit) fprintf(stderr," s %p %d:%d:%d:%d;",src, dest_r.lx, dest_r.ty, dest_r.rx, dest_r.by);
+void PicRoot::BlitSurface(Surface* src, const Rect& src_r, const unsigned char* alpha, const Rect& alpha_r,
+                          Surface* dest, const Rect& dest_r, int attribute) const
+{
 	SDL_Rect sr = SDLed(src_r); SDL_Rect dr = SDLed(dest_r);
 
-	if (attribute & PicBase::BLIT_MULTIPLY) {
-if (print_blit) fprintf(stderr,"M");
+	if (attribute & PicBase::BLIT_MULTIPLY)
+	{
 		DSurfaceBlitMultiply(src, src_r, dest, dest_r);
 		return;
-	} else if (attribute & PicBase::BLIT_SATURATE && src->format->Amask == 0) {
-if (print_blit) fprintf(stderr,"S");
+	}
+	else if (attribute & PicBase::BLIT_ADD)
+	{
 		unsigned char a = 255;
-		if (alpha && alpha_r.width() >= 1 && alpha_r.height() >= 1) a = *alpha;
-		DSurfaceBlitSaturate(src, src_r, dest, dest_r, a);
+		if (alpha != NULL && alpha_r.width() >= 1 && alpha_r.height() >= 1)
+			a = *alpha;
+		DSurfaceBlitAdd(src, src_r, dest, dest_r, a);
 		return;
 	}
 
-if (print_blit) fprintf(stderr,"N");
-	if (alpha == NULL || alpha_r.width() == 0) { // simple blit
-if (print_blit) fprintf(stderr,"X");
+	if (alpha == NULL || alpha_r.width() == 0) // simple blit
+	{
 		SDL_BlitSurface(src, &sr, dest, &dr);
 		return;
 	}
 	if (alpha_r.width() == 1 && alpha_r.height() == 1) {
 		if (*alpha == 255) {
-if (print_blit) fprintf(stderr,"Y");
 			SDL_BlitSurface(src, &sr, dest, &dr);
 			return;
 		}
 		if (src->format->Amask == 0) { // use per-surface alpha
-if (print_blit) fprintf(stderr,"Z");
 			SDL_SetAlpha(src, SDL_SRCALPHA, *alpha);
 			SDL_BlitSurface(src, &sr, dest, &dr);
 			SDL_SetAlpha(src, 0, 0);
@@ -1053,9 +1024,7 @@ if (print_blit) fprintf(stderr,"Z");
 		}
 	}
 	// generic alpha blit
-if (print_blit) fprintf(stderr,"W");
 	DSurfaceBlitAlpha(src, src_r, dest, dest_r, alpha, alpha_r);
-	return;
 }
 
 bool PicRoot::with_mask(Surface* s) {
--- a/window/picture.h
+++ b/window/picture.h
@@ -71,7 +71,7 @@ class PicBase {
 		bool is_hidden_now;
 		bool is_cached;
 	public:
-		enum { /*MOBILE=1,*/ CACHE_BACK=2, /* CACHE_SELF=4,*/ NO_PICTURE=8, SOLID = 16, SURFACE_FREE = 32, FIT_SURFACE = 64, BLIT_SATURATE = 128, BLIT_MULTIPLY = 256, ALPHA_FREE=512};
+		enum { /*MOBILE=1,*/ CACHE_BACK=2, /* CACHE_SELF=4,*/ NO_PICTURE=8, SOLID = 16, SURFACE_FREE = 32, FIT_SURFACE = 64, BLIT_ADD = 128, BLIT_MULTIPLY = 256, ALPHA_FREE=512};
 	private:
 		int attribute;
 
--- a/window/render.cc
+++ b/window/render.cc
@@ -251,49 +251,56 @@ void DSurfaceFillA(Surface* dsto, const 
 #define CMASK1 0xff00ff
 #define CMASK2 0x00ff00
 
-inline void blit_pixel(Uint32* dmem, Uint32* smem, const unsigned char* amem, bool use_srcalpha) {
-	Uint32 d = *dmem;
-	Uint32 s = *smem;
-	Uint32 as = s>>ASHIFT;
+inline void blit_pixel(Uint32* dest, Uint32* src, const unsigned char* alpha, bool use_srcalpha) {
+	Uint32 dest_value = *dest;
+	Uint32 src_value = *src;
+	Uint32 as = src_value >> ASHIFT;
 	if (as == 255 || (!use_srcalpha) ) {
-		as = *amem;
+		as = *alpha;
 	} else {
-		as += as>>7; /* 0-0xff -> 0-0x100 */
-		as *= *amem;
+		as += (as >> 7); /* 0-0xff -> 0-0x100 */
+		as *= *alpha;
 		as >>= 8;
 	}
-	as += as>>7;
-	Uint32 s1 = s & CMASK1;
-	Uint32 d1 = d & CMASK1;
-	d1 = (d1 + (((s1-d1) * as) >> 8)) & CMASK1;
-	s &= CMASK2;
-	d &= CMASK2;
-	d = (d + (((s-d) * as) >> 8)) & CMASK2;
-	*dmem = d1 | d | 0xff000000;
+	as += as >> 7;
+	// Isolate Red and Blue components
+	Uint32 src_c1 = src_value & CMASK1;
+	Uint32 dest_c1 = dest_value & CMASK1;
+	// Blend Red and Blue components
+	dest_c1 = (dest_c1 + (((src_c1-dest_c1) * as) >> 8)) & CMASK1;
+	// Isolate Green component
+	src_value &= CMASK2;
+	dest_value &= CMASK2;
+	// Blend Green component
+	dest_value = (dest_value + (((src_value-dest_value) * as) >> 8)) & CMASK2;
+	// Put it alltogether
+	*dest = dest_c1 | dest_value | 0xff000000;
 }
 
-static void blit_line(Uint32* dmem, Uint32* smem, const unsigned char* amem,int ax0, int ax1, int awidth, int aj0, int aj1, bool use_srcalpha) {
+static void blit_line(Uint32* dest, Uint32* src, const unsigned char* alpha,int ax0, int ax1, int awidth, int aj0, int aj1, bool use_srcalpha) {
 	int j;
 	int ax = ax0;
-	const unsigned char* a = amem + ax0;
-	Uint32* d = dmem;
-	Uint32* s = smem;
+	const unsigned char* a = alpha + ax0;
 	if (awidth == 1) { //  わりとよくあるので最適化
 		for (j=aj0; j < aj1; j++) {
-			blit_pixel(d++, s++, amem, use_srcalpha);
+			blit_pixel(dest++, src++, alpha, use_srcalpha);
 		}
-	} else {
+	}
+	else
+	{
 		for (j=aj0; j < aj1; j++) {
 			for (; ax<awidth; ax++)
-				blit_pixel(d++, s++, a++, use_srcalpha);
+				blit_pixel(dest++, src++, a++, use_srcalpha);
 			ax = 0;
-			a = amem;
+			a = alpha;
 		}
-		for (; ax < ax1; ax++) blit_pixel(d++, s++, a++, use_srcalpha);
+		for (; ax < ax1; ax++)
+			blit_pixel(dest++, src++, a++, use_srcalpha);
 	}
 }
 
-void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect) {
+void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect)
+{
 	SDL_Surface* dst = (SDL_Surface*)dst_o;
 	SDL_Surface* src = (SDL_Surface*)src_o;
 	SDL_PixelFormat& fmt = *dst->format;
@@ -346,7 +353,7 @@ void DSurfaceBlitAlpha(Surface* src_o, c
 	SDL_UnlockSurface(dst);
 }
 
-void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, unsigned char alpha) {
+void DSurfaceBlitAdd(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, unsigned char alpha) {
 	SDL_Surface* dst = (SDL_Surface*)dst_o;
 	SDL_Surface* src = (SDL_Surface*)src_o;
 
@@ -370,21 +377,31 @@ void DSurfaceBlitSaturate(Surface* src_o
 	int rshift = fmt.Rshift - fmt.Rloss; int rmask = fmt.Rmask;
 	int gshift = fmt.Gshift - fmt.Gloss; int gmask = fmt.Gmask;
 	int bshift = fmt.Bshift - fmt.Bloss; int bmask = fmt.Bmask;
+	int ashift = src->format->Ashift - src->format->Aloss; int amask = src->format->Amask;
 	int allmask = rmask | gmask | bmask;
-	int i;
-	for (i=0; i<height; i++) {
+	int i, j;
+	for (i=0; i < height; i++) {
 		char* d = dmem; char* s = smem;
-		int j; for (j=0; j<width; j++) {
+		for (j=0; j < width; j++) {
 			Uint32 sd = *(Uint32*)s;
 			Uint32 dd = *(Uint32*)d;
 			if (sd&allmask) {
 				Uint32 sr = (sd&rmask)>>rshift;
 				Uint32 sg = (sd&gmask)>>gshift;
 				Uint32 sb = (sd&bmask)>>bshift;
-				if (alpha != ALPHA_MAX) {
-					sr = (sr*alpha)>>8;
-					sg = (sg*alpha)>>8;
-					sb = (sb*alpha)>>8;
+				Uint32 alpha2 = alpha;
+				if (amask)
+				{
+					alpha2 = ((sd&amask)>>ashift);
+					alpha2 += alpha2 >> 7;
+					alpha2 *= alpha;
+					alpha2 >>= 8;
+				}
+				
+				if (alpha2 != ALPHA_MAX) {
+					sr = (sr*alpha2)>>8;
+					sg = (sg*alpha2)>>8;
+					sb = (sb*alpha2)>>8;
 				}
 				Uint32 dr = sr + ((dd&rmask)>>rshift);
 				Uint32 dg = sg + ((dd&gmask)>>gshift);
--- a/window/render.h
+++ b/window/render.h
@@ -38,7 +38,7 @@ void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a=0xff); // 促俗促棚促蔵
 void DSurfaceFillA(Surface* src, const Rect& rect, int r, int g, int b, int a=0xff); // 促促足促孫促促促贈促坦促促揃テ棚
 void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect); // 促続促臓
 void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect);
-void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
+void DSurfaceBlitAdd(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
 void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o);
 
 #endif