任意阶拼图游戏及自动求解算法

任意阶拼图游戏及自动求解算法,第1张

10号,不太舒服有点头疼。


千万别感冒,补点水饺。


这是《最强大脑》里出现过的一个拼图游戏


这个游戏的自动拼图算法是一个N数码问题。


原始图片被切割成n x n个小块,游戏可能出现的总状态数为 n平方的阶乘。


即使最简单的n=3,3阶分割也有(3*3)! = 362880个状态。


4阶分割时,拼图状态数飙升到(4*4)! = 20922789888000。


那么100阶分割呢,(100*100)! 绝对的天文数字。


如何来实现任意阶的拼图算法呢?

 方案一:
我们很容易想到的方法,按打乱的顺序逆序还原,有点作弊之嫌。


方案二:
A*算法剪枝, 避免电脑出现一万年也算不完任务的情况。


当阶数n足够大的时候效率仍然是堪忧的。


方案三:
本游戏采用的算法,模拟人脑的思路。


100*100阶的拼图也能很快求解,而且可以分步执行,即一次只计算一步,很适合游戏ai。


此方法也有一个缺点,不是最优解,求解出来的步数有点长。


 算法:先将色块和空格移动到目标位置附近,然后执行相应的公式化步骤。


具体直接看源码吧

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Pintu/MiniGamePintu.h
//  @Brief:     MiniGamePintu
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 

#ifndef  __MiniGamePintu__H__
#define  __MiniGamePintu__H__

#include "Rpg/MiniGame.h"

//拼图1 空格移动
class MiniGameSlidingBlock:public MiniGame
{
public:
	struct Cell
	{
		int texID;
		int x,y;
	};
	struct CellMesh
	{
		vec3 vVertex[8];
		vec2 tVertex[8];
	};
	MiniGameSlidingBlock();
	virtual~MiniGameSlidingBlock();
	virtual bool Start();
	virtual bool Stop();
	virtual bool Render();
	virtual void RenderUI();
	virtual bool Update();
	virtual bool Free();
	virtual void OnSize();
	virtual bool KeepResource(bool once,int& circle,String& nextTip);

	//三种类型结构
	virtual MiniPlayer*  CreatePlayer();
	virtual MiniPlayer*  CreateRobot ();
	virtual MiniPlayer*  CreateRole  ();

	void  UpdateGameRect();
	bool  IsEnd();
	void  MoveEmpty(int key);
	bool  IsCellOK(int x,int y);
	bool  IsCellEmpty(int x,int y);
	Cell* GetCell(int texID);

	bool  AIMoveSrcUp(int srcX,int srcY,int tarX,int tarY,int empX,int empY);
	bool  AIMoveSrcDown(int srcX,int srcY,int tarX,int tarY,int empX,int empY);
	bool  AIMoveSrcLeft(int srcX,int srcY,int tarX,int tarY,int empX,int empY);
	bool  AIMoveSrcRight(int srcX,int srcY,int tarX,int tarY,int empX,int empY);

//protected:
	float m_accumeTime;
	TexturePtr  m_texBack;
	TexturePtr  m_texPic;
	TexturePtr  m_texFrame;
	TexturePtr  m_texFrame2;
	TexturePtr  m_texCloud;

	int         m_Level;

	RectF       m_gameRect;
	RectF       m_rectLevel;
	vec2I       m_cellNum;
	int         m_cellNumXY;
	vec2I       m_cellExtend;
		  
	Cell*       m_emptyCell;
	Cell*       m_cells;
	CellMesh*   m_cellMeshs;
		  
	Cell        m_movingCell;
	vec2        m_movingDir;
	float       m_movingTime;
		  
	bool        m_workingWithAI;
	Cell*       m_aiSrcCell;
	int         m_aiCompleteSize;
		  
	int         m_stepNum;
		  
	int         m_aiTryNum;
	int         m_aiTrys[64];

	//box 索引
	int         CellIndex[30];
};

extern MiniGameSlidingBlock* G_SlideBlockGame;

#endif
//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Pintu/MiniGamePintu.cpp
//  @Brief:     MiniGamePintu
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================

#include "General/Pch.h"
#include "General/General.h"
#include "General/StringUtil.h"
#include "General/Timer.h"
#include "General/Window.h"
#include "Gui/GuiMgr.h"
#include "Gui/RpgGuis.h"
#include "Gui/GuiControlMisc.h"
#include "Input/InputMgr.h"
#include "MiniGameSlidingBlock.h"
#include "Render/Camera.h"
#include "Render/Font.h"
#include "Render/RendDriver.h"
#include "Render/Terrain.h"
#include "Render/MC_MovieClip.h"
#include "Render/Shader.h"
#include "Sound/SoundManager.h"
#include "General/List.cpp"
#include "General/Pce.h"

//static float MovingTime = 0.001f;
static float MovingTime = 0.08f;
static float GameRectWidth2D    = 460; 
static float GameRectWidth3D    = 66; 

MiniGameSlidingBlock* G_SlideBlockGame;

