#help_index "Graphics/Sprite;Sprites"
#help_file "::/Doc/Sprite"

U8 polypt_map[9] = {0, 1, 2, 3, 0, 4, 5, 6, 7};

I64 sprite_elem_base_sizes[SPT_TYPES_NUM] = {
	sizeof(CSpriteBase),		//SPT_END
	sizeof(CSpriteColor), 		//SPT_COLOR
	sizeof(CSpriteDitherColor),	//SPT_DITHER_COLOR
	sizeof(CSpriteT), 			//SPT_THICK
	sizeof(CSpritePtPt),		//SPT_PLANAR_SYMMETRY
	sizeof(CSpriteBase),		//SPT_TRANSFORM_ON
	sizeof(CSpriteBase),		//SPT_TRANSFORM_OFF
	sizeof(CSpritePt),			//SPT_SHIFT
	sizeof(CSpritePt),			//SPT_PT
	sizeof(CSpriteNumPtU8s),	//SPT_POLYPT
	sizeof(CSpritePtPt),		//SPT_LINE
	sizeof(CSpriteNumU8s),		//SPT_POLYLINE
	sizeof(CSpritePtPt),		//SPT_RECT
	sizeof(CSpritePtPtAng), 	//SPT_ROTATED_RECT
	sizeof(CSpritePtRad), 		//SPT_CIRCLE
	sizeof(CSpritePtWHAng), 	//SPT_ELLIPSE
	sizeof(CSpritePtWHAngSides),//SPT_POLYGON
	sizeof(CSpriteNumU8s),		//SPT_BSPLINE2
	sizeof(CSpriteNumU8s),		//SPT_BSPLINE2_CLOSED
	sizeof(CSpriteNumU8s),		//SPT_BSPLINE3
	sizeof(CSpriteNumU8s),		//SPT_BSPLINE3_CLOSED
	sizeof(CSpritePt),			//SPT_FLOOD_FILL
	sizeof(CSpritePt),			//SPT_FLOOD_FILL_NOT
	sizeof(CSpritePtWHU8s), 	//SPT_BITMAP
	sizeof(CSpriteMeshU8s), 	//SPT_MESH
	sizeof(CSpritePtMeshU8s),	//SPT_SHIFTABLE_MESH
	sizeof(CSpritePtPt),		//SPT_ARROW
	sizeof(CSpritePtStr),		//SPT_TEXT
	sizeof(CSpritePtStr),		//SPT_TEXT_BOX
	sizeof(CSpritePtStr),		//SPT_TEXT_DIAMOND
};

I64 SpriteElemQueuedBaseSize(I64 type)
{
	return sprite_elem_base_sizes[type & SPG_TYPE_MASK] + offset(CSprite.start);
}

I64 SpriteElemSize(CSprite *tmpg)
{
	I64 i = sprite_elem_base_sizes[tmpg->type & SPG_TYPE_MASK];

	switch (tmpg->type & SPG_TYPE_MASK)
	{
		case SPT_POLYLINE:
			i += tmpg->nu.num * sizeof(CD2I32);
			break;

		case SPT_TEXT:
		case SPT_TEXT_BOX:
		case SPT_TEXT_DIAMOND:
			i += StrLen(tmpg->ps.st) + 1;
			break;

		case SPT_BITMAP:
			i += ((tmpg->pwhu.width + 7) & ~7) * tmpg->pwhu.height;
			break;

		case SPT_POLYPT:
			i += (tmpg->npu.num * 3 + 7) >> 3;
			break;

		case SPT_BSPLINE2:
		case SPT_BSPLINE3:
		case SPT_BSPLINE2_CLOSED:
		case SPT_BSPLINE3_CLOSED:
			i += tmpg->nu.num * sizeof(CD3I32);
			break;

		case SPT_MESH:
			i += tmpg->mu.vertex_count * sizeof(CD3I32) + tmpg->mu.tri_count * sizeof(CMeshTri);
			break;

		case SPT_SHIFTABLE_MESH:
			i += tmpg->pmu.vertex_count * sizeof(CD3I32) + tmpg->pmu.tri_count * sizeof(CMeshTri);
			break;
	}

	return i;
}

public I64 SpriteSize(U8 *elems)
{//Walk sprite elements and return size of sprite as binary data.
	CSprite *tmpg = elems - offset(CSprite.start), *tmpg1 = tmpg;

	while (tmpg->type & SPG_TYPE_MASK)
		tmpg(U8 *) += SpriteElemSize(tmpg);

	return tmpg(U8 *) - tmpg1(U8 *) + sprite_elem_base_sizes[SPT_END];
}

