前面已经介绍雷达地图的类声明,现在就来仔细分析一下雷达地图是怎么样显示出来的。雷达地图显示函数
LLNetMap::draw代码如下:
#001 void LLNetMap::draw()
#002 {
#003
static LLFrameTimer map_timer;
#004
判断是否显示雷达地图。
#005
if (!getVisible() || !gWorldPointer)
#006
{
#007
return;
#008
}
创建对象图片。
#009
if (mObjectImagep.isNull())
#010
{
#011
createObjectImage();
#012
}
#013
#014
mCurPanX = lerp(mCurPanX, mTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
#015
mCurPanY = lerp(mCurPanY, mTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
#016
#017
// Prepare a scissor region
#018
F32 rotation = 0;
#019
#020
{
#021
LLGLEnable scissor(GL_SCISSOR_TEST);
#022
#023
{
#024
LLGLSNoTexture no_texture;
取得窗口显示的大小。
#025
LLLocalClipRect clip(getLocalRect());
#026
设置
GL显示的模式。
#027
glMatrixMode(GL_MODELVIEW);
#028
显示背景方框。
#029
// Draw background rectangle
#030
gGL.color4fv( mBackgroundColor.mV );
#031
gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0);
#032
}
#033
计算中心位置。
#034
// region 0,0 is in the middle
#035
S32 center_sw_left = getRect().getWidth() / 2 + llfloor(mCurPanX);
#036
S32 center_sw_bottom = getRect().getHeight() / 2 + llfloor(mCurPanY);
#037
#038
gGL.pushMatrix();
#039
#040
gGL.translatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f);
#041
判断是否旋转显示地图。
#042
if( LLNetMap::sRotateMap )
#043
{
#044
// rotate subsequent draws to agent rotation
#045
rotation = atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] );
#046
glRotatef( rotation * RAD_TO_DEG, 0.f, 0.f, 1.f);
#047
}
#048
#049
// figure out where agent is
#050
S32 region_width = llround(gWorldPointer->getRegionWidthInMeters());
#051
#052
for (LLWorld::region_list_t::iterator iter = gWorldp->mActiveRegionList.begin();
#053
iter != gWorldp->mActiveRegionList.end(); ++iter)
#054
{
计算以当前摄像机为中心的地图位置。
#055
LLViewerRegion* regionp = *iter;
#056
// Find x and y position relative to camera's center.
#057
LLVector3 origin_agent = regionp->getOriginAgent();
#058
LLVector3 rel_region_pos = origin_agent - gAgent.getCameraPositionAgent();
#059
F32 relative_x = (rel_region_pos.mV[0] / region_width) * gMiniMapScale;
#060
F32 relative_y = (rel_region_pos.mV[1] / region_width) * gMiniMapScale;
#061
#062
// background region rectangle
#063
F32 bottom = relative_y;
#064
F32 left = relative_x;
#065
F32 top = bottom + gMiniMapScale ;
#066
F32 right = left + gMiniMapScale ;
#067
#068
if (regionp == gAgent.getRegion())
#069
{
#070
gGL.color4f(1.f, 1.f, 1.f, 1.f);
#071
}
#072
else
#073
{
#074
gGL.color4f(0.8f, 0.8f, 0.8f, 1.f);
#075
}
#076
#077
if (!regionp->mAlive)
#078
{
#079
gGL.color4f(1.f, 0.5f, 0.5f, 1.f);
#080
}
#081
#082
显示背景边框。
#083
// Draw using texture.
#084
LLViewerImage::bindTexture(regionp->getLand().getSTexture());
#085
gGL.begin(GL_QUADS);
#086
gGL.texCoord2f(0.f, 1.f);
#087
gGL.vertex2f(left, top);
#088
gGL.texCoord2f(0.f, 0.f);
#089
gGL.vertex2f(left, bottom);
#090
gGL.texCoord2f(1.f, 0.f);
#091
gGL.vertex2f(right, bottom);
#092
gGL.texCoord2f(1.f, 1.f);
#093
gGL.vertex2f(right, top);
#094
gGL.end();
#095
显示水所在的区域。
#096
// Draw water
#097
glAlphaFunc(GL_GREATER, ABOVE_WATERLINE_ALPHA / 255.f );
#098
{
#099
if (regionp->getLand().getWaterTexture())
#100
{
#101
LLViewerImage::bindTexture(regionp->getLand().getWaterTexture());
#102
gGL.begin(GL_QUADS);
#103
gGL.texCoord2f(0.f, 1.f);
#104
gGL.vertex2f(left, top);
#105
gGL.texCoord2f(0.f, 0.f);
#106
gGL.vertex2f(left, bottom);
#107
gGL.texCoord2f(1.f, 0.f);
#108
gGL.vertex2f(right, bottom);
#109
gGL.texCoord2f(1.f, 1.f);
#110
gGL.vertex2f(right, top);
#111
gGL.end();
#112
}
#113
}
#114
glAlphaFunc(GL_GREATER,0.01f);
#115
}
#116
#117
#118
LLVector3d old_center = mObjectImageCenterGlobal;
#119
LLVector3d new_center = gAgent.getCameraPositionGlobal();
#120
#121
new_center.mdV[0] = (5.f/mObjectMapTPM)*floor(0.2f*mObjectMapTPM*new_center.mdV[0]);
#122
new_center.mdV[1] = (5.f/mObjectMapTPM)*floor(0.2f*mObjectMapTPM*new_center.mdV[1]);
#123
new_center.mdV[2] = 0.f;
#124
#125
if (mUpdateNow || (map_timer.getElapsedTimeF32() > 0.5f))
#126
{
#127
mUpdateNow = FALSE;
#128
mObjectImageCenterGlobal = new_center;
#129
#130
// Center moved enough.
#131
// Create the base texture.
#132
U8 *default_texture = mObjectRawImagep->getData();
#133
memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() );
#134
显示建筑物,根据水平面的高度来显示不同的颜色。
#135
// Draw buildings
#136
gObjectList.renderObjectsForMap(*this);
#137
#138
mObjectImagep->setSubImage(mObjectRawImagep, 0, 0, mObjectImagep->getWidth(), mObjectImagep->getHeight());
#139
#140
map_timer.reset();
#141
}
#142
#143
LLVector3 map_center_agent = gAgent.getPosAgentFromGlobal(mObjectImageCenterGlobal);
#144
map_center_agent -= gAgent.getCameraPositionAgent();
#145
map_center_agent.mV[VX] *= gMiniMapScale/region_width;
#146
map_center_agent.mV[VY] *= gMiniMapScale/region_width;
#147
#148
LLViewerImage::bindTexture(mObjectImagep);
#149
F32 image_half_width = 0.5f*mObjectMapPixels;
#150
F32 image_half_height = 0.5f*mObjectMapPixels;
#151
#152
gGL.begin(GL_QUADS);
#153
gGL.texCoord2f(0.f, 1.f);
#154
gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]);
#155
gGL.texCoord2f(0.f, 0.f);
#156
gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height);
#157
gGL.texCoord2f(1.f, 0.f);
#158
gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height);
#159
gGL.texCoord2f(1.f, 1.f);
#160
gGL.vertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]);
#161
gGL.end();
#162
#163
gGL.popMatrix();
#164
#165
LLVector3d pos_global;
#166
LLVector3 pos_map;
#167
下面开始显示整个地图上所有玩家。
#168
// Draw avatars
#169
for (LLWorld::region_list_t::iterator iter = gWorldp->mActiveRegionList.begin();
#170
iter != gWorldp->mActiveRegionList.end(); ++iter)
#171
{
获取所在区域。
#172
LLViewerRegion* regionp = *iter;
#173
const LLVector3d& origin_global = regionp->getOriginGlobal();
#174
获取当前玩家的人数。
#175
S32 count = regionp->mMapAvatars.count();
#176
S32 i;
#177
LLVector3 pos_local;
#178
U32 compact_local;
#179
U8 bits;
#180
// TODO: it'd be very cool to draw these in sorted order from lowest Z to highest.
#181
// just be careful to sort the avatar IDs along with the positions. –MG
开始在地图上显示所有玩家。
#182
for (i = 0; i < count; i++)
#183
{
#184
compact_local = regionp->mMapAvatars.get(i);
#185
#186
bits = compact_local & 0xFF;
#187
pos_local.mV[VZ] = F32(bits) * 4.f;
#188
compact_local >>= 8;
#189
#190
bits = compact_local & 0xFF;
#191
pos_local.mV[VY] = (F32)bits;
#192
compact_local >>= 8;
#193
#194
bits = compact_local & 0xFF;
#195
pos_local.mV[VX] = (F32)bits;
#196
#197
pos_global.setVec( pos_local );
#198
pos_global += origin_global;
#199
从全局坐标转换为地图坐标。
#200
pos_map = globalPosToView(pos_global);
#201
#202
BOOL show_as_friend = FALSE;
#203
if( i < regionp->mMapAvatarIDs.count())
#204
{
#205
show_as_friend = is_agent_friend(regionp->mMapAvatarIDs.get(i));
#206
}
在地图坐标上显示玩家。
#207
LLWorldMapView::drawAvatar(
#208
pos_map.mV[VX], pos_map.mV[VY],
#209
show_as_friend ? gFriendMapColor : gAvatarMapColor,
#210
pos_map.mV[VZ]);
#211
}
#212
}
#213
#214
// Draw dot for autopilot target
#215
if (gAgent.getAutoPilot())
#216
{
#217
drawTracking( gAgent.getAutoPilotTargetGlobal(), gTrackColor );
#218
}
#219
else
#220
{
#221
LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
#222
if ( LLTracker::TRACKING_AVATAR == tracking_status )
#223
{
#224
drawTracking( LLAvatarTracker::instance().getGlobalPos(), gTrackColor );
#225
}
#226
else if ( LLTracker::TRACKING_LANDMARK == tracking_status
#227
|| LLTracker::TRACKING_LOCATION == tracking_status )
#228
{
#229
drawTracking( LLTracker::getTrackedPositionGlobal(), gTrackColor );
#230
}
#231
}
#232
#233
// Draw dot for self avatar position
#234
//drawTracking( gAgent.getPosGlobalFromAgent(gAgent.getFrameAgent().getCenter()), gSelfMapColor );
#235
pos_global = gAgent.getPositionGlobal();
#236
pos_map = globalPosToView(pos_global);
#237
gl_draw_image(llround(pos_map.mV[VX]) - 4,
#238
llround(pos_map.mV[VY]) - 4,
#239
LLWorldMapView::sAvatarYouSmallImage,
#240
LLColor4::white);
#241
计算当前摄像机观看的视角。
#242
// Draw frustum
#243
F32 meters_to_pixels = gMiniMapScale/ gWorldPointer->getRegionWidthInMeters();
#244
#245
F32 horiz_fov = gCamera->getView() * gCamera->getAspect();
#246
F32 far_clip_meters = gCamera->getFar();
#247
F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
#248
#249
F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
#250
F32 half_width_pixels = half_width_meters * meters_to_pixels;
#251
#252
F32 ctr_x = (F32)center_sw_left;
#253
F32 ctr_y = (F32)center_sw_bottom;
#254
#255
#256
LLGLSNoTexture no_texture;
#257
旋转地图的显示。
#258
if( LLNetMap::sRotateMap )
#259
{
#260
gGL.color4fv(gFrustumMapColor.mV);
#261
#262
gGL.begin( GL_TRIANGLES );
#263
gGL.vertex2f( ctr_x, ctr_y );
#264
gGL.vertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels );
#265
gGL.vertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels );
#266
gGL.end();
#267
}
#268
else
#269
{
#270
gGL.color4fv(gRotatingFrustumMapColor.mV);
#271
#272
// If we don't rotate the map, we have to rotate the frustum.
#273
gGL.pushMatrix();
#274
gGL.translatef( ctr_x, ctr_y, 0 );
#275
glRotatef( atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
#276
gGL.begin( GL_TRIANGLES );
#277
gGL.vertex2f( 0, 0 );
#278
gGL.vertex2f( -half_width_pixels, far_clip_pixels );
#279
gGL.vertex2f( half_width_pixels, far_clip_pixels );
#280
gGL.end();
#281
gGL.popMatrix();
#282
}
#283
}
#284
下面显示
8个方向的文字提示。
#285
// Rotation of 0 means that North is up
#286
setDirectionPos( mTextBoxEast, rotation );
#287
setDirectionPos( mTextBoxNorth, rotation + F_PI_BY_TWO );
#288
setDirectionPos( mTextBoxWest, rotation + F_PI );
#289
setDirectionPos( mTextBoxSouth, rotation + F_PI + F_PI_BY_TWO );
#290
#291
setDirectionPos( mTextBoxNorthEast, rotation + F_PI_BY_TWO / 2);
#292
setDirectionPos( mTextBoxNorthWest, rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2);
#293
setDirectionPos( mTextBoxSouthWest, rotation + F_PI + F_PI_BY_TWO / 2);
#294
setDirectionPos( mTextBoxSouthEast, rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2);
#295
#296
LLUICtrl::draw();
#297 }
从上面的函数可以看到,先显示底层的边框,然后在上面显示水区域,接着显示建筑物层,最后在上面显示玩家所在的地方。当然还显示当前玩家所能看到的视角平面,显示地图八个方向的文字显示。
第二人生开发包提供,价格
198
元
/
套(含邮费)。
包括内容如下:
1.
《第二人生的源码分析》
PDF
文档。
2.
第二人生客户端源程序。
3.
2G
U
盘一个,主要用来拷贝源程序以及相关开发工具。
提供三个月的技术服务,
提供快速编译指导,比如通过
QQ
远程编译操作。
提供完整的书参考。
联系方式:
QQ:
9073204
MSN:
caimouse1976@sina.com
EMAIL:
ccaimouse@gmail.com
第二人生的源码分析(100)雷达地图详细显示