MiniGameSlidingBlock::MiniGameSlidingBlock()
:m_cells(NULL)
{
    G_SlideBlockGame = this;
	//m_Level = 0;
	m_Level = 4;
	//box 索引
	/*
	  0  1
	  2  3
	  4  5
	  6  7
	*/
	int indexs[30] = 
	{
		0,2,1,
		1,2,3,
		3,2,6,
		3,6,7,
		1,3,7,
		1,7,5,
		0,1,5,
		0,5,4,
		2,0,4,
		2,4,6
	};
	memcpy(CellIndex,indexs,sizeof(CellIndex));
}
MiniGameSlidingBlock::~MiniGameSlidingBlock()
{
    Free();
	G_SlideBlockGame = NULL;
}
bool MiniGameSlidingBlock::Start()
{
	//m_myRolePlayer = NULL;
    if(!MiniGame::Start())
        return false;

	m_gameState = MS_Gamming;
    m_accumeTime = 0;
	
    //进入miniplaygui,(选人、选关卡都已在房间里进行完毕)。


if(GetStyle()) G_GuiMgr->PushGui(GetStyle()->playGUI.c_str(),GL_DIALOG); G_TextureMgr->AddTexture(m_texBack, "data/minigame/Pintu/backframe.png"); G_TextureMgr->AddTexture(m_texPic, "data/minigame/Pintu/pic1.png"); G_TextureMgr->AddTexture(m_texFrame, "data/minigame/Pintu/frame.png"); G_TextureMgr->AddTexture(m_texFrame2, "data/minigame/Pintu/frame2.png"); //G_TextureMgr->AddTexture(m_texCloud, "data/environment/clouds/cloud2.png"); G_TextureMgr->AddTexture(m_texCloud, "data/environment/clouds/cloud_1.png"); // if (m_movieScene == NULL) { LoadConfig loader(LoadConfig::GenDonotReShrinkBound, true, true); m_movieScene = new RendSys::MovieClip; m_movieScene->LoadFromFile("data/minigame/pintu/board.movie", &loader); Frame frame; frame.SetPos(m_startPos); m_movieScene->SetProgramFrame(&frame); m_movieScene->Advance(); } if (m_movieScene->IsLoadComplete() == false) { m_gameState = MS_End; return false; } m_movieScene->GetMovieClip("preview")->ReAttachTexture(m_texPic); //m_cellNum.x = 6; //m_cellNum.y = 7; m_cellNum.x = 2+m_Level; m_cellNum.y = 2+m_Level; m_cellNumXY = m_cellNum.x*m_cellNum.y; UpdateGameRect(); m_workingWithAI=FALSE; m_aiSrcCell = NULL; m_aiTryNum = 0; m_aiCompleteSize = -1; m_stepNum = 0; m_movingTime = 0; m_movingCell.texID = -1; // m_cells = new Cell[m_cellNumXY]; for(int i=0;itexID = -1; // int num = 0; for(int i=1;i<200;i++) { int ran1=Rand()%(m_cellNumXY-1);//empty不交换 int ran2=Rand()%(m_cellNumXY-1); if(ran1!=ran2) { num++; Swap(m_cells[ran1].texID,m_cells[ran2].texID); } } if (num%2==1) { //必须交换偶数次 Swap(m_cells[0].texID,m_cells[1].texID); } // /* 0 1 2 3 4 5 6 7 */ m_cellMeshs = new CellMesh[m_cellNumXY]; TerrainData terrain; //terrain.New(48,48,GameRectWidth3D/48,GameRectWidth3D/48); terrain.New(17,17,GameRectWidth3D/16,GameRectWidth3D/16); terrain.FillFractSurface(0,0,10,0.5f,false,0); Cell* cell; CellMesh* mesh; vec2 cellExtend3D; cellExtend3D.x = GameRectWidth3D/m_cellNum.x; cellExtend3D.y = GameRectWidth3D/m_cellNum.y; for(int i=0;ivVertex[0].x = X0; mesh->vVertex[0].y = terrain.GetHeight(cell->x,cell->y); mesh->vVertex[0].z = Z0; mesh->vVertex[4].x = X0; mesh->vVertex[4].y = Y0; mesh->vVertex[4].z = Z0; mesh->vVertex[1].x = X1; mesh->vVertex[1].y = terrain.GetHeight(cell->x+1,cell->y); mesh->vVertex[1].z = Z0; mesh->vVertex[5].x = X1; mesh->vVertex[5].y = Y0; mesh->vVertex[5].z = Z0; mesh->vVertex[2].x = X0; mesh->vVertex[2].y = terrain.GetHeight(cell->x,cell->y+1); mesh->vVertex[2].z = Z1; mesh->vVertex[6].x = X0; mesh->vVertex[6].y = Y0; mesh->vVertex[6].z = Z1; mesh->vVertex[3].x = X1; mesh->vVertex[3].y = terrain.GetHeight(cell->x+1,cell->y+1); mesh->vVertex[3].z = Z1; mesh->vVertex[7].x = X1; mesh->vVertex[7].y = Y0; mesh->vVertex[7].z = Z1; float TX0 = float(cell->x)/m_cellNum.x; float TX1 = float(cell->x+1)/m_cellNum.x; float TZ0 = float(cell->y)/m_cellNum.y; float TZ1 = float(cell->y+1)/m_cellNum.y; mesh->tVertex[0].x = TX0; mesh->tVertex[0].y = TZ0; mesh->tVertex[4].x = TX0; mesh->tVertex[4].y = TZ0; mesh->tVertex[1].x = TX1; mesh->tVertex[1].y = TZ0; mesh->tVertex[5].x = TX1; mesh->tVertex[5].y = TZ0; mesh->tVertex[2].x = TX0; mesh->tVertex[2].y = TZ1; mesh->tVertex[6].x = TX0; mesh->tVertex[6].y = TZ1; mesh->tVertex[3].x = TX1; mesh->tVertex[3].y = TZ1; mesh->tVertex[7].x = TX1; mesh->tVertex[7].y = TZ1; } // for(int i = 0; i < m_allPlayerNum; i++) { if(m_miniPlayer[i]) m_miniPlayer[i]->Start(); } //设置摄像机 CameraCtrlerTarget* ctrler = new CameraCtrlerTarget; ctrler->SetDistToTar(60); ctrler->SetTarPos(m_startPos); G_Camera->PushCtrler(ctrler); G_Camera->SetEuler(0, -60, 0); //片头摄像机 PushIntroCamera(); return true; } MiniPlayer* MiniGameSlidingBlock::CreatePlayer() { return new MiniPlayer; } MiniPlayer* MiniGameSlidingBlock::CreateRobot() { return new MiniPlayer; } MiniPlayer* MiniGameSlidingBlock::CreateRole() { return new MiniPlayer; } bool MiniGameSlidingBlock::Stop() { // char buf[256]; G_GuiMgr->PopGui("MiPintu_PlayGui"); { if (m_myPlayer && m_myPlayer->m_liveNum>0) { G_GuiMgr->GetGui()->ShowResult(true); } else { G_GuiMgr->GetGui()->ShowResult(false); } G_GuiMgr->PushGui("Rpg_ResultDialog",GL_DIALOGBOTTOM); } MiniGame::Stop(); return true; } bool MiniGameSlidingBlock::Render() { if (m_3dMode) { G_RendDriver->EndUI(); if(m_movieScene==NULL ||m_movieScene->IsLoadComplete()==false) return false; G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,true); m_movieScene->RendClip(); 画等级 //m_rectLevel = RectF(BoardRect2D.x+623, BoardRect2D.y+24, 39, 23); //if(m_rectLevel.IsPointIn(G_Mouse->GetMousePos())) //{ // G_RendDriver->Color4f(1, 1, 0, 1); //} //else //{ // G_RendDriver->Color4f(1, 0, 0, 1); //} //m_texLcdNumber->Bind(); //DrawLcd(3,m_Level+1, m_rectLevel); //G_RendDriver->Color4f(1, 1, 1, 1); 画时间和得分 //m_texLcdNumber->Bind(); //G_RendDriver->Color4f(1, 0, 0, 1); //DrawLcd(3,m_gameTime, RectF(BoardRect2D.x +613, BoardRect2D.y+213, 39, 23)); DrawLcd(3,m_life, RectF(m_uiOffset.x+623, m_uiOffset.y +52, 39, 23)); //DrawLcd(4,m_stepNum, RectF(BoardRect2D.x+623, BoardRect2D.y +79, 52, 23)); // G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f); G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true); m_texPic->Bind(); //cell Cell* cell; CellMesh* mesh; for(int i = 0;itexID!=-1 &&cell->texID!=m_movingCell.texID) { mesh = &m_cellMeshs[cell->texID]; G_RendDriver->PushMatrix(); G_RendDriver->Translatef(m_gameRect.x+cell->x *m_cellExtend.x, m_startPos.y+9, m_gameRect.y+cell->y *m_cellExtend.y); G_RendDriver->RendTrigon(10,mesh->vVertex,mesh->tVertex,NULL,NULL,CellIndex,8); G_RendDriver->PopMatrix(); //G_RendDriver->Color4f(0.0f, 0.0f, 0.0f, 0.5f); //G_RendDriver->DrawRect(RectF(dst.x+3,dst.y+3,20,20)); //G_FontMgr->SetColor(Color(1.0f, 1.0f, 1.0f, 1.0f)); //sprintf(buf,"%d",cell->texID); //G_FontMgr->TextAtPos(dst,buf); } } //moving if (m_movingCell.texID!=-1) { vec2 pos; pos.x = m_movingCell.x *m_cellExtend.x; pos.y = m_movingCell.y *m_cellExtend.y; pos += m_movingDir*vec2(m_cellExtend.x,m_cellExtend.y)*(1-m_movingTime/MovingTime); mesh = &m_cellMeshs[m_movingCell.texID]; G_RendDriver->PushMatrix(); G_RendDriver->Translatef(m_gameRect.x+pos.x, m_startPos.y+9, m_gameRect.y+pos.y); G_RendDriver->RendTrigon(10,mesh->vVertex,mesh->tVertex,NULL,NULL,CellIndex,8); G_RendDriver->PopMatrix(); // G_RendDriver->Color4f(0.0f, 0.0f, 0.0f, 0.5f); // G_RendDriver->DrawRect(RectF(dst.x+3,dst.y+3,20,20)); // sprintf(buf,"%d",m_movingCell.texID); // G_FontMgr->SetColor(Color(1.0f, 1.0f, 1.0f, 1.0f)); // G_FontMgr->TextAtPos(dst,buf); } } else { //G_RendDriver->ClearClipRect(); G_RendDriver->BeginUI(); //frame G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f); m_texBack->Bind(); G_RendDriver->DrawTextureRect(BoardRect2D, RectF(0, 0, 1, 1)); // G_RendDriver->PushMatrix(); G_RendDriver->Translatef(m_gameRect.x,-m_gameRect.y,0); vec2 dst; //cell char buf[128]; vec2I tex; //纹理排序后速度微小增加 //picture Cell* cell = m_cells; m_texPic->Bind(); G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f); if (G_ShaderMgr&& G_ShaderMgr->m_curEffect) { G_ShaderMgr->MapChangeParm(); } for(int i = 0;itexID!=-1 &&cell->texID!=m_movingCell.texID) { tex.x = cell->texID%m_cellNum.x; tex.y = cell->texID/m_cellNum.x; dst.x = cell->x *m_cellExtend.x; dst.y = cell->y *m_cellExtend.y; G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y), RectF(float(tex.x)/m_cellNum.x,float(tex.y)/m_cellNum.y,1.0f/m_cellNum.x,1.0f/m_cellNum.y)); } } //cloud cell = m_cells; m_texCloud->Bind(); for(int i = 0;itexID!=-1 &&cell->texID!=m_movingCell.texID) { tex.x = cell->texID%m_cellNum.x; tex.y = cell->texID/m_cellNum.x; dst.x = cell->x *m_cellExtend.x; dst.y = cell->y *m_cellExtend.y; // G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y), RectF(float(tex.x)/m_cellNum.x+m_gameTime*0.1f,float(tex.y)/m_cellNum.y,1.0f/m_cellNum.x,1.0f/m_cellNum.y)); } } //frame cell = m_cells; m_texFrame->Bind(); for(int i = 0;itexID!=-1 &&cell->texID!=m_movingCell.texID) { tex.x = cell->texID%m_cellNum.x; tex.y = cell->texID/m_cellNum.x; dst.x = cell->x *m_cellExtend.x; dst.y = cell->y *m_cellExtend.y; int t = 0; if (m_workingWithAI && cell==m_aiSrcCell) { t = 1; G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(t/10.0f,0,1/10.0f,1)); } else { if (IsCellOK(cell->x,cell->y)) { RectF frameRect(dst.x-2,dst.y-2,m_cellExtend.x+4,m_cellExtend.y+4); if (IsCellOK(cell->x-1,cell->y)==false) { t = 2; G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1)); } if (IsCellOK(cell->x+1,cell->y)==false) { t = 3; G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1)); } if (IsCellOK(cell->x,cell->y-1)==false) { t = 4; G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1)); } if (IsCellOK(cell->x,cell->y+1)==false) { t = 5; G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1)); } } else { if (IsCellOK(cell->x,cell->y+1)==false) { t = 0; G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(t/10.0f,0,1/10.0f,1)); } } } } } //text cell = m_cells; m_texLcdNumber->Bind(); for(int i = 0;itexID!=-1 &&cell->texID!=m_movingCell.texID) { tex.x = cell->texID%m_cellNum.x; tex.y = cell->texID/m_cellNum.x; dst.x = cell->x *m_cellExtend.x; dst.y = cell->y *m_cellExtend.y; DrawLcd(3,cell->texID, RectF(dst.x+3,dst.y+3,20,10)); //slow //G_RendDriver->Color4f(0.0f, 0.0f, 0.0f, 0.5f); //G_RendDriver->DrawRect(RectF(dst.x+3,dst.y+3,20,20)); //G_FontMgr->SetColor(Color(1.0f, 1.0f, 1.0f, 1.0f)); //sprintf(buf,"%d",cell->texID); //G_FontMgr->TextAtPos(dst,buf); } } //moving if (m_movingCell.texID!=-1) { tex.x = m_movingCell.texID%m_cellNum.x; tex.y = m_movingCell.texID/m_cellNum.x; dst.x = m_movingCell.x *m_cellExtend.x; dst.y = m_movingCell.y *m_cellExtend.y; dst += m_movingDir*vec2(m_cellExtend.x,m_cellExtend.y)*(1-m_movingTime/MovingTime); G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f); m_texPic->Bind(); G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y), RectF(float(tex.x)/m_cellNum.x,float(tex.y)/m_cellNum.y,1.0f/m_cellNum.x,1.0f/m_cellNum.y)); m_texFrame->Bind(); if (IsCellOK(m_movingCell.x,m_movingCell.y)) { Cell* cell = &m_movingCell; RectF frameRect(dst.x-2,dst.y-2,m_cellExtend.x+4,m_cellExtend.y+4); int t = 0; if (IsCellOK(cell->x-1,cell->y)==false) { t = 2; G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1)); } if (IsCellOK(cell->x+1,cell->y)==false) { t = 3; G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1)); } if (IsCellOK(cell->x,cell->y-1)==false) { t = 4; G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1)); } if (IsCellOK(cell->x,cell->y+1)==false) { t = 5; G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1)); } } else { int t = 0; if (m_workingWithAI && m_aiSrcCell && m_movingCell.texID==m_aiSrcCell->texID) t = 1; G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(t/10.0f,0,1/10.0f,1)); } G_RendDriver->Color4f(0.0f, 0.0f, 0.0f, 0.5f); G_RendDriver->DrawRect(RectF(dst.x+3,dst.y+3,20,20)); sprintf(buf,"%d",m_movingCell.texID); G_FontMgr->SetColor(Color(1.0f, 1.0f, 1.0f, 1.0f)); G_FontMgr->TextAtPos(dst,buf); } G_RendDriver->PopMatrix(); //preview G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f); RectF previewRect(BoardRect2D.x+517,BoardRect2D.y+306,175,175.0f/m_texPic->GetWidth()*m_texPic->GetHeight()); m_texPic->Bind(); G_RendDriver->DrawTextureRect(previewRect, RectF(0, 0, 1, 1)); } // if (m_3dMode) { G_RendDriver->PushMatrix(); G_RendDriver->MultMatrix(mat2Dto3D); } //画等级 m_rectLevel = RectF(BoardRect2D.x+633, BoardRect2D.y+36, 39, 23); if(m_rectLevel.IsPointIn(G_Mouse->GetMousePos())) { G_RendDriver->Color4f(1, 1, 0, 1); } else { G_RendDriver->Color4f(1, 0, 0, 1); } m_texLcdNumber->Bind(); DrawLcd(3,m_Level+1, m_rectLevel); G_RendDriver->Color4f(1, 1, 1, 1); //画时间和得分 m_texLcdNumber->Bind(); G_RendDriver->Color4f(1, 0, 0, 1); DrawLcd(3,m_gameTime, RectF(BoardRect2D.x +623, BoardRect2D.y+223, 39, 23)); DrawLcd(4,m_stepNum, RectF(BoardRect2D.x+633, BoardRect2D.y +89, 52, 23)); if (m_3dMode) { G_RendDriver->PopMatrix(); } return true; } void MiniGameSlidingBlock::RenderUI() { Render(); G_RendDriver->BeginUI(); } void MiniGameSlidingBlock::UpdateGameRect() { float width__ = m_texBack->GetWidth(); float height_ = m_texBack->GetHeight(); SetBoardRect(RectF((G_Window->m_iWidth-width__)/2,(G_Window->m_iHeight-height_)/2,width__,height_), RectF(m_startPos.x-50,m_startPos.z-33,100,66), m_startPos.y+10.1f); if (m_3dMode) { m_gameRect = RectF(m_startPos.x-38, m_startPos.z-GameRectWidth3D/2, GameRectWidth3D,GameRectWidth3D); } else { m_gameRect = RectF(BoardRect2D.x + 26, BoardRect2D.y + 22, GameRectWidth2D,GameRectWidth2D); } m_cellExtend.x = m_gameRect.width/m_cellNum.x; m_cellExtend.y = m_gameRect.height/m_cellNum.y; //取整 if (m_3dMode==false) { m_gameRect.width = m_cellExtend.x*m_cellNum.x; m_gameRect.height = m_cellExtend.y*m_cellNum.y; } } bool MiniGameSlidingBlock::Update() { MiniGame::Update(); m_movieScene->Advance(); UpdateGameRect(); if (m_movingCell.texID!=-1) { m_movingTime += G_Timer->GetStepTimeLimited(); if (m_movingTime>MovingTime) { m_movingTime = MovingTime; } } if (G_SlideBlockGame->IsButtonDowning(MOUSE_LEFT)) { int click = 0; if (m_3dMode) { vec3 dir; vec3 start; G_Camera->GetMouseTray(start,dir); RayMovieCollideRes res; res.vStart = start; res.vEnd = start+PICKLEN*dir; res.justBond = false; if(m_movieScene->GetMovieClip("board")->IntersectTray(res)) { vec2 point(res.resPos.x- m_gameRect.x,res.resPos.z- m_gameRect.y); click = int(point.x/m_cellExtend.x) + int(point.y/m_cellExtend.y)*m_cellNum.x; } } else { vec2 point = G_Mouse->GetMousePos()-m_gameRect.GetPos(); click = int(point.x/m_cellExtend.x) + int(point.y/m_cellExtend.y)*m_cellNum.x; } int empty = (m_emptyCell->x) + (m_emptyCell->y)*m_cellNum.x; if(click - empty == 1) { MoveEmpty(DIK_RIGHT); } else if(click - empty == -1) { MoveEmpty(DIK_LEFT); } else if(click - empty == m_cellNum.x) { MoveEmpty(DIK_DOWN); } else if(click - empty == -m_cellNum.x) { MoveEmpty(DIK_UP); } else { PlaySound__("data/sound/poker/cannot.wav"); } if(m_rectLevel.IsPointIn(G_Mouse->GetMousePos())) { //重新开始 m_Level++; m_Level%=10; //Start(); } } if (G_SlideBlockGame->IsKeyDowning(KeyLeft)) { MoveEmpty(DIK_LEFT); } else if (G_SlideBlockGame->IsKeyDowning(KeyRight)) { MoveEmpty(DIK_RIGHT); } else if (G_SlideBlockGame->IsKeyDowning(KeyUp)) { MoveEmpty(DIK_UP); } else if (G_SlideBlockGame->IsKeyDowning(KeyDown)) { MoveEmpty(DIK_DOWN); } //算法优化:毗邻后可以不断的移位大循环圈 而不是小循环圈, 这样可以在大循环圈内构造长的正确序列一起移位 正确序列越长加速效果越好 if (m_workingWithAI &&IsEnd()==false &&(m_movingCell.texID==-1||m_movingTime>=MovingTime) ) { if (m_aiTryNum) { m_aiTryNum--; MoveEmpty(m_aiTrys[m_aiTryNum]); } else { //将块srcTexID挪动到tarX,tarY int empX = m_emptyCell->x; int empY = m_emptyCell->y; //最后两排两列 if (m_aiCompleteSize>=m_cellNum.x-2-1 &&m_aiCompleteSize>=m_cellNum.y-2-1) { //找要匹配的色块 m_aiSrcCell = NULL; int srcTexID = -1; int aiCompleteSizeX = -1; //底面两排 for(int size = 0;sizesize+1) { m_aiTrys[m_aiTryNum++] = DIK_LEFT; break; } m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_UP; //先移动倒叙插入 //for (int i=m_cellNum.y-1-empY;i>0;i--) //{ // m_aiTrys[m_aiTryNum++] = DIK_DOWN; //} //for (int i=empX-size-1;i>0;i--) //{ // m_aiTrys[m_aiTryNum++] = DIK_LEFT; //} break; } //特殊处理避免死循环 /* |empty |index2 | |index1 |any | */ if(m_cells[index2].texID==index1 &&m_cells[index1].texID==-1 &&m_cells[index1+m_cellNum.x].texID==index2 ) { //变成 /* |index2 |any | |index1 |empty | */ MoveEmpty(DIK_DOWN); break; } if(m_cells[m_cellNumXY-m_cellNum.x+size].texID==index1)//先将index1挪到左下角,再将index2挪到左下角时index1自动归位 { /* |empty |any | |index1 |index2| index2归位时index1自动归位 */ srcTexID = index2; } else { srcTexID = index1; } //找到色块位置 m_aiSrcCell = GetCell(srcTexID); int srcX = m_aiSrcCell->x; int srcY = m_aiSrcCell->y; int tarX = aiCompleteSizeX+1; int tarY = m_cellNum.y-1; //先毗邻 if (abs(empX-srcX)>1 || abs(empY-srcY)>1) { if (empYsrcY+1) { MoveEmpty(DIK_UP); } else if (empY<=srcY-1) { MoveEmpty(DIK_DOWN); } else if (empX>srcX+1) { MoveEmpty(DIK_LEFT); } else if (empX<=srcX-1) { MoveEmpty(DIK_RIGHT); } } else { //先毗邻x (空白从底面两排毗邻到右面两排) if (empX>srcX+1) { MoveEmpty(DIK_LEFT); } else if (empX<=srcX-1) { MoveEmpty(DIK_RIGHT); } else if (empY>srcY+1) { MoveEmpty(DIK_UP); } else if (empY<=srcY-1) { MoveEmpty(DIK_DOWN); } } } else { //先挪到底部 if (srcYtarX) { //挪到左边 AIMoveSrcLeft(srcX,srcY,tarX,tarY,empX,empY); } } break; } //右面两排 int aiCompleteSizeY = -1; if (aiCompleteSizeX>=m_cellNum.x-2-1) { for(int size = 0;sizesize+1) { m_aiTrys[m_aiTryNum++] = DIK_UP; break; } m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_UP; //先移动倒叙插入 //for (int i=m_cellNum.x-1-empX;i>0;i--) //{ // m_aiTrys[m_aiTryNum++] = DIK_RIGHT; //} //for (int i=empY-size-1;i>0;i--) //{ // m_aiTrys[m_aiTryNum++] = DIK_UP; //} break; } //特殊处理避免死循环 /* |empty |index1| |index2|any | */ if(m_cells[index2].texID==index1 &&m_cells[index1].texID==-1 &&m_cells[index1+m_cellNum.x].texID==index2 ) { //变成 /* |index2 |index1| |any |empty | */ MoveEmpty(DIK_DOWN); break; } if(m_cells[index2].texID==index1)//先将index1挪到右上角,再讲index2挪到右上角时index1自动归位 { srcTexID = index2; } else { srcTexID = index1; } //找到色块位置 m_aiSrcCell = GetCell(srcTexID); int srcX = m_aiSrcCell->x; int srcY = m_aiSrcCell->y; int tarX = m_cellNum.x-1; int tarY = aiCompleteSizeY+1; //先毗邻 if (abs(empX-srcX)>1 || abs(empY-srcY)>1) { if (empYsrcY+1) { MoveEmpty(DIK_UP); } else if (empY<=srcY-1) { MoveEmpty(DIK_DOWN); } else if (empX>srcX+1) { MoveEmpty(DIK_LEFT); } else if (empX<=srcX-1) { MoveEmpty(DIK_RIGHT); } } else { //先毗邻x if (empX>srcX+1) { MoveEmpty(DIK_LEFT); } else if (empX<=srcX-1) { MoveEmpty(DIK_RIGHT); } else if (empY>srcY+1) { MoveEmpty(DIK_UP); } else if (empY<=srcY-1) { MoveEmpty(DIK_DOWN); } } } else { //先挪到右部 if (srcXtarY) { //挪到上边 AIMoveSrcUp(srcX,srcY,tarX,tarY,empX,empY); } } break; } } //最后四个 if (aiCompleteSizeY>=m_cellNum.y-2-1) { //没结束就顺时针转 if(empY==m_cellNum.y-2) { if (empX==m_cellNum.x-2) { MoveEmpty(DIK_RIGHT); } else { MoveEmpty(DIK_DOWN); } } else { if (empX==m_cellNum.x-2) { MoveEmpty(DIK_UP); } else { MoveEmpty(DIK_LEFT); } } //if(m_emptyCell->x==m_cellNum.x-2) //{ // MoveEmpty(DIK_RIGHT); //} //else if(m_emptyCell->y==m_cellNum.y-2) //{ // MoveEmpty(DIK_DOWN); //} } } //先拼左上角 else { //找到不匹配的色块 m_aiSrcCell = NULL; int srcTexID = -1; //for(int i = 0;i=m_cellNum.y-2 ) //最下面两排另拼 { break; } } if (srcTexID!=-1) { break; } for(int j = 0;j<=size;j++) { index = j*m_cellNum.x+size; if(IsCellOK(size,j)==false) { srcTexID = index; break; } if(size>=m_cellNum.x-2) //最右面两排另拼 { break; } } if (srcTexID!=-1) { break; } m_aiCompleteSize = size; } //找到色块位置 m_aiSrcCell = GetCell(srcTexID); int srcX = m_aiSrcCell->x; int srcY = m_aiSrcCell->y; // int tarX = m_aiSrcCell->texID%m_cellNum.x; int tarY = m_aiSrcCell->texID/m_cellNum.x; if (abs(empX-srcX)>1 || abs(empY-srcY)>1) { //先毗邻 if (empY=empY && empX>srcX)) { //先毗邻y if (empY>srcY+1) { MoveEmpty(DIK_UP); } else if (empY<=srcY-1) { MoveEmpty(DIK_DOWN); } else if (empX>srcX+1) { MoveEmpty(DIK_LEFT); } else if (empX<=srcX-1) { MoveEmpty(DIK_RIGHT); } } else { //先毗邻x if (empX>srcX+1) { MoveEmpty(DIK_LEFT); } else if (empX<=srcX-1) { MoveEmpty(DIK_RIGHT); } else if (empY>srcY+1) { MoveEmpty(DIK_UP); } else if (empY<=srcY-1) { MoveEmpty(DIK_DOWN); } } } else { if (srcX>srcY) { //先y if(tarYsrcY) { AIMoveSrcDown(srcX,srcY,tarX,tarY,empX,empY); } else if(tarX>srcX) { AIMoveSrcRight(srcX,srcY,tarX,tarY,empX,empY); return true; } else if(tarXsrcX) { AIMoveSrcRight(srcX,srcY,tarX,tarY,empX,empY); return true; } else if(tarXsrcY) { AIMoveSrcDown(srcX,srcY,tarX,tarY,empX,empY); } } } } } } IsEnd(); return true; } bool MiniGameSlidingBlock::AIMoveSrcUp(int srcX,int srcY,int tarX,int tarY,int empX,int empY) { //将空格转到上侧 //倒叙插入移动 m_aiTrys[m_aiTryNum++] = DIK_DOWN; //第1排 if(empX==srcX-1 && empY==srcY-1) { m_aiTrys[m_aiTryNum++] = DIK_RIGHT; } else if(empX==srcX+1 && empY==srcY-1) { m_aiTrys[m_aiTryNum++] = DIK_LEFT; } //第2排 else if(empX==srcX-1 && empY==srcY) { if (IsCellOK(empX,empY-1)==false) { //不会破坏已经拼好的 m_aiTrys[m_aiTryNum++] = DIK_RIGHT; m_aiTrys[m_aiTryNum++] = DIK_UP; } else { if (srcY= m_cellNum.x-1) //没法从右绕 { //不会破坏已经拼好的 m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_LEFT; } else { m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_RIGHT; } } else if(empX==srcX+1 && empY==srcY-1) { m_aiTrys[m_aiTryNum++] = DIK_UP; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_LEFT; m_aiTrys[m_aiTryNum++] = DIK_DOWN; m_aiTrys[m_aiTryNum++] = DIK_DOWN; } //第2排 else if(empX==srcX+1 && empY==srcY) { if (srcYx>0) { srcCell = m_emptyCell-1; sucess = true; } break; case DIK_RIGHT: if(m_emptyCell->xy>0) { srcCell = m_emptyCell - m_cellNum.x; sucess = true; } break; case DIK_DOWN: if(m_emptyCell->yx-m_emptyCell->x,srcCell->y-m_emptyCell->y); if (srcCell==m_aiSrcCell) { m_aiSrcCell = m_emptyCell; } m_movingCell.x = m_emptyCell->x; m_movingCell.y = m_emptyCell->y; m_movingCell.texID = srcCell->texID; m_movingTime = 0; Swap(tarCell->texID,srcCell->texID); m_emptyCell = srcCell; if (IsCellOK(tarCell->x,tarCell->y)) { PlaySound__("data/sound/event_equip.wav"); } else { PlaySound__("data/sound/ui_click.wav"); } } else { PlaySound__("data/sound/poker/cannot.wav"); } } bool MiniGameSlidingBlock::IsEnd() { //if (m_gameState==MS_End) //{ // return true; //} int lastState = m_gameState; if (m_cells[m_cellNumXY-1].texID!=-1) { return false; } for(int i = 0;im_cellNum.x-1 ||y<0||y>m_cellNum.y-1) { return false; } int index = y*m_cellNum.x+x; if(m_cells[index].texID != index) return false; return true; } bool MiniGameSlidingBlock::IsCellEmpty(int x,int y) { int index = y*m_cellNum.x+x; if(m_cells[index].texID != -1) return false; return true; } MiniGameSlidingBlock::Cell* MiniGameSlidingBlock::GetCell(int texID) { //找到色块位置 for(int i = 0;i

附送一份3D模型切割算法,方便制作3D版拼图游戏:

//========================================================
//  @Date:     2016.05
//  @File:     Include/Render/ReproductMesh.h
//  @Brief:     ReproductMesh
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================

#pragma once

#ifndef  __ReproductMesh__H__
#define  __ReproductMesh__H__

//#include "Math/Mathlib.h"
#include "Render/RendDriver.h"
#include 

class TopoSegment;
class TopoVertex;
class TopoFace;
class TopoVertexSet;
class TopoVertexPtrSet;
class TopoFaceSet;
class Sloid;
class TVertex;

class Box;

//typedef unsigned int IndexInt;
static const float   _ModellerEpsilon    = 0.001f;//1e-6f;

class TVertex
{
public:
	float u;
	float v;
	float w;
	float r;
	float g;
	float b;
};

class Line3D
{
public:
	Line3D();
	Line3D(TopoFace * face1, TopoFace * face2);
	Line3D(const vec3 & direction, const vec3 & point);

	//!到参考点的有向距离
	float getPointToPointDistance(const vec3 & otherPoint);
	//!线段交点
	vec3  getLineIntersection(Line3D * otherLine);
	//!线面相交
	vec3  getPlaneIntersection(const vec3 & normal, const vec3 & planePoint, bool & bResult);

	void  perturbDirection();

	vec3 m_pos;
	vec3 m_dir;
};

class TopoSegment
{
public:
	TopoSegment();
	TopoSegment(Line3D & line, TopoFace & face, int sign1, int sign2, int sign3);

	enum Status
	{
		VERTEX = 1,
		FACE = 2,
		EDGE = 3,
	};
	//!起点状态:在面的端点上还是边上或面上
	int startType;
	//!中段状态:在面的边上或面上
	int middleType;
	//!结束点状态
	int endType;

	/** nearest vertex from the starting point */
	TopoVertex * startVertex;
	TopoVertex * endVertex; 

	//!两个面的交线
	vec3 startPos;
	vec3 endPos;
	//!两个面的交线
	Line3D line;
	//
	int endsNum;

	/** distance from the segment starting point to the point defining the plane */
	float startDist;
	float endDist;

	bool intersect(const TopoSegment & segment);

private:
	bool setVertex(TopoVertex * vertex);
	bool setEdge(TopoVertex * vertex1, TopoVertex * vertex2);
	void swapEnds();
};


class TopoVertex
{
public:
	enum Status
	{
		UNKNOWN = 1,
		INSIDE = 2,
		OUTSIDE = 3,
		BOUNDARY = 4,
	};

	TopoVertex();
	TopoVertex(const TopoVertex & v);
	TopoVertex(const vec3 & position, const TVertex & tVertex, Status eStatus);
	virtual ~TopoVertex();
	TopoVertex & operator=(const TopoVertex & v);

	bool equals(TopoVertex * vertex);
	void addAdjacentVertex(TopoVertex * adjacentVertex);

	void mark(Status eStatus);
	TopoVertexPtrSet * m_adjacentVertices;	

	vec3     pos;
	TVertex  tVertex;
	Status   status;
	
};

class TopoFace
{
public:
	enum Status
	{
		UNKNOWN     = 1,
		INSIDE      = 2,//被切割sloid的面 包含于 切割sloid的内部
		OUTSIDE     = 3,//外部
		SAME        = 4,//被切割sloid的面 共面于 切割sloid的某个面
		OPPOSITE    = 5,//被切割sloid的面 反共面于 切割sloid的某个面
	};
	TopoFace();
	TopoFace(const TopoFace & v);
	TopoFace(TopoVertex * v1, TopoVertex * v2, TopoVertex * v3);
	~TopoFace();
	TopoFace& operator=(const TopoFace & face);
	bool  equals_pointersmatch(TopoFace * pFace);
	bool  equals(TopoFace * pOtherObject);
	//!预计算提高速度,不会失效
	Box*  getBound();
	vec3& getNormal();
	float getArea();

	void invert();

	bool simpleClassify();
	void rayTraceClassify(Sloid & object);

	//!判断点在面内
	bool hasPoint(const vec3 & point);

	Status status;
	Box*   bound;
	vec3   normal;
	TopoVertex * v1;
	TopoVertex * v2;
	TopoVertex * v3;
};


class TopoVertexPtrSet
{
public:
	TopoVertexPtrSet();
	virtual ~TopoVertexPtrSet();

	TopoVertex * GetTopoVertexPtr(int nIndex);
	void AddTopoVertexPtr(TopoVertex * pPointer);
	int  GetTopoVertexPtrNum();
	void ClearTopoVertexPtr();
	TopoVertex* operator[](int index);

private:
	typedef std::vector Vertices;
	Vertices m_pPointers;
};

class TopoVertexSet
{
public:
	TopoVertexSet();
	virtual ~TopoVertexSet();

	TopoVertex * GetTopoVertex(int nIndex);
	TopoVertex * AddTopoVertex(const TopoVertex & vertex);
	int GetTopoVertexNum();

	TopoVertex& operator[](int index);

	bool HasTopoVertex(TopoVertex * pVertex);
	int  IndexOfTopoVertex(TopoVertex * pVertex);
	void ClearTopoVertex();

private:
	typedef std::vector Vertices;
	Vertices m_pVertices;
};

class TopoFaceSet
{
public:
	TopoFaceSet();
	virtual ~TopoFaceSet();

	TopoFace * GetTopoFace(int i);
	void       SetTopoFace(int i, TopoFace & vFace);
	TopoFace * AddTopoFace(TopoFace & vFace);
	TopoFace * InsertTopoFace(int i, TopoFace & vFace);
	void       RemoveTopoFace(int i);

	int  GetTopoFaceNum();
	void ClearTopoFace();

private:

	TopoFace * m_pFaces;
	int m_nMaxSize;
	int m_nSize;
};


//==================^_^==================^_^==================^_^==================^_^

class Sloid
{
public:
	Sloid();
	virtual ~Sloid();

	//!使用object来切分自身
	void SplitFaces(Sloid * pObject);
	void Translate(const vec3 & t);
	void Render();
	void RefMesh(RendSys::Mesh* mesh);

//private:

	TopoFace*   AddTopoFace(TopoVertex * v1, TopoVertex * v2, TopoVertex * v3);
	TopoVertex* AddTopoVertex(const vec3 & pos, const TVertex & tVertex, int status);

	float ComputeDistance(TopoVertex & vertex, TopoFace & face);

	void SplitFace(int faceIndex, TopoSegment & segment1, TopoSegment & segment2);
	  
	//插值纹理坐标
	void CalTopoVertexTex(TopoVertex * v1, TopoVertex * v2,const vec3 & pos, TopoVertex * result);
	void CalTopoVertexTex(TopoVertex * v1, TopoVertex * v2,TopoVertex * v3,const vec3 & pos, TopoVertex * result);

	//一个三角形切割为2、3、4、5个
	void BreakFaceInTwo(int faceIndex, const vec3 & newPos, int splitEdge);
	void BreakFaceInTwo(int faceIndex, const vec3 & newPos, TopoVertex & endVertex);
	void BreakFaceInThree(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, TopoVertex & startVertex, TopoVertex & endVertex);
	void BreakFaceInThree(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, int splitEdge);
	void BreakFaceInThree(int faceIndex, const vec3 & newPos, TopoVertex & endVertex);
	void BreakFaceInThree(int faceIndex, const vec3 & newPos);
	void BreakFaceInFour (int faceIndex, const vec3 & newPos1, const vec3 & newPos2, TopoVertex & endVertex);
	void BreakFaceInFive (int faceIndex, const vec3 & newPos1, const vec3 & newPos2, int linedVertex);
	
	//!标记面在切割sloid的内部还是外部..
	void ClassifyFaces(Sloid & pObject);
	//!反转内部面,减法使用
	void InvertInsideFaces();

	void GenTopologyFromRend();
	void GenRendFromTopology();
	void Free();
	TopoVertexSet * m_topoVertexs;
	TopoFaceSet *   m_topoFaces;
	Box *           m_bound;


	int m_indexNum;
	int m_vVertexNum;
	int m_tVertexNum;

	//Vertex*  m_vVertexs;
	//TVertex* m_tVertexs;
	//Trigon*  m_trigons;

	IndexInt* m_indexs;
	vec3*     m_vertexs;
	TVertex*  m_tVertexs;

};

//==================^_^==================^_^==================^_^==================^_^
//!注意所有面逆时针顺序要统一
class BooleanModeller
{
public:
	Sloid * m_pSloid1;
	Sloid * m_pSloid2;
	//!注意初始化后原来的solid topology已经被分割了,可能需要重新GenTopologyData
	BooleanModeller(Sloid * solid1, Sloid * solid2);

	Sloid * GetUnion();
	Sloid * GetIntersection();
	Sloid * GetDifference();

private:
	void    MergeSloid(Sloid* pSrcSloid, Sloid* pDstSloid, int faceStatus1, int faceStatus2);
	void    PreMergeSloid(Sloid* pSrcSloid, Sloid* pDstSloid, int faceStatus1, int faceStatus2);
};

#endif

//========================================================
//  @Date:     2016.05
//  @File:     SourceLib/Render/ReproductMesh.cpp
//  @Brief:     ReproductMesh
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#include "General/Pch.h"
#include "General/General.h"
#include "Render/MC_Misc.h"
#include "Render/MC_MovieClip.h"
#include "Render/MC_Boolean.h"
#include "Math/MathLibAdvance.h"
#include "Ozcollide/box.h"
#include "General/Pce.h"

//constructive solid geometry modeller

#pragma warning(disable : 4244)
#pragma warning(disable: 4305)

Line3D::Line3D()
{
	m_pos = vec3(0,0,0);
	m_dir = vec3(1,0,0);
}

Line3D::Line3D(const vec3 & directioni, const vec3 & pointi)
{
	m_dir = directioni;
	m_dir.Normalize();
	m_pos = pointi;
}

Line3D::Line3D(TopoFace * face1, TopoFace * face2)
{
	vec3 normalFace1 = face1->getNormal();
	vec3 normalFace2 = face2->getNormal();

	m_dir = Cross(normalFace1, normalFace2);

	//m_direction长度为0,则两个面平行
	if (!(m_dir.Length()<_ModellerEpsilon))
	{
		//getting a line point, zero is set to a coordinate whose direction 
		//component isn't zero (line intersecting its origin plan)
		float d1 = -normalFace1.Dot(face1->v1->pos);
		float d2 = -normalFace2.Dot(face2->v1->pos);
		if(fabs(m_dir.x)>_ModellerEpsilon)
		{
			m_pos.x = 0;
			m_pos.y = (d2*normalFace1.z - d1*normalFace2.z)/m_dir.x;
			m_pos.z = (d1*normalFace2.y - d2*normalFace1.y)/m_dir.x;
		}
		else if(fabs(m_dir.y)>_ModellerEpsilon)
		{
			m_pos.x = (d1*normalFace2.z - d2*normalFace1.z)/m_dir.y;
			m_pos.y = 0;
			m_pos.z = (d2*normalFace1.x - d1*normalFace2.x)/m_dir.y;
		}
		else
		{
			m_pos.x = (d2*normalFace1.y - d1*normalFace2.y)/m_dir.z;
			m_pos.y = (d1*normalFace2.x - d2*normalFace1.x)/m_dir.z;
			m_pos.z = 0;
		}
	}
	m_dir.Normalize();
}

//到参考点的有向距离
float Line3D::getPointToPointDistance(const vec3 & otherPoint)
{
	vec3 dif = otherPoint - m_pos;
	float distance = dif.Length();
	if ((dif.Dot(m_dir))<0)
	{
		return -distance;			
	}
	else
	{
		return distance;
	}
}

//线段交点
vec3 Line3D::getLineIntersection(Line3D * otherLine)
{
	//x = x1 + a1*t = x2 + b1*s
	//y = y1 + a2*t = y2 + b2*s
	//z = z1 + a3*t = z2 + b3*s
	vec3 linePos = otherLine->m_pos; 
	vec3 lineDir = otherLine->m_dir;
	float t;
	if(fabs(m_dir.y*lineDir.x-m_dir.x*lineDir.y)>_ModellerEpsilon)
	{
		t = (-m_pos.y*lineDir.x+linePos.y*lineDir.x+lineDir.y*m_pos.x-lineDir.y*linePos.x)/(m_dir.y*lineDir.x-m_dir.x*lineDir.y);
	}
	else if (fabs(-m_dir.x*lineDir.z+m_dir.z*lineDir.x)>_ModellerEpsilon)
	{
		t=-(-lineDir.z*m_pos.x+lineDir.z*linePos.x+lineDir.x*m_pos.z-lineDir.x*linePos.z)/(-m_dir.x*lineDir.z+m_dir.z*lineDir.x);
	}
	else if (fabs(-m_dir.z*lineDir.y+m_dir.y*lineDir.z)>_ModellerEpsilon)
	{
		t = (m_pos.z*lineDir.y-linePos.z*lineDir.y-lineDir.z*m_pos.y+lineDir.z*linePos.y)/(-m_dir.z*lineDir.y+m_dir.y*lineDir.z);
	}
	else
	{
		return vec3(0,0,0);
	}

	vec3 vResult = m_pos + m_dir * t;
	return vResult;
}
//线面相交
vec3 Line3D::getPlaneIntersection(const vec3 & normal, const vec3 & planePoint, bool & bResult)
{
	bResult = true;
	//Ax + By + Cz + D = 0
	//x = x0 + t(x1 ?x0)
	//y = y0 + t(y1 ?y0)
	//z = z0 + t(z1 ?z0)
	//(x1 - x0) = dx, (y1 - y0) = dy, (z1 - z0) = dz
	//t = -(A*x0 + B*y0 + C*z0 )/(A*dx + B*dy + C*dz)
	float A = normal.x;
	float B = normal.y;
	float C = normal.z;
	float D = (normal.Dot(planePoint)) * -1.0f;

	float numerator = (normal.Dot(m_pos)) + D;
	float denominator = (normal.Dot(m_dir));

	//线面平行
	if(fabs(denominator)<_ModellerEpsilon)
	{
		//线在面上
		if(fabs(numerator)<_ModellerEpsilon)
		{
			return m_pos;
		}
		else
		{
			//平行 分离
			bResult = false;
			return vec3(0,0,0);
		}
	}
	//线面相交
	else
	{
		float t = -numerator/denominator;
		vec3 resultPoint = m_pos + m_dir * t;
		return resultPoint;
	}
}

float LineRandomNum()
{
	int nRand = Rand() % 10000;
	float fRand = (float)nRand;
	fRand *= 0.0001f;
	fRand *= 2.0f;
	fRand -= 1.0f;
	return fRand;
}

void Line3D::perturbDirection()
{
	//direction.x += LineRandomNum();			
	//direction.y += LineRandomNum();			
	//direction.z += LineRandomNum();
	m_dir.x += LineRandomNum() * 0.001f;			
	m_dir.y += LineRandomNum() * 0.001f;			
	m_dir.z += LineRandomNum() * 0.001f;
	//direction.Normalise();
}



TopoSegment::TopoSegment()
{
}

TopoSegment::TopoSegment(Line3D & line, TopoFace & face, int sign1, int sign2, int sign3)
{
	(*this).line = line;
	endsNum = 0;
	
	if(sign1 == 0)
	{
		//点1在面上(距离为0)
		setVertex(face.v1);
		//点2 3同侧 - 只有一个点相交 VERTEX-VERTEX VERTEX
		if(sign2 == sign3)
		{
			setVertex(face.v1);
		}
	}

	if(sign2 == 0)
	{
		setVertex(face.v2);
		if(sign1 == sign3)
		{
			setVertex(face.v2);
		}
	}
	
	if(sign3 == 0)
	{
		setVertex(face.v3);
		if(sign1 == sign2)
		{
			setVertex(face.v3);
		}
	}
	
	//切割边
	if(endsNum != 2)
	{
		//点1 2异侧
		if((sign1==1 && sign2==-1)||(sign1==-1 && sign2==1))
		{
			setEdge(face.v1, face.v2);
		}
		if((sign2==1 && sign3==-1)||(sign2==-1 && sign3==1))
		{
			setEdge(face.v2, face.v3);
		}
		if((sign3==1 && sign1==-1)||(sign3==-1 && sign1==1))
		{
			setEdge(face.v3, face.v1);
		}
	}
}


bool TopoSegment::intersect(const TopoSegment & segment)
{
	if(endDistpos);
	 	startPos = startVertex->pos;
	 	endsNum++;
	 	return true;
	}

	if(endsNum == 1)
	{
		//终点
		endVertex = vertex;
		endType = VERTEX;
		endDist = line.getPointToPointDistance(vertex->pos);
		endPos = endVertex->pos;
		endsNum++;
		
		//defining middle based on the starting point
		//VERTEX-VERTEX-VERTEX
		//if(startVertex.equals(endVertex)) // Need close-enough-to...
		if(true)
		{
			middleType = VERTEX;
		}
		//VERTEX-EDGE-VERTEX
		else if(startType==VERTEX)
		{
			middleType = EDGE;
		}
		
		//the ending point distance should be smaller than  starting point distance 
		if(startDist>endDist)
		{
			swapEnds();
		}
		
		return true;
	}
	else
	{
		return false;
	}
}