I64 SpriteTypeMask(U8 *elems)
{
	I64		 res = 0;
	CSprite	*tmpg = elems - offset(CSprite.start);

	while (tmpg->type & SPG_TYPE_MASK)
	{
		if (tmpg->type & SPG_TYPE_MASK >= SPT_TYPES_NUM)
			return 1 << SPT_TYPES_NUM;
		Bts(&res, tmpg->type & SPG_TYPE_MASK);
		tmpg(U8 *) += SpriteElemSize(tmpg);
	}

	return res;
}

U0 SpriteSelAll(U8 *elems, Bool val)
{
	CSprite *tmpg = elems-offset(CSprite.start);

	while (tmpg->type & SPG_TYPE_MASK)
	{
		BEqual(&tmpg->type, SPf_SEL, val);
		tmpg(U8 *) += SpriteElemSize(tmpg);
	}
}

public U8 *DC2Sprite(CDC *tmpb)
{//Convert device context to sprite.
	CSprite *tmpg;

	tmpg = CAlloc(sprite_elem_base_sizes[SPT_BITMAP]	 +
				  tmpb->width_internal * tmpb->height	 +
				  sprite_elem_base_sizes[SPT_END])(U8 *) -
				  offset(CSprite.start);

	tmpg->type			= SPT_BITMAP;
	tmpg->pwhu.width	= tmpb->width;
	tmpg->pwhu.height	= tmpb->height;
	tmpg->pwhu.x1		= 0;
	tmpg->pwhu.y1		= 0;
	MemCopy(&tmpg->pwhu.u, tmpb->body, tmpb->width_internal * tmpb->height);

	return tmpg(U8 *) + offset(CSprite.start);
}

public U8 *SpriteElem2Summary(CSprite *tmpg)
{//Study $LK,"::/Demo/Graphics/SpriteText.CC"$.
	U8   buf[STR_LEN], buf2[STR_LEN];
	I32 *ptr;

	StrPrint(buf, "%Z", tmpg->type & SPG_TYPE_MASK, "ST_SPRITE_ELEM_TYPES");
	switch (tmpg->type & SPG_TYPE_MASK)
	{
		case SPT_COLOR:
			CatPrint(buf, " %s", Color2Str(buf2, tmpg->c.color));
			break;

		case SPT_DITHER_COLOR:
			CatPrint(buf, " %s",
					 Color2Str(buf2, ROPF_DITHER | tmpg->d.dither_color.u8[0] | tmpg->d.dither_color.u8[1] << COLORROP_BITS));
			break;

		case SPT_PT:
		case SPT_FLOOD_FILL:
		case SPT_FLOOD_FILL_NOT:
		case SPT_SHIFT:
			CatPrint(buf, " (%d,%d)", tmpg->p.x1, tmpg->p.y1);
			break;

		case SPT_LINE:
		case SPT_ARROW:
		case SPT_PLANAR_SYMMETRY:
		case SPT_RECT:
		case SPT_ROTATED_RECT:
			CatPrint(buf, " (%d,%d),(%d,%d)", tmpg->pp.x1, tmpg->pp.y1, tmpg->pp.x2, tmpg->pp.y2);
			break;

		case SPT_CIRCLE:
			CatPrint(buf, " (%d,%d):%dR", tmpg->pr.x1, tmpg->pr.y1, tmpg->pr.radius);
			break;

		case SPT_THICK:
			CatPrint(buf, " %d", tmpg->t.thick);
			break;

		case SPT_TEXT:
		case SPT_TEXT_BOX:
		case SPT_TEXT_DIAMOND:
			CatPrint(buf, " %d,%d:%-16t$$Q", tmpg->ps.x1, tmpg->ps.y1, tmpg->ps.st);
			break;

		case SPT_POLYLINE:
		case SPT_POLYPT:
			ptr = &tmpg->npu.x;
			CatPrint(buf, " %d (%d,%d)", tmpg->npu.num, ptr[0], ptr[1]);
			break;

		case SPT_ELLIPSE:
		case SPT_POLYGON:
		case SPT_BITMAP:
			CatPrint(buf, " (%d,%d):%dW,%dH", tmpg->pwhu.x1, tmpg->pwhu.y1, tmpg->pwhu.width, tmpg->pwhu.height);
			break;

		case SPT_BSPLINE2:
		case SPT_BSPLINE3:
		case SPT_BSPLINE2_CLOSED:
		case SPT_BSPLINE3_CLOSED:
			CatPrint(buf, " %d", tmpg->nu.num);
			break;

		case SPT_MESH:
			CatPrint(buf, " %dV,%dT", tmpg->mu.vertex_count, tmpg->mu.tri_count);
			break;

		case SPT_SHIFTABLE_MESH:
			CatPrint(buf, " %dV,%dT", tmpg->pmu.vertex_count, tmpg->pmu.tri_count);
			break;
	}

	return StrNew(buf);
}
