www.pudn.com > 3dterrain.zip > OcTree_Terrain.cpp


// OcTree_Terrain.cpp: implementation of the OcTree_Terrain class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "OcTree_Terrain.h" 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
float *OcTree_Terrain::vertex; 
vector *OcTree_Terrain::pasy_terrain; 
int OcTree_Terrain::split_x, OcTree_Terrain::split_z; 
int OcTree_Terrain::pocet_vrcholov=0; 
int OcTree_Terrain::max_pocet_vrcholov=10000; 
int OcTree_Terrain::max_stvorcov_v_kocke=100; 
CFrustum *OcTree_Terrain::Frustum=NULL; 
 
OcTree_Terrain::OcTree_Terrain() 
{ 
	pocet_vrcholov++; 
	if(pocet_vrcholov%(max_pocet_vrcholov/100)==0) 
	{ 
		char p[50]; 
		itoa(pocet_vrcholov, p, 10); 
		load->percenta=pocet_vrcholov/ (float)max_pocet_vrcholov; 
		load->Update(p,load->index); 
	} 
	je_deleny = 0; 
	size = 0; 
	pocet_stvorcov = 0; 
	center.x = 0; 
	center.y = 0; 
	center.z = 0; 
	q.clear(); 
	for(int i=0; i<8; i++) vrchol[i] = NULL; 
} 
 
OcTree_Terrain::OcTree_Terrain( float *vertex_, vector *pasy_terrain_, float velkost_, int split_x_, int split_z_) 
{ 
	vertex = vertex_; 
	pasy_terrain = pasy_terrain_; 
	split_x = split_x_; 
	split_z = split_z_; 
 
	je_deleny = 0; 
	size = velkost_; 
	pocet_stvorcov = split_x*split_z; 
	center.x = 0; 
	center.y = 0.5f*size; 
	center.z = 0; 
 
	{ 
		float uroven = (float)log(pocet_stvorcov/(double)max_stvorcov_v_kocke)/log(5.3f); 
		max_pocet_vrcholov = (int)(1+pow( 5.3f, uroven) )*(uroven+1); 
		if(max_pocet_vrcholov<100)max_pocet_vrcholov=100; 
	} 
 
	for(int i=0; i<8; i++) vrchol[i] = NULL; 
 
	stvorce s; 
	s.left = 0; 
	s.right= split_x-1; 
	for( s.z=0; s.z pom_q[8]; 
	XYZ stred[8];					// stredy kociek, ktore vzniknu delenim velkej (aktualnej) kocky 
 
	je_deleny = 1;					// kocka je delena 
	// vypocet stredov vsetkych mensich kociek 
	stred[TOP_LEFT_FRONT].x = center.x - size/4; 
	stred[TOP_LEFT_FRONT].y = center.y + size/4; 
	stred[TOP_LEFT_FRONT].z = center.z + size/4; 
 
	stred[TOP_LEFT_BACK].x = center.x - size/4; 
	stred[TOP_LEFT_BACK].y = center.y + size/4; 
	stred[TOP_LEFT_BACK].z = center.z - size/4; 
 
	stred[TOP_RIGHT_BACK].x = center.x + size/4; 
	stred[TOP_RIGHT_BACK].y = center.y + size/4; 
	stred[TOP_RIGHT_BACK].z = center.z - size/4; 
 
	stred[TOP_RIGHT_FRONT].x = center.x + size/4; 
	stred[TOP_RIGHT_FRONT].y = center.y + size/4; 
	stred[TOP_RIGHT_FRONT].z = center.z + size/4; 
 
	stred[BOTTOM_LEFT_FRONT].x = center.x - size/4; 
	stred[BOTTOM_LEFT_FRONT].y = center.y - size/4; 
	stred[BOTTOM_LEFT_FRONT].z = center.z + size/4; 
 
	stred[BOTTOM_LEFT_BACK].x = center.x - size/4; 
	stred[BOTTOM_LEFT_BACK].y = center.y - size/4; 
	stred[BOTTOM_LEFT_BACK].z = center.z - size/4; 
 
	stred[BOTTOM_RIGHT_BACK].x = center.x + size/4; 
	stred[BOTTOM_RIGHT_BACK].y = center.y - size/4; 
	stred[BOTTOM_RIGHT_BACK].z = center.z - size/4; 
 
	stred[BOTTOM_RIGHT_FRONT].x = center.x + size/4; 
	stred[BOTTOM_RIGHT_FRONT].y = center.y - size/4; 
	stred[BOTTOM_RIGHT_FRONT].z = center.z + size/4;		 
 
	// rozdelenie stvorcov do pomocnych pasov 
	for(int i=0; isize = size/2; 
			vrchol[i]->center.x = stred[i].x; 
			vrchol[i]->center.y = stred[i].y; 
			vrchol[i]->center.z = stred[i].z; 
			vrchol[i]->pocet_stvorcov = Pocet_stvorcov( &pom_q[i]); 
			vrchol[i]->q = pom_q[i]; 
 
		} 
		else		// v kocke nie su stvoce, kocku nepridavame do stromu 
		{ 
			pom_q[i].clear(); 
			vrchol[i] = NULL; 
		} 
	} 
	q.clear();		// uvolnime pamet, ktoru nepotrebujeme 
	// rekurentne pokracujeme vo vytvarani stromu, pokial je v kocke viac ako max_stvorcov_v_kocke 
	for( i=0; i<8; i++) 
	{ 
		if(vrchol[i] == NULL) continue; 
		if(vrchol[i]->pocet_stvorcov>max_stvorcov_v_kocke) vrchol[i]->Vytvor_vrchol(); 
	} 
} 
 
bool OcTree_Terrain::Stvorec_v_kocke(XYZ stred, float polovicna_velkost, int x, int z) 
{ 
	if( Bod_v_kocke(stred, polovicna_velkost, &vertex[3*( (split_x+1)*z + x)] ) ) return 1; 
	if( Bod_v_kocke(stred, polovicna_velkost, &vertex[3*( (split_x+1)*z + x+1)] ) ) return 1; 
	if( Bod_v_kocke(stred, polovicna_velkost, &vertex[3*( (split_x+1)*(z+1) + x)] ) ) return 1; 
	if( Bod_v_kocke(stred, polovicna_velkost, &vertex[3*( (split_x+1)*(z+1) + x+1)] ) ) return 1; 
	return 0; 
} 
 
bool OcTree_Terrain::Bod_v_kocke(XYZ stred, float pol_velkost, float *v) 
{ 
	if( v[0]<(stred.x - pol_velkost) || v[0]>(stred.x + pol_velkost) ) return 0; 
	if( v[1]<(stred.y - pol_velkost) || v[1]>(stred.y + pol_velkost) ) return 0; 
	if( v[2]<(stred.z - pol_velkost) || v[2]>(stred.z + pol_velkost) ) return 0; 
	return 1; 
} 
 
void OcTree_Terrain::Pridaj_stvorec(vector *q_p, int x, int z) 
{ 
	for(int i=0; i<(*q_p).size(); i++)		// prehladavame vsetky skupiny stvorcov 
	{ 
		if( z!=(*q_p)[i].z) continue;		// preskakujeme skupiny s inou z suradnicou 
		if( x >= (*q_p)[i].left && x<= (*q_p)[i].right )return;	// ak je stvorec uz v kocke 
		if( x == (*q_p)[i].left-1 )			// ak je na hranici z lava 
		{ 
			(*q_p)[i].left--; 
			return; 
		} 
		if( x == (*q_p)[i].right+1)			// ak je na hranici z prava 
		{ 
			(*q_p)[i].right++; 
			return; 
		} 
	} 
	{		// inak pridame stvorec ssamostatne 
		stvorce s; 
		s.left = x; 
		s.right = x; 
		s.z = z; 
		(*q_p).push_back(s); 
	} 
} 
 
int OcTree_Terrain::Pocet_stvorcov( vector *s) 
{ 
	int pocet=0; 
	for(int i=0; i< (*s).size(); i++) 
	{ 
		pocet += (*s)[i].right - (*s)[i].left + 1; 
	} 
	return pocet; 
} 
 
void OcTree_Terrain::Nastav_pasy() 
{ 
	if(Frustum->CubeInFrustum( center.x, center.y, center.z, size*0.5f )) 
	{ 
		if(je_deleny)  
			for(int i=0; i<8; i++)  
			{ 
				if(vrchol[i]!=NULL)vrchol[i]->Nastav_pasy(); 
			} 
		else Pridaj_pasy(); 
	} 
} 
 
void OcTree_Terrain::Nastav_pasy2() 
{ 
	int stav; 
 
	if(stav = Frustum->CubeInFrustum2( center.x, center.y, center.z, size*0.5f )) 
	{ 
		if(je_deleny && stav!=2)  
			for(int i=0; i<8; i++)  
			{ 
				if(vrchol[i]!=NULL)vrchol[i]->Nastav_pasy2(); 
			} 
		else Pridaj_pasy(); 
	} 
} 
 
void OcTree_Terrain::Maz_a_nastav_pasy() 
{ 
	for(int z=0; z=pasy_terrain[z][i].right)	// ak je pridavany vacsi z oboh stran 
		{ 
			pasy_terrain[z][i].left = left; 
			pasy_terrain[z][i].right = right; 
			return; 
		} 
 
		if( left>=pasy_terrain[z][i].left && right<=pasy_terrain[z][i].right) return;	// ak je pridavany vo vnutry povodneho 
 
		if( left<=pasy_terrain[z][i].left && right>=pasy_terrain[z][i].left-1) 
		{	// ak pridavany pridava z lavej strany 
			pasy_terrain[z][i].left = left; 
			return; 
		} 
 
		if( right>=pasy_terrain[z][i].right && left<=pasy_terrain[z][i].right+1) 
		{	// ak pridavany zvecsuje z pravej strany 
			pasy_terrain[z][i].right = right; 
			return; 
		} 
	} 
	{ 
		cast_pasu p; 
		p.left = left; 
		p.right = right; 
		if(pasy_terrain[z].size() == 0) 
		{ 
			pasy_terrain[z].push_back(p); 
			return; 
		} 
		pasy_terrain[z].push_back(p);	// inak pridame dalsi kus stvorcov 
	} 
} 
 
void OcTree_Terrain::Kresli_kocky() 
{	 
	int stav; 
	glColor3f(1,1,0); 
 
	if(keys['E']) 
		stav = Frustum->CubeInFrustum2( center.x, center.y, center.z, size*0.5f ); 
	else 
		stav = Frustum->CubeInFrustum( center.x, center.y, center.z, size*0.5f ); 
	 
//	if( stav = Frustum.CubeInFrustum2( center.x, center.y, center.z, size*0.5f )) 
	if(stav) 
	{ 
		if(je_deleny) 
		{ 
			if(stav==2) 
			{ 
				glColor3f(1,0,0); 
				Kresli_kocku(); 
				return; 
			} 
			for(int i=0; i<8; i++)  
			{ 
				if(vrchol[i]!=NULL)vrchol[i]->Kresli_kocky(); 
			} 
		} 
		else Kresli_kocku(); 
	} 
} 
 
void OcTree_Terrain::Kresli_kocku() 
{ 
	float s = size*0.5f; 
	float x = center.x; 
	float y = center.y; 
	float z = center.z; 
 
	glDisable(GL_TEXTURE_2D); 
//	glColor3f(1,1,0); 
	glBegin(GL_LINE_STRIP ); 
	glVertex3f( x-s, y-s, z+s); 
	glVertex3f( x+s, y-s, z+s); 
	glVertex3f( x+s, y-s, z-s); 
	glVertex3f( x-s, y-s, z-s); 
	glVertex3f( x-s, y-s, z+s); 
	 
	glVertex3f( x-s, y+s, z+s); 
	glVertex3f( x+s, y+s, z+s); 
	glVertex3f( x+s, y+s, z-s); 
	glVertex3f( x-s, y+s, z-s); 
	glVertex3f( x-s, y+s, z+s); 
	glEnd(); 
 
	glBegin(GL_LINES ); 
	glVertex3f( x+s, y-s, z+s); 
	glVertex3f( x+s, y+s, z+s); 
 
	glVertex3f( x+s, y-s, z-s); 
	glVertex3f( x+s, y+s, z-s); 
 
	glVertex3f( x-s, y-s, z-s); 
	glVertex3f( x-s, y+s, z-s); 
	glEnd(); 
 
	glColor3f(1,1,1); 
	glEnable(GL_TEXTURE_2D); 
} 
 
void OcTree_Terrain::Zapis_vrchol(FILE *sub) 
{ 
	zapis_OcTree_Terrain pom; 
 
	pom.center.x = center.x; 
	pom.center.y = center.y; 
	pom.center.z = center.z; 
 
	pom.pocet_stvorcov = pocet_stvorcov; 
	pom.size = size; 
	pom.zapisanych_stvorcov = q.size(); 
	pom.vrchol = 0; 
	for(int i=0; i<8; i++) 
	{ 
		if(vrchol[i]!=NULL)	pom.vrchol |= 1<Zapis_vrchol( sub); 
	} 
} 
 
int OcTree_Terrain::Nacitaj_vrchol(FILE *sub) 
{ 
	zapis_OcTree_Terrain pom; 
 
	if(!fread( &pom, sizeof(zapis_OcTree_Terrain), 1, sub) ) return 0; 
	center.x = pom.center.x; 
	center.y = pom.center.y; 
	center.z = pom.center.z; 
	 
	if(pom.vrchol) je_deleny = 1; 
	else je_deleny = 0; 
 
	pocet_stvorcov = pom.pocet_stvorcov; 
	size = pom.size; 
 
	for(int i=0; iNacitaj_vrchol( sub))return 0; 
			} 
		} 
	} 
	return 1; 
} 
 
void OcTree_Terrain::Save(char *meno) 
{ 
	FILE *sub; 
	int poc_vrcholov = 0; 
	 
	Pocet_vrcholov( &poc_vrcholov); 
	 
	sub = fopen( meno, "wb"); 
	fwrite( &poc_vrcholov, sizeof(int), 1, sub);		// pocet vrcholov - pouzitie pre loader 
	fwrite( &split_x, sizeof(int), 1, sub);				// pocet stvorcov v smere x 
	fwrite( &split_z, sizeof(int), 1, sub);				// pocet stvorcov v smere z 
	fwrite( &size, sizeof(float), 1, sub);				// velkost plochy 
	fwrite( &max_stvorcov_v_kocke, sizeof(int), 1, sub);// max_stvorcov_v_kocke 
	Zapis_vrchol(sub); 
	fclose(sub); 
} 
 
int OcTree_Terrain::Load(char *meno) 
{ 
	FILE *sub; 
	int delenie_x, delenie_z, max_stvorcov_v_kocke_; 
	float velkost; 
 
	q.clear(); 
	sub = fopen( meno, "rb"); 
 
	if(sub == NULL)	return 0; 
	 
	if(!fread( &max_pocet_vrcholov, sizeof(int), 1, sub) ){	fclose(sub); return 0;} 
	if(!fread( &delenie_x, sizeof(int), 1, sub) ){	fclose(sub); return 0;} 
	if(!fread( &delenie_z, sizeof(int), 1, sub) ){	fclose(sub); return 0;} 
	if(!fread( &velkost, sizeof(float), 1, sub) ){	fclose(sub); return 0;} 
	if(!fread( &max_stvorcov_v_kocke_, sizeof(int), 1, sub) ){	fclose(sub); return 0;} 
 
	if( delenie_x!=split_x || delenie_z!=split_z || velkost!=size || max_stvorcov_v_kocke_!=max_stvorcov_v_kocke) { fclose(sub);	return 0;} 
 
	if(max_pocet_vrcholov<100)max_pocet_vrcholov=100; 
 
	if(!Nacitaj_vrchol(sub)) { fclose(sub);	return 0;} 
	 
	fclose(sub); 
	return 1; 
} 
 
void OcTree_Terrain::Pocet_vrcholov(int *p) 
{ 
	(*p)++; 
	if(!je_deleny)return; 
	for( int i=0; i<8; i++) 
	{ 
		if(vrchol[i]!=NULL) vrchol[i]->Pocet_vrcholov( p); 
	} 
}