Esempio n. 1
0
 // Checks each pixel immediately adjacent to the given pixel in the bitmap. If
 // any of them are not the halo color, returns true. This defines the halo of
 // pixels that will appear around the text. Note that we have to check each
 // pixel against both the halo color and transparent since DrawStringWithHalo
 // will modify the bitmap as it goes, and clears pixels shouldn't count as
 // changed.
 static bool pixelShouldGetHalo(const Bitmap& bitmap,
     int x, int y, const Color& halo_color)
 {
     if(x>0 &&
         bitmap.GetPixel(x-1, y).GetValue()!=halo_color.GetValue() &&
         bitmap.GetPixel(x-1, y).GetValue()!=0)
     {
         return true; // Touched pixel to the left.
     }
     if(x<bitmap.Width()-1 &&
         bitmap.GetPixel(x+1, y).GetValue()!=halo_color.GetValue() &&
         bitmap.GetPixel(x+1, y).GetValue()!=0)
     {
         return true; // Touched pixel to the right.
     }
     if(y>0 &&
         bitmap.GetPixel(x, y-1).GetValue()!=halo_color.GetValue() &&
         bitmap.GetPixel(x, y-1).GetValue()!=0)
     {
         return true; // Touched pixel above.
     }
     if(y<bitmap.Height()-1 &&
         bitmap.GetPixel(x, y+1).GetValue()!=halo_color.GetValue() &&
         bitmap.GetPixel(x, y+1).GetValue()!=0)
     {
         return true; // Touched pixel below.
     }
     return false;
 }
Esempio n. 2
0
void GPCreateFlashFrame( Bitmap& bmpSrc, CRect& rcBegin, CRect& rcEnd, Bitmap& bmpDes, CRect& rcDes, double dPercent )
{
	int  nWidth = bmpSrc.GetWidth();
	int  nHeight = bmpSrc.GetHeight();
	double dPercent2 = 1.0 - dPercent;
	int  nWidthDes = bmpDes.GetWidth();
	int  nHeightDes = bmpDes.GetHeight();
	CRect rcBmpSrc(0,0, nWidth, nHeight);
	CRect rcBmpDes(0,0, nWidthDes, nHeightDes);

	ASSERT(IsInRect(rcBegin, rcBmpSrc));
	ASSERT(IsInRect(rcEnd, rcBmpSrc));
	ASSERT(IsInRect(rcDes, rcBmpDes));
	ASSERT(rcBegin.Size() == rcEnd.Size());
	ASSERT(rcEnd.Size() == rcDes.Size());
	int nLoopWidth = rcBegin.Width();
	int nLoopHeight = rcBegin.Height();
	for (int i = 0; i <nLoopWidth; i++)
	{
		for (int j = 0; j < nLoopHeight; j++)
		{
			Color clrBegin;
			bmpSrc.GetPixel(i+ rcBegin.left, j+ rcBegin.top, &clrBegin);
			Color clrEnd;
			bmpSrc.GetPixel(i+ rcEnd.left, j+ rcEnd.top, &clrEnd);
			Color clrDes = Color::MakeARGB(clrBegin.GetA()*dPercent + clrEnd.GetA()* dPercent2, 
				clrBegin.GetR()*dPercent + clrEnd.GetR()* dPercent2,
				clrBegin.GetG()*dPercent + clrEnd.GetG()* dPercent2,
				clrBegin.GetB()*dPercent + clrEnd.GetB()* dPercent2);
			bmpDes.SetPixel(rcDes.left + i, rcDes.top+j, clrDes);
		}
	}
	

}
Esempio n. 3
0
File: utils.cpp Progetto: menpo/mesa
void OpenBitmapFromFile(
    const WCHAR *pFilename,
    void **pBuffer,
    uint32_t *width,
    uint32_t *height)
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);

    Bitmap *bitmap  = new Bitmap(pFilename);

    *width          = bitmap->GetWidth();
    *height         = bitmap->GetHeight();
    *pBuffer        = new BYTE[*width * *height * 4]; // width * height * |RGBA|

    // The folder 'stb_image' contains a PNG open/close module which
    // is far less painful than this is, yo.
    Gdiplus::Color clr;
    for (uint32_t y = 0, idx = 0; y < *height; ++y)
    {
        for (uint32_t x = 0; x < *width; ++x, idx += 4)
        {
            bitmap->GetPixel(x, *height - y - 1, &clr);
            ((BYTE*)*pBuffer)[idx + 0] = clr.GetBlue();
            ((BYTE*)*pBuffer)[idx + 1] = clr.GetGreen();
            ((BYTE*)*pBuffer)[idx + 2] = clr.GetRed();
            ((BYTE*)*pBuffer)[idx + 3] = clr.GetAlpha();
        }
    }

    delete bitmap;
    bitmap = 0;
}
Esempio n. 4
0
	//*************************************************************************
	// Method:		MeasureDisplayString
	// Description: Gets the size of a string in pixels
	//
	// Parameters:
	//	graphics - the graphics object the string will be measured on
	//	test - the string to measure
	//	font - the font to measure the string in
	//
	// Return Value: the size of the string
	//*************************************************************************
	SizeF StringTools::MeasureDisplayString(Graphics *graphics, String *text, Font *font)
	{
		const int width = 32;

		Bitmap *bitmap = new Bitmap(width, 1, graphics);
		SizeF size = graphics->MeasureString(text, font);
		Graphics *g = Graphics::FromImage(bitmap);

		int measuredWidth = (int)size.Width;
		if (g)
		{
			g->Clear(Color::White);
			g->DrawString(String::Concat(text, "|"), font, Brushes::Black, (float)(width - measuredWidth), (float)(0 - (font->Height / 2)));

			for (int i = width - 1; i >= 0; i--)
			{
				measuredWidth--;
				if (bitmap->GetPixel(i, 0).R == 0)
				{
					break;
				}
			}
		}

		return SizeF((float)measuredWidth, size.Height);
	}