/**
 * @param vertex1 one of the vertices of the intercepted edge 
 * @param vertex2 one of the vertices of the intercepted edge
 * @return false if all ends were already defined, true otherwise
 */
bool TopoSegment::setEdge(TopoVertex * vertex1, TopoVertex * vertex2)
{
	vec3 point1 = vertex1->pos;
	vec3 point2 = vertex2->pos;

	vec3 edgeDirection(point2.x - point1.x, point2.y - point1.y, point2.z - point1.z);
	Line3D edgeLine(edgeDirection, point1);
	
	if(endsNum==0)
	{
		startVertex = vertex1;
		startType = EDGE;
		startPos = line.getLineIntersection(&edgeLine);
		startDist = line.getPointToPointDistance(startPos);
		middleType = FACE;
		endsNum++;
		return true;		
	}
	else if(endsNum==1)
	{
		endVertex = vertex1;
		endType = EDGE;
		endPos = line.getLineIntersection(&edgeLine);
		endDist = line.getPointToPointDistance(endPos);
		middleType = FACE;
		endsNum++;
		
		//the ending point distance should be smaller than  starting point distance 
		if(startDist>endDist)
		{
		  	swapEnds();
		}
		
		return true;
	}
	else
	{
		return false;
	}
}

/** Swaps the starting point and the ending point */	
void TopoSegment::swapEnds()
{
	float distTemp = startDist;
	startDist = endDist;
	endDist = distTemp;
	
	int typeTemp = startType;
	startType = endType;
	endType = typeTemp;
	
	TopoVertex * vertexTemp = startVertex;
	startVertex = endVertex;
	endVertex = vertexTemp;
	
	vec3 posTemp = startPos;
	startPos = endPos;
	endPos = posTemp;		
}


