⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clvertexmatrix.cpp

📁 在GPU上实现数值模拟技术(线性方程组)的通用架构
💻 CPP
字号:
/************************************************************
 *															*
 * decr     : vertex based matrix class						*
 * version  : 1.01											*
 * author   : Jens Kr黦er									*
 * date     : 16.09.2003									*
 * modified	: 06.10.2003									*
 * e-mail   : jens.krueger@in.tum.de						*
 *															*
 ************************************************************/

#include "clAbstractMatrix.h"
#include "clPackedVector.h"
#include "clUnpackedVector.h"

#include "clVertexMatrix.h"

const DWORD CLVECMATRIXVERTEX::FVF = D3DFVF_XYZ | D3DFVF_TEX6 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE2(1) | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE2(3) |D3DFVF_TEXCOORDSIZE4(4) | D3DFVF_TEXCOORDSIZE2(5);

LPD3DXEFFECT		clVertexMatrix::ms_pShaderVMatrix=NULL;
int					clVertexMatrix::ms_iVertexMatrixCount=0;
clUnpackedVector*	clVertexMatrix::ms_pUnpackedVectorRes=NULL;
clUnpackedVector*	clVertexMatrix::ms_pUnpackedVectorX=NULL;

D3DXHANDLE			clVertexMatrix::ms_tVector;
D3DXHANDLE			clVertexMatrix::ms_tLastPass;
D3DXHANDLE			clVertexMatrix::ms_tMatrixMultiplyNoLast;
D3DXHANDLE			clVertexMatrix::ms_tMatrixMultiply;

clVertexMatrix::clVertexMatrix(LPDIRECT3DDEVICE9 pd3dDevice, int iSize) {
	float fLog = DirectXUtils::log2(iSize)/2.0f;
	init(pd3dDevice,1<<(int)ceil(fLog),1<<(int)floor(fLog));
}

clVertexMatrix::clVertexMatrix(LPDIRECT3DDEVICE9 pd3dDevice, int iSizeX, int iSizeY) {
	init(pd3dDevice, iSizeX, iSizeY);
}

void clVertexMatrix::init(LPDIRECT3DDEVICE9 pd3dDevice, int iSizeX, int iSizeY) {
	// store values
	m_pd3dDevice = pd3dDevice;
	m_iSizeX	 = iSizeX;
	m_iSizeY	 = iSizeY;
	m_ppVertexBuffers = NULL;
	m_iVertexBufferCount = 0;


	// init static variables
	loadShaders();
	if (ms_iVertexMatrixCount < 1)	{
		// nothing yet
	}

	ms_iVertexMatrixCount++;
}

void clVertexMatrix::clPreparePackedUse() {
	ms_pUnpackedVectorX   = new clUnpackedVector(m_pd3dDevice, m_iSizeX, m_iSizeY);
	ms_pUnpackedVectorRes = new clUnpackedVector(m_pd3dDevice, m_iSizeX, m_iSizeY);
}

/*******************************************************************************************
   Name:    loadShaders
   Purpose: loads all shaders required for this vector, if loaded already use the old one
********************************************************************************************/
void clVertexMatrix::loadShaders() {
	if (ms_iVertexMatrixCount < 1)	{
		if (FAILED(DirectXUtils::checkLoadShader(_T("clMatrix.fx"), ms_pShaderVMatrix, m_pd3dDevice, clFrameworkShaderPath, NULL, clClass::ms_clPSProfile))) exit(-1);

		ms_tVector					= ms_pShaderVMatrix->GetParameterByName(NULL,"tVector");
		ms_tLastPass				= ms_pShaderVMatrix->GetParameterByName(NULL,"tLastPass");

		ms_tMatrixMultiplyNoLast	= ms_pShaderVMatrix->GetTechniqueByName("tMatrixMultiplyNoLast");
		ms_tMatrixMultiply			= ms_pShaderVMatrix->GetTechniqueByName("tMatrixMultiply");
	}
}

clVertexMatrix::~clVertexMatrix(void) {
	deleteVertexBuffers();

	// if this is the last matrix-object alive, destroy static members
	ms_iVertexMatrixCount--;
	if (ms_iVertexMatrixCount==0) 	{
		SAFE_RELEASE( ms_pShaderVMatrix);

		// maybe the unpacked objects do not exist, but SAFE_DELETE checks that
		SAFE_DELETE ( ms_pUnpackedVectorX );
		SAFE_DELETE ( ms_pUnpackedVectorRes );
	}
}

