Beispiel #1
0
bool can_be_mfc_app() {
	netnode importz("$ imports");
	if (importz != BADNODE) for (ulong ndx = importz.sup1st(); ndx != BADNODE; ndx = importz.supnxt(ndx)) try {
		char impname[MAXSPECSIZE];
		if (importz.supstr(ndx, CPY(impname)) > 0
			&& pcre_match("^mfc\\d{2,}", impname, PCRE_CASELESS)) return true; // assumed by imported rtl
#ifdef _DEBUG
	} catch (const std::exception &e) {
		_RPT3(_CRT_ERROR, "%s(...): %s on iterating import node: index=0x%IX\n",
			__FUNCTION__, e.what(), ndx);
#endif // _DEBUG
	} catch (...) {
		_RPT3(_CRT_ERROR, "%s(...): %s on iterating import node: index=0x%IX\n",
			__FUNCTION__, "unknown exception", ndx);
	}
	char buf[MAXSPECSIZE/*??*/];
	ulong total(0);
	for (int counter = 0; counter < get_idasgn_qty(); ++counter) {
		const long applieds(get_idasgn_desc(counter, CPY(buf), NULL, 0));
		if (applieds != -1 && pcre_match("^vc(?:32|64)mfc", buf, PCRE_CASELESS))
			switch (calc_idasgn_state(counter)) {
				case IDASGN_APPLIED: total += applieds; break;
				case IDASGN_CURRENT:
				case IDASGN_PLANNED: return true;
			}
	}
	return total > 0;
}
Beispiel #2
0
STDMETHODIMP CAVIStreamRemote::QueryInterface(const IID& iid, void **ppv) {
	_RPT1(0,"%08lx->CAVIStreamRemote::QueryInterface()\n", this);

	_RPT3(0,"\tGUID: {%08lx-%04x-%04x-", iid.Data1, iid.Data2, iid.Data3);
	_RPT4(0,"%02x%02x-%02x%02x", iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3]);
	_RPT4(0,"%02x%02x%02x%02x} (", iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7]);

	if (iid == IID_IUnknown) {
		*ppv = (IUnknown *)this;
		_RPT0(0,"IUnknown)\n");
	} else if (iid == IID_IClassFactory) {
		*ppv = (IClassFactory *)&iclassfactory;
		_RPT0(0,"IClassFactory)\n");
	} else if (iid == IID_IAVIStream) {
		*ppv = (IAVIStream *)this;
		_RPT0(0,"IAVIStream)\n");
	} else {
		_RPT0(0,"unknown)\n");
		*ppv = NULL;
		return ResultFromScode(E_NOINTERFACE);
	}

	AddRef();

	return NULL;
}
Beispiel #3
0
// If the cache is not being used reset it
void Cache::ResetCache(IScriptEnvironment* env)
{
  InterlockedIncrement(&g_Cache_stats.resets);
  minframe = vi.num_frames;
  maxframe = -1;
  CachedVideoFrame *i, *j;

  _RPT3(0, "Cache:%x: Cache Reset, cache_limit %d, cache_init %d\n", this, cache_limit, cache_init<<CACHE_SCALE_SHIFT);

  int count=0;
  for (i = video_frames.next; i != &video_frames; i = i->next) {
    if (++count >= cache_init) goto purge_old_frame;

    const int ifn = i->frame_number;
    if (ifn < minframe) minframe = ifn;
    if (ifn > maxframe) maxframe = ifn;
  }
  return;

purge_old_frame:

  // Truncate the tail of the chain
  video_frames.prev = i;
  j = (CachedVideoFrame*)InterlockedExchangePointer(&i->next, &video_frames);

  // Delete the excess CachedVideoFrames
  while (j != &video_frames) {
    i = j->next;
    ReturnVideoFrameBuffer(j, env); // Return old vfb to vfb pool for early reuse
    delete j;
    j = i;
  }
  cache_limit = cache_init << CACHE_SCALE_SHIFT;
}
Beispiel #4
0
// Copy data from the memory bitmap into a buffer
void
vncDesktop::CopyToBuffer(const rfb::Rect &rect, BYTE *destbuff, UINT destbuffsize)
{
	// Finish drawing anything in this thread 
	// Wish we could do this for the whole system - maybe we should
	// do something with LockWindowUpdate here.
	GdiFlush();

	// Are we being asked to blit from the DIBsection to itself?
	if (destbuff == m_DIBbits) {
		// Yes.  Ignore the request!
		return;
	}

	int y_inv;
	BYTE * destbuffpos;

	// Calculate the scanline-ordered y position to copy from
	y_inv = m_scrinfo.framebufferHeight-rect.tl.y-(rect.br.y-rect.tl.y);

	// Calculate where in the output buffer to put the data
	destbuffpos = destbuff + (m_bytesPerRow * rect.tl.y);

	// Set the number of bytes for GetDIBits to actually write
	// NOTE : GetDIBits pads the destination buffer if biSizeImage < no. of bytes required
	m_bminfo.bmi.bmiHeader.biSizeImage = (rect.br.y-rect.tl.y) * m_bytesPerRow;

	// Get the actual bits from the bitmap into the bit buffer
	// If fast (DIBsection) blits are disabled then use the old GetDIBits technique
	if (m_DIBbits == NULL) {
		if (GetDIBits(m_hmemdc, m_membitmap, y_inv,
					(rect.br.y-rect.tl.y), destbuffpos,
					&m_bminfo.bmi, DIB_RGB_COLORS) == 0)
		{
			_RPT1(_CRT_WARN, "vncDesktop : [1] GetDIBits failed! %d\n", GetLastError());
			_RPT3(_CRT_WARN, "vncDesktop : thread = %d, DC = %d, bitmap = %d\n", omni_thread::self(), m_hmemdc, m_membitmap);
			_RPT2(_CRT_WARN, "vncDesktop : y = %d, height = %d\n", y_inv, (rect.br.y-rect.tl.y));
		}
	} else {
		// Fast blits are enabled.  [I have a sneaking suspicion this will never get used, unless
		// something weird goes wrong in the code.  It's here to keep the function general, though!]

		int bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
		BYTE *srcbuffpos = (BYTE*)m_DIBbits;

		srcbuffpos += (m_bytesPerRow * rect.tl.y) + (bytesPerPixel * rect.tl.x);
		destbuffpos += bytesPerPixel * rect.tl.x;

		int widthBytes = (rect.br.x-rect.tl.x) * bytesPerPixel;

		for(int y = rect.tl.y; y < rect.br.y; y++)
		{
			memcpy(destbuffpos, srcbuffpos, widthBytes);
			srcbuffpos += m_bytesPerRow;
			destbuffpos += m_bytesPerRow;
		}
	}
}
Beispiel #5
0
	bool set(const char *loc) {
		setlocale(LC_ALL, loc);
		__super::reset(pcre_maketables());
#ifdef _DEBUG
		if (operator !()) _RPT3(_CRT_ERROR, "%s(\"%s\"): %s() returned NULL\n",
			__FUNCTION__, loc, "pcre_maketables");
#endif // _DEBUG
		return get() != 0;
	}
Beispiel #6
0
static HMODULE WINAPI
exerb_hook_load_library_ex(LPCTSTR filename, HANDLE file, DWORD flags)
{
    _RPT3(_CRT_WARN, "exerb_hook_load_library_ex('%s', %i, %i)\n", filename, file, flags);

    if ( filename ) {
        if ( ::stricmp(filename, "msvcrt-ruby18") == 0 || ::stricmp(filename, "msvcrt-ruby18.dll") == 0 ) {
            return ::GetModuleHandle(NULL);
        } else if ( FILE_ENTRY_HEADER *file_entry = ::exerb_find_file_entry(filename, "dll") ) {
            if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ||
                    file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_DYNAMIC_LIBRARY ) {
                return ::exerb_preload_library(file_entry);
            }
        }
    }

    return ::LoadLibraryEx(filename, file, flags);
}
void memblockinfo_output_memleak()
{
	if(!Cmdline_show_mem_usage)	return;

	if(TotalRam == 0) 
		return;

	if(TotalRam < 0) {
		 _RPT1(_CRT_WARN, "TotalRam bad value!",TotalRam);
		return;
	}

	_RPT1(_CRT_WARN, "malloc memory leak of %d\n",TotalRam);

// Now if system is compiled register it with the fuller system
#ifdef _REPORT_MEM_LEAKS

	int total = 0;
	// Find empty slot
	for(int f = 0; f < MAX_MEM_POINTERS; f++)
	{
		if(mem_ptr_list[f].ptr)
		{
		 	_RPT3(_CRT_WARN, "Memory leaks: (%s line %d) of %d bytes\n", mem_ptr_list[f].filename, mem_ptr_list[f].line, mem_ptr_list[f].size);
			total += mem_ptr_list[f].size;
		}
	}

	Assert(TotalRam == total);

#else

	for(int i = 0; i < MAX_MEM_MODULES; i++)
	{
		// Found the first empty entry, fill it
	  	if(mem_block_list[i].size > 0)
		{
			// Oh... bad code... making assumsions...
		 	_RPT2(_CRT_WARN, "Possible memory leaks: %s %d\n", mem_block_list[i].filename, mem_block_list[i].size);
		}
	}
#endif
}
std::string getImageUrlFromReddit(std::string subreddit)
{
	JsonManager jsonMan;

	// get and parse json page from reddit
	char* jsonPage = NULL;
	InternetManager::DownloadPage(subreddit, &jsonPage);
	jsonMan.setInput(jsonPage);
	jsonMan.parseInput();

	// if it doesn't find urls exit
	if (jsonMan.getUrlN() == 0)
		return "";

	// random and download the background
	srand(time(NULL));
	int indexRand = rand() % jsonMan.getUrlN();
	std::string urlImg = jsonMan.getUrl(indexRand);
	_RPT3(0, "Random: %d/%d, Url: %s\n", indexRand, jsonMan.getUrlN(), urlImg.c_str());

	delete jsonPage;
	return urlImg;
}
/*!***************************************************************************
 @Function		PVRTGeometrySort
 @Modified		pVtxData		Pointer to array of vertices
 @Modified		pwIdx			Pointer to array of indices
 @Input			nStride			Size of a vertex (in bytes)
 @Input			nVertNum		Number of vertices. Length of pVtxData array
 @Input			nTriNum			Number of triangles. Length of pwIdx array is 3* this
 @Input			nBufferVtxLimit	Number of vertices that can be stored in a buffer
 @Input			nBufferTriLimit	Number of triangles that can be stored in a buffer
 @Input			dwFlags			PVRTGEOMETRY_SORT_* flags
 @Description	Triangle sorter
*****************************************************************************/
void PVRTGeometrySort(
	void				* const pVtxData,
	PVRTGEOMETRY_IDX	* const pwIdx,
	const int			nStride,
	const int			nVertNum,
	const int			nTriNum,
	const int			nBufferVtxLimit,
	const int			nBufferTriLimit,
	const unsigned int	dwFlags)
{
	CObject				sOb(pwIdx, nVertNum, nTriNum, nBufferVtxLimit, nBufferTriLimit);
	CBlock				sBlock(nBufferVtxLimit, nBufferTriLimit);
	PVRTGEOMETRY_IDX	*pwIdxOut;
	int					nTriCnt, nVtxCnt;
	int					nOutTriCnt, nOutVtxCnt, nOutBlockCnt;
	int					nMeshToResize;
#ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
	int					i;
	int					pnBlockTriCnt[PVRVGPBLOCKTEST_MAX_BLOCKS];
	SVGPModel			sVGPMdlBefore;
	SVGPModel			sVGPMdlAfter;
#endif

	if(dwFlags & PVRTGEOMETRY_SORT_VERTEXCACHE) {
#ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
		VGP590Test(&sVGPMdlBefore, pwIdx, nTriNum);
		_RPT4(_CRT_WARN, "OptimiseTriListPVR() Before: Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nTriNum, sVGPMdlBefore.nVtxCnt, (float)sVGPMdlBefore.nVtxCnt / (float)nTriNum, sVGPMdlBefore.nBlockCnt);
#endif

		pwIdxOut	= (PVRTGEOMETRY_IDX*)malloc(nTriNum * 3 * sizeof(*pwIdxOut));
		_ASSERT(pwIdxOut);

		// Sort geometry into blocks
		nOutTriCnt		= 0;
		nOutVtxCnt		= 0;
		nOutBlockCnt	= 0;
		do {
			// Clear & fill the block
			sBlock.Clear();
			nMeshToResize = sBlock.Fill(&sOb);

			// Copy indices into output
			sBlock.Output(&pwIdxOut[3*nOutTriCnt], &nVtxCnt, &nTriCnt, &sOb);
			sOb.m_nTriNumFree	-= nTriCnt;
			nOutTriCnt			+= nTriCnt;

			if(nMeshToResize >= 0) {
				SMesh	*pMesh;
				_ASSERT(nMeshToResize <= (nBufferVtxLimit-3));
				pMesh = &sOb.m_pvMesh[nMeshToResize].back();
				sOb.ResizeMesh(pMesh->nVtxNum, pMesh->ppVtx);
				sOb.m_pvMesh[nMeshToResize].pop_back();
			}

			_ASSERT(nVtxCnt <= nBufferVtxLimit);
			_ASSERT(nTriCnt <= nBufferTriLimit);

#ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
			_ASSERT(nOutBlockCnt < PVRVGPBLOCKTEST_MAX_BLOCKS);
			pnBlockTriCnt[nOutBlockCnt] = nTriCnt;
#endif
			nOutVtxCnt += nVtxCnt;
			nOutBlockCnt++;

//			_RPT4(_CRT_WARN, "%d/%d tris (+%d), %d blocks\n", nOutTriCnt, nTriNum, nTriCnt, nOutBlockCnt);

			_ASSERT(nTriCnt == nBufferTriLimit || (nBufferVtxLimit - nVtxCnt) < 3 || nOutTriCnt == nTriNum);
		} while(nOutTriCnt < nTriNum);

		_ASSERT(nOutTriCnt == nTriNum);
		// The following will fail if optimising a subset of the mesh (e.g. a bone batching)
		//_ASSERT(nOutVtxCnt >= nVertNum);

		// Done!
		memcpy(pwIdx, pwIdxOut, nTriNum * 3 * sizeof(*pwIdx));
		FREE(pwIdxOut);

		_RPT3(_CRT_WARN, "OptimiseTriListPVR() In: Tri: %d, Vtx: %d, vtx/tri=%f\n", nTriNum, nVertNum, (float)nVertNum / (float)nTriNum);
		_RPT4(_CRT_WARN, "OptimiseTriListPVR() HW: Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nOutTriCnt, nOutVtxCnt, (float)nOutVtxCnt / (float)nOutTriCnt, nOutBlockCnt);

#ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
		VGP590Test(&sVGPMdlAfter, pwIdx, nTriNum);
		_RPT4(_CRT_WARN, "OptimiseTriListPVR() After : Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nTriNum, sVGPMdlAfter.nVtxCnt, (float)sVGPMdlAfter.nVtxCnt / (float)nTriNum, sVGPMdlAfter.nBlockCnt);
		_ASSERTE(sVGPMdlAfter.nVtxCnt <= sVGPMdlBefore.nVtxCnt);
		_ASSERTE(sVGPMdlAfter.nBlockCnt <= sVGPMdlBefore.nBlockCnt);

		for(i = 0; i < nOutBlockCnt; ++i) {
			_ASSERT(pnBlockTriCnt[i] == sVGPMdlAfter.pnBlockTriCnt[i]);
		}
#endif
	}

	if(!(dwFlags & PVRTGEOMETRY_SORT_IGNOREVERTS)) {
		// Re-order the vertices so maybe they're accessed in a more linear
		// manner. Should cut page-breaks on the initial memory read of
		// vertices. Affects both the order of vertices, and the values
		// of indices, but the triangle order is unchanged.
		SortVertices(pVtxData, pwIdx, nStride, nVertNum, nTriNum*3);
	}
}
Beispiel #10
0
// Generic interface to poke all cache instances
void Cache::PokeCache(int key, int data, IScriptEnvironment* env)
{
  switch (key) {
    case PC_Nil: { // Do Nothing!
      return;
    }
    case PC_UnlockOld: { // Unlock head vfb
      // Release the head vfb if it is locked and this
      // instance is not with the current GetFrame chain.
      if (Tick != Clock) {
        if (UnlockVFB(video_frames.next)) {
          _RPT3(0, "Cache:%x: PokeCache UnlockOld vfb %x, frame %d\n",
                this, video_frames.next->vfb, video_frames.next->frame_number);
        }
      }
      break;
    }
    case PC_UnlockAll: { // Unlock all vfb's if the vfb size is big enough to satisfy
//    EnterCriticalSection(&cs_cache_V);
      for (CachedVideoFrame* i = video_frames.next; i != &video_frames; i = i->next) {
        if (i->vfb->data_size >= data) {
          if (UnlockVFB(i)) {
            _RPT3(0, "Cache:%x: PokeCache UnlockAll vfb %x, frame %d\n",
                  this, video_frames.next->vfb, video_frames.next->frame_number);
          }
        }
      }
//    LeaveCriticalSection(&cs_cache_V);
      break;
    }
    case PC_UnProtect: {   // Unprotect 1 vfb if this instance is
      if (Tick != Clock) { // not with the current GetFrame chain.
//      EnterCriticalSection(&cs_cache_V);
        for (CachedVideoFrame* i = video_frames.next; i != &video_frames; i = i->next) {
          // Unprotect the youngest because it might be the easiest
          // to regenerate from parent caches that are still current.
          // And to give it a fair chance we also promote it.
          if (i->vfb->data_size >= data) {
            if (UnProtectVFB(i)) {
              UnlockVFB(i);
              env->ManageCache(MC_PromoteVideoFrameBuffer, i->vfb);
              _RPT3(0, "Cache:%x: PokeCache UnProtect vfb %x, frame %d\n",
                    this, video_frames.next->vfb, video_frames.next->frame_number);
              break;
            }
          }
        }
//      LeaveCriticalSection(&cs_cache_V);
      }
      break;
    }
    case PC_UnProtectAll: { // Unprotect all vfb's
//    EnterCriticalSection(&cs_cache_V);
      for (CachedVideoFrame* i = video_frames.next; i != &video_frames; i = i->next) {
        if (i->vfb->data_size >= data) {
          if (UnProtectVFB(i)) {
            UnlockVFB(i);
            env->ManageCache(MC_PromoteVideoFrameBuffer, i->vfb);
            _RPT3(0, "Cache:%x: PokeCache UnProtectAll vfb %x, frame %d\n",
                  this, video_frames.next->vfb, video_frames.next->frame_number);
          }
        }
      }
//    LeaveCriticalSection(&cs_cache_V);
      break;
    }
    default:
      return;
  }
  // Poke the next Cache in the chain
  if (nextCache) nextCache->PokeCache(key, data, env);
}
HRESULT	mmSource::OnThreadStartPlay()
{
	_RPT3(_CRT_WARN,"OnThreadStartPlay %d %d %f\n",(int)m_rtStart, (int)m_rtStop, (float)m_dRateSeeking);
	return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking);
}
DWORD WINAPI cProxyServer::TsReader(LPVOID pv)
{
	stTsReaderArg *pArg = static_cast<stTsReaderArg *>(pv);
	IBonDriver *pIBon = pArg->pIBon;
	volatile BOOL &StopTsRead = pArg->StopTsRead;
	volatile BOOL &ChannelChanged = pArg->ChannelChanged;
	DWORD &pos = pArg->pos;
	std::list<cProxyServer *> &TsReceiversList = pArg->TsReceiversList;
	cCriticalSection &TsLock = pArg->TsLock;
	DWORD dwSize, dwRemain, now, before = 0;
	float fSignalLevel = 0;
	DWORD ret = 300;
	const DWORD TsPacketBufSize = g_TsPacketBufSize;
	BYTE *pBuf, *pTsBuf = new BYTE[TsPacketBufSize];
#if _DEBUG && DETAILLOG
	DWORD Counter = 0;
#endif

	// 内部でCOMを使用しているBonDriverに対する対策
	HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY);
	// TS読み込みループ
	while (!StopTsRead)
	{
		dwSize = dwRemain = 0;
		{
			LOCK(TsLock);
			if ((((now = ::GetTickCount()) - before) >= 1000) || ChannelChanged)
			{
				fSignalLevel = pIBon->GetSignalLevel();
				before = now;
				ChannelChanged = FALSE;
			}
			if (pIBon->GetTsStream(&pBuf, &dwSize, &dwRemain) && (dwSize != 0))
			{
				if ((pos + dwSize) < TsPacketBufSize)
				{
					::memcpy(&pTsBuf[pos], pBuf, dwSize);
					pos += dwSize;
					if (dwRemain == 0)
					{
						for (std::list<cProxyServer *>::iterator it = TsReceiversList.begin(); it != TsReceiversList.end(); ++it)
							(*it)->makePacket(eGetTsStream, pTsBuf, pos, fSignalLevel);
#if _DEBUG && DETAILLOG
						_RPT3(_CRT_WARN, "makePacket0() : %u : size[%x] / dwRemain[%d]\n", Counter++, pos, dwRemain);
#endif
						pos = 0;
					}
				}
				else
				{
					DWORD left, dwLen = TsPacketBufSize - pos;
					::memcpy(&pTsBuf[pos], pBuf, dwLen);
					for (std::list<cProxyServer *>::iterator it = TsReceiversList.begin(); it != TsReceiversList.end(); ++it)
						(*it)->makePacket(eGetTsStream, pTsBuf, TsPacketBufSize, fSignalLevel);
#if _DEBUG && DETAILLOG
					_RPT3(_CRT_WARN, "makePacket1() : %u : size[%x] / dwRemain[%d]\n", Counter++, TsPacketBufSize, dwRemain);
#endif
					left = dwSize - dwLen;
					pBuf += dwLen;
					while (left >= TsPacketBufSize)
					{
						for (std::list<cProxyServer *>::iterator it = TsReceiversList.begin(); it != TsReceiversList.end(); ++it)
							(*it)->makePacket(eGetTsStream, pBuf, TsPacketBufSize, fSignalLevel);
#if _DEBUG && DETAILLOG
						_RPT2(_CRT_WARN, "makePacket2() : %u : size[%x]\n", Counter++, TsPacketBufSize);
#endif
						left -= TsPacketBufSize;
						pBuf += TsPacketBufSize;
					}
					if (left != 0)
					{
						if (dwRemain == 0)
						{
							for (std::list<cProxyServer *>::iterator it = TsReceiversList.begin(); it != TsReceiversList.end(); ++it)
								(*it)->makePacket(eGetTsStream, pBuf, left, fSignalLevel);
#if _DEBUG && DETAILLOG
							_RPT3(_CRT_WARN, "makePacket3() : %u : size[%x] / dwRemain[%d]\n", Counter++, left, dwRemain);
#endif
							left = 0;
						}
						else
							::memcpy(pTsBuf, pBuf, left);
					}
					pos = left;
				}
			}
		}
		if (dwRemain == 0)
			::Sleep(WAIT_TIME);
	}
	if (SUCCEEDED(hr))
		::CoUninitialize();
	delete[] pTsBuf;
	return ret;
}
void IslandGame::loadLevel( const char *filename )
{
	TiXmlDocument *xmlDoc = new TiXmlDocument( filename );
	
	// clear the level
	clearLevel();

	if (!xmlDoc->LoadFile() ) {
		errorMessage("ERR! Can't load %s\n", filename );
	}

	TiXmlElement *xLevel;
	TiXmlNode *xText;

	xLevel = xmlDoc->FirstChildElement( "level" );
	assert( xLevel );
	m_mapName = xLevel->Attribute( "isleName" );	
	m_mapText = xLevel->Attribute( "intro" );

	showHudText( m_mapName, m_mapText );

	const char *waterTex = xLevel->Attribute( "water" );
	if (waterTex)
	{
		char buff[200];
		sprintf( buff, "gamedata/%s.png", waterTex );
		m_waterTexId = loadTexture( buff );
	}
	else
	{
		m_waterTexId  = loadTexture( "gamedata/water.png", 4 );
	}

	// Get width and height
	TiXmlElement *xTag;
	xTag = xLevel->FirstChildElement( "width" );
	xText = xTag->FirstChild();
	m_mapSizeX = atoi( xText->Value() ) / 16;

	xTag = xLevel->FirstChildElement( "height" );
	xText = xTag->FirstChild();
	m_mapSizeY = atoi( xText->Value() ) / 16;

	// Load elevations
	TiXmlElement *xTile;
	TiXmlElement *xElevTiles = xLevel->FirstChildElement( "elevTiles" );
	
	xTile = xElevTiles->FirstChildElement( "tile" );	
	while (xTile) 
	{
		int id, xpos, ypos;
		id = atoi( xTile->Attribute( "id" ) );
		xpos = atoi( xTile->Attribute( "x" ) ) / 16;
		ypos = atoi( xTile->Attribute( "y" ) ) / 16;		

		xTile = xTile->NextSiblingElement( "tile" );

		MapSquare &m = m_map[xpos][ypos];
		m.m_elevation = id;
		m.m_terrain = 0; // TODO get from terrain tileset
	}

	// Load terrain indices
	TiXmlElement *xTerrainTiles = xLevel->FirstChildElement( "terrainTiles" );
	
	xTile = xTerrainTiles->FirstChildElement( "tile" );	
	while (xTile) 
	{
		int id, xpos, ypos;
		id = atoi( xTile->Attribute( "id" ) );
		xpos = atoi( xTile->Attribute( "x" ) ) / 16;
		ypos = atoi( xTile->Attribute( "y" ) ) / 16;

		_RPT3( _CRT_WARN, "loc %d %d id %d\n", xpos, ypos, id );

		xTile = xTile->NextSiblingElement( "tile" );

		MapSquare &m = m_map[xpos][ypos];		
		m.m_terrain = id;
	}

	// Load actors	
	TiXmlElement *xActorLayer = xLevel->FirstChildElement( "actors" );
	
	// Get the player start pos
	TiXmlElement *xActor = xActorLayer->FirstChildElement( "pstart" );
	m_px = atoi( xActor->Attribute( "x" ) ) / 16;
	m_py = atoi( xActor->Attribute( "y" ) ) / 16;

	m_camTarg = vec3f( m_px + 0.5f, 
					(m_map[m_px][m_py].m_elevation+1.0) * 0.3f, 
					m_py + 0.5f );
	m_camPos = m_camTarg;

	// first, make sure all master critters are loaded
	xActor = xActorLayer->FirstChildElement( "critter" );
	while (xActor)
	{
		// If this is the master copy of the critter, load it
		if (!strcmp( xActor->Attribute("master"), "true" ) )
		{
			Critter *mcrit = NULL;
			std::string critKey = xActor->Attribute("displayName" );			
			std::transform( critKey.begin(), critKey.end(), critKey.begin(), toupper );

			// is it in the master list?
			if ( m_masterCritter.find( critKey ) == m_masterCritter.end() )
			{
				// Nope, load it
				mcrit = new Critter();
				mcrit->m_displayName = xActor->Attribute( "displayName" );
				mcrit->m_level = atoi( xActor->Attribute( "level" ) );
				mcrit->m_name = atoi( xActor->Attribute( "map" ) );
				mcrit->m_behavior = atoi( xActor->Attribute( "behave" ) );

				// DBG:
				mcrit->m_behavior = BEHAVIOR_SEEK_PLAYER;

				char buff[1000];
				sprintf( buff, "gamedata/critter_%s.png", xActor->Attribute( "map" ) );
				mcrit->m_critterTex = loadTexture( buff, 4 );

				// store in master list
				m_masterCritter[ critKey ] = mcrit;
			}
		}
		xActor = xActor->NextSiblingElement( "critter" );
	}

	// Now go through all the critters again and create them
	for (std::vector<Critter*>::iterator ci = m_critters.begin();
		 ci != m_critters.end(); ++ci )
	{
		delete *ci;
	}
	//m_critters.clear( m_critters.begin(), m_critters.end() );
	m_critters.clear();

	xActor = xActorLayer->FirstChildElement( "critter" );
	while (xActor)
	{
		Critter *mcrit = NULL;
		std::string critKey = xActor->Attribute("displayName" );			
		std::transform( critKey.begin(), critKey.end(), critKey.begin(), toupper );
	
		std::map<std::string, Critter*>::iterator mcriti = m_masterCritter.find( critKey );
		if ( mcriti == m_masterCritter.end() )
		{
			DBG::warn( "Couldn't find master critter: %s\n", critKey.c_str() );
		}
		else
		{
			mcrit = (*mcriti).second;
			Critter *crit = new Critter();
			*crit = *mcrit;
			crit->m_x = atoi( xActor->Attribute( "x" ) ) / 16;
			crit->m_y = atoi( xActor->Attribute( "y" ) ) / 16;

			crit->m_dir = rand() % 4;
			m_critters.push_back( crit );
		}

		xActor = xActor->NextSiblingElement( "critter" );
	}

	// Now, load all the NPCs... npcs are simpler than critters
	for (std::vector<Npc*>::iterator ci = m_npcs.begin();
		 ci != m_npcs.end(); ++ci )
	{
		delete *ci;
	}
	m_npcs.clear();
	xActor = xActorLayer->FirstChildElement( "npc" );
	while (xActor)
	{
		Npc *npc = new Npc();
		npc->m_x = atoi( xActor->Attribute( "x" ) ) / 16;
		npc->m_y = atoi( xActor->Attribute( "y" ) ) / 16;
		npc->m_displayName = xActor->Attribute("displayName" );
		npc->m_name = xActor->Attribute( "map" );
		npc->m_speech = xActor->Attribute( "speech" );

		char buff[1000];
		sprintf( buff, "gamedata/npc_%s.png", xActor->Attribute( "map" ) );
		npc->m_personTex = loadTexture( buff, 4 );
		
		m_npcs.push_back( npc );

		xActor = xActor->NextSiblingElement( "npc" );
	}

	// Finally, fill in any portal info
	xActor = xActorLayer->FirstChildElement( "portal" );
	while (xActor)
	{
		int x = atoi( xActor->Attribute( "x" ) ) / 16;
		int y = atoi( xActor->Attribute( "y" ) ) / 16;
		m_map[x][y].m_portal = strdup( xActor->Attribute("dest") );

		xActor = xActor->NextSiblingElement( "portal" );
	}

	// And finally, rebuild the graphics
	buildMap();
}