前两章的涉及一些很表面的东西,这一节开始我们要慢慢进入游戏的核心技术拉
我们先从图像生成这一个方向入手,我们可以看到CGame中有两个与图形生成有关的方法:bool Draw(); 和 bool DrawWorld();
我们先来看 bool DrawWorld();
bool CGame::DrawWorld()
{
START_TIME_PROFILE("Draw world");
CBaseGroundDrawer* gd = readmap->GetGroundDrawer();
sky->Draw();
gd->UpdateExtraTexture();
gd->Draw();
----------------该章就讲解这生成地图图像两句话,其他不用管
if(!readmap->voidWater && water->drawSolid)
water->Draw();
selectedUnits.Draw();
luaCallIns.DrawWorldPreUnit();
unitDrawer->Draw(false);
featureHandler->Draw();
if(gu->drawdebug && gs->cheatEnabled)
pathManager->Draw();
//transparent stuff
glEnable(GL_BLEND);
glDepthFunc(GL_LEQUAL);
if(treeDrawer->drawTrees)
treeDrawer->DrawGrass();
if(!readmap->voidWater && !water->drawSolid)
water->Draw();
unitDrawer->DrawCloakedUnits();
ph->Draw(false);
sky->DrawSun();
luaCallIns.DrawWorld();
lineDrawer.UpdateLineStipple();
LuaUnsyncedCtrl::DrawUnitCommandQueues();
if (cmdColors.AlwaysDrawQueue() || guihandler->GetQueueKeystate()) {
selectedUnits.DrawCommands();
}
cursorIcons.Draw();
cursorIcons.Clear();
mouse->Draw();
guihandler->DrawMapStuff(0);
inMapDrawer->Draw();
// underwater overlay
if (camera->pos.y < 0.0f) {
const float3& cpos = camera->pos;
const float vr = gu->viewRange * 0.5f;
glDisable(GL_TEXTURE_2D);
glColor4f(0.0f, 0.5f, 0.3f, 0.50f);
glBegin(GL_QUADS);
glVertex3f(cpos.x - vr, 0.0f, cpos.z - vr);
glVertex3f(cpos.x - vr, 0.0f, cpos.z + vr);
glVertex3f(cpos.x + vr, 0.0f, cpos.z + vr);
glVertex3f(cpos.x + vr, 0.0f, cpos.z - vr);
glEnd();
glBegin(GL_QUAD_STRIP);
glVertex3f(cpos.x - vr, 0.0f, cpos.z - vr);
glVertex3f(cpos.x - vr, -vr, cpos.z - vr);
glVertex3f(cpos.x - vr, 0.0f, cpos.z + vr);
glVertex3f(cpos.x - vr, -vr, cpos.z + vr);
glVertex3f(cpos.x + vr, 0.0f, cpos.z + vr);
glVertex3f(cpos.x + vr, -vr, cpos.z + vr);
glVertex3f(cpos.x + vr, 0.0f, cpos.z - vr);
glVertex3f(cpos.x + vr, -vr, cpos.z - vr);
glVertex3f(cpos.x - vr, 0.0f, cpos.z - vr);
glVertex3f(cpos.x - vr, -vr, cpos.z - vr);
glEnd();
}
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
//reset fov
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,1,0,1);
glMatrixMode(GL_MODELVIEW);
if (shadowHandler->drawShadows && shadowHandler->showShadowMap) {
shadowHandler->DrawShadowTex();
}
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLoadIdentity();
// underwater overlay, part 2
if (camera->pos.y < 0.0f) {
glDisable(GL_TEXTURE_2D);
glColor4f(0.0f, 0.2f, 0.8f, 0.333f);
glRectf(0.0f, 0.0f, 1.0f, 1.0f);
}
END_TIME_PROFILE("Draw world");
return true;
}
一开始我们就看到一个类叫CBaseGroundDrawer 这个类是干什么的呢?它就是本节的主角生成地图。分析他先上代码:
我们可以看到CBaseGroundDrawer* gd = readmap->GetGroundDrawer();
从readmap读出存有CBaseGroundDrawer的指针后进行了如下方法调用:gd->UpdateExtraTexture();gd->Draw();
那我们来先来看 gd->UpdateExtraTexture();方法是在干什么的
bool CBaseGroundDrawer::UpdateExtraTexture()
{
if(drawMode == drawNormal)
return true;
unsigned short* myLos=&loshandler->losMap[gu->myAllyTeam].front();
unsigned short* myAirLos=&loshandler->airLosMap[gu->myAllyTeam].front();
unsigned short* myRadar=&radarhandler->radarMaps[gu->myAllyTeam].front();
unsigned short* myJammer=&radarhandler->jammerMaps[gu->myAllyTeam].front();
if(updateTextureState<50){ ---50的意思是分50次加载
int starty;
int endy;
if(highResInfoTexWanted){
starty=updateTextureState*gs->mapy/50;
endy=(updateTextureState+1)*gs->mapy/50;
} else {
starty=updateTextureState*gs->hmapy/50;
endy=(updateTextureState+1)*gs->hmapy/50; ---将地图的X,Y分为50块
}
switch(drawMode) {
case drawPath: {
if (guihandler->inCommand > 0 && guihandler->inCommand < guihandler->commands.size() &&
guihandler->commands[guihandler->inCommand].type == CMDTYPE_ICON_BUILDING) { ---如果当前命令为建造
// use the current build order
for (int y = starty; y < endy; ++y) {
for (int x = 0; x < gs->hmapx; ++x) {
float m;
if (!loshandler->InLos(float3(x*16+8, 0, y*16+8), gu->myAllyTeam)) {
m = 0.25f;
} else {
const UnitDef* unitdef = unitDefHandler->GetUnitByID(-guihandler->commands[guihandler->inCommand].id);
CFeature* f;
if(uh->TestUnitBuildSquare(BuildInfo(unitdef, float3(x*16+8, 0, y*16+8), guihandler->buildFacing), f, gu->myAllyTeam)) {
if (f) {
m = 0.5f;
} else {
m = 1.0f;
}
} else {
m = 0.0f;
}
}
const int a=y*gs->pwr2mapx/2+x;
infoTexMem[a*4+0]=255-int(m*255.0f);
infoTexMem[a*4+1]=int(m*255.0f);
infoTexMem[a*4+2]=0; ---- 计算缓冲区大小填入缓冲区
}
}
}
else {
// use the first selected unit
if (selectedUnits.selectedUnits.empty()) {
return true;
}
const MoveData* md = (*selectedUnits.selectedUnits.begin())->unitDef->movedata;
if (md == NULL) {
return true;
}
for (int y = starty; y < endy; ++y) {
for (int x = 0; x < gs->hmapx; ++x) {
float m = md->moveMath->SpeedMod(*md, x*2, y*2);
if (gs->cheatEnabled && md->moveMath->IsBlocked2(*md, x*2+1, y*2+1) & (CMoveMath::BLOCK_STRUCTURE | CMoveMath::BLOCK_TERRAIN)) {
m = 0.0f;
}
m = min(1.0f, (float)sqrt(m));
const int a=y*gs->pwr2mapx/2+x;
infoTexMem[a*4+0]=255-int(m*255.0f);
infoTexMem[a*4+1]=int(m*255.0f);
infoTexMem[a*4+2]=0; ---- 计算缓冲区大小填入缓冲区
}
}
}
break;
}
case drawMetal: {
for(int y=starty;y<endy;++y){
for(int x=0;x<gs->hmapx;++x){
int a=y*gs->pwr2mapx/2+x;
if(myAirLos[((y*2)>>loshandler->airMipLevel)*loshandler->airSizeX+((x*2)>>loshandler->airMipLevel)]) {
float extractDepth = extractDepthMap[y*gs->hmapx+x];
infoTexMem[a*4]=(unsigned char)min(255.0f,(float)sqrt(sqrt(extractDepth))*900);
} else {
infoTexMem[a*4]=0;
}
infoTexMem[a*4+1]=(extraTexPal[extraTex[y*gs->hmapx+x]*3+1]);
infoTexMem[a*4+2]=(extraTexPal[extraTex[y*gs->hmapx+x]*3+2]); ---- 计算缓冲区大小填入缓冲区
}
}
break;
}
case drawHeight: {
extraTexPal=readmap->heightLinePal;
for(int y=starty;y<endy;++y){
for(int x=0;x<gs->mapx;++x){
int a=y*gs->pwr2mapx+x;
float height=readmap->centerheightmap[y*gs->mapx+x];
unsigned char value=(unsigned char)(height*8);
infoTexMem[a*4]=64+(extraTexPal[value*3]>>1);
infoTexMem[a*4+1]=64+(extraTexPal[value*3+1]>>1);
infoTexMem[a*4+2]=64+(extraTexPal[value*3+2]>>1); ---- 计算缓冲区大小填入缓冲区
}
}
break;
}
case drawLos: {
int lowRes = highResInfoTexWanted ? 0 : -1;
int endx = highResInfoTexWanted ? gs->mapx : gs->hmapx;
int pwr2mapx = gs->pwr2mapx >> (-lowRes);
for(int y=starty;y<endy;++y){
for(int x=0;x<endx;++x){
int a=y*pwr2mapx+x;
int inRadar=0;
int inJam=0;
if (drawRadarAndJammer){
inRadar = InterpolateLos(myRadar, radarhandler->xsize, radarhandler->ysize, 3+lowRes, 50, x, y);
inJam = InterpolateLos(myJammer, radarhandler->xsize, radarhandler->ysize, 3+lowRes, 50, x, y);
}
int inLos = InterpolateLos(myLos, loshandler->losSizeX, loshandler->losSizeY, loshandler->losMipLevel+lowRes, 32, x, y);
int inAir = InterpolateLos(myAirLos, loshandler->airSizeX, loshandler->airSizeY, loshandler->airMipLevel+lowRes, 32, x, y);
infoTexMem[a*4] = 64+inLos+inAir+inJam;
infoTexMem[a*4+1] = 64+inLos+inAir+inRadar;
infoTexMem[a*4+2] = 64+inLos+inAir; ---- 计算缓冲区大小填入缓冲区
}
}
break;
}
case drawNormal:
break;
} // switch (drawMode)
} // if (updateTextureState < 50)
if(updateTextureState==50){
if(infoTex!=0 && highResInfoTexWanted!=highResInfoTex){
glDeleteTextures(1,&infoTex);
infoTex=0;
}
if(infoTex==0){
glGenTextures(1,&infoTex);
glBindTexture(GL_TEXTURE_2D, infoTex);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
if(highResInfoTexWanted)
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8, gs->pwr2mapx, gs->pwr2mapy,0,GL_RGBA, GL_UNSIGNED_BYTE, infoTexMem);
else
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8, gs->pwr2mapx>>1, gs->pwr2mapy>>1,0,GL_RGBA, GL_UNSIGNED_BYTE, infoTexMem);
highResInfoTex=highResInfoTexWanted;
updateTextureState=0;
return true;
}
}
if(updateTextureState>=50){
glBindTexture(GL_TEXTURE_2D, infoTex);
if(highResInfoTex)
glTexSubImage2D(GL_TEXTURE_2D,0, 0,(updateTextureState-50)*(gs->pwr2mapy/8),gs->pwr2mapx, (gs->pwr2mapy/8),GL_RGBA, GL_UNSIGNED_BYTE, &infoTexMem[(updateTextureState-50)*(gs->pwr2mapy/8)*gs->pwr2mapx*4]);
else
glTexSubImage2D(GL_TEXTURE_2D,0, 0,(updateTextureState-50)*(gs->pwr2mapy/16),gs->pwr2mapx>>1, (gs->pwr2mapy/16),GL_RGBA, GL_UNSIGNED_BYTE, &infoTexMem[(updateTextureState-50)*(gs->pwr2mapy/16)*(gs->pwr2mapx>>1)*4]);
if(updateTextureState==57){
updateTextureState=0;
return true;
}
}
updateTextureState++;
return false;
}
恩,这个方法让我们看到头晕,不知所云,跟载入地图有什么关系呢, 给大家提醒下,这是在更新地图质材的方法
当
updateTextureState < 50: 计算质材的颜色值,填入缓冲区
updateTextureState >= 50: 从缓冲区填入质材
updateTextureState = 57: 重设updateTextureState为0,重新更新
想知道他们各自做了什么呢,看看我上面为他们做的注释。