int clVertexMatrix::sortData(clVertexMatrixElement *meData, int iElemCount) {

	clVertexMatrixElement meTemp;
	int i;

	// sort by row
	for (i = 0;i<iElemCount;i++) {
		for (int j = i+1;j<iElemCount;j++) {
			if (meData[j].iY < meData[i].iY) {
				meTemp.iX    = meData[j].iX;meTemp.iY    = meData[j].iY;meTemp.fVal    = meData[j].fVal;
				meData[j].iX = meData[i].iX;meData[j].iY = meData[i].iY;meData[j].fVal = meData[i].fVal;
				meData[i].iX = meTemp.iX;meData[i].iY    = meTemp.iY;meData[i].fVal    = meTemp.fVal;
			}
		}
	}

	// find longest row --> determins the vertex-buffer count
	int iMaxRowLength     = 0;
	int iCurrentRowLength = 1;
	for (i = 1;i<iElemCount;i++) {
		if (meData[i-1].iY != meData[i].iY) {
			if (iMaxRowLength < iCurrentRowLength) iMaxRowLength = iCurrentRowLength;
			iCurrentRowLength = 1;
		} else iCurrentRowLength++;
	}
	if (iMaxRowLength < iCurrentRowLength) iMaxRowLength = iCurrentRowLength;

	return (int)ceil((float)iMaxRowLength/4.0f);
}

int clVertexMatrix::setData(clVertexMatrixElement *meData, int iElemCount) {
	int iVertexBufferCount = sortData(meData,iElemCount);
	setDataSorted(meData,iElemCount,iVertexBufferCount);
	return iVertexBufferCount;
}



void clVertexMatrix::deleteVertexBuffers() {
	if (m_ppVertexBuffers != NULL) {
		for (int i=0;i<m_iVertexBufferCount;i++) SAFE_RELEASE(m_ppVertexBuffers[i]);
		delete [] m_ppVertexBuffers;
		m_ppVertexBuffers = NULL;
		m_iVertexBufferCount = 0;
		delete [] m_iElemCounter;
	}
}

void clVertexMatrix::coordsTo2D(int i1DCoord, float &f2Dx, float &f2Dy) {
	f2Dx = (float)(i1DCoord%m_iSizeX)/(float)m_iSizeX;
	f2Dy = (float)(i1DCoord/m_iSizeX)/(float)m_iSizeY;
}

void clVertexMatrix::coordsToPos(int i1DCoord, float &f2Dx, float &f2Dy) {
	f2Dx = ((float)(i1DCoord%m_iSizeX)/(float)m_iSizeX)*2.0f-1.0f+1.0f/m_iSizeX;
	f2Dy = ((float)(i1DCoord/m_iSizeX)/(float)m_iSizeY)*2.0f-1.0f+1.0f/m_iSizeY;
}

void clVertexMatrix::insertElement(clVertexMatrixElement &meData, CLVECMATRIXVERTEX &vbData, int iRGBAIndex) {
	switch (iRGBAIndex) {
		case 0 : coordsTo2D(meData.iX,vbData.tu_0,vbData.tv_0);
				 vbData.val0 = meData.fVal;
				 coordsToPos(meData.iY,vbData.x,vbData.y); vbData.z = 1;
			     coordsTo2D(meData.iY,vbData.posX,vbData.posY);
				 break;
		case 1 : coordsTo2D(meData.iX,vbData.tu_1,vbData.tv_1);
				 vbData.val1 = meData.fVal;
				 break;
		case 2 : coordsTo2D(meData.iX,vbData.tu_2,vbData.tv_2);
				 vbData.val2 = meData.fVal;
				 break;
		case 3 : coordsTo2D(meData.iX,vbData.tu_3,vbData.tv_3);
				 vbData.val3 = meData.fVal;
				 break;
		default : throw "invalid index in insertElement"; 
	}
}

