www.pudn.com > packmk2.rar > software_noisemaker.cpp


#include "software_noisemaker.h" 
#include  
#include  
#include "tools.h" 
 
#define SSE false	// SSE is broken atm 
#define quadpipe false 
#define packednoise true 
 
software_noisemaker::software_noisemaker(int sX, int sY, parameterhandler *prm, const LPDIRECT3DDEVICE9 dev) 
{ 
	this->device = dev; 
	this->sizeX = sX; 
	this->sizeY = sY; 
	this->prm = prm; 
	time = 0.0; 
	last_time = timeGetTime(); 
	octaves = 0;	// don't want to have the noise accessed before it's calculated 
 
	f_sizeX = (float) sizeX; 
	f_sizeY = (float) sizeY;	 
 
	// reset normals 
	vertices	= new SOFTWARESURFACEVERTEX[sizeX*sizeY];	 
	for(int v=0; vinit_noise();	 
	#ifndef CPU_NORMALS 
	this->load_effects(); 
	this->init_textures(); 
	#endif 
} 
 
void software_noisemaker::resize(int sX, int sY) 
{ 
	delete vertices; 
	this->sizeX = sX; 
	this->sizeY = sY; 
 
	f_sizeX = (float) sizeX; 
	f_sizeY = (float) sizeY; 
 
	// reset normals 
	delete vertices; 
	vertices	= new SOFTWARESURFACEVERTEX[sizeX*sizeY];	 
	for(int v=0; vnoise[i] = rand()&0x0000FFFF;		 
		float temp = (float) rand()/RAND_MAX;		 
		tempnoise[i] = 4*(temp - 0.5f);	 
	}	 
 
	for(int frame=0; framenoise[frame*n_size_sq + v*n_size + u] = noise_magnitude*temp; 
			} 
		} 
	}	 
	 
} 
 