//==================^_^==================^_^==================^_^==================^_^
TopoVertex::TopoVertex()
{
	m_adjacentVertices = new TopoVertexPtrSet();
	status = UNKNOWN;
}

TopoVertex::TopoVertex(const vec3 & position, const TVertex & tVertex_, Status status)
{
	tVertex = tVertex_;
	pos = position;
	m_adjacentVertices = new TopoVertexPtrSet();
	status = status;
}

TopoVertex::TopoVertex(const TopoVertex & v)
{
	tVertex = v.tVertex;
	pos = v.pos;
	m_adjacentVertices = new TopoVertexPtrSet();
	status = v.status;
}
TopoVertex & TopoVertex::operator=(const TopoVertex & v)
{
	tVertex = v.tVertex;
	pos = v.pos;
	m_adjacentVertices = new TopoVertexPtrSet();
	status = v.status;
	return *this;
}
TopoVertex::~TopoVertex()
{
	SafeDelete(m_adjacentVertices);
}

//TopologyVertex & TopologyVertex::operator=(const TopologyVertex & v)
//{
//	for(int i = 0; i < v.m_adjacentVertices->length(); i++)
//	{
//		m_adjacentVertices->add(v.m_adjacentVertices->GetVertexPtr(i));
//	}
//
//	status = v.status;
//	color = v.color;
//	x = v.x;
//	y = v.y;
//	z = v.z;
//	return *this;
//}

//判断是否同一个点
bool TopoVertex::equals(TopoVertex * vertex)
{
	//float _ModellerEpsilon = 1.0f;
	float _ModellerEpsilon = 0.01f;
	bool bPositionMatch =
		(fabs(pos.x-vertex->pos.x)<_ModellerEpsilon &&
		fabs(pos.y-vertex->pos.y)<_ModellerEpsilon &&
		fabs(pos.z-vertex->pos.z)<_ModellerEpsilon);

	bool bColorMatch =
		(tVertex.r == vertex->tVertex.r) &&
		(tVertex.g == vertex->tVertex.g) &&
		(tVertex.b == vertex->tVertex.b);

	return bPositionMatch && bColorMatch;
}

void TopoVertex::addAdjacentVertex(TopoVertex * adjacentVertex)
{
	bool bAlready = false;
	for(int i = 0; i < m_adjacentVertices->GetTopoVertexPtrNum(); i++)
	{
		TopoVertex * pVertexI = m_adjacentVertices->GetTopoVertexPtr(i);
		//已经存在该指针
		if(pVertexI == adjacentVertex)
		{
			bAlready = true;
		}
	}
	if(!bAlready)
	{
		m_adjacentVertices->AddTopoVertexPtr(adjacentVertex);
	}
}