void clVertexMatrix::completeLastRow(CLVECMATRIXVERTEX &vbData, int iRGBAIndex) {
	switch (iRGBAIndex) {
		case 1 : vbData.tu_1 = 0;
			     vbData.tv_1 = 0;
				 vbData.val1 = 0;
		case 2 : vbData.tu_2 = 0;
			     vbData.tv_2 = 0;
				 vbData.val2 = 0;
		case 3 : vbData.tu_3 = 0;
			     vbData.tv_3 = 0;
				 vbData.val3 = 0;
	}
}

void clVertexMatrix::setDataSorted(clVertexMatrixElement *meData, int iElemCount,int iVertexBufferCount) {

	int i;
	deleteVertexBuffers();
	if (iElemCount < 1) return;

	// create the vertex buffers
	m_iVertexBufferCount = iVertexBufferCount;
	m_ppVertexBuffers = new LPDIRECT3DVERTEXBUFFER9[m_iVertexBufferCount];
	m_iElemCounter    = new int[m_iVertexBufferCount];

	// create the intermediate buffers
	CLVECMATRIXVERTEX **pVbData = new CLVECMATRIXVERTEX*[m_iVertexBufferCount];
	for (i = 0;i<iVertexBufferCount;i++) {
		pVbData[i]      = new CLVECMATRIXVERTEX[iElemCount];
		m_iElemCounter[i] = 0;
	}

	// fill the intermediate buffers
	int iLastRow    = meData[0].iY;
	int iInRowCount = 0;
	for (i = 0;i<iElemCount;i++) {
		if (iLastRow == meData[i].iY) {
			insertElement(meData[i],pVbData[iInRowCount/4][m_iElemCounter[iInRowCount/4]/4],iInRowCount%4);
			m_iElemCounter[iInRowCount/4]++;
			iInRowCount++;
		} else {
			completeLastRow(pVbData[iInRowCount/4][m_iElemCounter[iInRowCount/4]/4],iInRowCount%4);
			m_iElemCounter[iInRowCount/4] += 3-(iInRowCount-1)%4;
			iInRowCount = 0;
			insertElement(meData[i],pVbData[iInRowCount/4][m_iElemCounter[iInRowCount/4]/4],iInRowCount%4);
			m_iElemCounter[iInRowCount/4]++;
			iLastRow = meData[i].iY;
			iInRowCount++;
		}
	}
	completeLastRow(pVbData[iInRowCount/4][m_iElemCounter[iInRowCount/4]/4],iInRowCount%4);
	m_iElemCounter[iInRowCount/4] += 3-(iInRowCount-1)%4;


	// copy vertices into vertexbuffers and rescale counters
	for (i = 0;i<iVertexBufferCount;i++) {
		m_iElemCounter[i] = m_iElemCounter[i]/4;
		DirectXUtils::createFilledVertexBuffer(m_pd3dDevice,pVbData[i],sizeof(CLVECMATRIXVERTEX)*(m_iElemCounter[i]),
			                                   CLVECMATRIXVERTEX::FVF,D3DPOOL_DEFAULT,m_ppVertexBuffers[i]);
	}

	// delete the intermediate vertexData
	for (i = 0;i<iVertexBufferCount;i++) delete [] pVbData[i];
	delete [] pVbData;
}


