Esempio n. 1
0
cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ)
{
	int AbsX = a_RelX + m_ChunkX * cChunkDef::Width;
	int AbsZ = a_RelZ + m_ChunkZ * cChunkDef::Width;
	for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr)
	{
		if (((*itr)->GetPosX() == AbsX) && ((*itr)->GetPosY() == a_RelY) && ((*itr)->GetPosZ() == AbsZ))
		{
			// Already in the list:
			if ((*itr)->GetBlockType() != GetBlockType(a_RelX, a_RelY, a_RelZ))
			{
				// Wrong type, the block type has been overwritten. Erase and create new:
				m_BlockEntities.erase(itr);
				break;
			}
			// Correct type, already present. Return it:
			return *itr;
		}
	}  // for itr - m_BlockEntities[]
	
	// The block entity is not created yet, try to create it and add to list:
	cBlockEntity * be = cBlockEntity::CreateByBlockType(GetBlockType(a_RelX, a_RelY, a_RelZ), GetBlockMeta(a_RelX, a_RelY, a_RelZ), AbsX, a_RelY, AbsZ);
	if (be == NULL)
	{
		// No block entity for this block type
		return NULL;
	}
	m_BlockEntities.push_back(be);
	return be;
}
Esempio n. 2
0
cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ)
{
	auto Idx = cChunkDef::MakeIndex(a_RelX, a_RelY, a_RelZ);
	auto itr = m_BlockEntities.find(Idx);

	if (itr != m_BlockEntities.end())
	{
		// Already in the list:
		cBlockEntity * BlockEntity = itr->second;
		if (BlockEntity->GetBlockType() == GetBlockType(a_RelX, a_RelY, a_RelZ))
		{
			// Correct type, already present. Return it:
			return BlockEntity;
		}
		else
		{
			// Wrong type, the block type has been overwritten. Erase and create new:
			m_BlockEntities.erase(itr);
		}
	}

	int AbsX = a_RelX + m_ChunkX * cChunkDef::Width;
	int AbsZ = a_RelZ + m_ChunkZ * cChunkDef::Width;

	// The block entity is not created yet, try to create it and add to list:
	cBlockEntity * be = cBlockEntity::CreateByBlockType(GetBlockType(a_RelX, a_RelY, a_RelZ), GetBlockMeta(a_RelX, a_RelY, a_RelZ), AbsX, a_RelY, AbsZ);
	if (be == nullptr)
	{
		// No block entity for this block type
		return nullptr;
	}
	m_BlockEntities.insert({ Idx, be });
	return be;
}
Esempio n. 3
0
void cChunkDesc::FloorRelCuboid(
	int a_MinX, int a_MaxX,
	int a_MinY, int a_MaxY,
	int a_MinZ, int a_MaxZ,
	BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
)
{
	int MinX = std::max(a_MinX, 0);
	int MinY = std::max(a_MinY, 0);
	int MinZ = std::max(a_MinZ, 0);
	int MaxX = std::min(a_MaxX, cChunkDef::Width - 1);
	int MaxY = std::min(a_MaxY, cChunkDef::Height - 1);
	int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1);

	for (int y = MinY; y <= MaxY; y++)
	{
		for (int z = MinZ; z <= MaxZ; z++)
		{
			for (int x = MinX; x <= MaxX; x++)
			{
				switch (GetBlockType(x, y, z))
				{
					case E_BLOCK_AIR:
					case E_BLOCK_WATER:
					case E_BLOCK_STATIONARY_WATER:
					{
						SetBlockTypeMeta(x, y, z, a_DstType, a_DstMeta);
						break;
					}
				}  // switch (GetBlockType)
			}  // for x
		}  // for z
	}  // for y
}
Esempio n. 4
0
void CMonster::SetPosXY(float x, float y)
{
	// 将之前位置的阻挡去除
	if(GetFather())
		SetBlock(GetTileX(), GetTileY(), CRegion::BLOCK_NO);
	CShape::SetPosXY(x,y);
	// 设置新的阻挡位置
	if(GetFather())
		SetBlock(GetTileX(), GetTileY(), GetBlockType());
}
Esempio n. 5
0
/* virtual */
OP_STATUS
ES_Thread::Unblock(ES_ThreadBlockType type)
{
	OP_ASSERT(GetBlockType() == type);

	if (blocked_by_foreign_thread != 0)
		SetBlockType(ES_BLOCK_FOREIGN_THREAD);
	else if (scheduler)
		return scheduler->Unblock(this, type);
	else
		SetBlockType(ES_BLOCK_NONE);

	return OpStatus::OK;
}
Esempio n. 6
0
/* virtual */
void
ES_Thread::Block(ES_ThreadBlockType type)
{
	if (block_type == ES_BLOCK_FOREIGN_THREAD)
		SetBlockType(type);
	else
	{
		OP_ASSERT(GetBlockType() == ES_BLOCK_NONE);

		if (scheduler)
			scheduler->Block(this, type);
		else
			SetBlockType(type);
	}
}
CBCGPOutlineNode* CBCGPOutlineParser::AddNode (CBCGPOutlineNode* pNewNode, CBCGPOutlineNode* pParentNode, 
											   BCGP_EDIT_OUTLINE_CHANGES& changes) const
{
	ASSERT_VALID (pParentNode);

	const BlockType* pBlockTypeDef = GetBlockType (pNewNode->m_nBlockType);
	if (pBlockTypeDef != NULL && !pBlockTypeDef->m_bAllowNestedBlocks)
	{
		// Nested blocks are not allowed - delete nested blocks:
		pParentNode->DeleteBlocksInRange (
			pNewNode->m_nStart - pNewNode->m_nNameOffset, 
			pNewNode->m_nEnd, changes);
	}

	return pParentNode->AddNode (pNewNode, changes);
}
Esempio n. 8
0
void cChunkDesc::VerifyHeightmap(void)
{
	for (int x = 0; x < cChunkDef::Width; x++)
	{
		for (int z = 0; z < cChunkDef::Width; z++)
		{
			for (int y = cChunkDef::Height - 1; y > 0; y--)
			{
				BLOCKTYPE BlockType = GetBlockType(x, y, z);
				if (BlockType != E_BLOCK_AIR)
				{
					int Height = GetHeight(x, z);
					ASSERT(Height == y);
					break;
				}
			}  // for y
		}  // for z
	}  // for x
}
Esempio n. 9
0
void cChunkDesc::UpdateHeightmap(void)
{
	for (int x = 0; x < cChunkDef::Width; x++)
	{
		for (int z = 0; z < cChunkDef::Width; z++)
		{
			HEIGHTTYPE Height = 0;
			for (HEIGHTTYPE y = cChunkDef::Height - 1; y > 0; y--)
			{
				BLOCKTYPE BlockType = GetBlockType(x, y, z);
				if (BlockType != E_BLOCK_AIR)
				{
					Height = y;
					break;
				}
			}  // for y
			SetHeight(x, z, Height);
		}  // for z
	}  // for x
}
Esempio n. 10
0
void Chunk::Load(ConcurrentMeshData* meshData, int meshStorageID)
{
	meshStorage_ = meshData;
	meshStorageID_ = meshStorageID;
	glm::ivec3 worldPos;
	glm::ivec3 pos;
	Block* b;
	bool visible = false;

	for(int i = 0; i < CHUNK_SIZE; i++)
	{
		for(int j = 0; j < CHUNK_SIZE; j++)
		{
			for(int k = 0; k < CHUNK_SIZE; k++)
			{			
				b = &blocks_[i][j][k];
				pos = glm::vec3(i,j,k);
				worldPos = pos + (glm::ivec3)position_;

				if(GetBlockType(worldPos.x, worldPos.y, worldPos.z) == 1)
				{
					b->SetVisible(1);
					visible = true;
				}
				else
				{
					b->SetVisible(0);
				}	
				b->SetVisible(1);
				visible = true;
			}
		}
	}

	GenerateMesh(visible);

}
Esempio n. 11
0
/*
  This function is very slow.
  Look into greedy meshing algorithms as an alternative
*/
void Chunk::GenrateCube(const glm::ivec3& pos, const glm::ivec3& worldPos)
{

	visible_ = true;

	char drawSides;
	bool drawTop = true;
	bool drawBottom = true;
	bool drawLeft = true;
	bool drawRight = true;
	bool drawFront = true;
	bool drawBack = true;
	int x = pos.x;
	int y = pos.y;
	int z = pos.z;	

	//cube vertices.
	glm::ivec3 v1p = v1p_ + pos;
	glm::ivec3 v2p = v2p_ + pos;
	glm::ivec3 v3p = v3p_ + pos;
	glm::ivec3 v4p = v4p_ + pos;
	glm::ivec3 v5p = v5p_ + pos;
	glm::ivec3 v6p = v6p_ + pos;
	glm::ivec3 v7p = v7p_ + pos;
	glm::ivec3 v8p = v8p_ + pos;

	glm::vec2 uvCoords(0,0); 
	int v1, v2, v3, v4, v5, v6, v7, v8; //vertex indexes 

	//below if block filters out any block sides which cant be visible. Reducing vertex count, and preventing graphical artifacts
	if(y > 0)
		drawTop = !blocks_[x][y-1][z].IsVisible();
	if(y < chunkSize_-1)
		drawBottom = !blocks_[x][y+1][z].IsVisible();
	if(x > 0)
	   drawLeft = !blocks_[x-1][y][z].IsVisible();
	if(x < chunkSize_-1)
	   drawRight = !blocks_[x+1][y][z].IsVisible();
	if(z > 0)
	   drawBack = !blocks_[x][y][z-1].IsVisible();
	if(z < chunkSize_-1)
	   drawFront = !blocks_[x][y][z+1].IsVisible();

	////this if block checks the squares next to the outer edge blocks in the chunk to see if they are invisible. If they are
	////visible, dont draw these edges.
	if(y == 0)
		drawTop = !GetBlockType(worldPos.x, worldPos.y - 1, worldPos.z );
	if(y == CHUNK_SIZE-1)
		drawBottom = !GetBlockType(worldPos.x, worldPos.y + 1, worldPos.z );
	if(x == 0)
		drawLeft = !GetBlockType(worldPos.x - 1, worldPos.y, worldPos.z );
	if(x == CHUNK_SIZE-1)
		drawRight = !GetBlockType(worldPos.x + 1, worldPos.y, worldPos.z );
	if(z == 0)
		drawBack = !GetBlockType(worldPos.x , worldPos.y, worldPos.z - 1);
	if(z == CHUNK_SIZE-1)
		drawFront = !GetBlockType(worldPos.x , worldPos.y, worldPos.z + 1);

	////bottom
	if(drawBottom)
	{	
		//uvCoords = glm::vec2(1-uvStep_ + d_,0);
		v5 = AddMeshVertex(v5p, downNormal_, uvCoords);
		//uvCoords = glm::vec2(1 - d_,0);
		v6 = AddMeshVertex(v6p, downNormal_, uvCoords);
		//uvCoords = glm::vec2(1 ,uvStep_ - d_);
		v7 = AddMeshVertex(v7p, downNormal_, uvCoords);
		//uvCoords = glm::vec2(1-uvStep_ + d_,uvStep_ - d_);
		v8 = AddMeshVertex(v8p, downNormal_, uvCoords);

		//tessilate face
		meshStorage_->GetData().AddTriangleToMesh(v8, v5, v7);
		meshStorage_->GetData().AddTriangleToMesh(v8, v7, v6);
	}
	////top
	if(drawTop)
	{
		//uvCoords = glm::vec2(0+d_,0+d_);
		v1 = AddMeshVertex(v1p, upNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_ -d_,0+d_);
		v2 = AddMeshVertex(v2p, upNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_ -d_,uvStep_-d_);
		v3 = AddMeshVertex(v3p, upNormal_, uvCoords);
		//uvCoords = glm::vec2(0+d_,uvStep_ - d_);
		v4 = AddMeshVertex(v4p, upNormal_, uvCoords);

		meshStorage_->GetData().AddTriangleToMesh(v2, v4, v1);
		meshStorage_->GetData().AddTriangleToMesh(v3, v4, v2);
	}

	//left face
	if(drawLeft)
	{
		//uvCoords = glm::vec2(uvStep_,0);
		v1 = AddMeshVertex(v1p, leftNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_*2, 0);
		v4 = AddMeshVertex(v4p, leftNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_*2,uvStep_);
		v5 = AddMeshVertex(v5p, leftNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_,uvStep_);
		v7 = AddMeshVertex(v7p, leftNormal_, uvCoords);

		meshStorage_->GetData().AddTriangleToMesh(v4, v5, v1);
		meshStorage_->GetData().AddTriangleToMesh(v4, v7, v5);

	}
	//right face
	if(drawRight)
	{
		//uvCoords = glm::vec2(uvStep_,0);
		v2 = AddMeshVertex(v2p, rightNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_*2, 0);
		v3 = AddMeshVertex(v3p, rightNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_*2,uvStep_);
		v6 = AddMeshVertex(v6p, rightNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_,uvStep_);
		v8 = AddMeshVertex(v8p, rightNormal_, uvCoords);

		meshStorage_->GetData().AddTriangleToMesh(v6, v3, v2);
		meshStorage_->GetData().AddTriangleToMesh(v6, v2, v8);
	}
	//front face
	if(drawFront)
	{
		//uvCoords = glm::vec2(uvStep_,0);
		v7 = AddMeshVertex(v7p, frontNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_*2, 0);
		v6 = AddMeshVertex(v6p, frontNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_*2,uvStep_);
		v3 = AddMeshVertex(v3p, frontNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_,uvStep_);
		v4 = AddMeshVertex(v4p, frontNormal_, uvCoords);

		meshStorage_->GetData().AddTriangleToMesh(v7, v4, v3);
		meshStorage_->GetData().AddTriangleToMesh(v7, v3, v6);
	}
	//back face
	if(drawBack)
	{
		//uvCoords = glm::vec2(uvStep_,0);
		v1 = AddMeshVertex(v1p, backNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_*2, 0);
		v2 = AddMeshVertex(v2p, backNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_*2,uvStep_);
		v5 = AddMeshVertex(v5p, backNormal_, uvCoords);
		//uvCoords = glm::vec2(uvStep_,uvStep_);
		v8 = AddMeshVertex(v8p, backNormal_, uvCoords);

		meshStorage_->GetData().AddTriangleToMesh(v5, v2, v1);
		meshStorage_->GetData().AddTriangleToMesh(v5, v8, v2);
	}
}
//************************************************************************************
BOOL CBCGPOutlineParser::AddMarker (CBCGPOutlineNode* pMarkerBlock, CBCGPOutlineNode* pParentNode,
									BCGP_EDIT_OUTLINE_CHANGES& changes) const
{
	ASSERT_VALID (pMarkerBlock);
	ASSERT_VALID (pParentNode);
	ASSERT ((pMarkerBlock->m_dwFlags & g_dwOBFLeft) != 0 ||
			(pMarkerBlock->m_dwFlags & g_dwOBFRight) != 0);

	// ---------------------------------------
	// Search for marker fitting for this one:
	// ---------------------------------------
	CBCGPOutlineNode* pComposeWith = FindFittingBlock (pMarkerBlock, pParentNode);

	if (pComposeWith != NULL)
	{
		ASSERT_VALID (pComposeWith);

		// ---------------------------------------------------------
		// Combine new marker with existed block or with pair marker
		// ---------------------------------------------------------
		CBCGPOutlineBaseNode* pLeft = NULL;
		CBCGPOutlineBaseNode* pRight = NULL;

		if ((pMarkerBlock->m_dwFlags & g_dwOBFLeft) != 0)
		{
			ASSERT ((pComposeWith->m_dwFlags & g_dwOBFComplete) != 0 ||
					(pComposeWith->m_dwFlags & g_dwOBFRight) != 0);

			pLeft = pMarkerBlock;
			pRight = pComposeWith;
		}
		else if ((pMarkerBlock->m_dwFlags & g_dwOBFRight) != 0)
		{
			ASSERT ((pComposeWith->m_dwFlags & g_dwOBFComplete) != 0 ||
					(pComposeWith->m_dwFlags & g_dwOBFLeft) != 0);

			pLeft = pComposeWith;
			pRight = pMarkerBlock;
		}
		else
		{
			ASSERT (FALSE);
			return FALSE;
		}

		CBCGPOutlineNode* pParent = pComposeWith->GetParentNode ();
		ASSERT_VALID (pParent);

		if (pLeft != NULL && pRight != NULL)
		{
			ASSERT (pLeft->m_nStart < pRight->m_nEnd);
			ASSERT (pLeft->m_strReplace == pRight->m_strReplace);

			// ---------------
			// Make new block:
			// ---------------
			RemoveNode (pComposeWith, pParent, changes);
			CBCGPOutlineNode* pNewBlock = new CBCGPOutlineNode (*pLeft);
			pNewBlock->m_dwFlags &= ~g_dwOBFLeft;
			pNewBlock->m_dwFlags |= g_dwOBFComplete;
			pNewBlock->m_bCollapsed = FALSE;
			pNewBlock->m_nEnd = pRight->m_nEnd;

			AddNode (pNewBlock, pParent, changes);
		}
		else
		{
			ASSERT (FALSE);
			return FALSE;
		}

		if ((pComposeWith->m_dwFlags & g_dwOBFComplete) != 0)
		{
			// ----------------------------------------------------------------------
			// The rest of old block contains start/close sequence - add it as marker
			// ----------------------------------------------------------------------
			CBCGPOutlineNode* pNewMarker = new CBCGPOutlineNode (*pComposeWith->GetValue ());
			const BlockType* pBlockType = GetBlockType (pNewMarker->m_nBlockType);
			if ((pMarkerBlock->m_dwFlags & g_dwOBFLeft) != 0)
			{
				// add start marker (g_dwOBFLeft):
				const int nOpenStrLen = (pBlockType != NULL) ? pBlockType->m_strOpen.GetLength () : 1;
				pNewMarker->m_dwFlags &= ~g_dwOBFComplete;
				pNewMarker->m_dwFlags |= g_dwOBFLeft;
				pNewMarker->m_bCollapsed = FALSE;
				pNewMarker->m_nEnd = pNewMarker->m_nStart + nOpenStrLen - 1;
			}
			else if ((pMarkerBlock->m_dwFlags & g_dwOBFRight) != 0)
			{
				// add end marker (g_dwOBFRight):
				const int nCloseStrLen = (pBlockType != NULL) ? pBlockType->m_strClose.GetLength () : 1;
				pNewMarker->m_dwFlags &= ~g_dwOBFComplete;
				pNewMarker->m_dwFlags |= g_dwOBFRight;
				pNewMarker->m_bCollapsed = FALSE;
				pNewMarker->m_nStart = pNewMarker->m_nEnd - nCloseStrLen - 1;
				pNewMarker->DestroyData (); // end marker has no data
			}

			// Recursive call:
			AddMarker (pNewMarker, pParent, changes);
		}

		// ------------------
		// Delete old blocks:
		// ------------------
		delete pMarkerBlock;
	}
	else
	{
		// --------------------------------------------
		// Add non-completed block (marker) in the root
		// --------------------------------------------
		CBCGPOutlineNode* pRoot = pParentNode;
		while (pRoot->GetParentNode () != NULL)
		{
			ASSERT_VALID (pRoot);
			pRoot = pRoot->GetParentNode ();
		}
		AddNode (pMarkerBlock, pRoot, changes);
	}

	return TRUE;
}
//************************************************************************************
void CBCGPOutlineParser::DoUpdateOffsets (const CString& strBuffer, 
										  const int nStartOffset, const int nEndOffset, 
										  CObList& lstBlocks)
{
	// Update name offsets, start offsets and end offsets:
	CBCGPOutlineNode* pPreviousNode = NULL;
	CObList lstIgnoreBlocks;
	for (POSITION pos = lstBlocks.GetHeadPosition (); pos != NULL; )
	{
		CBCGPOutlineNode* pNode = (CBCGPOutlineNode*) lstBlocks.GetNext (pos);
		ASSERT_VALID (pNode);

		const BlockType* pBlockType = GetBlockType (pNode->m_nBlockType);
		if (pBlockType != NULL && !pBlockType->m_bIgnore)
		{
			// --------------------------------------
			// Update name offsets and start offsets:
			// --------------------------------------
			CString strName;
			int nSearchTo = nStartOffset;
			if (pPreviousNode != NULL && 
				pPreviousNode->m_nEnd < pNode->m_nStart &&
				pPreviousNode->m_nEnd > nStartOffset)
			{
				nSearchTo = pPreviousNode->m_nEnd;
			}
			pNode->m_nNameOffset = GetNameOffset (strBuffer, pNode->m_nStart, nSearchTo,
												  pBlockType, lstIgnoreBlocks, strName);
			int nNewStart = GetStartOffset (strBuffer, pNode->m_nStart, pNode->m_nStart - pNode->m_nNameOffset, lstIgnoreBlocks);
			ASSERT (nNewStart >= nSearchTo);

			int nDelta = nNewStart - pNode->m_nStart;
			pNode->m_nNameOffset += nDelta;
			pNode->m_nStart = nNewStart;
			// strName = strName.Left (strName.GetLength () + nDelta);
			// pNode->m_strName = strName;

			// -------------------
			// Update end offsets:
			// -------------------
			nSearchTo = nEndOffset;
			if (pos != NULL)
			{
				CBCGPOutlineNode* pNextNode = (CBCGPOutlineNode*) lstBlocks.GetAt (pos);
				ASSERT_VALID (pNextNode);

				if (pNextNode->m_nStart > pNode->m_nEnd &&
					pNextNode->m_nStart < nEndOffset)
				{
					nSearchTo = pNextNode->m_nStart;
				}
			}
			int nNewEnd = GetEndOffset (strBuffer, pNode->m_nEnd, nSearchTo);
			ASSERT (nNewEnd <= nSearchTo);
			pNode->m_nEnd = nNewEnd;

			pPreviousNode = pNode;
			lstIgnoreBlocks.AddTail (pNode);
		}
		else
		{
			lstIgnoreBlocks.AddTail (pNode);
		}
	}
}
//************************************************************************************
CBCGPOutlineNode* CBCGPOutlineParser::GetRangeToReparse (CBCGPOutlineNode* pOutlineNode,
														int& nStartOffset, int& nEndOffset) const
{
	ASSERT_VALID (pOutlineNode);
	
	// --------------------------------------
	// Enlarge to start close string lengths:
	// --------------------------------------
	int nMaxBlockOpenStrLen = 1;
	int nMaxBlockCloseStrLen = 1;
	for (int i = 0; i <= m_arrBlockTypes.GetUpperBound (); i++)
	{
		BlockType* pBlockType = m_arrBlockTypes [i];
		ASSERT (pBlockType != NULL);

		if (pBlockType->m_strOpen.GetLength () > nMaxBlockOpenStrLen)
		{
			nMaxBlockOpenStrLen = pBlockType->m_strOpen.GetLength ();
		}
		if (pBlockType->m_strClose.GetLength () > nMaxBlockCloseStrLen)
		{
			nMaxBlockCloseStrLen = pBlockType->m_strClose.GetLength ();
		}
	}
	nStartOffset -= nMaxBlockOpenStrLen - 1;
	nEndOffset += nMaxBlockCloseStrLen - 1;

	// ----------------------
	// Enlarge to block size:
	// ----------------------
	CBCGPOutlineNode* pParentNode = pOutlineNode;
	CBCGPOutlineNode* pNode = NULL;
	POSITION pos = pParentNode->GetNodes ()->GetHeadPosition ();

	// By offset:
	if (nStartOffset > nEndOffset) // no range - use nStartOffset:
	{
		pParentNode = pOutlineNode->GetInnermostBlock (nStartOffset);

		// Ensure the block it's not user block:
		while (pParentNode != NULL && pParentNode != pOutlineNode && 
			   pParentNode->m_nBlockType < 0)
		{
			pParentNode = pParentNode->GetParentNode ();
		}

		if (pParentNode != NULL && pParentNode != pOutlineNode)
		{
			nStartOffset = pParentNode->m_nStart - pParentNode->m_nNameOffset;
			nEndOffset = pParentNode->m_nEnd;
			return pParentNode;
		}
		else
		{
			return pOutlineNode;
		}
	}

	// By range:
	while (pos != NULL)
	{
		pNode = (CBCGPOutlineNode*) pParentNode->GetNodes ()->GetNext (pos);
		ASSERT_VALID (pNode);

		CBCGPOutlineBaseNode::CBCGPEditOutlineRange range = 
			pNode->IsInRangeByOffset (nStartOffset, nEndOffset);
		if (range == FULL_IN_RANGE ||
			(pNode->m_nStart - pNode->m_nNameOffset >= nStartOffset && 
			 pNode->m_nStart - pNode->m_nNameOffset <= nEndOffset))
		{
			// full in range 
			// or left side in range - enlarge nEndOffset:
			nStartOffset = min (nStartOffset, pNode->m_nStart - pNode->m_nNameOffset);
			nEndOffset = max (nEndOffset, pNode->m_nEnd);
		}
		else if (range == PARTIAL_IN_RANGE)
		{
			if (pNode->m_nEnd >= nStartOffset && 
				pNode->m_nEnd <= nEndOffset)
			{
				// right side in range - enlarge nStartOffset:
				nStartOffset = min (nStartOffset, pNode->m_nStart - pNode->m_nNameOffset);
				nEndOffset = max (nEndOffset, pNode->m_nEnd);
			}
			else
			{
				// middle in range - level down:
				pParentNode = pNode;
				pNode = NULL;
				pos = pParentNode->GetNodes ()->GetHeadPosition ();

				const BlockType* pBlockType = GetBlockType (pParentNode->m_nBlockType);
				if (pBlockType == NULL || !pBlockType->m_bAllowNestedBlocks)
				{
					nStartOffset = min (nStartOffset, pParentNode->m_nStart - pParentNode->m_nNameOffset);
					nEndOffset = max (nEndOffset, pParentNode->m_nEnd);
				}
			}
		}
	}

	if (pParentNode != NULL && pParentNode->GetParentNode () != NULL)
	{
		nStartOffset = min (nStartOffset, pParentNode->m_nStart - pParentNode->m_nNameOffset);
		nEndOffset = max (nEndOffset, pParentNode->m_nEnd);
	}
	return pParentNode;
}
//************************************************************************************
void CBCGPOutlineParser::PushResult (Lexeme lexem, CObList& lstResults)
{
#ifdef _DEBUG
	CString str;
#endif // _DEBUG

	const BlockType* pBlockType = GetBlockType (lexem.m_nBlockType);
	ASSERT (pBlockType != NULL);

	switch (lexem.m_nType)
	{
	case LT_CompleteBlock:
		{
			CBCGPOutlineBaseNode block;
			block.m_nStart		= lexem.m_nStart;
			block.m_nEnd		= lexem.m_nEnd;
			block.m_nNameOffset;
			block.m_strReplace	= pBlockType->m_strReplace;
			block.m_nBlockType	= lexem.m_nBlockType;
			block.m_dwFlags		= g_dwOBFComplete;

			CBCGPOutlineNode* pNode = new CBCGPOutlineNode (block);
			ASSERT_VALID (pNode);

			lstResults.AddTail (pNode);
		}
		DEBUG_ONLY (str.Format (_T("%s_%d_%d, "), pBlockType->m_strReplace, lexem.m_nStart, lexem.m_nEnd));
		break;
	case LT_BlockStart:
		{
			CBCGPOutlineBaseNode block;
			block.m_nStart		= lexem.m_nStart;
			block.m_nEnd		= lexem.m_nEnd;
			block.m_nNameOffset;
			block.m_strReplace	= pBlockType->m_strReplace;
			block.m_nBlockType	= lexem.m_nBlockType;
			block.m_dwFlags		= g_dwOBFLeft;

			CBCGPOutlineNode* pNode = new CBCGPOutlineNode (block);
			ASSERT_VALID (pNode);

			lstResults.AddTail (pNode);
		}
		DEBUG_ONLY (str.Format (_T("{_%d, "), lexem.m_nStart));
		break;
	case LT_BlockEnd:
		{
			CBCGPOutlineBaseNode block;
			block.m_nStart		= lexem.m_nStart;
			block.m_nEnd		= lexem.m_nEnd;
			block.m_nNameOffset;
			block.m_strReplace	= pBlockType->m_strReplace;
			block.m_nBlockType	= lexem.m_nBlockType;
			block.m_dwFlags		= g_dwOBFRight;

			CBCGPOutlineNode* pNode = new CBCGPOutlineNode (block);
			ASSERT_VALID (pNode);

			lstResults.AddTail (pNode);
		}
		DEBUG_ONLY (str.Format (_T("}_%d, "), lexem.m_nEnd));
		break;
	case LT_Eps:
		DEBUG_ONLY (str = _T("Finished"));
		break;
	default:
		DEBUG_ONLY (str = _T("Error! "));
	}
	DEBUG_ONLY (m_strOut += str);
}