void TopoVertex::mark(Status status)
{
	status = status;
	//return;
	for(int i = 0; i < m_adjacentVertices->GetTopoVertexPtrNum(); i++)
	{
		TopoVertex * pVertexI = m_adjacentVertices->GetTopoVertexPtr(i);

		if(pVertexI->status==TopoVertex::UNKNOWN)
		{
			pVertexI->mark(status);
		}
	}
}

//==================^_^==================^_^==================^_^==================^_^

TopoVertexPtrSet::TopoVertexPtrSet()
{
}

TopoVertexPtrSet::~TopoVertexPtrSet()
{
	m_pPointers.clear();
}

TopoVertex * TopoVertexPtrSet::GetTopoVertexPtr(int nIndex)
{
	if(nIndex < 0) return 0;
	if(nIndex >= m_pPointers.size()) return 0;
	TopoVertex * pVertex = m_pPointers[nIndex];
	return pVertex;
}

int TopoVertexPtrSet::GetTopoVertexPtrNum()
{
	return m_pPointers.size();
}

void TopoVertexPtrSet::AddTopoVertexPtr(TopoVertex * pPointer)
{
	m_pPointers.push_back(pPointer);
}

TopoVertex* TopoVertexPtrSet::operator[](int index)
{
	if(index < 0) return 0;
	if(index >= m_pPointers.size()) return 0;
	TopoVertex * pVertex = m_pPointers[index];
	return pVertex;
}

void TopoVertexPtrSet::ClearTopoVertexPtr()
{
	m_pPointers.clear();
}

//==================^_^==================^_^==================^_^==================^_^

TopoVertexSet::TopoVertexSet()
{
}

TopoVertexSet::~TopoVertexSet()
{
	for(int i = 0; i < m_pVertices.size(); i++)
	{
		delete m_pVertices[i];
	}
	m_pVertices.clear();
}

TopoVertex * TopoVertexSet::GetTopoVertex(int nIndex)
{
	if(nIndex < 0) return 0;
	if(nIndex >= m_pVertices.size()) return 0;
	TopoVertex * pVertex = m_pVertices[nIndex];
	return pVertex;
}

int TopoVertexSet::GetTopoVertexNum()
{
	return m_pVertices.size();
}

TopoVertex * TopoVertexSet::AddTopoVertex(const TopoVertex & vertex)
{
	//if(m_nNumVertices >= m_nMaxVertices) return 0;
	m_pVertices.push_back(new TopoVertex(vertex));
	return m_pVertices[m_pVertices.size() - 1];
	//return &m_pVertices[m_nNumVertices - 1];
}

TopoVertex& TopoVertexSet::operator[](int index)
{
	TopoVertex * pVertex = GetTopoVertex(index);
	return *pVertex;
}

bool TopoVertexSet::HasTopoVertex(TopoVertex * pVertex)
{
	// Match pointers or content??
	for(int i = 0; i < GetTopoVertexNum(); i++)
	{
		TopoVertex * pOurVertex = GetTopoVertex(i);
		if(pOurVertex == pVertex)
		{
			return true;
		}
	}
	return false;
}

int TopoVertexSet::IndexOfTopoVertex(TopoVertex * pVertex)
{
	for(int i = 0; i < GetTopoVertexNum(); i++)
	{
		TopoVertex * pOurVertex = GetTopoVertex(i);

		if(pOurVertex == pVertex)
		{
			return i;
		}
	}
	return -1;
}

void TopoVertexSet::ClearTopoVertex()
{
	for(int i = 0; i < m_pVertices.size(); i++)
	{
		delete m_pVertices[i];
	}
	m_pVertices.clear();
}

//==================^_^==================^_^==================^_^==================^_^
TopoFace::TopoFace()
{
	v1 = 0;
	v2 = 0;
	v3 = 0;
	status = UNKNOWN;
	bound = new Box();


}
TopoFace::TopoFace(const TopoFace & face)
{
	status = face.status;
	v1 = face.v1;
	v2 = face.v2;
	v3 = face.v3;

	bound = new Box();
	bound->setFromPoints(v1->pos,v2->pos);
	bound->mergePoint(v3->pos);
	vec3 xy = v2->pos - v1->pos;
	vec3 xz = v3->pos - v1->pos;
	normal = Cross(xy, xz);
	normal.Normalize();
}
TopoFace::TopoFace(TopoVertex * v1i, TopoVertex * v2i, TopoVertex * v3i)
{
	v1 = v1i;
	v2 = v2i;
	v3 = v3i;
	status = UNKNOWN;

	bound = new Box();
	bound->setFromPoints(v1->pos,v2->pos);
	bound->mergePoint(v3->pos);
	vec3 xy = v2->pos - v1->pos;
	vec3 xz = v3->pos - v1->pos;
	normal = Cross(xy, xz);
	normal.Normalize();
}

TopoFace::~TopoFace()
{
	SafeDelete(bound);
}
TopoFace& TopoFace::operator=(const TopoFace & face)
{
	status = face.status;
	v1 = face.v1;
	v2 = face.v2;
	v3 = face.v3;

	if(bound==NULL)
	    bound = new Box();
	bound->setFromPoints(v1->pos,v2->pos);
	bound->mergePoint(v3->pos);
	vec3 xy = v2->pos - v1->pos;
	vec3 xz = v3->pos - v1->pos;
	normal = Cross(xy, xz);
	normal.Normalize();
	return *this;
}
bool TopoFace::equals_pointersmatch(TopoFace * pFace)
{
	TopoFace & face = *pFace;
	bool cond = v1 == face.v1 && v2 == face.v2 && v3 == face.v3;
	return cond;
}

bool TopoFace::equals(TopoFace * pFace)
{
	TopoFace & face = *pFace;
	bool cond1 = v1->equals(face.v1) && v2->equals(face.v2) && v3->equals(face.v3);
	bool cond2 = v1->equals(face.v2) && v2->equals(face.v3) && v3->equals(face.v1);
	bool cond3 = v1->equals(face.v3) && v2->equals(face.v1) && v3->equals(face.v2);
	return cond1 || cond2 || cond3;  	 			
}

Box* TopoFace::getBound()
{
	//只是加点而不减少点 也不改变点所以无需重新计算
#ifdef _DEBUG
	//Box old = *bound;
	//bound->setFromPoints(v1->pos,v2->pos);
	//bound->mergePoint(v3->pos);

	//if (old.min!=bound->min)
	//{
	//	MsgBox(0,"TopoFace::getBound","error",MB_OK);
	//}
	//if (old.max!=bound->max)
	//{
	//	MsgBox(0,"TopoFace::getBound","error",MB_OK);
	//}
#endif
	return bound;
}

vec3& TopoFace::getNormal()
{
#ifdef _DEBUG
	//vec3 xy = v2->pos - v1->pos;
	//vec3 xz = v3->pos - v1->pos;
	//vec3 newnormal = Cross(xy, xz);
	//newnormal.Normalize();
	//if (normal!=newnormal)
	//{
	//	MsgBox(0,"TopoFace::getBound","error",MB_OK);
	//}
#endif
	return normal;
}

float TopoFace::getArea()
{
	//area = (a * c * sen(B))/2
	vec3 xy = v2->pos - v1->pos;
	vec3 xz = v3->pos - v1->pos;
	vec3 yz = v3->pos - v2->pos;
	
	float a = xy.Length();
	float c = xz.Length();
	float b = yz.Length();
	float _ModellerEpsilon = 0.001f;
	if (a<_ModellerEpsilon||c<_ModellerEpsilon||b<_ModellerEpsilon)
	{
		//继续计算出来有误差
		return 0;
	}

	xy.Normalize();
	xz.Normalize();
	float fDot = xy.Dot(xz);
	float fAngle = SafeAcos(fDot);
	return (a * c * sin(fAngle))/2.0f;

	//float a = xy.LengthSq();
	//float c = xz.LengthSq();
	//xy.Normalize();
	//xz.Normalize();
	//float fDot = xy.Dot(xz);
	//return sqrt(a*c*(1-fDot*fDot))/2.0f;
}

void TopoFace::invert()
{
	TopoVertex * vertexTemp = v2;
	v2 = v1;
	v1 = vertexTemp;
}

bool TopoFace::simpleClassify()
{
	int status1 = v1->status;
	int status2 = v2->status;
	int status3 = v3->status;
		
	if(status1==TopoVertex::INSIDE)
	{
		status = INSIDE;
		return true; 
	}

	if(status1==TopoVertex::OUTSIDE)
	{
		status = OUTSIDE;
		return true; 
	}

	if(status2==TopoVertex::INSIDE)
	{
		status = INSIDE;
		return true;
	}

	if(status2==TopoVertex::OUTSIDE)
	{
		status = OUTSIDE;
		return true;
	}

	if(status3==TopoVertex::INSIDE)
	{
		status = INSIDE;
		return true;
	}

	if(status3==TopoVertex::OUTSIDE)
	{
		status = OUTSIDE;
		return true;
	}

	return false;
}

void TopoFace::rayTraceClassify(Sloid & sloid)
{
	//从面的重心沿法线发射线
	vec3 p0 = (v1->pos + v2->pos + v3->pos)/3.0f;

	Line3D ray(getNormal(),p0);
	
	bool success;
	float dotProduct, distance; 
	vec3 intersectPos;
	TopoFace * closestFace = 0;
	float closestDistance;
	//float TOL = 0.0001f;		
	do
	{
		success = true;
		closestDistance = 99999999.9f;
		//other solid...
		for(int i=0;iGetTopoFaceNum();i++)
		{
			TopoFace & otherFace = *(sloid.m_topoFaces->GetTopoFace(i));
			dotProduct = otherFace.getNormal().Dot(ray.m_dir); 
			bool bIntersect = false;
			intersectPos = ray.getPlaneIntersection(otherFace.getNormal(), otherFace.v1->pos, bIntersect);
			//相交
			if(bIntersect)
			{
				distance = ray.getPointToPointDistance(intersectPos);
				//整条线在面上..
				if(fabs(distance)<_ModellerEpsilon && fabs(dotProduct)<_ModellerEpsilon)
				{
					//disturb the ray in order to not lie into another plane ?
					ray.perturbDirection();
					success = false;
					break;
				}
				//只有起点在面上 
				else if(fabs(distance)<_ModellerEpsilon && fabs(dotProduct)>_ModellerEpsilon)
				{
					//如果射线和面相交,即交点在面上
					if(otherFace.hasPoint(intersectPos))
					{
						//此时起点距离最近为0
						closestFace = &otherFace;
						closestDistance = 0;
						break;
					}
				}
				//起点也不在面上 且正向相交distance>0
				else if(fabs(dotProduct)>_ModellerEpsilon && distance>_ModellerEpsilon)
				{
					//记录最近距离的分割面
					if(distancegetNormal().Dot(ray.m_dir);
		
		//distance = 0: 
		if(fabs(closestDistance)<_ModellerEpsilon)
		{
			if(dotProduct>_ModellerEpsilon)
			{
				//共面
				status = SAME;
			}
			else if(dotProduct<-_ModellerEpsilon)
			{
				//反共面
				status = OPPOSITE;
			}
		}
		else if(dotProduct>_ModellerEpsilon)
		{
			//正向相交,内部dot>0
			status = INSIDE;
		}
		else if(dotProduct<-_ModellerEpsilon)
		{
			status = OUTSIDE;
		}
	}
}

//判断点在面内
bool TopoFace::hasPoint(const vec3 &  point)
{
	vec3 u = v2->pos - v1->pos;
	vec3 v = v3->pos - v1->pos;
	vec3 w = point - v1->pos;

	float uu = u.Dot(u);
	float uv = u.Dot(v);
	float vv = v.Dot(v);
	float wu = w.Dot(u);
	float wv = w.Dot(v);
	float d = uv * uv - uu * vv;

	float invD = 1 / d;
	float s = (uv * wv - vv * wu) * invD;
	if (s < 0 || s > 1)
		return false;
	float t = (uv * wu - uu * wv) * invD;
	if (t < 0 || (s + t) > 1)
		return false;

	return true;
}


TopoFaceSet::TopoFaceSet()
{
	m_nMaxSize = 20000;
	m_nSize = 0;
	m_pFaces = new TopoFace[m_nMaxSize];
}

TopoFaceSet::~TopoFaceSet()
{
	delete [] m_pFaces;
}

int TopoFaceSet::GetTopoFaceNum()
{
	return m_nSize;
}

TopoFace * TopoFaceSet::GetTopoFace(int i)
{
	if(i < 0) return 0;
	if(i >= m_nSize) return 0;

	return &m_pFaces[i];
}

void TopoFaceSet::SetTopoFace(int i, TopoFace & vFace)
{
	if(i < 0) return;
	if(i >= m_nSize) return;
	m_pFaces[i] = vFace;
}

TopoFace * TopoFaceSet::AddTopoFace(TopoFace & vFace)
{
	if(m_nSize >= m_nMaxSize)
	{
		return 0;
	}
	m_pFaces[m_nSize] = vFace;
	m_nSize++;

	return &m_pFaces[m_nSize - 1];
}

TopoFace * TopoFaceSet::InsertTopoFace(int i, TopoFace & vFace)
{
	if(m_nSize >= m_nMaxSize)
	{
		return 0;
	}
	// Shift everything along
	for(int j = m_nSize; j >= i+1; j--)
	{
		m_pFaces[j] = m_pFaces[j-1];
	}

	m_pFaces[i] = vFace;
	m_nSize++;

	return &m_pFaces[i];
}

void TopoFaceSet::RemoveTopoFace(int i)
{
	if(m_nSize <= 0)
	{
		return;
	}
	for(int j = i; j < m_nSize-1; j++)
	{
		m_pFaces[j] = m_pFaces[j+1];
	}
	m_nSize--;
}

void TopoFaceSet::ClearTopoFace()
{
	m_nSize = 0;
}




//==================^_^==================^_^==================^_^==================^_^


Sloid::Sloid()
:m_vertexs(NULL)
,m_tVertexs(NULL)
,m_indexs(NULL)
{
	m_topoVertexs = new TopoVertexSet();
	m_topoFaces = new TopoFaceSet();
	m_bound = 0;
	m_indexNum = 0;
	m_vVertexNum = 0;
	m_tVertexNum = 0;
}

Sloid::~Sloid()
{
	Free();
	SafeDelete(m_topoVertexs) ;
	SafeDelete(m_topoFaces);
	SafeDelete(m_bound);
}
void Sloid::Free()
{
	SafeDeleteArray (m_vertexs);
	SafeDeleteArray (m_tVertexs);
	SafeDeleteArray (m_indexs);
}

TopoFace * Sloid::AddTopoFace(TopoVertex * v1, TopoVertex * v2, TopoVertex * v3)
{
	float _ModellerEpsilon = 0.1;
	if(!(v1->equals(v2)||v1->equals(v3)||v2->equals(v3)))
	{
		TopoFace face(v1, v2, v3);
		//不加面积很小的面
		if(face.getArea()<_ModellerEpsilon)
			return 0;
		TopoFace * pAddedFace = (*m_topoFaces).AddTopoFace(face);
		return pAddedFace;
	}
	else
	{
		return 0;
	}
}

TopoVertex * Sloid::AddTopoVertex(const vec3 & pos, const TVertex & tVertex, int status)
{
	int i;
	TopoVertex * pVertex;
	TopoVertex vertex(pos, tVertex, (TopoVertex::Status)status);
	for(i=0;iGetTopoVertexNum();i++)
	{
		//已经存在点
		pVertex = m_topoVertexs->GetTopoVertex(i);
		if(vertex.equals(pVertex)) 
		{
			pVertex->status = ((TopoVertex::Status)status);
			return pVertex;			
		}
	}

	pVertex = m_topoVertexs->AddTopoVertex(vertex);
	return pVertex;
}


//使用object来切分自身
void Sloid::SplitFaces(Sloid * sloid2)
{
	if(m_bound->isOverlap(*sloid2->m_bound)==false)
		return;

	Line3D line;
	TopoFace * face1;
	TopoFace * face2;
	TopoSegment segmentf1p2, segmentf2p1;

	float distFace1Vert1, distFace1Vert2, distFace1Vert3, distFace2Vert1, distFace2Vert2, distFace2Vert3;
	int signFace1Vert1, signFace1Vert2, signFace1Vert3, signFace2Vert1, signFace2Vert2, signFace2Vert3;
	int numFacesBefore = m_topoFaces->GetTopoFaceNum();
	int numFacesStart = m_topoFaces->GetTopoFaceNum();
	int facesIgnored = 0;
												
	//int faceNum1 = m_topologyFaces->GetSize();
	for(int i=0;iGetTopoFaceNum();i++)
	{
		face1 = m_topoFaces->GetTopoFace(i);
		TopoFace face1Orig = *face1;
		
		if(face1->getBound()->isOverlap(*sloid2->m_bound))
		{
			//遍历face2
			for(int j=0;jm_topoFaces->GetTopoFaceNum();j++)
			{
				face2 = sloid2->m_topoFaces->GetTopoFace(j);
				TopoFace face2Orig = *face2;
				if(face1->getBound()->isOverlap(*face2->getBound()))
				{
					//distance from the face1 vertices to the face2 plane
					distFace1Vert1 = ComputeDistance(*(face1->v1), *face2);
					distFace1Vert2 = ComputeDistance(*(face1->v2), *face2);
					distFace1Vert3 = ComputeDistance(*(face1->v3), *face2);
					
					//距离的正负
					signFace1Vert1 = (distFace1Vert1>_ModellerEpsilon? 1 :(distFace1Vert1<-_ModellerEpsilon? -1 : 0)); 
					signFace1Vert2 = (distFace1Vert2>_ModellerEpsilon? 1 :(distFace1Vert2<-_ModellerEpsilon? -1 : 0));
					signFace1Vert3 = (distFace1Vert3>_ModellerEpsilon? 1 :(distFace1Vert3<-_ModellerEpsilon? -1 : 0));
					
					//全0为共面coplanar
					//同号不相交,异号相交
					if (!(signFace1Vert1==signFace1Vert2 && signFace1Vert2==signFace1Vert3))
					{
						//distance from the face2 vertices to the face1 plane
						distFace2Vert1 = ComputeDistance(*(face2->v1), *face1);
						distFace2Vert2 = ComputeDistance(*(face2->v2), *face1);
						distFace2Vert3 = ComputeDistance(*(face2->v3), *face1);
						
						//距离的正负
						signFace2Vert1 = (distFace2Vert1>_ModellerEpsilon? 1 :(distFace2Vert1<-_ModellerEpsilon? -1 : 0)); 
						signFace2Vert2 = (distFace2Vert2>_ModellerEpsilon? 1 :(distFace2Vert2<-_ModellerEpsilon? -1 : 0));
						signFace2Vert3 = (distFace2Vert3>_ModellerEpsilon? 1 :(distFace2Vert3<-_ModellerEpsilon? -1 : 0));
					
						//全0为共面coplanar
						//同号不相交,异号相交
						if (!(signFace2Vert1==signFace2Vert2 && signFace2Vert2==signFace2Vert3))
						{
							line = Line3D(face1, face2);
					
							//face1、plane2 的相交线
							segmentf1p2 = TopoSegment(line, *face1, signFace1Vert1, signFace1Vert2, signFace1Vert3);
							segmentf2p1 = TopoSegment(line, *face2, signFace2Vert1, signFace2Vert2, signFace2Vert3);
														
							//线段相交时 两个面才相交
							if(segmentf1p2.intersect(segmentf2p1))
							{
								//PART II - SUBDIVIDING NON-COPLANAR POLYGONS
								int lastNumFaces = m_topoFaces->GetTopoFaceNum();
								SplitFace(i, segmentf1p2, segmentf2p1);													
								if(numFacesStart*20GetTopoFaceNum())
								{
									//可能死循环
									//return;
								}
						
								// "if the face in the position isn't the same, there was a break"

								//if(face1!=getFace(i)) 
								if(!(face1->equals_pointersmatch(&face1Orig)))
								{
									//if 拆分后没变化
									if(face1Orig.equals(m_topoFaces->GetTopoFace(m_topoFaces->GetTopoFaceNum()-1)))
									{
										//一般不会进入
										if(i!=(m_topoFaces->GetTopoFaceNum()-1))
										{
											m_topoFaces->RemoveTopoFace(m_topoFaces->GetTopoFaceNum()-1);
											m_topoFaces->InsertTopoFace(i, face1Orig);
										}
										else
										{
											continue;
										}
									}
									else
									{
										// This is because the whole face list was shunted down when the current face was removed, so
										// the next face is the face at the current position in the list.
										i--;
										break;
									}
								}
							}
						}
					}
				}
			}
		}
	}

}

/**
 * Computes closest distance from a vertex to a plane
 * 
 * @param vertex vertex used to compute the distance
 * @param face face representing the plane where it is contained
 * @return the closest distance from the vertex to the plane
 */
float Sloid::ComputeDistance(TopoVertex & vertex, TopoFace & face)
{
	vec3 normal = face.getNormal();
	return normal.Dot(vertex.pos) - normal.Dot(face.v1->pos);
}

/**
 * @param segment1 segment representing the intersection of the face with the plane
 * of another face
 * @return segment2 segment representing the intersection of other face with the
 * plane of the current face plane
 */	  
void Sloid::SplitFace(int faceIndex, TopoSegment & segment1, TopoSegment & segment2)
{
	TopoVertex startPosVertex, endPosVertex;
	vec3 startPos, endPos;
	int startType, endType, middleType;
	float startDist, endDist;
	
	TopoFace & face = *m_topoFaces->GetTopoFace(faceIndex);
	TopoVertex * startVertex = segment1.startVertex;
	TopoVertex * endVertex = segment1.endVertex;
	
	//starting point: deeper starting point 		
	if (segment2.startDist > segment1.startDist+_ModellerEpsilon)
	{
		startDist = segment2.startDist;
		startType = segment1.middleType;
		startPos = segment2.startPos;
	}
	else
	{
		startDist = segment1.startDist;
		startType = segment1.startType;
		startPos = segment1.startPos;
	}
	
	//ending point: deepest ending point
	if (segment2.endDist < segment1.endDist-_ModellerEpsilon)
	{
		endDist = segment2.endDist;
		endType = segment1.middleType;
		endPos = segment2.endPos;
	}
	else
	{
		endDist = segment1.endDist;
		endType = segment1.endType;
		endPos = segment1.endPos;
	}		
	middleType = segment1.middleType;
	
	//set vertex to BOUNDARY if it is start type		
	if (startType == TopoSegment::VERTEX)
	{
		startVertex->status=(TopoVertex::BOUNDARY);
	}
			
	//set vertex to BOUNDARY if it is end type
	if (endType == TopoSegment::VERTEX)
	{
		endVertex->status=(TopoVertex::BOUNDARY);
	}
	
	//VERTEX-_______-VERTEX 
	if (startType == TopoSegment::VERTEX && endType == TopoSegment::VERTEX)
	{
		return;
	}
	
	//______-EDGE-______
	else if (middleType == TopoSegment::EDGE)
	{
		//gets the edge 
		int splitEdge;
		if ((startVertex == face.v1 && endVertex == face.v2) || (startVertex == face.v2 && endVertex == face.v1))
		{
			splitEdge = 1;
		}
		else if ((startVertex == face.v2 && endVertex == face.v3) || (startVertex == face.v3 && endVertex == face.v2))
		{	  
			splitEdge = 2; 
		} 
		else
		{
			splitEdge = 3;
		} 
		
		//VERTEX-EDGE-EDGE
		if (startType == TopoSegment::VERTEX)
		{
			BreakFaceInTwo(faceIndex, endPos, splitEdge);
			return;
		}
		
		//EDGE-EDGE-VERTEX
		else if (endType == TopoSegment::VERTEX)
		{
			BreakFaceInTwo(faceIndex, startPos, splitEdge);
			return;
		}
    
		// EDGE-EDGE-EDGE
		else if (startDist == endDist)
		{
			BreakFaceInTwo(faceIndex, endPos, splitEdge);
		}
		else
		{
			if((startVertex == face.v1 && endVertex == face.v2) || (startVertex == face.v2 && endVertex == face.v3) || (startVertex == face.v3 && endVertex == face.v1))
			{
				BreakFaceInThree(faceIndex, startPos, endPos, splitEdge);
			}
			else
			{
				BreakFaceInThree(faceIndex, endPos, startPos, splitEdge);
			}
		}
		return;
	}
	
	//______-FACE-______
	
	//VERTEX-FACE-EDGE
	else if (startType == TopoSegment::VERTEX && endType == TopoSegment::EDGE)
	{
	    BreakFaceInTwo(faceIndex, endPos, *endVertex);//ori
		//BreakFaceInTwo(faceIndex, endPos, *startVertex);
	}
	//EDGE-FACE-VERTEX
	else if (startType == TopoSegment::EDGE && endType == TopoSegment::VERTEX)
	{
		BreakFaceInTwo(faceIndex, startPos, *startVertex);//ori
		//BreakFaceInTwo(faceIndex, startPos, *endVertex);
	}
	//VERTEX-FACE-FACE
	else if (startType == TopoSegment::VERTEX && endType == TopoSegment::FACE)
	{
		BreakFaceInThree(faceIndex, endPos, *startVertex);
	}
	//FACE-FACE-VERTEX
	else if (startType == TopoSegment::FACE && endType == TopoSegment::VERTEX)
	{
		BreakFaceInThree(faceIndex, startPos, *endVertex);
	}
	//EDGE-FACE-EDGE
	else if (startType == TopoSegment::EDGE && endType == TopoSegment::EDGE)
	{
		BreakFaceInThree(faceIndex, startPos, endPos, *startVertex, *endVertex);
	}
	//EDGE-FACE-FACE
	else if (startType == TopoSegment::EDGE && endType == TopoSegment::FACE)
	{
		BreakFaceInFour(faceIndex, startPos, endPos, *startVertex);
	}
	//FACE-FACE-EDGE
	else if (startType == TopoSegment::FACE && endType == TopoSegment::EDGE)
	{
		BreakFaceInFour(faceIndex, endPos, startPos, *endVertex);
	}
	//FACE-FACE-FACE
	else if (startType == TopoSegment::FACE && endType == TopoSegment::FACE)
	{
		vec3 segmentVector(startPos.x-endPos.x, startPos.y-endPos.y, startPos.z-endPos.z);
					
		//if the intersection segment is a point only...
		if (fabs(segmentVector.x)<_ModellerEpsilon && fabs(segmentVector.y)<_ModellerEpsilon && fabs(segmentVector.z)<_ModellerEpsilon)
		{
			BreakFaceInThree(faceIndex, startPos);
			return;
		}
		
		//gets the vertex more lined with the intersection segment
		int linedVertex;
		vec3 linedVertexPos;
		vec3 vertexVector = endPos - face.v1->pos;
		vertexVector.Normalize();
		float dot1 = fabs(segmentVector.Dot(vertexVector));
		vertexVector = endPos -face.v2->pos;

		vertexVector.Normalize();
		float dot2 = fabs(segmentVector.Dot(vertexVector));
		vertexVector =  endPos -face.v3->pos;
		vertexVector.Normalize();
		float dot3 = fabs(segmentVector.Dot(vertexVector));
		if (dot1 > dot2 && dot1 > dot3)
		{
		 	linedVertex = 1;
			linedVertexPos = face.v1->pos;
		}
		else if (dot2 > dot3 && dot2 > dot1)
		{
			linedVertex = 2;
			linedVertexPos = face.v2->pos;
		}
		else
		{
			linedVertex = 3;
			linedVertexPos = face.v3->pos;
		}
    
		// Now find which of the intersection endpoints is nearest to that vertex.
		if ((linedVertexPos - startPos).Length() > (linedVertexPos - endPos).Length())
		{
			BreakFaceInFive(faceIndex, startPos, endPos, linedVertex);
		}
		else
		{
			BreakFaceInFive(faceIndex, endPos, startPos, linedVertex);
		}
	}
}

void Sloid::CalTopoVertexTex(TopoVertex * v1, TopoVertex * v2,const vec3 & pos, TopoVertex * result)
{
	float rat = 0.5f;
	float len = (v2->pos-v1->pos).Length();
	if (len>0)
	{
		rat = (pos-v1->pos).Length()/len;
		if (rat>1)
		{
			rat=1;
		}
	}
	float invRat = 1-rat;
	result->tVertex.u = rat*v2->tVertex.u + v1->tVertex.u*invRat;
	result->tVertex.v = rat*v2->tVertex.v + v1->tVertex.v*invRat;
	result->tVertex.w = rat*v2->tVertex.w + v1->tVertex.w*invRat;
}
void Sloid::CalTopoVertexTex(TopoVertex * v1, TopoVertex * v2,TopoVertex * v3,const vec3 & pos, TopoVertex * result)
{
	vec2 res = GetUVOnTrigon(v1->pos,v2->pos,v3->pos,
		                     vec2(v1->tVertex.u,v1->tVertex.v),vec2(v2->tVertex.u,v2->tVertex.v),vec2(v3->tVertex.u,v3->tVertex.v),pos);
		
	result->tVertex.u = res.x;
	result->tVertex.v = res.y;
	result->tVertex.w = 1;
}

/**
分割线穿过一个顶点和邻边,一个三角形拆分为两个
 * Face breaker for VERTEX-EDGE-EDGE / EDGE-EDGE-VERTEX
 * @param faceIndex 待拆的面
 * @param newPos  拆边上的点
 * @param splitEdge 待拆的边
                          v1
                          /\
						 /  \
					  e1/    \e3
					   /      \
				    v2/________\v3
					      e2
 */		
void Sloid::BreakFaceInTwo(int faceIndex, const vec3 & newPos, int splitEdge)
{
	TopoFace & face = *m_topoFaces->GetTopoFace(faceIndex);
	TopoVertex * vertex = AddTopoVertex(newPos, face.v1->tVertex, TopoVertex::BOUNDARY);
					
	if (splitEdge == 1)
	{
		//分割线v1~p,p在邻边e1上
		AddTopoFace(face.v1, vertex, face.v3);
		AddTopoFace(vertex, face.v2, face.v3);
		CalTopoVertexTex(face.v1,face.v2,newPos,vertex);
	}
	else if (splitEdge == 2)
	{
		AddTopoFace(face.v2, vertex, face.v1);
		AddTopoFace(vertex, face.v3, face.v1);
		CalTopoVertexTex(face.v3,face.v2,newPos,vertex);
	}
	else
	{
		AddTopoFace(face.v3, vertex, face.v2);
		AddTopoFace(vertex, face.v1, face.v2);
		CalTopoVertexTex(face.v1,face.v3,newPos,vertex);
	}
	m_topoFaces->RemoveTopoFace(faceIndex);
}

/**
分割线穿过一个顶点和对边,一个三角形拆分为两个
 * Face breaker for VERTEX-FACE-EDGE / EDGE-FACE-VERTEX
 * @param faceIndex 待拆的面
 * @param newPos  拆边(对边)上的点
 * @param endVertex 经过的顶点
                          v1
                          /\
						 /  \
					  e1/    \e3
					   /      \
				    v2/________\v3
					      e2
 */		
void Sloid::BreakFaceInTwo(int faceIndex, const vec3 & newPos, TopoVertex & endVertex)
{
	TopoFace & face = *m_topoFaces->GetTopoFace(faceIndex);
	TopoVertex * vertex = AddTopoVertex(newPos, face.v1->tVertex, TopoVertex::BOUNDARY);
				
	if (endVertex.equals(face.v1))
	{
		//穿过点1,边2
		AddTopoFace(face.v1, vertex, face.v3);
		AddTopoFace(vertex, face.v2, face.v3);
		CalTopoVertexTex(face.v1,face.v2,newPos,vertex);
	}
	else if (endVertex.equals(face.v2))
	{
		AddTopoFace(face.v2, vertex, face.v1);
		AddTopoFace(vertex, face.v3, face.v1);
		CalTopoVertexTex(face.v3,face.v2,newPos,vertex);
	}
	else
	{
		AddTopoFace(face.v3, vertex, face.v2);
		AddTopoFace(vertex, face.v1, face.v2);
		CalTopoVertexTex(face.v1,face.v3,newPos,vertex);
	}

	m_topoFaces->RemoveTopoFace(faceIndex);
}
//???  my
//void Sloid::BreakFaceInTwo(int faceIndex, const vec3 & newPos, Vertex & startVertex)
//{
//	Face & face = *m_topologyFaces->GetFace(faceIndex);
//	Vertex * vertex = addVertex(newPos, face.v1->color, Vertex::BOUNDARY);
//
//	if (startVertex.equals(face.v3))
//	{
//		//穿过点1,边2
//		addFace(face.v1, vertex, face.v3);
//		addFace(vertex, face.v2, face.v3);
//	}
//	else if (startVertex.equals(face.v1))
//	{
//		addFace(face.v2, vertex, face.v1);
//		addFace(vertex, face.v3, face.v1);
//	}
//	else
//	{
//		addFace(face.v3, vertex, face.v2);
//		addFace(vertex, face.v1, face.v2);
//	}
//
//	m_topologyFaces->RemoveFace(faceIndex);
//}

/**
分割线包含于一条边,一个三角形拆分为3个
 * Face breaker for EDGE-EDGE-EDGE
                          v1
                          /\
						 /  \
					  e1/    \e3
					   /      \
				    v2/________\v3
					      e2	
 */
void Sloid::BreakFaceInThree(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, int splitEdge)
{
	TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));
	TopoVertex * vertex1 = AddTopoVertex(newPos1, face.v1->tVertex, TopoVertex::BOUNDARY);	
	TopoVertex * vertex2 = AddTopoVertex(newPos2, face.v1->tVertex, TopoVertex::BOUNDARY);
					
	if (splitEdge == 1)
	{
		AddTopoFace(face.v1, vertex1, face.v3);
		AddTopoFace(vertex1, vertex2, face.v3);
		AddTopoFace(vertex2, face.v2, face.v3);
		CalTopoVertexTex(face.v1,face.v2,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v2,newPos2,vertex2);
	}
	else if (splitEdge == 2)
	{
		AddTopoFace(face.v2, vertex1, face.v1);
		AddTopoFace(vertex1, vertex2, face.v1);
		AddTopoFace(vertex2, face.v3, face.v1);
		CalTopoVertexTex(face.v3,face.v2,newPos1,vertex1);
		CalTopoVertexTex(face.v3,face.v2,newPos2,vertex2);
	}
	else
	{
		AddTopoFace(face.v3, vertex1, face.v2);
		AddTopoFace(vertex1, vertex2, face.v2);
		AddTopoFace(vertex2, face.v1, face.v2);
		CalTopoVertexTex(face.v1,face.v3,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v3,newPos2,vertex2);
	}
	m_topoFaces->RemoveTopoFace(faceIndex);
}

/**
 * VERTEX-FACE-FACE / FACE-FACE-VERTEX
 分割线一个点在端点,一个点在面内部
                          v1
                          /\
						 /  \
					  e1/    \e3
					   /      \
				    v2/________\v3
					      e2	
 */
void Sloid::BreakFaceInThree(int faceIndex, const vec3 & newPos, TopoVertex & endVertex)
{
	TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));
	TopoVertex * vertex = AddTopoVertex(newPos, face.v1->tVertex, TopoVertex::BOUNDARY);
					
	//if (endVertex.equals(face.v1))
	//{
	//	addFace(face.v1, face.v2, vertex);
	//	addFace(face.v2, face.v3, vertex);
	//	addFace(face.v3, face.v1, vertex);
	//}
	//else if (endVertex.equals(face.v2))
	//{
	//	addFace(face.v2, face.v3, vertex);
	//	addFace(face.v3, face.v1, vertex);
	//	addFace(face.v1, face.v2, vertex);
	//}
	//else
	{
		AddTopoFace(face.v3, face.v1, vertex);
		AddTopoFace(face.v1, face.v2, vertex);
		AddTopoFace(face.v2, face.v3, vertex);
		CalTopoVertexTex(face.v1,face.v2,face.v3,newPos,vertex);
	}
	m_topoFaces->RemoveTopoFace(faceIndex);
}