Esempio n. 5
0
BOOL CImageBaseImplBitmap::TransformColor(const CImageTransformParam* pParam, LONG color, LONG& transformColor)
{
	transformColor = color;

	if (color == -1)
		return TRUE;

	if (pParam->enTransformType != TRANSFORM_TYPE_COLORIZE)
		return FALSE;

	BOOL bSuc = FALSE;

#ifdef GDIPVER
#if GDIPVER >= 0x0110
	static Bitmap bitmap(1, 1, PixelFormat24bppRGB);
	Color clr(GetRValue(color), GetGValue(color), GetBValue(color));
	bitmap.SetPixel(0, 0, clr);
	HueSaturationLightness hsl;
	HueSaturationLightnessParams hslParam;
	int temp = pParam->hue;
	hslParam.hueLevel = (temp - 128) * 360 / 256;
	temp = pParam->sat;
	hslParam.saturationLevel = (temp - 128) * 200 / 256;
	hslParam.lightnessLevel = (INT)((pParam->blend - 0.5) * 200);
	hsl.SetParameters(&hslParam);
	bSuc = (bitmap.ApplyEffect(&hsl, NULL) == Ok);
	if (bSuc) {
		bitmap.GetPixel(0, 0, &clr);
		transformColor = RGB(clr.GetR(), clr.GetG(), clr.GetB());
	}
#endif
#endif

	return bSuc;
}
Esempio n. 6
0
	static Color Sample(const Bitmap& bitmap, float u, float v)
	{
		int width = bitmap.GetWidth();
		int height = bitmap.GetHeight();

		float fx = XAddresserType::CalcAddress(u, width);
		int x = XAddresserType::FixAddress(Mathf::RoundToInt(fx), width);
		float fy = YAddresserType::CalcAddress(v, height);
		int y = YAddresserType::FixAddress(Mathf::RoundToInt(fy), height);

		return bitmap.GetPixel(x, y);
	}
