📄 grassdrawer.cpp
字号:
#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 + -