/**
 * Face breaker for EDGE-FACE-EDGE
  分割线切掉一个角
                          v1
                          /\
						 /  \
					  e1/    \e3
					   /      \
				    v2/________\v3
					      e2	
 */
void Sloid::BreakFaceInThree(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, TopoVertex & startVertex, TopoVertex & endVertex)
{
	TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));
	TopoVertex * vertex1 = AddTopoVertex(newPos1, face.v1->tVertex, TopoVertex::BOUNDARY);
	TopoVertex * vertex2 = AddTopoVertex(newPos2, face.v1->tVertex, TopoVertex::BOUNDARY);
					
	if (startVertex.equals(face.v1) && endVertex.equals(face.v2))
	{
		//切角2
		AddTopoFace(face.v1, vertex1, vertex2);
		AddTopoFace(face.v1, vertex2, face.v3);
		AddTopoFace(vertex1, face.v2, vertex2);
		CalTopoVertexTex(face.v1,face.v2,newPos1,vertex1);
		CalTopoVertexTex(face.v2,face.v3,newPos2,vertex2);
	}
	else if (startVertex.equals(face.v2) && endVertex.equals(face.v1))
	{
		//反切角2
		AddTopoFace(face.v1, vertex2, vertex1);
		AddTopoFace(face.v1, vertex1, face.v3);
		AddTopoFace(vertex2, face.v2, vertex1);
		CalTopoVertexTex(face.v1,face.v2,newPos1,vertex1);
		CalTopoVertexTex(face.v2,face.v3,newPos2,vertex2);
	}
	else if (startVertex.equals(face.v2) && endVertex.equals(face.v3))
	{
		//切角3
		AddTopoFace(face.v2, vertex1, vertex2);
		AddTopoFace(face.v2, vertex2, face.v1);
		AddTopoFace(vertex1, face.v3, vertex2);
		CalTopoVertexTex(face.v2,face.v3,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v3,newPos2,vertex2);
	}
	else if (startVertex.equals(face.v3) && endVertex.equals(face.v2))
	{
		AddTopoFace(face.v2, vertex2, vertex1);
		AddTopoFace(face.v2, vertex1, face.v1);
		AddTopoFace(vertex2, face.v3, vertex1);
		CalTopoVertexTex(face.v2,face.v3,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v3,newPos2,vertex2);
	}
	else if (startVertex.equals(face.v3) && endVertex.equals(face.v1))
	{
		//切角1
		AddTopoFace(face.v3, vertex1, vertex2);
		AddTopoFace(face.v3, vertex2, face.v2);
		AddTopoFace(vertex1, face.v1, vertex2);
		CalTopoVertexTex(face.v1,face.v3,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v2,newPos2,vertex2);
	}
	else
	{
		AddTopoFace(face.v3, vertex2, vertex1);
		AddTopoFace(face.v3, vertex1, face.v2);
		AddTopoFace(vertex2, face.v1, vertex1);
		CalTopoVertexTex(face.v1,face.v3,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v2,newPos2,vertex2);
	}

	m_topoFaces->RemoveTopoFace(faceIndex);
}

/**
 * Face breaker for FACE-FACE-FACE (a point only)
   分割线包含于面内?
                          v1
                          /\
						 /  \
					  e1/    \e3
					   /      \
				    v2/________\v3
					      e2	
 */
void Sloid::BreakFaceInThree(int faceIndex, const vec3 & newPos)
{
	TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));
	TopoVertex * vertex = AddTopoVertex(newPos, face.v1->tVertex, TopoVertex::BOUNDARY);
			
	AddTopoFace(face.v1, face.v2, vertex);
	AddTopoFace(face.v2, face.v3, vertex);
	AddTopoFace(face.v3, face.v1, vertex);
	CalTopoVertexTex(face.v1,face.v3,face.v3,newPos,vertex);

	m_topoFaces->RemoveTopoFace(faceIndex);
}

/**
 * Face breaker for EDGE-FACE-FACE / FACE-FACE-EDGE
   分割线一个点在边上,一个点在面内部
                          v1
                          /\
						 /  \
					  e1/    \e3
					   /      \
				    v2/________\v3
					      e2	
 */	
void Sloid::BreakFaceInFour(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, TopoVertex & endVertex)
{
	TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));
	TopoVertex * vertex1 = AddTopoVertex(newPos1, face.v1->tVertex, TopoVertex::BOUNDARY);
	TopoVertex * vertex2 = AddTopoVertex(newPos2, face.v1->tVertex, TopoVertex::BOUNDARY);
	
	if (endVertex.equals(face.v1))
	{
		//vertex2在内部
		AddTopoFace(face.v1, vertex1, vertex2);
		AddTopoFace(vertex1, face.v2, vertex2);
		AddTopoFace(face.v2, face.v3, vertex2);
		AddTopoFace(face.v3, face.v1, vertex2);
		CalTopoVertexTex(face.v1,face.v2,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v2,face.v3,newPos2,vertex2);
	}
	else if (endVertex.equals(face.v2))
	{
		AddTopoFace(face.v2, vertex1, vertex2);
		AddTopoFace(vertex1, face.v3, vertex2);
		AddTopoFace(face.v3, face.v1, vertex2);
		AddTopoFace(face.v1, face.v2, vertex2);
		CalTopoVertexTex(face.v2,face.v3,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v2,face.v3,newPos2,vertex2);
	}
	else
	{
		AddTopoFace(face.v3, vertex1, vertex2);
		AddTopoFace(vertex1, face.v1, vertex2);
		AddTopoFace(face.v1, face.v2, vertex2);
		AddTopoFace(face.v2, face.v3, vertex2);
		CalTopoVertexTex(face.v3,face.v1,newPos1,vertex1);
		CalTopoVertexTex(face.v1,face.v2,face.v3,newPos2,vertex2);
	}

	m_topoFaces->RemoveTopoFace(faceIndex);
}

/**
 * Face breaker for FACE-FACE-FACE
  分割线一个点在面内部,另一个点也在面内部
                          v1
                          /\
						 /  \
					  e1/    \e3
					   /      \
				    v2/________\v3
					      e2	
 */		
void Sloid::BreakFaceInFive(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, int linedVertex)
{
	TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));	
	TopoVertex * vertex1 = AddTopoVertex(newPos1, face.v1->tVertex, TopoVertex::BOUNDARY);
	TopoVertex * vertex2 = AddTopoVertex(newPos2, face.v1->tVertex, TopoVertex::BOUNDARY);
	CalTopoVertexTex(face.v1,face.v2,face.v3,newPos1,vertex1);
	CalTopoVertexTex(face.v1,face.v2,face.v3,newPos2,vertex2);
	float cont = 0;
	if (linedVertex == 1)
	{
		AddTopoFace(face.v2, face.v3, vertex1);
		AddTopoFace(face.v2, vertex1, vertex2);
		AddTopoFace(face.v3, vertex2, vertex1);
		AddTopoFace(face.v2, vertex2, face.v1);
		AddTopoFace(face.v3, face.v1, vertex2);
	}
	else if(linedVertex == 2)
	{
		AddTopoFace(face.v3, face.v1, vertex1);
		AddTopoFace(face.v3, vertex1, vertex2);
		AddTopoFace(face.v1, vertex2, vertex1);
		AddTopoFace(face.v3, vertex2, face.v2);
		AddTopoFace(face.v1, face.v2, vertex2);
	}
	else
	{
		AddTopoFace(face.v1, face.v2, vertex1);
		AddTopoFace(face.v1, vertex1, vertex2);
		AddTopoFace(face.v2, vertex2, vertex1);
		AddTopoFace(face.v1, vertex2, face.v3);
		AddTopoFace(face.v2, face.v3, vertex2);
	}

	// Calling it at the end, because the java garbage collection won't destroy it until after the end of the function,
	// (when there is nothing referencing it anymore)
	m_topoFaces->RemoveTopoFace(faceIndex);
}


//标记面在切割sloid的内部还是外部..
void Sloid::ClassifyFaces(Sloid & sloid)
{
	//清空重建邻边拓补信息
	//for(int i=0;iGetSize();i++)
	//{
	//}
	//for(int i=0;iGetSize();i++)
	//{
	//	TopologyFace & face = *(m_topologyFaces->GetFace(i));
	//	face.v1->addAdjacentVertex(face.v2);
	//	face.v1->addAdjacentVertex(face.v3);
	//	face.v2->addAdjacentVertex(face.v1);
	//	face.v2->addAdjacentVertex(face.v3);
	//	face.v3->addAdjacentVertex(face.v1);
	//	face.v3->addAdjacentVertex(face.v2);
	//}
	//
	for(int i=0;iGetTopoFaceNum();i++)
	{
		TopoFace & face = *(m_topoFaces->GetTopoFace(i));
		//
		if(face.simpleClassify()==false)
		{
			face.rayTraceClassify(sloid);
			if(face.v1->status==TopoVertex::UNKNOWN) 
			{
				face.v1->mark((TopoVertex::Status)face.status);
			}
			if(face.v2->status==TopoVertex::UNKNOWN) 
			{
				face.v2->mark((TopoVertex::Status)face.status);
			}
			if(face.v3->status==TopoVertex::UNKNOWN) 
			{
				face.v3->mark((TopoVertex::Status)face.status);
			}
		}
	}
}

//反转内部面,减法使用
void Sloid::InvertInsideFaces()
{
	TopoFace * face = 0;
	for(int i=0;iGetTopoFaceNum();i++)
	{
		face = m_topoFaces->GetTopoFace(i);
		if(face->status==TopoFace::INSIDE)
		{
			face->invert();
		}
	}
}

void Sloid::GenTopologyFromRend()
{
	///后期拓补处理
	m_topoVertexs->ClearTopoVertex();
	m_topoFaces->ClearTopoFace();

	TopoVertex * v1 = 0;
	TopoVertex * v2 = 0;
	TopoVertex * v3 = 0;
	TopoVertex * topoVertex = 0;
	TopoVertexPtrSet * tmpTopoVertexPtrSet = new TopoVertexPtrSet();
	// 
	for(int i=0;iAddTopoVertexPtr(topoVertex); 
	}

	// faces
	for(int i=0; iGetTopoVertexPtr(m_indexs[i]);
		v2 = tmpTopoVertexPtrSet->GetTopoVertexPtr(m_indexs[i+1]);
		v3 = tmpTopoVertexPtrSet->GetTopoVertexPtr(m_indexs[i+2]);
		AddTopoFace(v1, v2, v3);
	}

	//create bound
	if (m_bound==NULL)
	{
		m_bound = new Box();
	}
	m_bound->setFromPoints(m_vertexs[0],m_vertexs[1]);
	for(int i=1;imergePoint(m_vertexs[i]);
	}

	delete tmpTopoVertexPtrSet;
}


void Sloid::GenRendFromTopology()
{
	//m_topologyVertexs->clear();
	//m_vertices->clear();

	//for(int i = 0; i < m_topoVertexs->GetNumVertices(); i++)
	//{
	//	TopoVertex * pVertex = m_topoVertexs->GetVertex(i);
	//	//m_vertexs.AddVector(pVertex->pos);
	//	m_vertexs.SetVector(i,pVertex->pos);
	//}

}

void Sloid::Translate(const vec3 & t)
{
	for(int i = 0; i < m_vVertexNum; i++)
	{
		vec3 v = m_vertexs[i];
		v = v + t;
		m_vertexs[i] = v;
	}
	GenTopologyFromRend();
}

void Sloid::Render()
{

	G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,true);
	G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true);
	G_RendDriver->SetRenderStateEnable(RS_ALPHA_TEST,true);
	G_RendDriver->SetRenderStateEnable(RS_BLEND,true);
	G_RendDriver->BlendFunc(RS_SRC_ALPHA,RS_ONE_MINUS_SRC_ALPHA);
	G_RendDriver->AlphaFunc(RS_GREATER,0.0f);
	G_RendDriver->Color4f(1,1,1,1);

//		for (int i=0;i<8;i++)
//		{
//			G_RendDriver->SetSamplerState(i, SS_MINFILTER, TF_LINEAR);
//			G_RendDriver->SetSamplerState(i, SS_MAGFILTER, TF_LINEAR);
//		}

	G_RendDriver->RendBegin(RS_TRIANGLES);

	int nNumTriangles = m_indexNum / 3;

	for(int i = 0; i < nNumTriangles; i++)
	{
		int nIndex1 = m_indexs[i * 3 + 0];
		int nIndex2 = m_indexs[i * 3 + 1];
		int nIndex3 = m_indexs[i * 3 + 2];

		vec3 vP1 = m_vertexs[nIndex1];
		vec3 vP2 = m_vertexs[nIndex2];
		vec3 vP3 = m_vertexs[nIndex3];
		TVertex col1 = m_tVertexs[nIndex1];
		TVertex col2 = m_tVertexs[nIndex2];
		TVertex col3 = m_tVertexs[nIndex3];

		//glColor4f(col1.r, col1.g, col1.b, 255);
		G_RendDriver->TexCoord2f(col1.u, col1.v);
		G_RendDriver->Vertex3f(vP1.x, vP1.y, vP1.z);

		//glColor4f(col2.r, col2.g, col2.b, 255);
		G_RendDriver->TexCoord2f(col2.u, col2.v);
		G_RendDriver->Vertex3f(vP2.x, vP2.y, vP2.z);

		//glColor4f(col3.r, col3.g, col3.b, 255);
		G_RendDriver->TexCoord2f(col3.u, col3.v);
		G_RendDriver->Vertex3f(vP3.x, vP3.y, vP3.z);
	}

	G_RendDriver->RendEnd();

	//glLineWidth(1);
	//glDisable(GL_TEXTURE_2D);
	//glDisable (GL_DEPTH_TEST);

	//glBegin(GL_LINES);

	//for(int i = 0; i < nNumTriangles; i++)
	//{
	//	int nIndex1 = m_indexs[i * 3 + 0];
	//	int nIndex2 = m_indexs[i * 3 + 1];
	//	int nIndex3 = m_indexs[i * 3 + 2];

	//	vec3 vP1 = m_vertexs[nIndex1];
	//	vec3 vP2 = m_vertexs[nIndex2];
	//	vec3 vP3 = m_vertexs[nIndex3];

	//	TVertex col1 = m_tVertexs[nIndex1];
	//	TVertex col2 = m_tVertexs[nIndex2];
	//	TVertex col3 = m_tVertexs[nIndex3];

	//	glColor4ub(200,200,200, 255);

	//	glVertex3d(vP1.x, vP1.y, vP1.z);
	//	glVertex3d(vP2.x, vP2.y, vP2.z);

	//	glVertex3d(vP2.x, vP2.y, vP2.z);
	//	glVertex3d(vP3.x, vP3.y, vP3.z);

	//	glVertex3d(vP3.x, vP3.y, vP3.z);
	//	glVertex3d(vP1.x, vP1.y, vP1.z);
	//}

	//glEnd();

	//glLineWidth(1);
	//glColor4ub(255,255,255, 255);
}


void Sloid::RefMesh(RendSys::Mesh* mesh)
{
	Free();
	if (mesh)
	{
		//添加点面
		m_vVertexNum = mesh->m_vVertexNum;
		m_vertexs= new vec3[m_vVertexNum];

		for(int i = 0; i < m_vVertexNum; i++)
		{
			Mesh::Vertex& v =mesh->m_vVertexs[i];
			m_vertexs[i] = vec3(v.x,v.y,v.z);
		}

		//
		m_indexNum = mesh->m_trigonNum*3;
		m_indexs = new IndexInt[m_indexNum];
		for(int i = 0; i < mesh->m_trigonNum; i++)
		{
			Mesh::Trigon& f = mesh->m_trigons[i];
			m_indexs[i*3]   = f.vIndex[0];
			m_indexs[i*3+1] = f.vIndex[1];
			m_indexs[i*3+2] = f.vIndex[2];
		}

		//
		m_tVertexs = new TVertex[m_vVertexNum];
		TVertex col;
		float colorr = (Rand() % 255)/255.0f;
		float colorg = (Rand() % 255)/255.0f;
		float colorb = (Rand() % 255)/255.0f;
		for(int i = 0; i < m_vVertexNum; i++)
		{
			float colorr = (Rand() % 255)/255.0f;
			float colorg = (Rand() % 255)/255.0f;
			float colorb = (Rand() % 255)/255.0f;
			Mesh::TVertex& v =mesh->m_tVertexs[i];
			col.r = colorr;
			col.g =  colorg;
			col.b =  colorb;
			col.u =  v.u;
			col.v =  v.v;
			m_tVertexs[i] = (col);
		}
	}

	GenTopologyFromRend();
}



//==================^_^==================^_^==================^_^==================^_^

BooleanModeller::BooleanModeller(Sloid * solid1, Sloid * solid2)
{
	m_pSloid1 = solid1;
	m_pSloid2 = solid2;

	//切割
	m_pSloid1->SplitFaces(m_pSloid2);
	//模拟爆炸不做联合不补面时可以省略分割sloid2
    m_pSloid2->SplitFaces(m_pSloid1);

	//classify faces as being inside or outside the other solid
	m_pSloid1->ClassifyFaces(*m_pSloid2);
	m_pSloid2->ClassifyFaces(*m_pSloid1);
}

Sloid * BooleanModeller::GetUnion()
{
	Sloid *result = new Sloid();
	PreMergeSloid(m_pSloid1, result, TopoFace::OUTSIDE, TopoFace::SAME);
	PreMergeSloid(m_pSloid2, result, TopoFace::OUTSIDE, TopoFace::OUTSIDE);
	result->m_indexs = new IndexInt[result->m_indexNum];//肯比实际的多少许
	result->m_vertexs = new vec3[result->m_vVertexNum];
	result->m_tVertexs = new TVertex[result->m_tVertexNum];
	result->m_indexNum = 0;
	result->m_vVertexNum = 0;
	result->m_tVertexNum = 0;

	MergeSloid(m_pSloid1, result, TopoFace::OUTSIDE, TopoFace::SAME);
	MergeSloid(m_pSloid2, result, TopoFace::OUTSIDE, TopoFace::OUTSIDE);

	//拓扑的面依赖于点指针不遍即时加入
	//result->GenRendFromTopology();
	return result;
}

Sloid * BooleanModeller::GetIntersection()
{
	Sloid *result = new Sloid();
	PreMergeSloid(m_pSloid1, result, TopoFace::INSIDE, TopoFace::SAME);
	PreMergeSloid(m_pSloid2, result, TopoFace::INSIDE, TopoFace::INSIDE);
	result->m_indexs = new IndexInt[result->m_indexNum];//肯比实际的多少许
	result->m_vertexs = new vec3[result->m_vVertexNum];
	result->m_tVertexs = new TVertex[result->m_tVertexNum];
	result->m_indexNum = 0;
	result->m_vVertexNum = 0;
	result->m_tVertexNum = 0;
	
	MergeSloid(m_pSloid1, result, TopoFace::INSIDE, TopoFace::SAME);
	MergeSloid(m_pSloid2, result, TopoFace::INSIDE, TopoFace::INSIDE);
	//result->GenRendFromTopology();
	return result;
}

Sloid * BooleanModeller::GetDifference()
{
	m_pSloid2->InvertInsideFaces();
	Sloid *result = new Sloid();
	PreMergeSloid(m_pSloid1, result, TopoFace::OUTSIDE, TopoFace::OPPOSITE);
	PreMergeSloid(m_pSloid2, result, TopoFace::INSIDE, TopoFace::INSIDE);
	result->m_indexs = new IndexInt[result->m_indexNum];//肯比实际的多少许
	result->m_vertexs = new vec3[result->m_vVertexNum];
	result->m_tVertexs = new TVertex[result->m_tVertexNum];
	result->m_indexNum = 0;
	result->m_vVertexNum = 0;
	result->m_tVertexNum = 0;

	MergeSloid(m_pSloid1, result, TopoFace::OUTSIDE, TopoFace::OPPOSITE);
	MergeSloid(m_pSloid2, result, TopoFace::INSIDE, TopoFace::INSIDE);//减法:sloid的内部面作为补面,需要反转法线。


//result->GenRendFromTopology(); m_pSloid2->InvertInsideFaces(); return result; } void BooleanModeller::MergeSloid(Sloid* pSrcSloid, Sloid* pDstSloid, int faceStatus1, int faceStatus2) { for(int i=0;im_topoFaces->GetTopoFaceNum();i++) { TopoFace & face = *(pSrcSloid->m_topoFaces->GetTopoFace(i)); if(face.status==faceStatus1 || face.status==faceStatus2) { TopoVertexPtrSet faceVerts; faceVerts.AddTopoVertexPtr(face.v1); faceVerts.AddTopoVertexPtr(face.v2); faceVerts.AddTopoVertexPtr(face.v3); for(int j=0;jm_topoVertexs->HasTopoVertex(faceVerts[j])) { pDstSloid->m_indexs[pDstSloid->m_indexNum] = pDstSloid->m_topoVertexs->IndexOfTopoVertex(faceVerts[j]); pDstSloid->m_indexNum++; } else { pDstSloid->m_indexs[pDstSloid->m_indexNum] = pDstSloid->m_topoVertexs->GetTopoVertexNum(); pDstSloid->m_topoVertexs->AddTopoVertex(*faceVerts[j]); pDstSloid->m_vertexs[pDstSloid->m_vVertexNum] = faceVerts[j]->pos; pDstSloid->m_tVertexs[pDstSloid->m_tVertexNum] = faceVerts[j]->tVertex; pDstSloid->m_indexNum++; pDstSloid->m_vVertexNum++; pDstSloid->m_tVertexNum++; } } } } } void BooleanModeller::PreMergeSloid(Sloid* pSrcSloid, Sloid* pDstSloid, int faceStatus1, int faceStatus2) { for(int i=0;im_topoFaces->GetTopoFaceNum();i++) { TopoFace & face = *(pSrcSloid->m_topoFaces->GetTopoFace(i)); if(face.status==faceStatus1 || face.status==faceStatus2) { pDstSloid->m_indexNum+=3; pDstSloid->m_vVertexNum+=3; pDstSloid->m_tVertexNum+=3; } } }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/578918.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-11
下一篇 2022-04-11

发表评论

登录后才能评论

评论列表(0条)