/** The mask is inpainted with ValidValue in this function. */
  void FinishVertex(VertexDescriptorType targetNode, VertexDescriptorType sourceNode)// __attribute__((optimize(0))) // This supposedly makes this function build in debug mode (-g -O0) when the rest of the program is built in -O3 or similar)
  {
    // Mark this pixel and the area around it as filled, and mark the mask in this region as filled.
    // Determine the new boundary, and setup the nodes in the boundary queue.

//    std::cout << "InpaintingVisitor::FinishVertex()" << std::endl;

    // Construct the region around the vertex
    itk::Index<2> indexToFinish = ITKHelpers::CreateIndex(targetNode);

    itk::ImageRegion<2> regionToFinishFull = ITKHelpers::GetRegionInRadiusAroundPixel(indexToFinish, this->PatchHalfWidth);

    // Copy this region so that we can change (crop) the regionToFinish and still have a copy of the original region
    itk::ImageRegion<2> regionToFinish = regionToFinishFull;

    // Make sure the region is entirely inside the image
    // (because we allow target patches to not be entirely inside the image to handle the case where
    // the hole boundary is near the image boundary)
    regionToFinish.Crop(this->Image->GetLargestPossibleRegion());

    if(this->DebugImages)
    {
      ITKHelpers::WriteImage(this->MaskImage, Helpers::GetSequentialFileName("Mask_Before", this->NumberOfFinishedPatches, "png", 3));
    }

    // Mark all the pixels in this region as filled in the mask.
    ITKHelpers::SetRegionToConstant(this->MaskImage, regionToFinish, this->MaskImage->GetValidValue());

    if(this->DebugImages)
    {
      ITKHelpers::WriteImage(this->MaskImage, Helpers::GetSequentialFileName("Mask_After", this->NumberOfFinishedPatches, "png", 3));

      typename TImage::PixelType red;
      red.Fill(0);
      red[0] = 255;

      typename TImage::PixelType green;
      green.Fill(0);
      green[1] = 255;

      typename TImage::Pointer patchesCopiedImage = TImage::New();
      ITKHelpers::DeepCopy(this->Image, patchesCopiedImage.GetPointer());
      ITKHelpers::OutlineRegion(patchesCopiedImage.GetPointer(), regionToFinish, red);

      itk::Index<2> sourceRegionCenter = ITKHelpers::CreateIndex(sourceNode);
      itk::ImageRegion<2> sourceRegion = ITKHelpers::GetRegionInRadiusAroundPixel(sourceRegionCenter, this->PatchHalfWidth);

      sourceRegion = ITKHelpers::CropRegionAtPosition(sourceRegion, this->Image->GetLargestPossibleRegion(), regionToFinishFull);

      ITKHelpers::OutlineRegion(patchesCopiedImage.GetPointer(), sourceRegion, green);

      ITKHelpers::WriteRGBImage(patchesCopiedImage.GetPointer(), Helpers::GetSequentialFileName("PatchesCopied", this->NumberOfFinishedPatches, "png", 3));
    }

    // Update the priority function. This must be done AFTER the mask is filled,
    // as some of the Priority functors only compute things on the hole boundary, or only
    // use data from the valid region of the image (indicated by valid pixels in the mask).
    this->PriorityFunction->Update(sourceNode, targetNode, this->NumberOfFinishedPatches);

    // Initialize (if requested) all vertices in the newly filled region because they may now be valid source nodes.
    // (You may not want to do this in some cases (i.e. if the descriptors needed cannot be
    // computed on newly filled regions))

    if(this->AllowNewPatches)
    {
      itk::ImageRegionConstIteratorWithIndex<TImage> gridIterator(Image, regionToFinish);
      while(!gridIterator.IsAtEnd())
      {
        VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(gridIterator.GetIndex());

        InitializeVertex(v);
        ++gridIterator;
      }
    }

    // Add pixels that are on the new boundary to the queue, and mark other pixels as not in the queue.
    itk::ImageRegionConstIteratorWithIndex<Mask> imageIterator(this->MaskImage, regionToFinish);

    typedef typename TBoundaryNodeQueue::HandleType HandleType;

    while(!imageIterator.IsAtEnd())
    {
      VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(imageIterator.GetIndex());

      if(this->MaskImage->HasHoleNeighbor(imageIterator.GetIndex()))
      {
        float priority = this->PriorityFunction->ComputePriority(imageIterator.GetIndex());
        this->BoundaryNodeQueue.push_or_update(v, priority);
      }
      else
      {
        this->BoundaryNodeQueue.mark_as_invalid(v);
      }

      ++imageIterator;
    }

    // std::cout << "FinishVertex after traversing finishing region there are "
    //           << BoostHelpers::CountValidQueueNodes(BoundaryNodeQueue, BoundaryStatusMap)
    //           << " valid nodes in the queue." << std::endl;
    
    // Sometimes pixels that are not in the finishing region that were boundary pixels are no longer
    // boundary pixels after the filling. Check for these.
    // E.g. (H=hole, B=boundary, V=valid, Q=query, F=filled, N=new boundary,
    // R=old boundary pixel that needs to be removed because it is no longer on the boundary)
    // Before filling

    /* V V V B H H H H
     * V V V B H H H H
     * V V V B H H H H
     * V V V B B Q B B
     * V V V V V V V V
     */
    // After filling

    /* V V V B H H H H
     * V V V B H H H H
     * V V V B F F F H
     * V V V B F F F B
     * V V V V F F F V
     */
    // New boundary
    /* V V V B H H H H
     * V V V B H H H H
     * V V V B N N N H
     * V V V R F F N B
     * V V V V F F F V
     */

    // Expand the region
    itk::ImageRegion<2> expandedRegion = ITKHelpers::GetRegionInRadiusAroundPixel(indexToFinish, PatchHalfWidth + 1);
    // Make sure the region is entirely inside the image (to allow for target regions near the image boundary)
    expandedRegion.Crop(this->Image->GetLargestPossibleRegion());
    std::vector<itk::Index<2> > boundaryPixels = ITKHelpers::GetBoundaryPixels(expandedRegion);
    for(unsigned int i = 0; i < boundaryPixels.size(); ++i)
    {
      // the region (the entire image) can be omitted, as this function automatically checks if the pixels are inside the image
      if(!this->MaskImage->HasHoleNeighbor(boundaryPixels[i]))
      {
        VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(boundaryPixels[i]);

        put(this->BoundaryNodeQueue.BoundaryStatusMap, v, false);
      }
    }

    // std::cout << "FinishVertex after removing stale nodes outside finishing region there are "
    //               << BoostHelpers::CountValidQueueNodes(BoundaryNodeQueue, BoundaryStatusMap)
    //               << " valid nodes in the queue." << std::endl;

    this->NumberOfFinishedPatches++;

//    std::cout << "Leave InpaintingVisitor::FinishVertex()" << std::endl;
  } // end FinishVertex
  /** The mask is inpainted with ValidValue in this function. */
  void FinishVertex(VertexDescriptorType targetNode, VertexDescriptorType sourceNode) override
  {
    // Mark this pixel and the area around it as filled, and mark the mask in this region as filled.
    // Determine the new boundary, and setup the nodes in the boundary queue.

//    std::cout << "InpaintingVisitor::FinishVertex()" << std::endl;

    // Construct the region around the vertex
    itk::Index<2> indexToFinish = ITKHelpers::CreateIndex(targetNode);

    // Mark this node as having been used as a source node.
    this->UsedNodesSet.insert(indexToFinish);

    itk::ImageRegion<2> regionToFinishFull =
        ITKHelpers::GetRegionInRadiusAroundPixel(indexToFinish, this->PatchHalfWidth);

    // Copy this region so that we can change (crop) the regionToFinish and still have a copy of the original region
    itk::ImageRegion<2> regionToFinish = regionToFinishFull;

    // Make sure the region is entirely inside the image
    // (because we allow target patches to not be entirely inside the image to handle the case where
    // the hole boundary is near the image boundary)
    regionToFinish.Crop(this->FullRegion);

    itk::Index<2> sourceRegionCenter = ITKHelpers::CreateIndex(sourceNode);
    itk::ImageRegion<2> sourceRegion =
        ITKHelpers::GetRegionInRadiusAroundPixel(sourceRegionCenter, this->PatchHalfWidth);

    sourceRegion = ITKHelpers::CropRegionAtPosition(sourceRegion, this->MaskImage->GetLargestPossibleRegion(),
                                                    regionToFinishFull);

    // Mark all pixels that were copied (in the hole region of the source patch) as having been used.
//    std::cout << "InpaintingVisitor::FinishVertex() mark pixels as used" << std::endl;
    itk::ImageRegionConstIteratorWithIndex<SourcePixelMapImageType> sourcePatchIterator(this->SourcePixelMapImage,
                                                                                        sourceRegion);
    itk::ImageRegionConstIteratorWithIndex<Mask> targetPatchIterator(this->MaskImage, regionToFinish);
    while(!sourcePatchIterator.IsAtEnd())
    {
      if(targetPatchIterator.Get() == this->MaskImage->GetHoleValue())
      {
        this->CopiedPixelsImage->SetPixel(sourcePatchIterator.GetIndex(), true); // Mark this pixel as used

        // Save the location from which this pixel came. We want to use the index value in the SourcePixelMapImage,
        // because the value might not equal the current index in the case where new patches are allowed.
        this->SourcePixelMapImage->SetPixel(targetPatchIterator.GetIndex(),
                                            sourcePatchIterator.Get());
      }

      ++sourcePatchIterator;
      ++targetPatchIterator;
    }

    if(this->DebugImages)
    {
      if(this->DebugLevel > 1)
      {
        ITKHelpers::WriteBoolImage(this->CopiedPixelsImage,
                                   Helpers::GetSequentialFileName("CopiedPixels",
                                                                  this->NumberOfFinishedPatches, "png", 3));
        ITKHelpers::WriteImage(this->MaskImage,
                               Helpers::GetSequentialFileName("Mask_Before",
                                                              this->NumberOfFinishedPatches, "png", 3));
      }
    }

    // Mark all the pixels in this region as filled in the mask.
//    std::cout << "InpaintingVisitor::FinishVertex() fill the mask" << std::endl;
    ITKHelpers::SetRegionToConstant(this->MaskImage, regionToFinish,
                                    this->MaskImage->GetValidValue());

    // Write an image of where the source and target patch were in this iteration.
//    if(this->DebugImages && this->Image)
//    {
//      typename TImage::PixelType red;
//      red.Fill(0);
//      red[0] = 255;

//      typename TImage::PixelType green;
//      green.Fill(0);
//      green[1] = 255;

//      typename TImage::Pointer patchesCopiedImage = TImage::New();
//      ITKHelpers::DeepCopy(this->Image, patchesCopiedImage.GetPointer());
//      ITKHelpers::OutlineRegion(patchesCopiedImage.GetPointer(), regionToFinish, red);

//      ITKHelpers::OutlineRegion(patchesCopiedImage.GetPointer(), sourceRegion, green);

//      ITKHelpers::WriteRGBImage(patchesCopiedImage.GetPointer(), Helpers::GetSequentialFileName("PatchesCopied", this->NumberOfFinishedPatches, "png", 3));

//      if(this->DebugLevel > 1)
//      {
//        ITKHelpers::WriteImage(this->MaskImage, Helpers::GetSequentialFileName("Mask_After", this->NumberOfFinishedPatches, "png", 3));
//      }
//    }

    // Update the priority function. This must be done AFTER the mask is filled,
    // as some of the Priority functors only compute things on the hole boundary, or only
    // use data from the valid region of the image (indicated by valid pixels in the mask).
//    std::cout << "InpaintingVisitor::FinishVertex() update priority" << std::endl;
    this->PriorityFunction->Update(sourceNode, targetNode, this->NumberOfFinishedPatches);
//    std::cout << "InpaintingVisitor::FinishVertex() finish update priority" << std::endl;
    // Initialize (if requested) all vertices in the newly filled region because they may now be valid source nodes.
    // (You may not want to do this in some cases (i.e. if the descriptors needed cannot be
    // computed on newly filled regions))

    if(this->AllowNewPatches)
    {
//      std::cout << "Initializing new vertices..." << std::endl;
      itk::ImageRegionConstIteratorWithIndex<Mask> gridIterator(this->MaskImage, regionToFinish);
      while(!gridIterator.IsAtEnd())
      {
        VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(gridIterator.GetIndex());

        InitializeVertex(v);
        ++gridIterator;
      }
    }

    // Add pixels that are on the new boundary to the queue, and mark other pixels as not in the queue.
//    std::cout << "InpaintingVisitor::FinishVertex() iterator" << std::endl;
    itk::ImageRegionConstIteratorWithIndex<Mask> imageIterator(this->MaskImage, regionToFinish);
//    std::cout << "InpaintingVisitor::FinishVertex() finish iterator" << std::endl;

    typedef typename TBoundaryNodeQueue::HandleType HandleType;

    // Naive, unparallelizable way
//    while(!imageIterator.IsAtEnd())
//    {
//      VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(imageIterator.GetIndex());

//      if(this->MaskImage->HasHoleNeighbor(imageIterator.GetIndex()))
//      {
//        float priority = this->PriorityFunction->ComputePriority(imageIterator.GetIndex());
//        this->BoundaryNodeQueue.push_or_update(v, priority);
//      }
//      else
//      {
//        this->BoundaryNodeQueue.mark_as_invalid(v);
//      }

//      ++imageIterator;
//    }

    // Parallelizable way - collect the pixels that need their priority computed
//    std::cout << "InpaintingVisitor::FinishVertex() Parallelizable way" << std::endl;
    typedef std::vector<itk::Index<2> > IndexVectorType;
    IndexVectorType pixelsToCompute;
    while(!imageIterator.IsAtEnd())
    {
      VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(imageIterator.GetIndex());

      if(this->MaskImage->GetPixel(imageIterator.GetIndex()) == this->MaskImage->GetValidValue() &&
         this->MaskImage->HasHoleNeighbor(imageIterator.GetIndex()))
      {
        pixelsToCompute.push_back(imageIterator.GetIndex());
      }
      else
      {
        this->BoundaryNodeQueue->mark_as_invalid(v);
      }

      ++imageIterator;
    }

//    std::cout << "InpaintingVisitor::FinishVertex() update queue" << std::endl;
    #pragma omp parallel for
    for(IndexVectorType::const_iterator pixelIterator = pixelsToCompute.begin();
        pixelIterator < pixelsToCompute.end(); ++pixelIterator)
    {
      VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(*pixelIterator);
      float priority = this->PriorityFunction->ComputePriority(*pixelIterator);
      #pragma omp critical // There are weird crashes without this guard
      this->BoundaryNodeQueue->push_or_update(v, priority);
    }

    // std::cout << "FinishVertex after traversing finishing region there are "
    //           << BoostHelpers::CountValidQueueNodes(BoundaryNodeQueue, BoundaryStatusMap)
    //           << " valid nodes in the queue." << std::endl;
    
    // Sometimes pixels that are not in the finishing region that were boundary pixels are no longer
    // boundary pixels after the filling. Check for these.
    // E.g. (H=hole, B=boundary, V=valid, Q=query, F=filled, N=new boundary,
    // R=old boundary pixel that needs to be removed because it is no longer on the boundary)
    // Before filling

    /* V V V B H H H H
     * V V V B H H H H
     * V V V B H H H H
     * V V V B B Q B B
     * V V V V V V V V
     */
    // After filling

    /* V V V B H H H H
     * V V V B H H H H
     * V V V B F F F H
     * V V V B F F F B
     * V V V V F F F V
     */
    // New boundary
    /* V V V B H H H H
     * V V V B H H H H
     * V V V B N N N H
     * V V V R F F N B
     * V V V V F F F V
     */

    // Expand the region
//    std::cout << "InpaintingVisitor::FinishVertex() expand" << std::endl;
    itk::ImageRegion<2> expandedRegion =
        ITKHelpers::GetRegionInRadiusAroundPixel(indexToFinish, PatchHalfWidth + 1);
    // Make sure the region is entirely inside the image (to allow for target regions near the image boundary)
    expandedRegion.Crop(this->FullRegion);
    std::vector<itk::Index<2> > boundaryPixels =
        ITKHelpers::GetBoundaryPixels(expandedRegion);
//    std::cout << "InpaintingVisitor::FinishVertex() boundary pixels" << std::endl;
    for(unsigned int i = 0; i < boundaryPixels.size(); ++i)
    {
      // the region (the entire image) can be omitted, as this function automatically checks if the pixels are inside the image
      if(!this->MaskImage->HasHoleNeighbor(boundaryPixels[i]))
      {
        VertexDescriptorType v =
            Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(boundaryPixels[i]);

        put(this->BoundaryNodeQueue->BoundaryStatusMap, v, false);
      }
    }

    // std::cout << "FinishVertex after removing stale nodes outside finishing region there are "
    //               << BoostHelpers::CountValidQueueNodes(BoundaryNodeQueue, BoundaryStatusMap)
    //               << " valid nodes in the queue." << std::endl;

    this->NumberOfFinishedPatches++;

//    std::cout << "Leave InpaintingVisitor::FinishVertex()" << std::endl;
  } // end FinishVertex