/*******************************************************************************************
   Name:    matrixVectorOp 
   Purpose: computes matrix vector operations of the kind:
	          clvResult = this*clvX OP clvY
	          where OP (eOpType) can be one of the following: CL_NULL,CL_ADD,CL_SUB,CL_MULT
********************************************************************************************/
void clVertexMatrix::matrixVectorOp(CL_enum eOpType, clFragmentVector* clvX, clFragmentVector* clvY, clFragmentVector *clvResult) {

	clUnpackedVector* pUnpackedVectorRes;
	clUnpackedVector* pUnpackedVectorX;

	if (typeid(clvResult)==typeid(clPackedVector)) {
		if (clvX == NULL) clPreparePackedUse();
		(static_cast<clPackedVector*>(clvX))->unpack(ms_pUnpackedVectorX);

		pUnpackedVectorRes = ms_pUnpackedVectorRes;
		pUnpackedVectorX   = ms_pUnpackedVectorX;
	} else {
		pUnpackedVectorRes = (static_cast<clUnpackedVector*>(clvResult));
		pUnpackedVectorX   = (static_cast<clUnpackedVector*>(clvX));
	}
	pUnpackedVectorRes->clear();

	// compute Ax first
	for (int i=0;i<m_iVertexBufferCount;i++) {
		pUnpackedVectorRes->BeginScene();
			ms_pShaderVMatrix->SetTexture(ms_tVector, pUnpackedVectorX->m_pVectorTexture);

			if (i==0) {
				ms_pShaderVMatrix->SetTechnique(ms_tMatrixMultiplyNoLast);
			} else {
				ms_pShaderVMatrix->SetTechnique(ms_tMatrixMultiply);
				ms_pShaderVMatrix->SetTexture(ms_tLastPass, pUnpackedVectorRes->m_pVectorTexture);
			}

			UINT cPasses;
			ms_pShaderVMatrix->Begin(&cPasses, 0);
				ms_pShaderVMatrix->BeginPass(0);
				m_pd3dDevice->SetStreamSource( 0, m_ppVertexBuffers[i], 0, sizeof(CLVECMATRIXVERTEX) );
				m_pd3dDevice->SetFVF( CLVECMATRIXVERTEX::FVF );
				m_pd3dDevice->DrawPrimitive(D3DPT_POINTLIST,0,m_iElemCounter[i]);
				ms_pShaderVMatrix->EndPass();
			ms_pShaderVMatrix->End();
		pUnpackedVectorRes->EndScene();
	}

	if (typeid(clvResult)==typeid(clPackedVector)) {
		(static_cast<clPackedVector*>(clvResult))->repack(pUnpackedVectorRes);
	}

	// now compute OP y
	if (clvY != NULL) clvResult->vectorOp(eOpType,clvY,clvResult);
}

/*******************************************************************************************
   Name:    matrixVectorOpAdd 
   Purpose: computes matrix vector operations of the kind:
	          clvResult = clvResult + this*clvX OP clvY
	          where OP (eOpType) can be one of the following: CL_NULL,CL_ADD,CL_SUB,CL_MULT
********************************************************************************************/
void clVertexMatrix::matrixVectorOpAdd(CL_enum eOpType, clFragmentVector* clvX, clFragmentVector* clvY, clFragmentVector *clvResult) {
	clUnpackedVector* pUnpackedVectorRes;
	clUnpackedVector* pUnpackedVectorX;

	if (typeid(clvResult)==typeid(clPackedVector)) {
		if (clvX == NULL) clPreparePackedUse();
		(static_cast<clPackedVector*>(clvResult))->unpack(ms_pUnpackedVectorRes);
		(static_cast<clPackedVector*>(clvX))->unpack(ms_pUnpackedVectorX);
		pUnpackedVectorRes = ms_pUnpackedVectorRes;
		pUnpackedVectorX   = ms_pUnpackedVectorX;
	} else {
		pUnpackedVectorRes = (static_cast<clUnpackedVector*>(clvResult));
		pUnpackedVectorX   = (static_cast<clUnpackedVector*>(clvX));
	}

	// compute Ax first
	for (int i=0;i<m_iVertexBufferCount;i++) {
		pUnpackedVectorRes->BeginScene();
			ms_pShaderVMatrix->SetTexture(ms_tVector,		  pUnpackedVectorX->m_pVectorTexture);
			ms_pShaderVMatrix->SetTechnique(ms_tMatrixMultiply);
			ms_pShaderVMatrix->SetTexture(ms_tLastPass, pUnpackedVectorRes->m_pVectorTexture);

			UINT cPasses;
			ms_pShaderVMatrix->Begin(&cPasses, 0);
				ms_pShaderVMatrix->BeginPass(0);
				m_pd3dDevice->SetStreamSource( 0, m_ppVertexBuffers[i], 0, sizeof(CLVECMATRIXVERTEX) );
				m_pd3dDevice->SetFVF( CLVECMATRIXVERTEX::FVF );
				m_pd3dDevice->DrawPrimitive(D3DPT_POINTLIST,0,m_iElemCounter[i]);
				ms_pShaderVMatrix->EndPass();
			ms_pShaderVMatrix->End();
		pUnpackedVectorRes->EndScene( );
	}

	if (typeid(clvResult)==typeid(clPackedVector)) {
		(static_cast<clPackedVector*>(clvResult))->repack(pUnpackedVectorRes);
	}

	// now compute OP y
	if (clvY != NULL) clvResult->vectorOp(eOpType,clvY,clvResult);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -