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

📄 grassdrawer.cpp

📁 这是整套横扫千军3D版游戏的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "StdAfx.h"
#include "GrassDrawer.h"
#include "Map/Ground.h"
#include "Game/Camera.h"
#include "Rendering/GL/VertexArray.h"
#include "Map/ReadMap.h"
#include "Map/BaseGroundDrawer.h"
#include "Rendering/GL/myGL.h"
#include <GL/glu.h>	
#include "AdvTreeDrawer.h"
#include "Rendering/Textures/Bitmap.h"
#include "LogOutput.h"
#include "myMath.h"
#include "Platform/ConfigHandler.h"
#include <algorithm>
#include "FileSystem/FileHandler.h"
#include "Map/ReadMap.h"
#include "Rendering/ShadowHandler.h"
//#include "TimeProfiler.h"
#include "mmgr.h"

static const float turfSize=20;				//single turf size
static const int grassSquareSize=4;		//mapsquares per grass square
static const int grassBlockSize=4;		//grass squares per grass block

extern GLfloat FogLand[]; 

static float fRand(float size)
{
	return float(rand())/RAND_MAX*size;
}

CGrassDrawer::CGrassDrawer()
{
	int detail=configHandler.GetInt("GrassDetail",3);

	if(detail==0){
		grassOff=true;
		return;
	} else{
		grassOff=false;
	}
	MapBitmapInfo grassbm;
	unsigned char* grassdata=readmap->GetInfoMap("grass", &grassbm);
	if (grassdata)
	{
		if (grassbm.width != gs->mapx/grassSquareSize || grassbm.height != gs->mapy/grassSquareSize) {
			char b[128];
			SNPRINTF(b, sizeof(b), "Grass map has wrong size (%dx%d, should be %dx%d)\n", 
				grassbm.width, grassbm.height, gs->mapx/4, gs->mapy/4);
			throw std::runtime_error (b);
		}

		int grassMapSize = gs->mapx*gs->mapy/(grassSquareSize*grassSquareSize);
		grassMap=SAFE_NEW unsigned char[grassMapSize];

		memcpy(grassMap, grassdata, grassMapSize);
		readmap->FreeInfoMap ("grass", grassdata);
	} else {
		grassOff=true;
		return;
	}

	maxGrassDist=800+sqrt((float)detail)*240;
	maxDetailedDist=146+detail*24;
	detailedBlocks=(int)((maxDetailedDist-24)/(SQUARE_SIZE*grassSquareSize*grassBlockSize))+1;
	numTurfs=3+(int)(detail*0.5f);
	strawPerTurf=50+(int)sqrt((float)detail)*10;

//	logOutput.Print("%f %f %i %i %i",maxGrassDist,maxDetailedDist,detailedBlocks,numTurfs,strawPerTurf);

	blocksX=gs->mapx/grassSquareSize/grassBlockSize;
	blocksY=gs->mapy/grassSquareSize/grassBlockSize;

	for(int y=0;y<32;y++){
		for(int x=0;x<32;x++){
			grass[y*32+x].va=0;
			grass[y*32+x].lastSeen=0;
			grass[y*32+x].pos=ZeroVector;
			grass[y*32+x].square=0;
		}
	}
	for(int y=0;y<32;y++){
		for(int x=0;x<32;x++){
			nearGrass[y*32+x].square=-1;
		}
	}
	lastListClean=0;

	grassFarNSVP=LoadVertexProgram("grassFarNS.vp");

	grassDL=glGenLists(8);
	srand(15);
	for(int a=0;a<1;++a){
		CreateGrassDispList(grassDL+a);
	}
	unsigned char gbt[64*256*4];
	for(int a=0;a<16;++a){
		CreateGrassBladeTex(&gbt[a*16*4]);
	}
	glGenTextures(1, &grassBladeTex);
	glBindTexture(GL_TEXTURE_2D, grassBladeTex);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
	gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA8 ,256, 64, GL_RGBA, GL_UNSIGNED_BYTE, gbt);

	CreateFarTex();

	if(shadowHandler->canUseShadows){
		grassVP=LoadVertexProgram("grass.vp");
		grassFarVP=LoadVertexProgram("grassFar.vp");
	}
}

CGrassDrawer::~CGrassDrawer(void)
{
	if(grassOff)
		return;

	for(int y=0;y<32;y++){
		for(int x=0;x<32;x++){
			if(grass[y*32+x].va)
				delete grass[y*32+x].va;
		}
	}
	delete[] grassMap;
	glDeleteLists(grassDL,8);
	glDeleteTextures(1,&grassBladeTex);
	glDeleteTextures(1,&farTex);	

	glSafeDeleteProgram( grassFarNSVP );

	if(shadowHandler->canUseShadows){
		glSafeDeleteProgram( grassVP );
		glSafeDeleteProgram( grassFarVP );
	}
}

struct InviewGrass {
	int num;
	float dist;
};

struct InviewNearGrass {
	int x;
	int y;
	float dist;
};

static const bool GrassSort(const InviewGrass* a,const InviewGrass* b){
	return a->dist > b->dist;
}

static const bool GrassSortNear(const InviewNearGrass* a,const InviewNearGrass* b){
	return a->dist > b->dist;
}

class CGrassBlockDrawer : public CReadMap::IQuadDrawer
{
public:
	std::vector<InviewGrass*> inviewGrass;
	std::vector<InviewNearGrass*> inviewNearGrass;
	CVertexArray* va;
	int cx,cy;
	CGrassDrawer *gd;

	void DrawQuad (int x,int y);
};

void CGrassBlockDrawer::DrawQuad (int x,int y)
{
	const int blockMapSize=grassSquareSize*grassBlockSize;
	float maxDetailedDist = gd->maxDetailedDist;
	CGrassDrawer::NearGrassStruct *nearGrass = gd->nearGrass;

	if(abs(x-cx)<=gd->detailedBlocks && abs(y-cy)<=gd->detailedBlocks){	//blocks close to the camera
		for(int y2=0;y2<grassBlockSize;y2++){
			for(int x2=0;x2<grassBlockSize;x2++){//loop over all squares in block
				if(gd->grassMap[(y*grassBlockSize+y2)*gs->mapx/grassSquareSize+(x*grassBlockSize+x2)]){
					srand((y*grassBlockSize+y2)*1025+(x*grassBlockSize+x2));
					rand();
					rand();
					float3 squarePos((x*grassBlockSize+x2+0.5f)*SQUARE_SIZE*grassSquareSize, 0, (y*grassBlockSize+y2+0.5f)*SQUARE_SIZE*grassSquareSize);
					squarePos.y=ground->GetHeight2(squarePos.x,squarePos.z);
					if(camera->InView(squarePos,SQUARE_SIZE*grassSquareSize)){
						float sqdist=(camera->pos-squarePos).SqLength();
						if(sqdist<maxDetailedDist*maxDetailedDist){//close grass, draw directly
							int numGrass=gd->numTurfs;
							for(int a=0;a<numGrass;a++){
								float dx=(x*grassBlockSize+x2+fRand(1))*SQUARE_SIZE*grassSquareSize;
								float dy=(y*grassBlockSize+y2+fRand(1))*SQUARE_SIZE*grassSquareSize;
								float3 pos(dx,ground->GetHeight2(dx,dy),dy);
								pos.y-=ground->GetSlope(dx,dy)*10+0.03f;
								float col=0.62f;
								glColor3f(col,col,col);
								if(camera->InView(pos,turfSize*0.7f)){
									glPushMatrix();
									glTranslatef3(pos);
									CGrassDrawer::NearGrassStruct* ng=&nearGrass[((y*grassBlockSize+y2)&31)*32+((x*grassBlockSize+x2)&31)];
									if(ng->square!=(y*grassBlockSize+y2)*2048+(x*grassBlockSize+x2)){
										float3 v=squarePos-camera->pos;
										ng->rotation=GetHeadingFromVector(v.x,v.z)*180.0f/32768+180;
										ng->square=(y*grassBlockSize+y2)*2048+(x*grassBlockSize+x2);
									}
									glRotatef(ng->rotation,0,1,0);
									glCallList(gd->grassDL);
									glPopMatrix();
								}
							}
						} else {//near but not close, save for later drawing
							InviewNearGrass* iv=SAFE_NEW InviewNearGrass;
							iv->dist=sqdist;
							iv->x=x*grassBlockSize+x2;
							iv->y=y*grassBlockSize+y2;
							inviewNearGrass.push_back(iv);
							nearGrass[((y*grassBlockSize+y2)&31)*32+((x*grassBlockSize+x2)&31)].square=-1;
						}
					}
				}
			}
		}
		return;
	}
	float3 dif;
	dif.x=camera->pos.x-((x+0.5f)*SQUARE_SIZE*blockMapSize);
	dif.y=0;
	dif.z=camera->pos.z-((y+0.5f)*SQUARE_SIZE*blockMapSize);
	float dist=dif.Length2D();
	dif/=dist;

	CGrassDrawer::GrassStruct *grass = gd->grass;
				
	if(dist<gd->maxGrassDist){
		int curSquare=y*gd->blocksX+x;
		int curModSquare=(y&31)*32+(x&31);
		grass[curModSquare].lastSeen=gs->frameNum;
		if(grass[curModSquare].square!=curSquare){
			grass[curModSquare].square=curSquare;
			if(grass[curModSquare].va){
				delete grass[curModSquare].va;
				grass[curModSquare].va=0;
			}
		}
		if(!grass[curModSquare].va){
			grass[curModSquare].va=SAFE_NEW CVertexArray;;
			grass[curModSquare].pos=float3((x+0.5f)*SQUARE_SIZE*blockMapSize,ground->GetHeight2((x+0.5f)*SQUARE_SIZE*blockMapSize,(y+0.5f)*SQUARE_SIZE*blockMapSize),(y+0.5f)*SQUARE_SIZE*blockMapSize);
			va=grass[curModSquare].va;
			va->Initialize();
			for(int y2=0;y2<grassBlockSize;y2++){
				for(int x2=0;x2<grassBlockSize;x2++){
					if(gd->grassMap[(y*grassBlockSize+y2)*gs->mapx/grassSquareSize+(x*grassBlockSize+x2)]){
						srand((y*grassBlockSize+y2)*1025+(x*grassBlockSize+x2));
						rand();
						rand();
						int numGrass=gd->numTurfs;
						for(int a=0;a<numGrass;a++){
							float dx=(x*grassBlockSize+x2+fRand(1))*SQUARE_SIZE*grassSquareSize;
							float dy=(y*grassBlockSize+y2+fRand(1))*SQUARE_SIZE*grassSquareSize;
							float3 pos(dx,ground->GetHeight2(dx,dy)+0.5f,dy);
							float col=1;

							pos.y-=ground->GetSlope(dx,dy)*10+0.03f;
							va->AddVertexTN(pos,0,0,float3(-turfSize*0.6f,-turfSize*0.6f,col));
							va->AddVertexTN(pos,1/16.0f,0,float3(turfSize*0.6f,-turfSize*0.6f,col));
							va->AddVertexTN(pos,1/16.0f,1,float3(turfSize*0.6f,turfSize*0.6f,col));
							va->AddVertexTN(pos,0,1,float3(-turfSize*0.6f,turfSize*0.6f,col));
						}
					}
				}
			}
		}
		InviewGrass* ig=SAFE_NEW InviewGrass;
		ig->num=curModSquare;
		ig->dist=dist;
		inviewGrass.push_back(ig);	
	}
}

void CGrassDrawer::Draw(void)
{
	if(grassOff || !readmap->GetGrassShadingTexture())
		return;

	glColor4f(0.62f,0.62f,0.62f,1);

	CBaseGroundDrawer *gd = readmap->GetGroundDrawer ();

	if(shadowHandler->drawShadows && !gd->DrawExtraTex()){
		glBindProgramARB( GL_VERTEX_PROGRAM_ARB, grassVP );
		glEnable(GL_VERTEX_PROGRAM_ARB);
		glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB,13, 1.0f/(gs->pwr2mapx*SQUARE_SIZE),1.0f/(gs->pwr2mapy*SQUARE_SIZE),0,1);
		glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB,14, 1.0f/(gs->mapx*SQUARE_SIZE),1.0f/(gs->mapy*SQUARE_SIZE),0,1);

		glActiveTextureARB(GL_TEXTURE0_ARB);
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, readmap->GetShadingTexture ());
		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_PREVIOUS_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_TEXTURE);
		glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR);
		glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_MODULATE);
		glTexEnvi(GL_TEXTURE_ENV,GL_RGB_SCALE_ARB,2);

		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA_ARB,GL_PREVIOUS_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_ALPHA_ARB,GL_TEXTURE);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA_ARB,GL_MODULATE);

		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);

		glActiveTextureARB(GL_TEXTURE1_ARB);
		glBindTexture(GL_TEXTURE_2D,  shadowHandler->shadowTexture);
		glEnable(GL_TEXTURE_2D);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
		glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 1-readmap->shadowDensity);
		
		float texConstant[]={readmap->ambientColor.x*1.24f,readmap->ambientColor.y*1.24f,readmap->ambientColor.z*1.24f,1};
		glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,texConstant); 
		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_PREVIOUS_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_CONSTANT);
		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE2_RGB_ARB,GL_TEXTURE);
		glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND2_RGB_ARB,GL_SRC_ALPHA);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_INTERPOLATE_ARB);

		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA_ARB,GL_PREVIOUS_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_ALPHA_ARB,GL_CONSTANT);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA_ARB,GL_MODULATE);

		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);

		glActiveTextureARB(GL_TEXTURE2_ARB);
		glEnable(GL_TEXTURE_2D);
		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);		
		glBindTexture(GL_TEXTURE_2D, readmap->GetGrassShadingTexture()); 

		glActiveTextureARB(GL_TEXTURE3_ARB);
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, grassBladeTex);
		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);		

		glActiveTextureARB(GL_TEXTURE0_ARB);

		float t[16];
		glGetFloatv(GL_MODELVIEW_MATRIX,t);

		glMatrixMode(GL_MATRIX0_ARB);
		glLoadMatrixf(shadowHandler->shadowMatrix.m);
		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glMultMatrixf(t);
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		glLoadIdentity();
	} else {
		if(gd->DrawExtraTex()){
			glActiveTextureARB(GL_TEXTURE3_ARB);
			glEnable(GL_TEXTURE_2D);
			glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_ADD_SIGNED_ARB);
			glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA_ARB,GL_MODULATE);
			glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA_ARB,GL_PREVIOUS_ARB);
			glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_ALPHA_ARB,GL_TEXTURE);
			glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);

			SetTexGen(1.0f/(gs->pwr2mapx*SQUARE_SIZE),1.0f/(gs->pwr2mapy*SQUARE_SIZE),0,0);

			glBindTexture(GL_TEXTURE_2D, gd->infoTex);
			glActiveTextureARB(GL_TEXTURE0_ARB);
		}
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, grassBladeTex);

		glActiveTextureARB(GL_TEXTURE1_ARB);
		glEnable(GL_TEXTURE_2D);
		SetTexGen(1.0f/(gs->mapx*SQUARE_SIZE),1.0f/(gs->mapy*SQUARE_SIZE),0,0);
		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
		glBindTexture(GL_TEXTURE_2D, readmap->GetGrassShadingTexture());

		glActiveTextureARB(GL_TEXTURE2_ARB);
		glEnable(GL_TEXTURE_2D);
		SetTexGen(1.0f/(gs->pwr2mapx*SQUARE_SIZE),1.0f/(gs->pwr2mapy*SQUARE_SIZE),0,0);
		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
		glBindTexture(GL_TEXTURE_2D, readmap->GetShadingTexture ());

		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_PREVIOUS_ARB);
		glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_TEXTURE);
		glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_MODULATE);
		glTexEnvi(GL_TEXTURE_ENV,GL_RGB_SCALE_ARB,2);

		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);

		glActiveTextureARB(GL_TEXTURE0_ARB);
	}
	glDisable(GL_BLEND);
	glDisable(GL_ALPHA_TEST);
	glEnable(GL_FOG);
	glFogfv(GL_FOG_COLOR,FogLand);

⌨️ 快捷键说明

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