Esempio n. 7
0
	static Color Sample(const Bitmap& bitmap, float u, float v)
	{
		int width = bitmap.GetWidth();
		int height = bitmap.GetHeight();

		float fx = XAddresserType::CalcAddress(u, width);
		int x0 = Mathf::FloorToInt(fx);
		float fy = YAddresserType::CalcAddress(v, height);
		int y0 = Mathf::FloorToInt(fy);
		float xFrac = fx - x0;
		float yFrac = fy - y0;
		x0 = XAddresserType::FixAddress(x0, width);
		y0 = YAddresserType::FixAddress(y0, height);
		int x1 = XAddresserType::FixAddress(x0 + 1, width);
		int y1 = YAddresserType::FixAddress(y0 + 1, height);

		Color c0 = bitmap.GetPixel(x0, y0);
		Color c1 = bitmap.GetPixel(x1, y0);
		Color c2 = bitmap.GetPixel(x0, y1);
		Color c3 = bitmap.GetPixel(x1, y1);

		return Color::Lerp(c0, c1, c2, c3, xFrac, yFrac);
	}
Esempio n. 8
0
//************************************
// Method:    getComplexImage
// FullName:  CFFTMachine::getComplexImage
// Access:    protected 
// Returns:   LPCOMPLEX
// Qualifier:
// Parameter: CImgSource * in_pSrcImg
//************************************
procStatus CFFTMachine::getComplexImage( CImgSource* in_pSrc, LPCOMPLEX* out_ppComplex )
{
	procStatus eRetCode = eNormal;

	Bitmap* pBmp = in_pSrc->GetSourceRef();
	ASSERT(pBmp != NULL);
	ASSERT(out_ppComplex);
	

	INT nWidth = pBmp->GetWidth();
	INT nHeight= pBmp->GetHeight();
	
	SourceType eType = in_pSrc->GetType();
	Status sts = Ok;
	BYTE nVal = 0;

	for (INT y=0;y<nHeight;y++)	//for all rows
	{
		for (INT x=0;x<nWidth; x++) //for all col
		{
			nVal = 0;
			Color clr(0,0,0);
			sts = pBmp->GetPixel(x,y, &clr);
			if(sts == Ok)
			{
				nVal = CUtility::GetMonoPixelValue(clr, eType);
				out_ppComplex[y][x].real = nVal; 
			}
			else
			{
				break;
			}
		}
		if(sts != Ok) break;
	}
	
	if (sts != Ok)
	{
		eRetCode = eSystemErr;
	}
	return eRetCode;
}
Esempio n. 9
0
int FontSheet::GetCharMaxX(Bitmap& charBitmap)
{
	int width  = charBitmap.GetWidth();
	int height = charBitmap.GetHeight();

	for(int x = width-1; x >= 0; --x)
	{
		for(int y = 0; y < height; ++y)
		{
			Color color;
			charBitmap.GetPixel(x, y, &color);
			if(color.GetAlpha() > 0)
			{
				 return x;
			}
		}
	}

	return width-1;
}
Esempio n. 10
0
void ShinonomeFont::Render(Bitmap& bmp, int const x, int const y, Bitmap const& sys, int color, unsigned code) {
	if(color != ColorShadow) {
		Render(bmp, x + 1, y + 1, sys, ColorShadow, code);
	}

	ShinonomeGlyph const* const glyph = func_(code);
	assert(glyph);
	size_t const width = glyph->is_full? FULL_WIDTH : HALF_WIDTH;

	unsigned const
		src_x = color == ColorShadow? 16 : color % 10 * 16 + (16 - width) / 2,
	    src_y = color == ColorShadow? 32 : color / 10 * 16 + 48 + (16 - HEIGHT) / 2;

	for(size_t y_ = 0; y_ < HEIGHT; ++y_) {
		for(size_t x_ = 0; x_ < width; ++x_) {
			if(glyph->data[y_] & (0x1 << x_)) {
				bmp.SetPixel(x + x_, y + y_, sys.GetPixel(src_x + x_, src_y + y_));
			}
		}
	}
}
Esempio n. 11
0
int DrawingSurface_GetPixel(ScriptDrawingSurface *sds, int x, int y) {
    sds->MultiplyCoordinates(&x, &y);
    Bitmap *ds = sds->StartDrawing();
    unsigned int rawPixel = ds->GetPixel(x, y);
    unsigned int maskColor = ds->GetMaskColor();
    int colDepth = ds->GetColorDepth();

    if (rawPixel == maskColor)
    {
        rawPixel = SCR_COLOR_TRANSPARENT;
    }
    else if (colDepth > 8)
    {
        int r = getr_depth(colDepth, rawPixel);
        int ds = getg_depth(colDepth, rawPixel);
        int b = getb_depth(colDepth, rawPixel);

        rawPixel = Game_GetColorFromRGB(r, ds, b);
    }

    sds->FinishedDrawingReadOnly();

    return rawPixel;
}
Esempio n. 12
0
Status CImgCutter::GenerateMask( UCHAR* pMask, int width, int height )
{	

	Status sts = Ok;
	ASSERT(pMask != NULL);
	//FillMemory(pMask, width * height, 0);

	// Change to image coordinate
	Point pPoint[256];
	// Compute the point coordinate according to the view area
	for (int i=0; i < m_oCurve.GetNumOfPoint(); i++)
	{
		pPoint[i].X = m_oCurve.GetPointAt(i).X - m_CutFrame.left;
		pPoint[i].Y = m_oCurve.GetPointAt(i).Y - m_CutFrame.top;

	}


	DOUBLE	dVerticalScale = (DOUBLE)height / (DOUBLE) m_CutFrame.Height();
	DOUBLE	dHorizontalScale = (DOUBLE)width / (DOUBLE) m_CutFrame.Width();

	for (int i=0; i< m_oCurve.GetNumOfPoint(); i++)
	{
		pPoint[i].X = pPoint[i].X*dHorizontalScale; 
		pPoint[i].Y = pPoint[i].Y*dVerticalScale;		
	}

	Bitmap* pMemBitmap = new Bitmap(width, height, PixelFormat24bppRGB);
	Graphics* pMemGraphics = Graphics::FromImage(pMemBitmap);
	SolidBrush solidBrush(Color(255, 255, 255));
	Rect cutRect;
	switch (m_nCutMode)
	{
	case SV_CUT_RECTANGLE:
		//sts = pMemGraphics->FillRectangle(&solidBrush, , 0, width, height);
		
		cutRect.X = min(pPoint[0].X, pPoint[1].X);
		cutRect.Y = min(pPoint[0].Y, pPoint[1].Y);;
		cutRect.Height = abs(pPoint[1].Y - pPoint[0].Y);
		cutRect.Width = abs(pPoint[1].X - pPoint[0].X);
		sts = pMemGraphics->FillRectangle(&solidBrush, cutRect);
		
		break;

	case SV_CUT_CURVES:
		sts = pMemGraphics->FillClosedCurve(&solidBrush, pPoint, m_oCurve.GetNumOfPoint());
		break;

	case SV_CUT_LINESEGMENTS:
		sts = pMemGraphics->FillClosedCurve(&solidBrush, pPoint, m_oCurve.GetNumOfPoint(),FillModeAlternate, 0.0f);
		break;
	default:
		break;
	}
	
	Color pixcolor;
	for (int y = 0; y < height; y ++) 
		for (int x = 0; x < width; x ++)
		{
			pMemBitmap->GetPixel(x,y, &pixcolor);
			pMask[y*width + x] = (UCHAR)pixcolor.GetRed();			
		}
	
/*
#ifdef _DEBUG
		CLSID pngClsid;	
		CUtility::GetEncoderClsid(L"image/bmp", &pngClsid);
		sts = pMemBitmap->Save(L"D:\\Temp\\Test.bmp", &pngClsid, NULL);
#endif // _DEBUG
*/

	delete pMemGraphics;
	delete pMemBitmap;
	return sts;
}
Esempio n. 13
0
void MainWindow::saveToFile() {
	std::ofstream outFile(mOutFile, std::ios::binary);
	std::stringstream out;
	uint32 signature = 'FNTI';
	out.write((const char*)&signature, sizeof(uint32));
	
	struct FNTIHeader
	{
		uint32 numPages;
		uint32 ofsPages;
	} header;

	header.numPages = mActiveBlocks.size();
	header.ofsPages = sizeof(FNTIHeader) + sizeof(uint32);
	out.write((const char*)&header, sizeof(FNTIHeader));

	struct FNTIBlockDesc
	{
		uint32 id;
		uint32 numChars;
		uint32 ofsChars;
		uint32 bmpWidth;
		uint32 bmpHeight;
		uint32 ofsBmp;
		wchar_t minChar;
		wchar_t maxChar;
		wchar_t pageName[64];
	};

	std::vector<FNTIBlockDesc> descriptions(mActiveBlocks.size());

	uint32 counter = 0;
	for(auto& block : mActiveBlocks) {
		FNTIBlockDesc desc;
		memset(&desc, 0, sizeof(desc));
		desc.id = block.id;
		desc.bmpWidth = 256;
		desc.bmpHeight = 256;
		desc.minChar = (wchar_t)block.minChar;
		desc.maxChar = (wchar_t)block.maxChar;
		wcsncpy_s(desc.pageName, block.name->c_str(), 64);
		desc.pageName[63] = L'\0';

		out.write((const char*)&desc, sizeof(desc));
		descriptions[counter++] = desc;
	}

	std::vector<Bitmap*> bitmaps(mActiveBlocks.size());

	Bitmap* tmp = new Bitmap(mFontSize * 2, mFontSize);
	Graphics* gchar = Graphics::FromImage(tmp);
	gchar->SetTextRenderingHint(TextRenderingHintAntiAlias);

	for(uint32 i = 0; i < mActiveBlocks.size(); ++i) {
		auto& desc = descriptions[i];
		desc.ofsChars = (uint32)out.tellp();

		Bitmap* bmp = new Bitmap(256, 256);
		bitmaps[i] = bmp;

		Graphics* g = Graphics::FromImage(bmp);
		g->Clear(Color::Transparent);
		g->SetTextRenderingHint(TextRenderingHintAntiAlias);

		uint32 curW = 0, curH = 0;
	
		for(uint32 j = mActiveBlocks[i].minChar; j < mActiveBlocks[i].maxChar; ++j) {
			char c = (char)j;
			wchar_t wc = (wchar_t)j;

			RectF rcChar;
			g->MeasureString(&wc, 1, mDefFont, PointF(0, 0), &rcChar);
			float width = rcChar.Width;
			if(curW + width > bmp->GetWidth()) {
				curW = 0;
				curH += mFontSize + 3;
			}

			g->DrawString(&wc, 1, mDefFont, PointF((float)curW, (float)curH), mWhiteBrush);

			gchar->Clear(Color::Black);
			gchar->DrawString(&wc, 1, mDefFont, PointF(0, 0), mWhiteBrush);

			Color pxl, pxr;
			uint32 ofsl = 0, ofsr = 0;
			bool lfound = false, rfound = false;

			for(uint32 l = 0; l < mFontSize * 2; ++l) {
				for(uint32 h = 0; h < mFontSize; ++h) {
					uint32 r = (2 * mFontSize - 1) - l;

					if(lfound == false) {
						tmp->GetPixel(l, h, &pxl);
						if(pxl.GetRed() > 5) {
							lfound = true;
							ofsl = l;
						}
					}

					if(rfound == false) {
						tmp->GetPixel(r, h, &pxr);
						if(pxr.GetRed() > 5) {
							rfound = true;
							ofsr = r;
						}
					}

					if(lfound && rfound) {
						break;
					}
				}

				if(lfound && rfound) {
					break;
				}
			}

			if(lfound == false || rfound == false || (ofsl >= ofsr)) {
				continue;
			}

			uint16 chrWidth = ofsr - ofsl + 1;

			float txs = (curW + ofsl) / (float)bmp->GetWidth();
			float txe = (curW + width - ofsr) / (float)bmp->GetWidth();
			float tys = curH / (float)bmp->GetHeight();
			float tye = (curH + mFontSize) / (float)bmp->GetHeight();

			curW += (uint32)ceil(width) + 2;

			++desc.numChars;
			out.write((const char*)&wc, sizeof(wchar_t));
			out.write((const char*)&chrWidth, sizeof(uint16));
			out.write((const char*)&txs, sizeof(float));
			out.write((const char*)&txe, sizeof(float));
			out.write((const char*)&tys, sizeof(float));
			out.write((const char*)&tye, sizeof(float));
		}

		delete g;
	}

	delete gchar;
	delete tmp;

	for(uint32 i = 0; i < mActiveBlocks.size(); ++i) {
		auto& desc = descriptions[i];
		desc.ofsBmp = (uint32)out.tellp();
		Bitmap* bmp = bitmaps[i];
		BitmapData data;
		bmp->LockBits(&Rect(0, 0, bmp->GetWidth(), bmp->GetHeight()), 0, PixelFormat32bppARGB, &data);
		out.write((const char*)data.Scan0, bmp->GetWidth() * bmp->GetHeight());
		bmp->UnlockBits(&data);

		delete bmp;
	}

	out.seekp(header.ofsPages, std::ios::beg);
	out.write((const char*)descriptions.data(), descriptions.size() * sizeof(FNTIBlockDesc));

	out.seekp(0, std::ios::end);

	uint32 end = (uint32)out.tellp();
	out.seekg(0, std::ios::beg);

	std::vector<char> content(end);
	out.read(content.data(), end);

	std::vector<char> compressed(end);
	Utils::ZDeflater defl;
	defl.begin();

	uint32 outPos = 0;
	defl.update(content, compressed, outPos);
	compressed.resize(outPos);

	defl.end();

	outFile.write((const char*)&end, sizeof(uint32));
	outFile.write(compressed.data(), compressed.size());
	outFile.close();
}
Esempio n. 14
0
BOOL SavePngFile(HICON hIcon, LPCSTR strPngFile,int iOutWith = -1,int iOutHeight = -1)
{
	if (hIcon == NULL)
		return FALSE;

	ICONINFO icInfo = { 0 };
	if (!::GetIconInfo(hIcon, &icInfo))
		return FALSE;


	BITMAP bitmap; 
	GetObject(icInfo.hbmColor, sizeof(BITMAP), &bitmap);

	Bitmap* pBitmap = NULL;
	Bitmap* pWrapBitmap = NULL;
	if (bitmap.bmBitsPixel != 32) 
	{   
		pBitmap = Bitmap::FromHICON(hIcon); 
	} 
	else
	{
		pWrapBitmap = Bitmap::FromHBITMAP(icInfo.hbmColor, NULL);
		BitmapData bitmapData;
		Rect rcImage(0,0, pWrapBitmap->GetWidth(), pWrapBitmap->GetHeight());
		pWrapBitmap->LockBits(&rcImage, ImageLockModeRead, pWrapBitmap->GetPixelFormat(), &bitmapData); 

		pBitmap = new Bitmap(bitmapData.Width, bitmapData.Height, bitmapData.Stride, 
			PixelFormat32bppARGB, (BYTE*)bitmapData.Scan0);

		pWrapBitmap->UnlockBits(&bitmapData);

		Gdiplus::Color Bmpcolor;
		BOOL BmpcolorTag=TRUE;
		for (UINT bmpx=0;bmpx<pBitmap->GetWidth();bmpx++)
		{
			for (UINT bmpy=0;bmpy<pBitmap->GetHeight();bmpy++)
			{
				pBitmap->GetPixel(bmpx,bmpy,&Bmpcolor);
				if(Bmpcolor.GetA()!=0)
				{
					BmpcolorTag=FALSE;
					break;	
				}
			}
			if (BmpcolorTag==FALSE)
				break;
		}
		if (BmpcolorTag==TRUE)
		{
			delete pWrapBitmap;
			pWrapBitmap = NULL;
			delete pBitmap;
			pBitmap = NULL;
			pBitmap = Gdiplus::Bitmap::FromHICON(hIcon); 
		} 
	}

	DeleteObject(icInfo.hbmColor); 
	DeleteObject(icInfo.hbmMask);

	static bool GetPngCode = false;
	static CLSID pngid;
	if (!GetPngCode)
	{
		GetPngCode = true;
		GetEncoderClsid(L"image/png", &pngid);
	}

	if (iOutWith !=-1 && iOutHeight!=-1)
	{
		Bitmap *pStretched =  StretchBitmap(pBitmap,128,128);
		if (pStretched)
		{
			delete pBitmap; 
			pBitmap = pStretched;
		}
	}

	_bstr_t bstr(strPngFile);
	wstring wstrPng = (WCHAR*)bstr;
	Gdiplus::Status s = pBitmap->Save(wstrPng.c_str(),&pngid,NULL);
	delete pBitmap; 
	if (pWrapBitmap)
		delete pWrapBitmap;

	DeleteObject(icInfo.hbmColor); 
	DeleteObject(icInfo.hbmMask); 

	if (s==Gdiplus::Ok)
		return TRUE;

	return FALSE;
}
Esempio n. 15
0
int is_route_possible(int fromx, int fromy, int tox, int toy, Bitmap *wss)
{
  wallscreen = wss;
  suggestx = -1;

  // ensure it's a memory bitmap, so we can use direct access to line[] array
  if ((wss == NULL) || (!wss->IsMemoryBitmap()) || (wss->GetColorDepth() != 8))
    quit("is_route_possible: invalid walkable areas bitmap supplied");

  if (wallscreen->GetPixel(fromx, fromy) < 1)
    return 0;

  Bitmap *tempw = BitmapHelper::CreateBitmapCopy(wallscreen, 8);

  if (tempw == NULL)
    quit("no memory for route calculation");
  if (!tempw->IsMemoryBitmap())
    quit("tempw is not memory bitmap");

  int dd, ff;
  // initialize array for finding widths of walkable areas
  int thisar, inarow = 0, lastarea = 0;
  int walk_area_times[MAX_WALK_AREAS + 1];
  for (dd = 0; dd <= MAX_WALK_AREAS; dd++) {
    walk_area_times[dd] = 0;
    walk_area_granularity[dd] = 0;
  }

  for (ff = 0; ff < tempw->GetHeight(); ff++) {
    const uint8_t *tempw_scanline = tempw->GetScanLine(ff);
    for (dd = 0; dd < tempw->GetWidth(); dd++) {
      thisar = tempw_scanline[dd];
      // count how high the area is at this point
      if ((thisar == lastarea) && (thisar > 0))
        inarow++;
      else if (lastarea > MAX_WALK_AREAS)
        quit("!Calculate_Route: invalid colours in walkable area mask");
      else if (lastarea != 0) {
        walk_area_granularity[lastarea] += inarow;
        walk_area_times[lastarea]++;
        inarow = 0;
      }
      lastarea = thisar;
    }
  }

  for (dd = 0; dd < tempw->GetWidth(); dd++) {
    for (ff = 0; ff < tempw->GetHeight(); ff++) {
      uint8_t *tempw_scanline = tempw->GetScanLineForWriting(ff);
      thisar = tempw_scanline[dd];
      if (thisar > 0)
        tempw_scanline[dd] = 1;
      // count how high the area is at this point
      if ((thisar == lastarea) && (thisar > 0))
        inarow++;
      else if (lastarea != 0) {
        walk_area_granularity[lastarea] += inarow;
        walk_area_times[lastarea]++;
        inarow = 0;
      }
      lastarea = thisar;
    }
  }

  // find the average "width" of a path in this walkable area
  for (dd = 1; dd <= MAX_WALK_AREAS; dd++) {
    if (walk_area_times[dd] == 0) {
      walk_area_granularity[dd] = MAX_GRANULARITY;
      continue;
    }

    walk_area_granularity[dd] /= walk_area_times[dd];
    if (walk_area_granularity[dd] <= 4)
      walk_area_granularity[dd] = 2;
    else if (walk_area_granularity[dd] <= 15)
      walk_area_granularity[dd] = 3;
    else
      walk_area_granularity[dd] = MAX_GRANULARITY;

    /*char toprnt[200];
       sprintf(toprnt,"area %d: Gran %d", dd, walk_area_granularity[dd]);
       winalert(toprnt); */
  }
  walk_area_granularity[0] = MAX_GRANULARITY;

  tempw->FloodFill(fromx, fromy, 232);
  if (tempw->GetPixel(tox, toy) != 232) 
  {
    // Destination pixel is not walkable
    // Try the 100x100 square around the target first at 3-pixel granularity
    int tryFirstX = tox - 50, tryToX = tox + 50;
    int tryFirstY = toy - 50, tryToY = toy + 50;

    if (!find_nearest_walkable_area(tempw, tryFirstX, tryFirstY, tryToX, tryToY, tox, toy, 3))
    {
      // Nothing found, sweep the whole room at 5 pixel granularity
      find_nearest_walkable_area(tempw, 0, 0, tempw->GetWidth(), tempw->GetHeight(), tox, toy, 5);
    }

    delete tempw;
    return 0;
  }
  delete tempw;

  return 1;
}