void software_noisemaker::calc_noise() 
{ 
	octaves = min(prm->params[p_iOctaves].iData, max_octaves);		 
 
	// calculate the strength of each octave 
	float sum=0.0f; 
	for(int i=0; iget_float(p_fFalloff),1.0f*i); 
		sum += f_multitable[i]; 
	} 
 
	{ 
	for(int i=0; iget_float( p_fAnimspeed ); 
	lp_itime = 0.99*lp_itime + 0.01 * itime; 
	if ( !prm->get_bool(p_bPaused) ) 
		time += lp_itime;			 
 
	 
	double	r_timemulti = 1.0; 
 
	for(int o=0; o>scale_decimalbits) +  
												((amount[1] * noise[i + n_size_sq * image[1]])>>scale_decimalbits) +  
												((amount[2] * noise[i + n_size_sq * image[2]])>>scale_decimalbits)); 
			} 
		} 
 
		r_timemulti *= prm->get_float( p_fTimemulti ); 
	} 
 
	if(packednoise) 
	{ 
		int octavepack = 0; 
		for(int o=0; o> upsamplepower; 
	int pv = v >> upsamplepower;	 
	int fu = u & (magnitude-1); 
	int fv = v & (magnitude-1); 
	int fu_m = magnitude - fu; 
	int fv_m = magnitude - fv; 
 
	int o = fu_m*fv_m*o_noise[octave*n_size_sq + ((pv)&n_size_m1)*n_size + ((pu)&n_size_m1)] + 
			fu*fv_m*o_noise[octave*n_size_sq + ((pv)&n_size_m1)*n_size + ((pu+1)&n_size_m1)] + 
			fu_m*fv*o_noise[octave*n_size_sq + ((pv+1)&n_size_m1)*n_size + ((pu)&n_size_m1)] + 
			fu*fv*o_noise[octave*n_size_sq + ((pv+1)&n_size_m1)*n_size + ((pu+1)&n_size_m1)]; 
 
	return o >> (upsamplepower+upsamplepower); 
} 
 
software_noisemaker::~software_noisemaker() 
{ 
	delete [] vertices; 
} 
 
bool software_noisemaker::render_geometry(const D3DXMATRIXA16 *m) 
{ 
 
	this->calc_noise(); 
 
	float magnitude = n_dec_magn * prm->get_float(p_fScale); 
	float inv_magnitude_sq = 1.0f/(prm->get_float(p_fScale)*prm->get_float(p_fScale)); 
 
	D3DXMATRIXA16 m_inv; 
	D3DXMatrixInverse( &m_inv, NULL, m ); 
	D3DXVec3TransformNormal( &e_u, &D3DXVECTOR3(1,0,0), m); 
	D3DXVec3TransformNormal( &e_v, &D3DXVECTOR3(0,1,0), m); 
	D3DXVec3Normalize( &e_u, &e_u ); 
	D3DXVec3Normalize( &e_v, &e_v ); 
 
 
	t_corners0 = this->calc_worldpos(D3DXVECTOR2(0.0f,0.0f),m); 
	t_corners1 = this->calc_worldpos(D3DXVECTOR2(+1.0f,0.0f),m); 
	t_corners2 = this->calc_worldpos(D3DXVECTOR2(0.0f,+1.0f),m); 
	t_corners3 = this->calc_worldpos(D3DXVECTOR2(+1.0f,+1.0f),m); 
 
	D3DXMATRIXA16 surface_to_world; 
 
 
	float	du = 1.0f/float(sizeX-1), 
		dv = 1.0f/float(sizeY-1), 
		u,v=0.0f; 
	D3DXVECTOR4 result; 
	int i=0; 
	for(int iv=0; ivparams[p_bSmooth].bData) 
	{ 
		//for(int n=0; n<3; n++) 
		for(int v=1; v<(sizeY-1); v++) 
		{ 
			for(int u=1; u<(sizeX-1); u++) 
			{				 
				vertices[v*sizeX + u].y =	0.2f * (vertices[v*sizeX + u].y + 
					vertices[v*sizeX + (u+1)].y +  
					vertices[v*sizeX + (u-1)].y +  
					vertices[(v+1)*sizeX + u].y +  
					vertices[(v-1)*sizeX + u].y);															 
			} 
		} 
	} 
 
	if(!prm->params[p_bDisplace].bData) 
	{ 
		// reset height to 0 
		for(int u=0; u<(sizeX*sizeY); u++) 
		{ 
			vertices[u].y = 0; 
		} 
 
	} 
 
 
	#ifdef CPU_NORMALS 
	calc_normals();	 
	#else 
	this->upload_noise(); 
	#endif	 
 
	return true; 
} 
 
 
 
// check the point of intersection with the plane (0,1,0,0) and return the position in homogenous coordinates  
D3DXVECTOR4 software_noisemaker::calc_worldpos(D3DXVECTOR2 uv, const D3DXMATRIXA16 *m) 
{	 
	// this is hacky.. this does take care of the homogenous coordinates in a correct way,  
	// but only when the plane lies at y=0 
	D3DXVECTOR4	origin(uv.x,uv.y,-1,1); 
	D3DXVECTOR4	direction(uv.x,uv.y,1,1); 
 
	D3DXVec4Transform( &origin, &origin, m ); 
	D3DXVec4Transform( &direction, &direction, m ); 
	direction -= origin;     
 
	float	l = -origin.y / direction.y;	// assumes the plane is y=0 
 
	D3DXVECTOR4 worldPos = origin + direction*l;     
	return worldPos; 
} 
 
void software_noisemaker::calc_normals() 
{ 
	for(int v=1; v<(sizeY-1); v++) 
	{ 
		for(int u=1; u<(sizeX-1); u++) 
		{ 
			D3DXVECTOR3 vec1(	vertices[v*sizeX + u + 1].x-vertices[v*sizeX + u - 1].x, 
				vertices[v*sizeX + u + 1].y-vertices[v*sizeX + u - 1].y,  
				vertices[v*sizeX + u + 1].z-vertices[v*sizeX + u - 1].z); 
 
			D3DXVECTOR3 vec2(	vertices[(v+1)*sizeX + u].x - vertices[(v-1)*sizeX + u].x, 
				vertices[(v+1)*sizeX + u].y - vertices[(v-1)*sizeX + u].y, 
				vertices[(v+1)*sizeX + u].z - vertices[(v-1)*sizeX + u].z); 
			D3DXVECTOR3 normal; 
			D3DXVec3Cross( &normal, &vec2, &vec1 ); 
			vertices[v*sizeX + u].nx = normal.x; 
			vertices[v*sizeX + u].ny = normal.y; 
			vertices[v*sizeX + u].nz = normal.z; 
 
		} 
	} 
} 
 
inline int software_noisemaker::readtexel_linear(int u, int v, int offset) 
{ 
	int iu, iup, iv, ivp, fu, fv; 
	iu = (u>>n_dec_bits)&n_size_m1; 
	iv = ((v>>n_dec_bits)&n_size_m1)*n_size; 
 
	iup = (((u>>n_dec_bits) + 1)&n_size_m1); 
	ivp = (((v>>n_dec_bits) + 1)&n_size_m1)*n_size; 
 
	fu = u & n_dec_magn_m1; 
	fv = v & n_dec_magn_m1; 
	/*float f_fu = (float) fu / n_dec_magn; 
	float f_fv = (float) fv / n_dec_magn;*/ 
	/*float ut01 = ((n_dec_magn_m1-fu)*o_noise[iv + iu + offset] + fu*o_noise[iv + iup + offset]); 
	float ut23 = ((n_dec_magn_m1-fu)*o_noise[ivp + iu + offset] + fu*o_noise[ivp + iup + offset]);*/ 
 
	int ut01 = ((n_dec_magn-fu)*o_noise[offset + iv + iu] + fu*o_noise[offset + iv + iup]) >> n_dec_bits; 
	int ut23 = ((n_dec_magn-fu)*o_noise[offset + ivp + iu] + fu*o_noise[offset + ivp + iup]) >> n_dec_bits ; 
	int ut = ((n_dec_magn-fv)*ut01 + fv*ut23) >> n_dec_bits; 
	return ut; 
} 
 
 
inline float software_noisemaker::get_height_at(int u, int v, int octaves) 
{	 
	int value=0;	 
	//r_noise = o_noise;	// pointer to the current noise source octave 
	for(int i=0; iparams[p_fStrength].fData / noise_magnitude; 
} 
 
float software_noisemaker::get_height_at(float u, float v) 
{ 
	float magnitude = n_dec_magn * prm->get_float(p_fScale); 
	//return get_height_at(magnitude*u, magnitude*v, octaves); 
	return get_height_dual(magnitude*u, magnitude*v); 
} 
 
void software_noisemaker::init_textures() 
{ 
	// the noise textures. currently two of them (= 8 levels) 
	device->CreateTexture(np_size,np_size,0,D3DUSAGE_DYNAMIC, D3DFMT_L16, D3DPOOL_DEFAULT, &(this->packed_noise_texture[0]),NULL);	 
	device->CreateTexture(np_size,np_size,0,D3DUSAGE_DYNAMIC, D3DFMT_L16, D3DPOOL_DEFAULT, &(this->packed_noise_texture[1]),NULL); 
 
	device->CreateTexture(nmapsize_x,nmapsize_y,1,D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16, D3DPOOL_DEFAULT, &(this->heightmap),NULL);	 
	device->CreateTexture(nmapsize_x,nmapsize_y,1,D3DUSAGE_AUTOGENMIPMAP|D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16, D3DPOOL_DEFAULT, &(this->normalmap),NULL);		 
 
	/*device->CreateTexture(nmapsize_x,nmapsize_y,1,D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &(this->heightmap),NULL);	 
	device->CreateTexture(nmapsize_x,nmapsize_y,1,D3DUSAGE_AUTOGENMIPMAP|D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &(this->normalmap),NULL);		*/ 
 
	// create z/stencil-buffer 
	device->CreateDepthStencilSurface( nmapsize_x, nmapsize_y,D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, true, &depthstencil, NULL ); 
} 
 
void software_noisemaker::upload_noise() 
{ 
	D3DLOCKED_RECT locked; 
	unsigned short *data; 
	int tempdata[np_size_sq]; 
	for(int t=0; t<2; t++) 
	{ 
		int offset = np_size_sq*t; 
		// upload the first level 
		packed_noise_texture[t]->LockRect( 0, &locked, NULL, D3DLOCK_DISCARD ); 
		data = (unsigned short*)locked.pBits; 
		for(int i=0; iUnlockRect( 0 ); 
 
		int c = packed_noise_texture[t]->GetLevelCount(); 
 
		// calculate the second level, and upload it 
		HRESULT hr = packed_noise_texture[t]->LockRect( 1, &locked, NULL, 0 ); 
		data = (unsigned short*)locked.pBits;		 
		int sz = np_size>>1; 
		for(int v=0; v>2; 
				data[v*sz+u] = 32768+tempdata[v*np_size + u]; 
			} 
		} 
 
		packed_noise_texture[t]->UnlockRect( 1 );		 
		 
		for(int j=2; jLockRect( j, &locked, NULL, 0 ); 
			data = (unsigned short*)locked.pBits; 
			int pitch = (locked.Pitch)>>1; 
			sz = np_size>>j;			 
			for(int v=0; v>2; 
					data[v*pitch+u] = 32768+tempdata[v*np_size + u]; 
				} 
			}		 
			packed_noise_texture[t]->UnlockRect( j ); 
		} 
	} 
} 
 
void software_noisemaker::generate_normalmap( ) 
{ 
#ifndef CPU_NORMALS 
	HRESULT hr; 
	 
	// do the heightmap thingy 
	LPDIRECT3DSURFACE9 target,bb,old_depthstencil; 
	hr = device->GetRenderTarget(0, &bb ); 
	hr = heightmap->GetSurfaceLevel( 0,&target ); 
	device->GetDepthStencilSurface( &old_depthstencil );	 
	 
	//hr = device->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW  );	 
	//device->SetStreamSource( 0, surf_software_vertices, 0, sizeof(SOFTWARESURFACEVERTEX) ); 
	hr = device->SetFVF( D3DFVF_SOFTWARESURFACEVERTEX);			 
	//device->SetIndices(surf->surf_indicies); 
	hr = hmap_effect->Begin(NULL,NULL); 
	hmap_effect->Pass(0);				 
	hmap_effect->SetFloat("scale", prm->params[p_fScale].fData); 
	 
	hmap_effect->SetTexture("noise0",packed_noise_texture[0]); 
	hmap_effect->SetTexture("noise1",packed_noise_texture[1]); 
	 
	hr = device->SetRenderTarget( 0, target ); 
	device->SetDepthStencilSurface( depthstencil ); 
	//device->Clear( 0, NULL,D3DCLEAR_TARGET, D3DCOLOR_XRGB(255,128,28), 1.0f, 0 ); 
	device->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE ); 
	device->DrawIndexedPrimitive(	D3DPT_TRIANGLELIST, 0,	0, sizeX*sizeY, 0, 2*(sizeX-1)*(sizeY-1) );			 
	hmap_effect->End(); 
	 
	// calculate normalmap 
 
	hr = normalmap->GetSurfaceLevel( 0,&target ); 
	hr = device->SetRenderTarget( 0, target ); 
	hr = nmap_effect->Begin(NULL,NULL); 
	nmap_effect->Pass(0);				 
	nmap_effect->SetFloat("inv_mapsize_x", 1.0f/nmapsize_x); 
	nmap_effect->SetFloat("inv_mapsize_y", 1.0f/nmapsize_y); 
	nmap_effect->SetVector("corner00", &t_corners0 ); 
	nmap_effect->SetVector("corner01", &t_corners1 ); 
	nmap_effect->SetVector("corner10", &t_corners2 ); 
	nmap_effect->SetVector("corner11", &t_corners3 ); 
	nmap_effect->SetFloat("amplitude", 2*prm->params[p_fStrength].fData); 
	nmap_effect->SetTexture("hmap",heightmap); 
	device->DrawIndexedPrimitive(	D3DPT_TRIANGLELIST, 0,	0, sizeX*sizeY, 0, 2*(sizeX-1)*(sizeY-1) );			 
	nmap_effect->End(); 
 
	// restore the device 
	device->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE ); 
	device->SetRenderTarget( 0, bb ); 
	device->SetDepthStencilSurface( old_depthstencil ); 
#endif 
} 
 
void software_noisemaker::load_effects() 
{ 
	char *errortext; 
	LPD3DXBUFFER errors; 
	D3DXHANDLE hTechnique; 
 
	// load effect 
	D3DXCreateEffectFromFile(device, "v2_heightmapgen.fx",  
		NULL, NULL, 0, NULL, &hmap_effect, &errors ); 
 
	if (errors != NULL){ 
		errortext = (char*) errors->GetBufferPointer(); 
		MessageBox(NULL, errortext, "hmap_effect", MB_OK);		 
	} 
 
	hmap_effect->FindNextValidTechnique(NULL, &hTechnique);     
	hmap_effect->SetTechnique(hTechnique); 
 
	// load effect 
	D3DXCreateEffectFromFile(device, "v2_normalmapgen.fx",  
		NULL, NULL, 0, NULL, &nmap_effect, &errors ); 
 
	if (errors != NULL){ 
		errortext = (char*) errors->GetBufferPointer(); 
		MessageBox(NULL, errortext, "nmap_effect", MB_OK);		 
	} 
 
	nmap_effect->FindNextValidTechnique(NULL, &hTechnique);     
	nmap_effect->SetTechnique(hTechnique); 
}