Esempio n. 3
0
void Encoder::Encode(DWORD ID, DWORD Class, DWORD CTNumber, DWORD MType)
{
	BOOL bInsertSurfaceNode = FALSE;
	BOOL bInsertTextureNode = FALSE;
	m_pCurrentNode = m_pRootNode;
	
	// COBRA - RED - Missing Last Texture Initialization to INVALID
	DWORD		dwCurrentTexture=-1;
	DWORD		dwCurrentzBias=0;
	NodeType	LastType=ROOT;
	DXFlagsType	LastFlags;

	LastFlags.w=0x00;
	bool		ChangeSurface=false;

	while(m_pCurrentNode != NULL)
	{
		IdleMode();
		NodeType	Type=m_pCurrentNode->Type;
		DXFlagsType	Flags;
		Flags.w=m_pCurrentNode->Flags.w;
	
		// Make all checks here
		ChangeSurface=false;
		if(Type!=LastType || Type==DOF || Type==CLOSEDOF || Type==SLOT ) ChangeSurface = true;
		if(Flags.b.Texture && m_pCurrentNode->Texture!=dwCurrentTexture) ChangeSurface = true;
		if(Flags.b.Texture != LastFlags.b.Texture) ChangeSurface=true;
		if(Flags.b.Alpha != LastFlags.b.Alpha) ChangeSurface=true;
		if(Flags.b.Gouraud != LastFlags.b.Gouraud ) ChangeSurface=true;
		if(Flags.b.Lite != LastFlags.b.Lite ) ChangeSurface=true;
		if((Flags.b.VColor) != (LastFlags.b.VColor)) ChangeSurface=true;
		if(Flags.b.zBias != LastFlags.b.zBias) ChangeSurface=true;
		if(Flags.b.zBias && m_pCurrentNode->dwzBias!=dwCurrentzBias) ChangeSurface=true;
		if(Flags.b.ChromaKey != LastFlags.b.ChromaKey) ChangeSurface=true;

		// if any change
		if(ChangeSurface){
			
			// Patch the segments
			PatchDWORD();

			switch (Type){

				case	DOT:
				case	LINE:
				case	TRIANGLE:	// Check if a Textured new surace and last texture still valid
									if(Flags.b.Texture && m_pCurrentNode->Texture!=dwCurrentTexture){
										// No moer used Texture node
										//WriteTextureNode(m_pCurrentNode);
										dwCurrentTexture=m_pCurrentNode->Texture;
									}
									dwCurrentzBias=m_pCurrentNode->dwzBias;
									// Write the new Surface
									WriteSurfaceNode(m_pCurrentNode, dwCurrentTexture);
									// New ID
									m_dwNodeID++;
									break;

				case	DOF:		// We've to insert a new DOF node
									{DXDof *pDof = (DXDof*)m_pCurrentNode;	WriteDofNode(pDof);}
									// and reset surfaces properties
									Flags.w=0;
									dwCurrentTexture=-1;
									// New ID
									m_dwNodeID++;
									break;

				case	SLOT:		// We've to insert a new SLOT node
									WriteSlotNode((DXSlot*)m_pCurrentNode);
									// New ID
									m_dwNodeID++;
									break;

		
				case CLOSEDOF:		// We've to insert a new END DOF node
									WriteDofEndNode();
									// and reset surfaces properties
									Flags.w=0;
									dwCurrentTexture=-1;
									// New ID
									m_dwNodeID++;
									break;

				default	:			MessageBox(NULL, "Unknown SURFACE TYPE!!", "Encoder", 0);
			}

			ChangeSurface=false;
			LastFlags=Flags;
			LastType=Type;

		}


		switch(Type)
		{
			case DOT:
			{
				DXVertex *pVertex = (DXVertex*)m_pCurrentNode;
				D3DVERTEXEX dxVertex;
				InitializeVertex(&dxVertex);

				CopyVertex(&(pVertex->Vertex), pVertex->VColor, &dxVertex);
				/*memcpy((void*)&dxVertex, (const void*)&pVertex->Vertex, sizeof(pVertex->Vertex));
				memcpy((void*)(&dxVertex + sizeof(pVertex->Vertex)), (const void*)&pVertex->VColor, sizeof(pVertex->VColor));*/

				// Add vertex in NON INDEXED MODE
				Int16 iIndex = AddVertexToPool(&dxVertex, false);
				WriteBuffer((const void*)&iIndex, sizeof(iIndex));
			}
			break;

			case LINE:
			{
				DXLine *pLine = (DXLine*)m_pCurrentNode;

				for(int i=0; i<2; i++)
				{
					D3DVERTEXEX dxVertex;
					InitializeVertex(&dxVertex);

					CopyVertex(&(pLine->Vertex[i]), pLine->VColor[i], &dxVertex);
					/*memcpy((void*)&dxVertex, (const void*)&pLine->Vertex[i], sizeof(pLine->Vertex[i]));
					memcpy((void*)(&dxVertex + sizeof(pLine->Vertex[i])), (const void*)&pLine->VColor[i], sizeof(pLine->VColor[0]));*/

					Int16 iIndex = AddVertexToPool(&dxVertex);
					WriteBuffer((const void*)&iIndex, sizeof(iIndex));
				}
			}
			break;

			case TRIANGLE:
			{
				DXTriangle *pTriangle = (DXTriangle*)m_pCurrentNode;

				for(int i=0; i<3; i++)
				{
					D3DVERTEXEX dxVertex;
					InitializeVertex(&dxVertex);
					
					CopyVertex(&(pTriangle->Vertex[i]), pTriangle->VColor[i], &dxVertex);
					
					/*BYTE *pVertex = (BYTE*)&dxVertex;
					memcpy((void*)&dxVertex, (const void*)&pTriangle->Vertex[i], sizeof(pTriangle->Vertex[i]));
					memcpy((void*)(pVertex + sizeof(pTriangle->Vertex[i])), (const void*)&pTriangle->VColor[i], sizeof(pTriangle->VColor[0]));*/

					Int16 iIndex = AddVertexToPool(&dxVertex);
					WriteBuffer((const void*)&iIndex, sizeof(iIndex));
				}
			}
			break;

		}
		// Update pointers
		//m_pPreviousNode = m_pCurrentNode;
		m_pCurrentNode  = m_pCurrentNode->Next;
		//m_pNextNode     = m_pCurrentNode != NULL ? m_pCurrentNode->Next : NULL;
	}

	//// Set last node total size (Node + Data (total indexes size))
	//DWORD dwTotalNodeSize = (m_dwTotalSurfaceVertexes*sizeof(Int16) + sizeof(DxSurfaceType));
	//memcpy((void*)m_pLastSurfaceNode, (const void*)&dwTotalNodeSize, sizeof(dwTotalNodeSize));
	//// Add last node Vertex Counter to last surface node
	//memcpy(m_pLastSurfaceNode + 12, (const void*)&m_dwTotalSurfaceVertexes, sizeof(m_dwTotalSurfaceVertexes));

	// Patch the segments
	PatchDWORD();

	// Write ENDMODEL node
	DxEndModelType dxEndModelNode;
	dxEndModelNode.h.dwNodeSize = sizeof(DxEndModelType);
	dxEndModelNode.h.Type = DX_MODELEND;
 	WriteBuffer((void*)&dxEndModelNode, sizeof(dxEndModelNode));

	// Write total number of nodes
	((DxDbHeader*)m_pHeader)->dwNodesNr=m_dwTotalNodeCount;

	// Write other header fields
	//DWORD dwVertexesPoolStart = (DWORD)(m_pBuffer + m_dwBufferOffset);
	((DxDbHeader*)m_pHeader)->pVPool=m_dwBufferOffset;
	((DxDbHeader*)m_pHeader)->dwPoolSize=m_dwVertexesPoolSize;
	((DxDbHeader*)m_pHeader)->dwNVertices=m_dwVertexesNumber;

	// Copy vertexes pool after nodes section
	WriteBuffer((const void*)m_pVertexesPool, m_dwVertexesPoolSize);

	((DxDbHeader*)m_pHeader)->Id=ID;
	((DxDbHeader*)m_pHeader)->ModelSize= m_dwBufferOffset;
	((DxDbHeader*)m_pHeader)->VBClass=Class;
	((DxDbHeader*)m_pHeader)->Version=MODEL_VERSION|((MODEL_VERSION^0xffff)<<16);

	// Assign Materials Features
	m_dwBufferOffset=AssignSurfaceFeatures(m_pBuffer, CTNumber, MType);

#ifdef	CRYPTED_MODELS
	TheVbManager.Encrypt((DWORD*)m_pBuffer);
#endif
	// Write file
	//WriteFile();
}
void Encoder::Encode()
{
	BOOL bInsertSurfaceNode = FALSE;
	BOOL bInsertTextureNode = FALSE;
	m_pCurrentNode = m_pRootNode;

	while(m_pCurrentNode != NULL)
	{
		m_pPreviousNode = m_pCurrentNode->Prev;
		//m_pNextNode     = m_pCurrentNode->Next;

		if(m_pCurrentNode == m_pRootNode)
		{
			// Root node, insert Texture and Surface node
			if(m_pCurrentNode->Flags.b.Texture)
				WriteTextureNode(m_pCurrentNode);
			WriteSurfaceNode(m_pCurrentNode);
		}
		else
		{
			// Check for node property changes
			if(m_pCurrentNode->Type != DOF && m_pCurrentNode->Type != CLOSEDOF)
			{
				if(m_pPreviousNode->Type == DOF || m_pPreviousNode->Type == CLOSEDOF)
				{
					if(m_pCurrentNode->Flags.b.Texture)
						WriteTextureNode(m_pCurrentNode);
					WriteSurfaceNode(m_pCurrentNode);
				}
				else
				{
					if(m_pCurrentNode->Flags.b.Texture)
					{
						if(m_pCurrentNode->Texture != m_pPreviousNode->Texture)
						{
							// Texture of current node differs from previous node, we've to insert a TEXTURE node before new SURFACE node
							WriteTextureNode(m_pCurrentNode);
							WriteSurfaceNode(m_pCurrentNode);
						}
						else
						{
							// Check if other fields are changed (in this case we've to insert a new SURFACE node
							if( m_pCurrentNode->Flags.b.ALpha   != m_pPreviousNode->Flags.b.ALpha   ||
								m_pCurrentNode->Flags.b.Gouraud != m_pPreviousNode->Flags.b.Gouraud ||
								m_pCurrentNode->Flags.b.Lite    != m_pPreviousNode->Flags.b.Lite    ||
								m_pCurrentNode->Type            != m_pPreviousNode->Type )
								WriteSurfaceNode(m_pCurrentNode);
						}
					}
					else if(m_pCurrentNode->Flags.b.Solid || m_pCurrentNode->Flags.b.VColor)
					{
						// Colour node, check only for Alpha changes
						if( m_pCurrentNode->Flags.b.ALpha != m_pPreviousNode->Flags.b.ALpha ||
							m_pCurrentNode->Type != m_pPreviousNode->Type )
							WriteSurfaceNode(m_pCurrentNode);
					}
				}
			}
		}

		switch(m_pCurrentNode->Type)
		{
			case DOT:
			{
				DXVertex *pVertex = (DXVertex*)m_pCurrentNode;
				D3DVERTEXEX dxVertex;
				InitializeVertex(&dxVertex);

				memcpy((void*)&dxVertex, (const void*)&pVertex->Vertex, sizeof(pVertex->Vertex));
				memcpy((void*)(&dxVertex + sizeof(pVertex->Vertex)), (const void*)&pVertex->VColor, sizeof(pVertex->VColor));

				Int16 iIndex = AddVertexToPool(&dxVertex);
				WriteBuffer((const void*)&iIndex, sizeof(iIndex));

				//if(m_pCurrentNode->Flags.b.Texture)
				//{
				//	// Write all D3DVertex information
				//	WriteBuffer((void*)&pVertex->Vertex, sizeof(pVertex->Vertex));
				//}
				//else
				//{
				//	// In this case, write only x,y,z,nx,ny,nz (24 bytes total) and VColour
				//	WriteBuffer((void*)&pVertex->Vertex, 24);
				//	WriteBuffer((void*)&pVertex->VColor, sizeof(pVertex->VColor));
				//}
				//m_dwTotalSurfaceVertexes++;
			}
			break;

			case LINE:
			{
				DXLine *pLine = (DXLine*)m_pCurrentNode;

				for(int i=0; i<2; i++)
				{
					D3DVERTEXEX dxVertex;
					InitializeVertex(&dxVertex);

					memcpy((void*)&dxVertex, (const void*)&pLine->Vertex[i], sizeof(pLine->Vertex[i]));
					memcpy((void*)(&dxVertex + sizeof(pLine->Vertex[i])), (const void*)&pLine->VColor[i], sizeof(pLine->VColor[0]));

					Int16 iIndex = AddVertexToPool(&dxVertex);
					WriteBuffer((const void*)&iIndex, sizeof(iIndex));
				}

				//if(m_pCurrentNode->Flags.b.Texture)
				//{
				//	// Write all D3DVertex information
				//	WriteBuffer((void*)&pLine->Vertex, sizeof(pLine->Vertex));
				//}
				//else
				//{
				//	// In this case, write only x,y,z,nx,ny,nz (24 bytes total) and VColour
				//	for(int i=0;i<2;i++)
				//	{
				//		WriteBuffer((void*)&pLine->Vertex[i], 24);
				//		WriteBuffer((void*)&pLine->VColor[i], sizeof(pLine->VColor[0]));
				//	}
				//}
				//m_dwTotalSurfaceVertexes += 2;
			}
			break;

			case TRIANGLE:
			{
				DXTriangle *pTriangle = (DXTriangle*)m_pCurrentNode;

				for(int i=0; i<3; i++)
				{
					D3DVERTEXEX dxVertex;
					InitializeVertex(&dxVertex);
					BYTE *pVertex = (BYTE*)&dxVertex;

					memcpy((void*)&dxVertex, (const void*)&pTriangle->Vertex[i], sizeof(pTriangle->Vertex[i]));
					memcpy((void*)(pVertex + sizeof(pTriangle->Vertex[i])), (const void*)&pTriangle->VColor[i], sizeof(pTriangle->VColor[0]));

					Int16 iIndex = AddVertexToPool(&dxVertex);
					WriteBuffer((const void*)&iIndex, sizeof(iIndex));
				}

				//if(m_pCurrentNode->Flags.b.Texture)
				//{
				//	// Write all D3DVertex information
				//	WriteBuffer((void*)&pTriangle->Vertex, sizeof(pTriangle->Vertex));
				//}
				//else
				//{
				//	// In this case, write only x,y,z,nx,ny,nz (24 bytes total) and VColour
				//	for(int i=0;i<3;i++)
				//	{
				//		WriteBuffer((void*)&pTriangle->Vertex[i], 24);
				//		WriteBuffer((void*)&pTriangle->VColor[i], sizeof(pTriangle->VColor[0]));
				//	}
				//}
				//m_dwTotalSurfaceVertexes += 3;
			}
			break;

			case DOF:
			{
				// We've to insert a new DOF node
				DXDof *pDof = (DXDof*)m_pCurrentNode;
				WriteDofNode(pDof);
			}
			break;

			case CLOSEDOF:
			{
				// We've to insert a new END DOF node
				WriteDofEndNode();
			}
			break;
		}
		// Update pointers
		//m_pPreviousNode = m_pCurrentNode;
		m_pCurrentNode  = m_pCurrentNode->Next;
		//m_pNextNode     = m_pCurrentNode != NULL ? m_pCurrentNode->Next : NULL;
	}

	// Set last node total size (Node + Data (total indexes size))
	DWORD dwTotalNodeSize = (m_dwTotalSurfaceVertexes*sizeof(Int16) + sizeof(DxSurfaceType));
	memcpy((void*)m_pLastSurfaceNode, (const void*)&dwTotalNodeSize, sizeof(dwTotalNodeSize));
	// Add last node Vertex Counter to last surface node
	memcpy(m_pLastSurfaceNode + 12, (const void*)&m_dwTotalSurfaceVertexes, sizeof(m_dwTotalSurfaceVertexes));
	// Write ENDMODEL node
	DxEndModelType dxEndModelNode;
	dxEndModelNode.h.dwNodeSize = sizeof(DxEndModelType);
	dxEndModelNode.h.Type = DX_MODELEND;
 	WriteBuffer((void*)&dxEndModelNode, sizeof(dxEndModelNode));
	// Write total number of nodes
	memcpy((void*)m_pHeader, (const void*)&m_dwTotalNodeCount, sizeof(m_dwTotalNodeCount));
	// Write other header fields
	//DWORD dwVertexesPoolStart = (DWORD)(m_pBuffer + m_dwBufferOffset);
	memcpy((void*)(m_pHeader+4), (const void*)&m_dwBufferOffset, sizeof(DWORD));
	memcpy((void*)(m_pHeader+8), (const void*)&m_dwVertexesPoolSize, sizeof(DWORD));
	memcpy((void*)(m_pHeader+12), (const void*)&m_dwVertexesNumber, sizeof(DWORD));
	// Copy vertexes pool after nodes section
	WriteBuffer((const void*)m_pVertexesPool, m_dwVertexesPoolSize);
	// Write file
	WriteFile();
}