00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <cmath>
00027 #include <limits>
00028 #include <sstream>
00029
00030 #include "pgeventsupplier.h"
00031
00032 #include "global.h"
00033 #include "typen.h"
00034 #include "mapdisplay.h"
00035 #include "vehicletype.h"
00036 #include "buildingtype.h"
00037 #include "spfst.h"
00038 #include "dialog.h"
00039 #include "loaders.h"
00040 #include "gameoptions.h"
00041 #include "loadbi3.h"
00042 #include "mapalgorithms.h"
00043 #include "graphicset.h"
00044 #include "graphics/blitter.h"
00045 #include "graphics/drawing.h"
00046 #include "loadpcx.h"
00047 #include "iconrepository.h"
00048 #include "mainscreenwidget.h"
00049 #include "sdl/sound.h"
00050 #include "spfst-legacy.h"
00051
00052 #ifndef karteneditor
00053 #include "dialogs/attackpanel.h"
00054 #endif
00055
00056
00057 #ifdef debugmapdisplay
00058 #include <iostream>
00059 #endif
00060
00061
00062 MapRenderer::Icons MapRenderer::icons;
00063
00064 bool tempsvisible = true;
00065
00066
00067 SigC::Signal0<void> lockMapdisplay;
00068 SigC::Signal0<void> unlockMapdisplay;
00069
00070
00071 class ContainerInfoLayer : public MapLayer {
00072 Surface& marker;
00073 bool hasCargo( const ContainerBase* c ) {
00074 for ( ContainerBase::Cargo::const_iterator i = c->getCargo().begin(); i != c->getCargo().end(); ++i )
00075 if ( *i )
00076 return true;
00077 return false;
00078 };
00079
00080 bool hasOwnCargo( const ContainerBase* c, int viewingPlayer ) {
00081 for ( ContainerBase::Cargo::const_iterator i = c->getCargo().begin(); i != c->getCargo().end(); ++i )
00082 if ( *i ) {
00083 if ( (*i)->getOwner() == viewingPlayer )
00084 return true;
00085 else
00086 if ( hasOwnCargo( *i, viewingPlayer ))
00087 return true;
00088 }
00089 return false;
00090 };
00091 public:
00092 ContainerInfoLayer() : marker( IconRepository::getIcon("fieldcontainermarker.png") ) {};
00093
00094 bool onLayer( int layer ) { return layer == 17; };
00095 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00096 };
00097
00098 void ContainerInfoLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00099 {
00100 if ( fieldInfo.visibility >= visible_ago) {
00101 if ( fieldInfo.fld->vehicle || (fieldInfo.fld->building && fieldInfo.fld->bdt.test(cbbuildingentry) )) {
00102 ContainerBase* c = fieldInfo.fld->getContainer();
00103 if ( hasCargo(c) ) {
00104 if ( c->getOwner() == fieldInfo.playerView )
00105 fieldInfo.surface.Blit( marker, pos );
00106 else
00107 if ( hasOwnCargo(c, fieldInfo.playerView ))
00108 fieldInfo.surface.Blit( marker, pos );
00109 }
00110 }
00111 }
00112 }
00113
00114
00115 class ResourceGraphLayer : public MapLayer {
00116 void paintBar( const MapRenderer::FieldRenderInfo& fieldInfo, const SPoint& pos, int row, int amount, int color ) {
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 int length = amount * 28 / 255;
00127 int maxlength = 28;
00128 if ( amount )
00129 paintFilledRectangle<4>( fieldInfo.surface, SPoint( pos.x + 10, pos.y + 12 + row*15), length, 8, ColorMerger_ColoredOverwrite<4>( color ));
00130 if ( length < maxlength )
00131 paintFilledRectangle<4>( fieldInfo.surface, SPoint( pos.x + 10 + length, pos.y + 12 + row*15), maxlength-length, 8, ColorMerger_ColoredOverwrite<4>( 0 ));
00132
00133 };
00134 public:
00135 bool onLayer( int layer ) { return layer == 17; };
00136 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00137 };
00138
00139 void ResourceGraphLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00140 {
00141 #ifndef karteneditor
00142 if ( fieldInfo.visibility >= visible_ago) {
00143 bool visible = false;
00144
00145 if ( fieldInfo.playerView == -1 )
00146 visible = true;
00147
00148 if ( fieldInfo.playerView >= 0 )
00149 if ( fieldInfo.fld->resourceview && (fieldInfo.fld->resourceview->visible & ( 1 << fieldInfo.playerView) ) )
00150 visible = true;
00151
00152 if ( visible ) {
00153 if ( fieldInfo.playerView>=0 && fieldInfo.gamemap->getPlayer(fieldInfo.playerView).stat == Player::supervisor ) {
00154 paintBar( fieldInfo, pos, 0, fieldInfo.fld->material, Resources::materialColor );
00155 paintBar( fieldInfo, pos, 1, fieldInfo.fld->fuel, Resources::fuelColor );
00156 } else {
00157 paintBar( fieldInfo, pos, 0, fieldInfo.fld->resourceview->materialvisible[max(fieldInfo.playerView,0)], Resources::materialColor );
00158 paintBar( fieldInfo, pos, 1, fieldInfo.fld->resourceview->fuelvisible[max(fieldInfo.playerView,0)], Resources::fuelColor );
00159 }
00160 }
00161 }
00162 #else
00163 paintBar( fieldInfo, pos, 0, fieldInfo.fld->material, Resources::materialColor );
00164 paintBar( fieldInfo, pos, 1, fieldInfo.fld->fuel, Resources::fuelColor );
00165 #endif
00166 }
00167
00168
00169
00170
00171 class PipeLayer : public MapLayer {
00172 ObjectType* buried_pipeline;
00173 ObjectType* pipeline;
00174 bool isPipe( const ContainerBase* c ) {
00175 for ( ContainerBase::Cargo::const_iterator i = c->getCargo().begin(); i != c->getCargo().end(); ++i )
00176 if ( *i )
00177 return true;
00178 return false;
00179 };
00180
00181 bool isObjectPipeline( const ObjectType* obj )
00182 {
00183 if ( !obj )
00184 return false;
00185 return (obj->displayMethod <= 1 ) && obj->fieldModification[0].terrain_or.test( cbpipeline );
00186 }
00187
00188 public:
00189 PipeLayer() : buried_pipeline( NULL ), pipeline ( NULL )
00190 {
00191 pipeline = objectTypeRepository.getObject_byID( 3 );
00192 if ( !isObjectPipeline( pipeline ))
00193 pipeline = NULL;
00194
00195 for ( int i = 0; i < objectTypeRepository.getNum(); ++i ) {
00196 ObjectType* obj = objectTypeRepository.getObject_byPos( i );
00197 if (obj->displayMethod == 1 && obj->fieldModification[0].terrain_or.test( cbpipeline )) {
00198 buried_pipeline = obj;
00199 }
00200 if (obj->displayMethod == 0 && obj->fieldModification[0].terrain_or.test( cbpipeline ) && !pipeline) {
00201 pipeline = obj;
00202 }
00203 }
00204 }
00205
00206 bool onLayer( int layer ) { return layer == 17; };
00207 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00208 };
00209
00210 void PipeLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00211 {
00212 if ( !pipeline )
00213 return;
00214
00215 if ( fieldInfo.visibility > visible_ago) {
00216 if ( fieldInfo.fld->building ) {
00217 pipeline->display( fieldInfo.surface, pos, 63, 0 );
00218 } else {
00219 if ( fieldInfo.fld->bdt.test( cbpipeline )) {
00220 Object* o = fieldInfo.fld->checkForObject( buried_pipeline );
00221 if ( o )
00222 pipeline->display( fieldInfo.surface, pos, o->dir, 0 );
00223 else {
00224 bool objfound = false;
00225 for ( MapField::ObjectContainer::iterator i = fieldInfo.fld->objects.begin(); i != fieldInfo.fld->objects.end(); ++i )
00226 if ( i->typ->fieldModification[0].terrain_or.test( cbpipeline ) ) {
00227 pipeline->display( fieldInfo.surface, pos, i->dir, 0 );
00228 objfound = true;
00229 break;
00230 }
00231
00232 if ( !objfound )
00233 pipeline->display( fieldInfo.surface, pos, 63, 0 );
00234
00235 }
00236 }
00237 }
00238 }
00239 }
00240
00241
00242
00243 class ReactionFireLayer : public MapLayer {
00244 Surface& image;
00245
00246 public:
00247 ReactionFireLayer() : image ( IconRepository::getIcon("rf-icon.png")) {} ;
00248 bool onLayer( int layer ) { return layer == 17; };
00249 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00250 };
00251
00252 void ReactionFireLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00253 {
00254 if ( fieldInfo.visibility > visible_ago) {
00255 if ( fieldInfo.fld->vehicle && fieldInfo.fld->vehicle->reactionfire.getStatus() != Vehicle::ReactionFire::off && fieldInfo.fld->vehicle->getOwner() == fieldInfo.playerView ) {
00256 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaMerge> blitter;
00257 blitter.blit( image, fieldInfo.surface, pos);
00258 }
00259 }
00260 }
00261
00262
00263 class UnitInfoLayer : public MapLayer {
00264
00265 Surface& image;
00266 void paintBar( const MapRenderer::FieldRenderInfo& fieldInfo, const SPoint& pos, int position, int max, int FromTop, int color, bool OverrideColor )
00267 {
00268 float FlLength = ((float)29 / (float)max * position);
00269 int length = int(floor(FlLength));
00270
00271 int paintcolor;
00272 if (OverrideColor == true) {
00273 if (length > 20)
00274 paintcolor = 0x00FF04;
00275 else if (length > 10)
00276 paintcolor = 0xFBFF00;
00277 else if (length >= 0)
00278 paintcolor = 0xFF0400;
00279 }
00280 else paintcolor = color;
00281 paintFilledRectangle<4>( fieldInfo.surface, SPoint( pos.x + 9 , pos.y + FromTop), length, 3, ColorMerger_ColoredOverwrite<4>( paintcolor ) );
00282 };
00283
00284
00285 public:
00286 UnitInfoLayer() : image ( IconRepository::getIcon("unitinfobg.png")) {} ;
00287 bool onLayer( int layer ) { return layer == 17; };
00288 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00289 };
00290
00291 void UnitInfoLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00292 {
00293
00294
00295 if ( fieldInfo.visibility > visible_ago) {
00296 if ( fieldInfo.fld->vehicle ) {
00297 if ( ( fieldInfo.fld->vehicle->getOwner() == fieldInfo.playerView ) || (fieldInfo.visibility == visible_all) || ((fieldInfo.fld->vehicle->height >= chschwimmend) && (fieldInfo.fld->vehicle->height <= chhochfliegend))) {
00298 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaMerge> blitter;
00299
00300 blitter.blit( image, fieldInfo.surface, pos);
00301
00302
00303 paintBar( fieldInfo, pos, 100-fieldInfo.fld->vehicle->damage, 100, 1, 0, true );
00304
00305 paintBar( fieldInfo, pos, fieldInfo.fld->vehicle->getTank().fuel, fieldInfo.fld->vehicle->getStorageCapacity().fuel, 4, 0xFFB700, false );
00306 }
00307 }
00308 }
00309 }
00310
00311
00312 class UnitTrainingLayer : public MapLayer {
00313
00314 public:
00315 bool onLayer( int layer ) { return layer == 17; };
00316 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00317 };
00318
00319
00320 void UnitTrainingLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00321 {
00322 if ( fieldInfo.visibility > visible_ago) {
00323 if ( fieldInfo.fld->vehicle ) {
00324 if ( ( fieldInfo.fld->vehicle->getOwner() == fieldInfo.playerView ) || (fieldInfo.visibility == visible_all) || ((fieldInfo.fld->vehicle->height >= chschwimmend) && (fieldInfo.fld->vehicle->height <= chhochfliegend))) {
00325
00326 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaMerge> blitter;
00327 ASCString training = "unitlevel-" + ASCString::toString(fieldInfo.fld->vehicle->experience+1) +".png";
00328 blitter.blit( IconRepository::getIcon(training), fieldInfo.surface, pos);
00329 }
00330
00331 }
00332 }
00333 }
00334
00335 class WeaponRange : public SearchFields
00336 {
00337 public:
00338 int run ( const Vehicle* veh );
00339 void testfield ( const MapCoordinate& mc )
00340 {
00341 gamemap->getField( mc )->tempw = 1;
00342 };
00343 WeaponRange ( GameMap* _gamemap ) : SearchFields ( _gamemap )
00344 {}
00345 ;
00346 };
00347
00348 int WeaponRange :: run ( const Vehicle* veh )
00349 {
00350 int found = 0;
00351 if ( fieldvisiblenow ( getfield ( veh->xpos, veh->ypos )))
00352 for ( int i = 0; i < veh->typ->weapons.count; i++ ) {
00353 if ( veh->typ->weapons.weapon[i].shootable() ) {
00354 initsearch ( veh->getPosition(), veh->typ->weapons.weapon[i].maxdistance/minmalq, (veh->typ->weapons.weapon[i].mindistance+maxmalq-1)/maxmalq );
00355 startsearch();
00356 found++;
00357 }
00358 }
00359 return found;
00360 }
00361
00362
00363
00364
00365
00366 MapRenderer::ViewPort::ViewPort( int x1, int y1, int x2, int y2 )
00367 {
00368 this->x1 = x1;
00369 this->y1 = y1;
00370 this->x2 = x2;
00371 this->y2 = y2;
00372 };
00373
00374 MapRenderer::ViewPort::ViewPort()
00375 {
00376 };
00377
00378 MapRenderer :: MapRenderer()
00379 {
00380 readData();
00381 };
00382
00383
00384 void MapRenderer::readData()
00385 {
00386 if ( !icons.mapBackground.valid() ) {
00387 icons.mapBackground = IconRepository::getIcon("mapbkgr.raw");
00388 icons.notVisible = IconRepository::getIcon("hexinvis.raw");
00389 icons.markField = IconRepository::getIcon("markedfield.png");
00390 icons.markField.detectColorKey();
00391 icons.markFieldDark = IconRepository::getIcon("markedfielddark.png");
00392 }
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 int MapRenderer::bitmappedHeight2pass( int height )
00420 {
00421 return getFirstBit(height) * 2 + 2;
00422 }
00423
00424
00425 void MapRenderer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00426 {
00427
00428 int binaryUnitHeight = 0;
00429 if ( layer > 1 )
00430 if ( !(layer & 1 ))
00431 binaryUnitHeight = 1 << (( layer-2)/2);
00432
00433 MapField* fld = fieldInfo.fld;
00434
00435 if ( layer == 0 && fieldInfo.visibility >= visible_ago )
00436 fld->typ->paint ( fieldInfo.surface, pos );
00437
00438
00439 if ( fieldInfo.visibility > visible_ago ) {
00440
00441
00442 if ( fld->building && (fld->building->typ->height & binaryUnitHeight) && fld->building->visible )
00443 if ((fieldInfo.visibility == visible_all) || (fld->building->typ->height >= chschwimmend) || ( fld->building->getOwner() == fieldInfo.playerView ))
00444 fld->building->paintSingleField( fieldInfo.surface, pos, fld->building->getLocalCoordinate( fieldInfo.pos ));
00445
00446
00447
00448 if ( fld->vehicle && (fld->vehicle->height == binaryUnitHeight))
00449 if ( ( fld->vehicle->getOwner() == fieldInfo.playerView ) || (fieldInfo.visibility == visible_all) || ((fld->vehicle->height >= chschwimmend) && (fld->vehicle->height <= chhochfliegend)))
00450 fld->vehicle->paint( fieldInfo.surface, pos );
00451
00452 }
00453
00454
00455 if ( layer & 1 )
00456 for ( MapField::ObjectContainer::iterator o = fld->objects.begin(); o != fld->objects.end(); o++ ) {
00457 int h = o->typ->imageHeight;
00458 if ( fieldInfo.visibility > visible_ago || (o->typ->visibleago && fieldInfo.visibility >= visible_ago ))
00459 if ( h >= ((layer-1)/2)*30 && h < (layer-1)/2*30+30 )
00460 o->display ( fieldInfo.surface, pos, fld->getWeather() );
00461 }
00462
00463
00464
00465
00466 if ( fieldInfo.visibility > visible_ago ) {
00467
00468
00469 if ( fieldInfo.visibility == visible_all )
00470 if ( !fld->mines.empty() && layer == 7 ) {
00471 for ( MapField::MineContainer::const_iterator i = fld->mines.begin(); i != fld->mines.end(); ++i )
00472 i->paint( fieldInfo.surface, pos );
00473 }
00474
00475
00476
00477
00478
00479 if ( layer == 18 ) {
00480 if ( fld->a.temp && tempsvisible )
00481 fieldInfo.surface.Blit( icons.markField, pos );
00482 else
00483 if ( fld->a.temp2 && tempsvisible )
00484 fieldInfo.surface.Blit( icons.markFieldDark, pos );
00485 }
00486
00487
00488 } else {
00489 if (fieldInfo.visibility == visible_ago ) {
00490 if ( fld->building && (fld->building->typ->height & binaryUnitHeight) && fld->building->visible )
00491 if ((fieldInfo.visibility == visible_all) || (fld->building->typ->height >= chschwimmend) || ( fld->building->getOwner() == fieldInfo.playerView ))
00492 fld->building->paintSingleField( fieldInfo.surface, pos, fld->building->getLocalCoordinate( fieldInfo.pos ));
00493
00494 }
00495 }
00496
00497
00498
00499 if ( layer == 18 ) {
00500 if ( fieldInfo.visibility == visible_ago) {
00501 MegaBlitter<1,colorDepth,ColorTransform_None,ColorMerger_AlphaShadow> blitter;
00502
00503 blitter.blit( icons.notVisible, fieldInfo.surface, pos);
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 } else
00515 if ( fieldInfo.visibility == visible_not) {
00516 fieldInfo.surface.Blit( icons.notVisible, pos );
00517
00518
00519
00520
00521
00522 }
00523
00524 }
00525
00526 for ( LayerRenderer::iterator i = layerRenderer.begin(); i != layerRenderer.end(); ++i )
00527 if ( (*i)->isActive() && (*i)->onLayer(layer))
00528 (*i)->paintSingleField( fieldInfo , layer, pos );
00529
00530 }
00531
00532
00533 void MapRenderer::paintBackground( Surface& surf, const ViewPort& viewPort )
00534 {
00535 for (int y= viewPort.y1; y < viewPort.y2; ++y )
00536 for ( int x=viewPort.x1; x < viewPort.x2; ++x )
00537 paintBackgroundField( surf, getFieldPos(x,y) );
00538 }
00539
00540 void MapRenderer::paintBackgroundField( Surface& surf, SPoint pos )
00541 {
00542 surf.Blit( icons.mapBackground, pos );
00543 }
00544
00545
00546
00547 void MapRenderer::paintTerrain( Surface& surf, GameMap* actmap, int playerView, const ViewPort& viewPort, const MapCoordinate& offset )
00548 {
00549 FieldRenderInfo fieldRenderInfo( surf, actmap );
00550 fieldRenderInfo.playerView = playerView;
00551
00552 GraphicSetManager::Instance().setActive ( actmap->graphicset );
00553
00554 for (int pass = 0; pass <= 18 ;pass++ ) {
00555 for (int y= viewPort.y1; y < viewPort.y2; ++y )
00556 for ( int x=viewPort.x1; x < viewPort.x2; ++x ) {
00557 fieldRenderInfo.pos = MapCoordinate( offset.x + x, offset.y + y );
00558 fieldRenderInfo.fld = actmap->getField ( fieldRenderInfo.pos );
00559 SPoint pos = getFieldPos(x,y);
00560 if ( fieldRenderInfo.fld ) {
00561 fieldRenderInfo.visibility = fieldVisibility ( fieldRenderInfo.fld, playerView );
00562 paintSingleField( fieldRenderInfo, pass, pos );
00563 } else
00564 if ( pass == 0 )
00565 paintBackgroundField( surf, pos );
00566
00567 }
00568 additionalItemDisplayHook( surf, pass );
00569 }
00570
00571 }
00572
00573
00574
00575 void benchMapDisplay()
00576 {
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 }
00593
00594
00595 MapDisplayPG* MapDisplayPG::theMapDisplay = NULL;
00596 MapDisplayPG* theGlobalMapDisplay = NULL;
00597
00598 MapDisplayPG::MapDisplayPG ( MainScreenWidget *parent, const PG_Rect r )
00599 : PG_Widget ( parent, r, false ) ,
00600 zoom(-1),
00601 surface(NULL),
00602 lastDisplayedMap(NULL),
00603 offset(0,0),
00604 dirty(Map),
00605 additionalUnit(NULL),
00606 disableKeyboardCursorMovement(false),
00607 signalPrio(0),
00608 cursor(this),
00609 lock(0)
00610 {
00611 SetDirtyUpdate(true);
00612 dataLoaderTicker();
00613
00614 readData();
00615
00616 dataLoaderTicker();
00617
00618 setNewZoom( CGameOptions::Instance()->mapzoom );
00619
00620 repaintMap.connect( SigC::slot( *this, &MapDisplayPG::updateWidget ));
00621
00622 PG_Application::GetApp()->sigKeyDown.connect( SigC::slot( *this, &MapDisplayPG::keyboardHandler ));
00623
00624 SetName( "THEMapDisplay");
00625
00626 dataLoaderTicker();
00627 SDL_Surface* ws = GetWidgetSurface ();
00628 if ( ws ) {
00629 Surface s = Surface::Wrap( ws );
00630 s.assignDefaultPalette();
00631 }
00632
00633 MapRenderer::additionalItemDisplayHook.connect( SigC::slot( *this, &MapDisplayPG::displayAddons ));
00634
00635 upperLeftSourceBlitCorner = SPoint( getFieldPosX(0,0), getFieldPosY(0,0));
00636
00637 theMapDisplay = this;
00638 theGlobalMapDisplay = this;
00639 dataLoaderTicker();
00640
00641 addMapLayer( new ResourceGraphLayer(), "resources" );
00642 addMapLayer( new ContainerInfoLayer(), "container" );
00643 addMapLayer( new PipeLayer() , "pipes" );
00644 addMapLayer( new ReactionFireLayer() , "reactionfire" );
00645 addMapLayer( new UnitInfoLayer() , "unitinfo" );
00646 addMapLayer( new UnitTrainingLayer() , "unittraining" );
00647
00648 parent->lockOptionsChanged.connect( SigC::slot( *this, &MapDisplayPG::lockOptionsChanged ));
00649 GameMap::sigMapDeletion.connect( SigC::slot( *this, &MapDisplayPG::sigMapDeleted ));
00650 }
00651
00652
00653
00654 void MapDisplayPG::lockOptionsChanged( int options )
00655 {
00656 if ( options & MainScreenWidget::LockOptions::MapControl )
00657 EnableReceiver(false);
00658 else
00659 EnableReceiver(true);
00660 }
00661
00662 void MapDisplayPG::sigMapDeleted( GameMap& deletedMap )
00663 {
00664 if ( &deletedMap == lastDisplayedMap ) {
00665 paintBackground();
00666 Update();
00667 }
00668 }
00669
00670
00671 MapDisplayPG::~MapDisplayPG ()
00672 {
00673 if ( surface ) {
00674 delete surface;
00675 surface = NULL;
00676 }
00677 }
00678
00679
00680 MapDisplayPG::Icons MapDisplayPG::icons;
00681
00682
00683 void MapDisplayPG::readData()
00684 {
00685 if ( !icons.cursor.valid() ) {
00686 icons.cursor = IconRepository::getIcon( "curshex.png" );
00687 icons.fieldShape = IconRepository::getIcon("hexinvis.raw");
00688 }
00689 }
00690
00691
00692 void MapDisplayPG::setNewZoom( int zoom )
00693 {
00694 if ( zoom > 100 )
00695 zoom = 100;
00696 if ( zoom < 20 )
00697 zoom = 20;
00698
00699 if ( zoom == this->zoom )
00700 return;
00701
00702 this->zoom = zoom;
00703
00704 field.numx = int( ceil(float(Width()) * 100 / zoom / fielddistx) );
00705 field.numy = int( ceil(float(Height()) * 100 / zoom / fielddisty) );
00706
00707 field.viewPort.x1 = -1;
00708 field.viewPort.y1 = -1;
00709 field.viewPort.x2 = field.numx + 1;
00710 field.viewPort.y2 = field.numy + 1;
00711
00712 if ( field.numy & 1 )
00713 field.numy += 1;
00714
00715 delete surface;
00716 surface = new Surface( Surface::createSurface ( field.numx * fielddistx + 2 * surfaceBorder, (field.numy - 1) * fielddisty + fieldysize + 2 * surfaceBorder, colorDepth*8 ));
00717
00718 dirty = Map;
00719 if ( zoom != CGameOptions::Instance()->mapzoom ) {
00720 CGameOptions::Instance()->mapzoom = zoom;
00721 CGameOptions::Instance()->setChanged();
00722 }
00723 newZoom( zoom );
00724 }
00725
00726
00727 void MapDisplayPG::fillSurface( int playerView )
00728 {
00729 checkViewPosition( offset );
00730 if ( !lock ) {
00731 paintTerrain( *surface, actmap, playerView, field.viewPort, offset );
00732 lastDisplayedMap = actmap;
00733 }
00734 else
00735 paintBackground();
00736 dirty = Curs;
00737 }
00738
00739 void MapDisplayPG::paintBackground( )
00740 {
00741 MapRenderer::paintBackground( *surface, field.viewPort );
00742 lastDisplayedMap = NULL;
00743 }
00744
00745
00746
00747 void MapDisplayPG::checkViewPosition( MapCoordinate& offset )
00748 {
00749 if ( offset.x + field.numx >= actmap->xsize +1 )
00750 offset.x = max(0,actmap->xsize - field.numx +1 );
00751
00752 if ( offset.y + field.numy >= actmap->ysize +4)
00753 offset.y = max(0,actmap->ysize - field.numy +4);
00754
00755 if ( offset.y & 1 )
00756 offset.y -= 1;
00757
00758 if ( offset.x < 0 )
00759 offset.x = 0;
00760
00761 if ( offset.y < 0 )
00762 offset.y = 0;
00763 }
00764
00765
00766
00767
00768 template<int pixelSize>
00769 class PixSel : public SourcePixelSelector_CacheZoom<pixelSize, SourcePixelSelector_DirectRectangle<pixelSize> >
00770 {}
00771 ;
00772
00773
00774 void MapDisplayPG::updateMap(bool force )
00775 {
00776 if ( !actmap )
00777 return;
00778
00779 if ( dirty > Curs || force )
00780 fillSurface( actmap->getPlayerView() );
00781 }
00782
00783 void MapDisplayPG::updateWidget()
00784 {
00785 updateMap(true);
00786 Update(true);
00787 }
00788
00789
00790
00791 void MapDisplayPG::blitInternalSurface( SDL_Surface* dest, const SPoint& pnt, const PG_Rect& dstClip )
00792 {
00793 if ( zoom != 100 ) {
00794 float fzoom = float(zoom) / 100.0;
00795 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,PixSel,TargetPixelSelector_Rect> blitter;
00796 blitter.setZoom( fzoom );
00797 blitter.initSource( *surface );
00798
00799
00800 blitter.setSrcRectangle( upperLeftSourceBlitCorner, int(float(Width()) / fzoom), int(float(Height()) / fzoom));
00801
00802 PG_Rect clip= dstClip.IntersectRect( dest->clip_rect );
00803 blitter.setTargetRect( clip );
00804
00805 Surface s = Surface::Wrap( dest );
00806 blitter.blit( *surface, s, SPoint(pnt.x, pnt.y ));
00807 } else {
00808 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_DirectRectangle,TargetPixelSelector_Rect> blitter;
00809 blitter.initSource( *surface );
00810
00811
00812 blitter.setSrcRectangle( upperLeftSourceBlitCorner, Width(), Height() );
00813
00814 PG_Rect clip= dstClip.IntersectRect( dest->clip_rect );
00815 blitter.setTargetRect( clip );
00816
00817 Surface s = Surface::Wrap( dest );
00818 blitter.blit( *surface, s, SPoint(pnt.x, pnt.y ));
00819 }
00820
00821 }
00822
00823
00824 void MapDisplayPG::displayCursor()
00825 {
00826 displayCursor( *this );
00827 }
00828
00829 void MapDisplayPG::displayCursor( const PG_Rect& dst )
00830 {
00831 if ( !actmap )
00832 return;
00833
00834 if ( dst.w <= 0 || dst.h <= 0 )
00835 return;
00836
00837 int x = cursor.pos().x - offset.x;
00838 int y = cursor.pos().y - offset.y;
00839 if( x >= field.viewPort.x1 && x < field.viewPort.x2 && y >= field.viewPort.y1 && y < field.viewPort.y2 && x >= 0 && y >= 0 && x < actmap->xsize && y < actmap->ysize ) {
00840
00841 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_DirectZoom,TargetPixelSelector_Rect> blitter;
00842 blitter.setZoom( float(zoom) / 100.0 );
00843
00844 PG_Rect clip= dst.IntersectRect( PG_Application::GetScreen()->clip_rect );
00845
00846 if ( clip.w && clip.h ) {
00847 blitter.setTargetRect ( clip );
00848
00849 Surface s = Surface::Wrap( PG_Application::GetScreen() );
00850 SPoint pos = widget2screen ( internal2widget( mapViewPos2internalPos( MapCoordinate(x,y))));
00851 blitter.blit( icons.cursor, s, pos );
00852 }
00853 }
00854 }
00855
00856
00857 void MapDisplayPG::UpdateRect( const PG_Rect& rect )
00858 {
00859 SPoint p = widget2screen ( SPoint( rect.x, rect.y));
00860 PG_Rect sc ( p.x, p.y, rect.w, rect.h );
00861 sc = sc.IntersectRect( *this );
00862 eventBlit( GetWidgetSurface (), rect, sc );
00863 if ( sc.w && sc.h )
00864 PG_Application::UpdateRect(PG_Application::GetScreen(), sc.x, sc.y, sc.w, sc.h );
00865 }
00866
00867
00868 void MapDisplayPG::eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst)
00869 {
00870 if ( !GetWidgetSurface ()) {
00871 if ( dirty > Nothing )
00872 updateMap();
00873
00874 PG_Point pnt = ClientToScreen( 0,0 );
00875 blitInternalSurface( PG_Application::GetScreen(), SPoint(pnt.x,pnt.y), dst );
00876 } else {
00877 PG_Widget::eventBlit(srf,src,dst);
00878 }
00879
00880 if ( !cursor.invisible )
00881 displayCursor( dst );
00882
00883
00884 }
00885
00886
00887 SPoint MapDisplayPG::mapGlobalPos2internalPos ( const MapCoordinate& pos )
00888 {
00889 return getFieldPos( pos.x - offset.x, pos.y - offset.y );
00890 }
00891
00892 SPoint MapDisplayPG::mapViewPos2internalPos ( const MapCoordinate& pos )
00893 {
00894 return getFieldPos( pos.x, pos.y );
00895 }
00896
00897
00898 SPoint MapDisplayPG::internal2widget( const SPoint& pos )
00899 {
00900 return SPoint( int(ceil(float(pos.x - surfaceBorder) * zoom / 100.0)), int(ceil(float(pos.y - surfaceBorder) * zoom / 100.0)));
00901 }
00902
00903 SPoint MapDisplayPG::widget2screen( const SPoint& pos )
00904 {
00905 PG_Point p = ClientToScreen ( pos.x, pos.y );
00906 return SPoint ( p.x, p.y );
00907 }
00908
00909
00910 MapCoordinate MapDisplayPG::screenPos2mapPos( const SPoint& pos )
00911 {
00912 PG_Point pnt = ScreenToClient( pos.x, pos.y );
00913 if ( pnt.x >= 0 && pnt.y >= 0 && pnt.x < Width() && pnt.y < Height() )
00914 return widgetPos2mapPos ( SPoint( pnt.x, pnt.y ));
00915 else
00916 return MapCoordinate();
00917 }
00918
00919 MapCoordinate MapDisplayPG::widgetPos2mapPos( const SPoint& pos )
00920 {
00921 int x = int( float(pos.x) * 100 / zoom ) + surfaceBorder;
00922 int y = int( float(pos.y) * 100 / zoom ) + surfaceBorder;
00923
00924 for (int yy= field.viewPort.y1; yy < field.viewPort.y2; ++yy )
00925 for ( int xx=field.viewPort.x1; xx < field.viewPort.x2; ++xx ) {
00926 int x1 = getFieldPosX(xx,yy);
00927 int y1 = getFieldPosY(xx,yy);
00928 if ( x >= x1 && x < x1+ fieldsizex && y >= y1 && y < y1+fieldsizey )
00929 if ( icons.fieldShape.GetPixel(x-x1,y-y1) != 255 )
00930 return MapCoordinate(xx+offset.x,yy+offset.y);
00931 }
00932
00933 return MapCoordinate();
00934 }
00935
00936 MapCoordinate MapDisplayPG::upperLeftCorner()
00937 {
00938 return offset;
00939 }
00940
00941 MapCoordinate MapDisplayPG::lowerRightCorner()
00942 {
00943 return MapCoordinate( offset.x + field.numx , offset.y + field.numy );
00944 }
00945
00946
00947 bool MapDisplayPG::centerOnField( const MapCoordinate& mc )
00948 {
00949 if ( !(mc.valid() && mc.x < actmap->xsize && mc.y < actmap->ysize ))
00950 return false;
00951
00952 MapCoordinate newpos ( mc.x - field.numx / 2, mc.y - field.numy / 2 );
00953
00954 checkViewPosition( newpos );
00955
00956 if ( newpos != offset ) {
00957 offset = newpos;
00958 dirty = Map;
00959 Redraw();
00960 viewChanged();
00961 }
00962 return true;
00963
00964 }
00965
00966 void MapDisplayPG::redrawMapAtCursor ( const MapCoordinate& oldpos )
00967 {
00968 if ( oldpos.valid() ) {
00969 SPoint p = internal2widget( mapGlobalPos2internalPos( oldpos ));
00970 UpdateRect( PG_Rect( p.x, p.y, fieldsizex, fieldsizey ) );
00971 }
00972
00973 SPoint p = internal2widget( mapGlobalPos2internalPos( cursor.pos() ));
00974 UpdateRect( PG_Rect( p.x, p.y, fieldsizex, fieldsizey ) );
00975 }
00976
00977
00978 int MapDisplayPG::setSignalPriority( int priority )
00979 {
00980 int old = signalPrio;
00981 signalPrio = priority;
00982 return old;
00983 }
00984
00985 void filterQueuedZoomEvents()
00986 {
00987 SDL_Event event;
00988 while ( PG_Application::GetEventSupplier()->PeepEvent(&event) && (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) && (event.button.button == CGameOptions::Instance()->mouse.zoomoutbutton || event.button.button == CGameOptions::Instance()->mouse.zoominbutton ))
00989 PG_Application::GetEventSupplier()->PollEvent ( &event );
00990 }
00991
00992 bool MapDisplayPG::eventMouseButtonDown (const SDL_MouseButtonEvent *button)
00993 {
00994 MapCoordinate mc = screenPos2mapPos( SPoint(button->x, button->y));
00995
00996 if ( button->type == SDL_MOUSEBUTTONDOWN && button->button == CGameOptions::Instance()->mouse.zoomoutbutton ) {
00997 changeZoom( 10 );
00998
00999 MapCoordinate newpos = screenPos2mapPos( SPoint(button->x, button->y));
01000 MapCoordinate newOffset ( offset.x - ( newpos.x - mc.x ), offset.y - ( newpos.y - mc.y ));
01001 checkViewPosition( newOffset );
01002 offset = newOffset;
01003
01004 viewChanged();
01005 repaintMap();
01006 filterQueuedZoomEvents();
01007 return true;
01008 }
01009
01010 if ( button->type == SDL_MOUSEBUTTONDOWN && button->button == CGameOptions::Instance()->mouse.zoominbutton ) {
01011 changeZoom( -10 );
01012
01013 MapCoordinate newpos = screenPos2mapPos( SPoint(button->x, button->y));
01014 MapCoordinate newOffset ( offset.x - ( newpos.x - mc.x ), offset.y - ( newpos.y - mc.y ));
01015 checkViewPosition( newOffset );
01016 offset = newOffset;
01017
01018 viewChanged();
01019 repaintMap();
01020 filterQueuedZoomEvents();
01021 return true;
01022 }
01023
01024
01025 if ( !(mc.valid() && mc.x < actmap->xsize && mc.y < actmap->ysize ))
01026 return false;
01027
01028 if ( button->type == SDL_MOUSEBUTTONDOWN && button->button == CGameOptions::Instance()->mouse.fieldmarkbutton ) {
01029 MapCoordinate oldpos = cursor.pos();
01030 bool changed = cursor.pos() != mc;
01031 cursor.pos() = mc;
01032 cursor.invisible = 0;
01033 dirty = Curs;
01034
01035 updateFieldInfo();
01036
01037 if ( changed )
01038 redrawMapAtCursor( oldpos );
01039
01040 mouseButtonOnField( mc, SPoint(button->x, button->y), changed, button->button, signalPrio );
01041 return true;
01042
01043 }
01044
01045 if ( button->type == SDL_MOUSEBUTTONDOWN && button->button == CGameOptions::Instance()->mouse.centerbutton ) {
01046 return centerOnField( mc );
01047 }
01048
01049 mouseButtonOnField( mc, SPoint(button->x, button->y), false, button->button, signalPrio );
01050
01051 return false;
01052 }
01053
01054 bool MapDisplayPG::eventMouseMotion (const SDL_MouseMotionEvent *button)
01055 {
01056 MapCoordinate mc = screenPos2mapPos( SPoint(button->x, button->y));
01057 if ( !(mc.valid() && mc.x < actmap->xsize && mc.y < actmap->ysize ))
01058 return false;
01059
01060 if ( button->type == SDL_MOUSEMOTION && (button->state == SDL_BUTTON( CGameOptions::Instance()->mouse.fieldmarkbutton) )) {
01061 bool changed = cursor.pos() != mc;
01062 if ( changed ) {
01063 MapCoordinate oldpos = cursor.pos();
01064 cursor.pos() = mc;
01065 cursor.invisible = 0;
01066 dirty = Curs;
01067
01068 redrawMapAtCursor( oldpos );
01069 cursorMoved();
01070
01071 mouseDraggedToField( mc, SPoint(button->x, button->y), changed, signalPrio );
01072
01073 return true;
01074 }
01075 }
01076 return false;
01077 }
01078
01079
01080 bool MapDisplayPG::eventMouseButtonUp (const SDL_MouseButtonEvent *button)
01081 {
01082 return false;
01083 }
01084
01085
01086 bool MapDisplayPG::fieldCompletelyInViewX( const MapCoordinate& pos )
01087 {
01088 SPoint internal = mapGlobalPos2internalPos( pos);
01089 SPoint s = widget2screen( internal2widget( internal ));
01090 SPoint s2 = widget2screen( internal2widget( internal + SPoint(fieldsizex,fieldsizey) ));
01091 return s.x >= my_xpos && s2.x < my_xpos + my_width;
01092 }
01093
01094 bool MapDisplayPG::fieldCompletelyInViewY( const MapCoordinate& pos )
01095 {
01096 SPoint internal = mapGlobalPos2internalPos( pos);
01097 SPoint s = widget2screen( internal2widget( internal ));
01098 SPoint s2 = widget2screen( internal2widget( internal + SPoint(fieldsizex,fieldsizey) ));
01099 return s.y >= my_ypos && s2.y < my_ypos + my_height;
01100 }
01101
01102 bool MapDisplayPG::fieldCompletelyInView( const MapCoordinate& pos )
01103 {
01104
01105 SPoint internal = mapGlobalPos2internalPos( pos);
01106 SPoint s = widget2screen( internal2widget( internal ));
01107 SPoint s2 = widget2screen( internal2widget( internal + SPoint(fieldsizex,fieldsizey) ));
01108 return (s.y >= my_ypos && s2.y < my_ypos + my_height) && (s.x >= my_xpos && s2.x < my_xpos + my_width);
01109
01110 }
01111
01112
01113 bool MapDisplayPG::fieldInView(const MapCoordinate& mc )
01114 {
01115 if ( mc.x < offset.x || mc.y < offset.y || mc.x >= offset.x + field.numx || mc.y >= offset.y + field.numy || !fieldCompletelyInView(mc) )
01116 return false;
01117 else
01118 return true;
01119 }
01120
01121
01122
01123 Surface MapDisplayPG::createMovementBufferSurface()
01124 {
01125 Surface s = Surface::createSurface( 2*surfaceBorder + effectiveMovementSurfaceWidth, 2*surfaceBorder + effectiveMovementSurfaceHeight, 8*colorDepth, 0x00ffffff ) ;
01126 s.SetColorKey( SDL_SRCCOLORKEY, 0xffffff);
01127 return s;
01128 }
01129
01130
01131 void MapDisplayPG::initMovementStructure()
01132 {
01133 if ( !movementMask[0].mask.valid() )
01134 for ( int dir = 0; dir < sidenum; ++dir ) {
01135 movementMask[dir].mask = createMovementBufferSurface();
01136 MapCoordinate start;
01137 if ( dir >= 2 && dir <= 4 )
01138 start = MapCoordinate( 1, 2 );
01139 else
01140 start = MapCoordinate( 1, 4 );
01141
01142 MapCoordinate dest = getNeighbouringFieldCoordinate( start, dir );
01143
01144 for ( int i = 0; i < sidenum; ++i)
01145 movementMask[dir].mask.Blit( icons.fieldShape, getFieldPos2( getNeighbouringFieldCoordinate( start, i )));
01146 for ( int i = 0; i < sidenum; ++i)
01147 movementMask[dir].mask.Blit( icons.fieldShape, getFieldPos2( getNeighbouringFieldCoordinate( dest, i )));
01148
01149 SPoint pix = getFieldPos2( start );
01150 movementMask[dir].startFieldPos = pix;
01151
01152 pix.x += fieldsizex/2;
01153 pix.y += fieldsizey/2;
01154 movementMask[dir].mask.SetColorKey( SDL_SRCCOLORKEY, movementMask[dir].mask.GetPixel( pix ) & ~movementMask[dir].mask.GetPixelFormat().Amask());
01155 }
01156 }
01157
01158
01159 template<int pixelsize>
01160 class SourcePixelSelector_DirectSubRectangle
01161 {
01162 typedef typename PixelSize2Type<pixelsize>::PixelType PixelType;
01163 int x,y,x1,y1;
01164 int w,h;
01165 PG_Rect innerRect;
01166 int outerwidth;
01167
01168 const PixelType* pointer;
01169 const PixelType* startPointer;
01170 int pitch;
01171 int linelength;
01172 const Surface* surface;
01173 protected:
01174 SourcePixelSelector_DirectSubRectangle() : x(0),y(0),x1(0),y1(0),w(0),h(0),outerwidth(0),pointer(NULL), surface(NULL)
01175 {}
01176 ;
01177
01178 int getWidth()
01179 {
01180 return min(w, surface->w() -x1 );
01181 };
01182 int getHeight()
01183 {
01184 return min(h, surface->h()-y1 );
01185 };
01186
01187
01188 void init ( const Surface& srv )
01189 {
01190 surface = &srv;
01191 startPointer = pointer = (const PixelType*)(srv.pixels());
01192 linelength = srv.pitch()/sizeof(PixelType);
01193 pitch = linelength - w -1 ;
01194 y = y1;
01195 x = x1;
01196 pointer += x1 + y1 * linelength;
01197 outerwidth = getWidth();
01198 };
01199
01200 PixelType getPixel(int x, int y)
01201 {
01202 x += x1;
01203 y += y1;
01204 if ( x >= 0 && y >= 0 && x < surface->w() && y < surface->h() )
01205 return surface->GetPixel(SPoint(x,y));
01206 else
01207 return surface->GetPixelFormat().colorkey();
01208 };
01209
01210
01211 PixelType nextPixel()
01212 {
01213 ++x;
01214 return *(pointer++);
01215 };
01216
01217
01218 void skipWholeLine()
01219 {
01220 pointer += linelength;
01221 ++y;
01222 };
01223
01224 void skipPixels( int pixNum )
01225 {
01226 pointer += pixNum;
01227 x += pixNum;
01228 };
01229
01230 int getSourcePixelSkip()
01231 {
01232 if ( y < innerRect.y )
01233 return outerwidth - (x - x1);
01234 else
01235 if ( y >= innerRect.y + innerRect.h )
01236 return outerwidth - (x - x1);
01237 else
01238 if ( x < innerRect.x )
01239 return innerRect.x - x;
01240 else
01241 if ( x >= innerRect.x + innerRect.w )
01242 return outerwidth - (x - x1);
01243 else
01244 return 0;
01245
01246 };
01247
01248 void nextLine()
01249 {
01250 pointer = startPointer + x1 + (y++) * linelength;
01251 x = x1;
01252 };
01253
01254 public:
01255 void setSrcRectangle( SPoint pos, int width, int height )
01256 {
01257 x1 = pos.x;
01258 y1 = pos.y;
01259 w = width;
01260 h = height;
01261 };
01262 void setInnerSrcRectangle( const PG_Rect& rect )
01263 {
01264 innerRect = rect;
01265 };
01266
01267 };
01268
01269 template<int pixelSize>
01270 class MovePixSel : public SourcePixelSelector_CacheZoom<pixelSize, SourcePixelSelector_DirectSubRectangle<pixelSize> >
01271 {}
01272 ;
01273
01274
01275 void MapDisplayPG::displayMovementStep( Movement& movement, int percentage )
01276 {
01277 #ifdef debugmapdisplay
01278 surface->Fill( 0xff00ff00);
01279 #endif
01280
01281 FieldRenderInfo fieldRenderInfo( *surface, movement.veh->getMap() );
01282 fieldRenderInfo.playerView = movement.playerView;
01283 for (int pass = 0; pass <= 18 ;pass++ ) {
01284 for ( int i = 0; i < movement.actualFieldNum; ++i ) {
01285 SPoint pos = movement.touchedFields[i].surfPos;
01286 fieldRenderInfo.pos = movement.touchedFields[i].mapPos;
01287 fieldRenderInfo.fld = movement.actmap->getField ( fieldRenderInfo.pos );
01288 if ( fieldRenderInfo.fld ) {
01289 fieldRenderInfo.visibility = fieldVisibility ( fieldRenderInfo.fld, fieldRenderInfo.playerView );
01290
01291 paintSingleField( fieldRenderInfo, pass, pos );
01292 }
01293 }
01294
01295 if ( pass >= 2 && pass < 18 )
01296 if ( !(pass & 1 ))
01297 if ( movement.veh->height & (1 << (( pass-2)/2))) {
01298 SPoint pos;
01299 pos.x = movement.from.x + (movement.to.x - movement.from.x) * percentage/100;
01300 pos.y = movement.from.y + (movement.to.y - movement.from.y) * percentage/100;
01301 int shadow = 0;
01302 if ( movement.fromShadow >= 0 && movement.toShadow >= 0 )
01303 shadow = movement.fromShadow + (movement.toShadow - movement.fromShadow) * percentage/100;
01304 movement.veh->paint( *surface, pos, false, shadow );
01305 }
01306 }
01307
01308 #ifdef debugmapdisplay
01309 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_Plain,TargetPixelSelector_Valid> alphaBlitter;
01310 alphaBlitter.blit( *movement.mask, *surface, movement.maskPosition);
01311 #endif
01312
01313 PG_Rect targetArea ( widget2screen( SPoint( 0, 0 )).x, widget2screen( SPoint( 0, 0 )).y, Width(), Height() );
01314 Surface s = Surface::Wrap( PG_Application::GetScreen() );
01315
01316 #ifdef debugmapdisplay
01317 s.Fill( 0xff00ff );
01318 #endif
01319
01320 if ( zoom != 100 ) {
01321 float fzoom = float(zoom) / 100.0;
01322 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,MovePixSel,TargetPixelSelector_Rect> blitter;
01323 blitter.setZoom( fzoom );
01324 blitter.initSource( *surface );
01325
01326 blitter.setSrcRectangle( SPoint( getFieldPosX(0,0), getFieldPosY(0,0)), int(float(Width()) / fzoom), int(float(Height()) / fzoom));
01327 blitter.setInnerSrcRectangle( movement.blitViewPortInternal );
01328
01329 blitter.setTargetRect( targetArea );
01330 blitter.blit( *surface, s, movement.targetBlitPos );
01331 } else {
01332 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_DirectSubRectangle,TargetPixelSelector_Rect> blitter;
01333 blitter.initSource( *surface );
01334
01335 blitter.setSrcRectangle( SPoint( getFieldPosX(0,0), getFieldPosY(0,0)), Width(), Height() );
01336 blitter.setInnerSrcRectangle( movement.blitViewPortInternal );
01337
01338 blitter.setTargetRect( targetArea );
01339 blitter.blit( *surface, s, movement.targetBlitPos );
01340 }
01341
01342 #ifdef debugmapdisplay
01343 rectangle<4>( s, SPoint(targetArea.x, targetArea.y), targetArea.w, targetArea.h, ColorMerger_ColoredOverwrite<4>( 0x00ffff ), ColorMerger_ColoredOverwrite<4>( 0x00ffff ) );
01344 rectangle<4>( s, SPoint(movement.blitViewPortScreen.x, movement.blitViewPortScreen.y), movement.blitViewPortScreen.w, movement.blitViewPortScreen.h, ColorMerger_ColoredOverwrite<4>( 0x0000ff ), ColorMerger_ColoredOverwrite<4>( 0x0000ff ) );
01345 PG_Application::UpdateRect(PG_Application::GetScreen(), 0, 0, PG_Application::GetScreen()->w, PG_Application::GetScreen()->h );
01346 #else
01347 PG_Application::UpdateRect(PG_Application::GetScreen(), movement.blitViewPortScreen.x, movement.blitViewPortScreen.y, movement.blitViewPortScreen.w, movement.blitViewPortScreen.h );
01348 #endif
01349 }
01350
01351
01352
01353
01354
01355 bool ccompare( const MapCoordinate& a, const MapCoordinate& b )
01356 {
01357 return a.y < b.y || (a.y == b.y && a.x < b.x);
01358 }
01359
01360
01361 void MapDisplayPG::displayUnitMovement( GameMap* actmap, Vehicle* veh, const MapCoordinate3D& from, const MapCoordinate3D& to, int duration )
01362 {
01363 static int col = 0xff;
01364
01365 #ifdef debugmapdisplay
01366 col += 30;
01367 if ( col > 255 )
01368 col -= 255;
01369 #endif
01370
01371 surface->Fill( col << 8 );
01372
01373 if ( !fieldInView( from ) && !fieldInView( to ))
01374 return;
01375
01376 if ( from.x == to.x && from.y == to.y && from.getBitmappedHeight() <= chschwimmend && to.getBitmappedHeight() <= chschwimmend )
01377
01378 return;
01379
01380 int startTime = ticker;
01381 int endTime = startTime + duration;
01382
01383
01384 initMovementStructure();
01385
01386 int dir = getdirection( from, to );
01387
01388 if ( from.x == to.x && from.y == to.y )
01389 dir = -1;
01390 else
01391 veh->direction = dir;
01392
01393 typedef vector< MapCoordinate > TouchedFields;
01394 TouchedFields touchedFields;
01395
01396 touchedFields.push_back ( from );
01397 for ( int ii = 0; ii < sidenum; ++ii ) {
01398 MapCoordinate p = getNeighbouringFieldCoordinate(from, ii);
01399 if ( fieldInView( p ) )
01400 touchedFields.push_back ( p );
01401 }
01402
01403 if ( dir != -1 ) {
01404 if ( fieldInView( to ))
01405 touchedFields.push_back ( to);
01406
01407 for ( int ii = 0; ii < sidenum; ++ii ) {
01408 MapCoordinate p = getNeighbouringFieldCoordinate(to, ii);
01409 if ( fieldInView( p ) )
01410 touchedFields.push_back ( p );
01411 }
01412 }
01413
01414
01415
01416
01417
01418 sort( touchedFields.begin(), touchedFields.end(), ccompare );
01419
01420 Movement movement;
01421 int i = 0;
01422 for ( TouchedFields::iterator j = touchedFields.begin(); j != touchedFields.end(); ++j ) {
01423 if ( i == 0 || movement.touchedFields[i-1].mapPos != *j ) {
01424 movement.touchedFields[i].mapPos = *j;
01425 movement.touchedFields[i].surfPos = mapGlobalPos2internalPos( *j );
01426 ++i;
01427 }
01428 }
01429 movement.actualFieldNum = i;
01430
01431 movement.veh = veh;
01432 movement.from = mapGlobalPos2internalPos( from );
01433 movement.to = mapGlobalPos2internalPos( to );
01434
01435 const int maxShadowWidth = 32;
01436 SPoint p1 = SPoint( min( movement.from.x, movement.to.x), min( movement.from.y, movement.to.y) );
01437 movement.blitViewPortInternal = PG_Rect( p1.x, p1.y, max( movement.from.x, movement.to.x) - p1.x + maxShadowWidth + fieldsizex,
01438 max( movement.from.y, movement.to.y) - p1.y + maxShadowWidth + fieldsizey );
01439
01440 movement.blitViewPortInternal = movement.blitViewPortInternal.IntersectRect( PG_Rect( 0, 0, surface->w(), surface->h() ) );
01441 movement.targetBlitPos = widget2screen ( SPoint( 0, 0));
01442 SPoint a = widget2screen( internal2widget( SPoint( movement.blitViewPortInternal.x, movement.blitViewPortInternal.y )));
01443 SPoint b = widget2screen( internal2widget( SPoint( movement.blitViewPortInternal.x + movement.blitViewPortInternal.w, movement.blitViewPortInternal.y + movement.blitViewPortInternal.h )));
01444
01445
01446 movement.blitViewPortScreen = PG_Rect( a.x, a.y, b.x - a.x + 1, b.y - a.y + 1 );
01447 movement.blitViewPortScreen = movement.blitViewPortScreen.IntersectRect( PG_Rect( 0, 0, PG_Application::GetScreenWidth(), PG_Application::GetScreenHeight() ));
01448
01449 movement.toShadow = ContainerBase::calcShadowDist( to.getNumericalHeight() );
01450 movement.fromShadow = ContainerBase::calcShadowDist( from.getNumericalHeight() );
01451
01452 movement.actmap = actmap;
01453
01454 if ( dir < 0 ) {
01455 movement.mask = &movementMask[0].mask;
01456 movement.maskPosition = mapGlobalPos2internalPos( from ) - movementMask[0].startFieldPos;
01457 } else {
01458 movement.mask = &movementMask[dir].mask;
01459 movement.maskPosition = mapGlobalPos2internalPos( from ) - movementMask[dir].startFieldPos;
01460 }
01461
01462 movement.playerView = actmap->getPlayerView();
01463
01464 int loopCounter = 0;
01465 #ifdef debugmapdisplay
01466 int loopStartTicker = ticker;
01467 #endif
01468
01469 while ( ticker < endTime ) {
01470 displayMovementStep( movement, (ticker - startTime) * 100 / duration );
01471 ++loopCounter;
01472 }
01473
01474 if( duration )
01475 displayMovementStep( movement, 100 );
01476
01477 #ifdef debugmapdisplay
01478 cout << (float(loopCounter) / float(ticker - loopStartTicker) * 100) << " / " << (float(loopCounter) / float(ticker - startTime) * 100) << " fps \n";
01479 #endif
01480 }
01481
01482 void MapDisplayPG::displayAddons( Surface& surf, int pass)
01483 {
01484 if( additionalUnit )
01485 if ( pass == bitmappedHeight2pass( additionalUnit->height ) ) {
01486 SPoint p = mapViewPos2internalPos( additionalUnit->getPosition() - offset );
01487 if ( p.x >= 0 && p.y >= 0 && p.x + fieldsizex + ContainerBase::calcShadowDist(getFirstBit(chsatellit)) < surf.w() && p.y + fieldsizey + ContainerBase::calcShadowDist(getFirstBit(chsatellit)) < surf.h() )
01488 additionalUnit->paint( surf, p, false, -1 );
01489 }
01490
01491 }
01492
01493 MapCoordinate& MapDisplayPG::Cursor::pos()
01494 {
01495 if ( actmap )
01496 return actmap->getCursor();
01497 else {
01498 static MapCoordinate mc;
01499 return mc;
01500 }
01501 }
01502
01503 void MapDisplayPG::scrollMap( int dir )
01504 {
01505 if ( !actmap )
01506 return;
01507
01508 MapCoordinate oldOffset = offset;
01509
01510 const int stepWidth = 2;
01511
01512
01513 if ( dir == 7 || dir == 0 || dir == 1 )
01514 offset.y -= 2 * stepWidth;
01515
01516 if ( dir >= 1 && dir <= 3 )
01517 offset.x += stepWidth;
01518
01519 if ( dir >= 3 && dir <= 5 )
01520 offset.y += 2 * stepWidth;
01521
01522 if ( dir >= 5 && dir <= 7)
01523 offset.x -= stepWidth;
01524
01525 checkViewPosition( offset );
01526
01527 if ( offset != oldOffset ) {
01528 dirty = Map;
01529 Update();
01530 viewChanged();
01531 }
01532 }
01533
01534
01535 void MapDisplayPG::moveCursor( int dir, int step )
01536 {
01537 MapCoordinate pos = cursor.pos();
01538
01539 switch ( dir ) {
01540 case 0: pos.y -= 2 * step;
01541 break;
01542 case 1: pos.y -= 1 * step;
01543 if ( !(pos.y & 1) )
01544 pos.x += 1 * step;
01545 break;
01546 case 2: if ( step & 1 ) {
01547 if ( pos.y & 1 ) {
01548 if ( pos.x < actmap->xsize-1 ) {
01549 pos.x += 1 * step;
01550 pos.y -= 1 * step;
01551 }
01552 } else
01553 pos.y += 1 * step;
01554 } else
01555 pos.x += step/2;
01556 break;
01557 case 3: pos.y += 1 * step;
01558 if ( !(pos.y & 1) )
01559 pos.x += 1 * step;
01560 break;
01561 case 4: pos.y += 2 * step;
01562 break;
01563 case 5: pos.y += 1 * step;
01564 if ( pos.y & 1 )
01565 pos.x -= 1 * step;
01566 break;
01567 case 6: if ( step & 1) {
01568 if ( pos.y & 1 ) {
01569 pos.y -= 1 * step;
01570 } else {
01571 if ( pos.x > 0 ) {
01572 pos.x -= 1 * step;
01573 pos.y += 1 * step;
01574 }
01575 }
01576 } else
01577 pos.x -= step/2;
01578 break;
01579 case 7: pos.y -= 1 * step;
01580 if ( pos.y & 1 )
01581 pos.x -= 1 * step;
01582 break;
01583 }
01584
01585 if ( pos.x >= actmap->xsize )
01586 pos.x = actmap->xsize -1;
01587
01588 if ( pos.x < 0 )
01589 pos.x = 0;
01590
01591 if ( pos.y >= actmap->ysize )
01592 pos.y = actmap->ysize -1;
01593
01594 if ( pos.y < 0 )
01595 pos.y = 0;
01596
01597 if ( pos != cursor.pos() ) {
01598 MapCoordinate oldpos = cursor.pos();
01599 cursor.invisible = 0;
01600 dirty = Curs;
01601
01602 cursor.pos() = pos;
01603
01604 MapCoordinate oldOffset = offset;
01605
01606 if ( pos.x < offset.x )
01607 offset.x = max( 0, pos.x );
01608
01609 if ( pos.y < offset.y )
01610 offset.y = min( 0, pos.y & ~1);
01611
01612 if ( pos.x > offset.x + field.numx - 2 || !fieldCompletelyInViewX( pos ))
01613 offset.x = pos.x - field.numx + 6;
01614
01615 if ( pos.y > offset.y + field.numy - 2 || !fieldCompletelyInViewY( pos ))
01616 offset.y = (pos.y - field.numy + 8) & ~1;
01617
01618 if ( offset != oldOffset )
01619 dirty = Map;
01620
01621 checkViewPosition( offset );
01622
01623 cursorMoved();
01624 if ( offset != oldOffset ) {
01625 Update();
01626 viewChanged();
01627 } else {
01628 redrawMapAtCursor( oldpos );
01629
01630
01631
01632
01633
01634
01635
01636 }
01637 }
01638 }
01639
01640
01641 bool MapDisplayPG::keyboardHandler( const SDL_KeyboardEvent* keyEvent)
01642 {
01643 if ( !keyEvent || !actmap )
01644 return false;
01645
01646 int keyStateNum;
01647 Uint8* keyStates = SDL_GetKeyState ( &keyStateNum );
01648
01649 if ( keyEvent->type == SDL_KEYDOWN ) {
01650 if ( !disableKeyboardCursorMovement ) {
01651 if ( keyEvent->keysym.sym == SDLK_RIGHT && keyStates[SDLK_RIGHT] ) {
01652 moveCursor(2, 1);
01653 return true;
01654 }
01655 if ( keyEvent->keysym.sym == SDLK_LEFT && keyStates[SDLK_LEFT] ) {
01656 moveCursor(6, 1);
01657 return true;
01658 }
01659 if ( (keyEvent->keysym.sym == SDLK_UP && keyStates[SDLK_UP] ) || ( keyEvent->keysym.sym == SDLK_KP8 && keyStates[SDLK_KP8] )) {
01660 moveCursor(0, 1);
01661 return true;
01662 }
01663 if ( (keyEvent->keysym.sym == SDLK_DOWN && keyStates[SDLK_DOWN]) || (keyEvent->keysym.sym == SDLK_KP2 && keyStates[SDLK_KP2] )) {
01664 moveCursor(4, 1);
01665 return true;
01666 }
01667 if ( keyEvent->keysym.sym == SDLK_KP6 && keyStates[SDLK_KP6] ) {
01668 moveCursor(2, 2);
01669 return true;
01670 }
01671 if ( keyEvent->keysym.sym == SDLK_KP4 && keyStates[SDLK_KP4] ) {
01672 moveCursor(6, 2);
01673 return true;
01674 }
01675 if ( keyEvent->keysym.sym == SDLK_KP7 && keyStates[SDLK_KP7] ) {
01676 moveCursor(7, 1);
01677 return true;
01678 }
01679 if ( keyEvent->keysym.sym == SDLK_KP9 && keyStates[SDLK_KP9]) {
01680 moveCursor(1, 1);
01681 return true;
01682 }
01683 if ( keyEvent->keysym.sym == SDLK_KP1 && keyStates[SDLK_KP1]) {
01684 moveCursor(5, 1);
01685 return true;
01686 }
01687 if ( keyEvent->keysym.sym == SDLK_KP3 && keyStates[SDLK_KP3]) {
01688 moveCursor(3, 1);
01689 return true;
01690 }
01691
01692 }
01693 }
01694 return false;
01695 }
01696
01697
01698 void MapDisplayPG::registerAdditionalUnit( Vehicle* veh )
01699 {
01700 additionalUnit = veh;
01701 }
01702
01703 void MapDisplayPG::addMapLayer( MapLayer* layer, const ASCString& name )
01704 {
01705 MapRenderer::addMapLayer( layer );
01706 layerMap[name] = layer;
01707 layer->setActive(false);
01708 }
01709
01710 void MapDisplayPG::activateMapLayer( const ASCString& name, bool active )
01711 {
01712 LayerMap::iterator i = layerMap.find( name );
01713 if ( i != layerMap.end() ) {
01714 i->second->setActive( active );
01715 layerChanged( active, name );
01716 }
01717 }
01718
01719 void MapDisplayPG::toggleMapLayer( const ASCString& name )
01720 {
01721 LayerMap::iterator i = layerMap.find( name );
01722 if ( i != layerMap.end() ) {
01723 i->second->setActive( !i->second->isActive() );
01724 layerChanged( i->second->isActive(), name );
01725 }
01726 }
01727
01728 bool MapDisplayPG::layerActive( const ASCString& name )
01729 {
01730 LayerMap::iterator i = layerMap.find( name );
01731 if ( i != layerMap.end() )
01732 return i->second->isActive();
01733 else
01734 return false;
01735 }
01736
01737
01738 void MapDisplayPG::getActiveLayers( vector<ASCString>& list )
01739 {
01740 list.clear();
01741 for ( LayerMap::iterator i = layerMap.begin(); i != layerMap.end(); ++i )
01742 if ( i->second->isActive() )
01743 list.push_back( i->first );
01744 }
01745
01746
01747
01748
01749 MapDisplayPG::CursorHiding::CursorHiding()
01750 {
01751 if ( theMapDisplay )
01752 ++theMapDisplay->cursor.invisible;
01753 }
01754
01755 MapDisplayPG::CursorHiding::~CursorHiding()
01756 {
01757 if ( theMapDisplay ) {
01758 --theMapDisplay->cursor.invisible;
01759 if ( !theMapDisplay->cursor.invisible )
01760 theMapDisplay->displayCursor();
01761 }
01762 }
01763
01764
01765 void MapDisplayPG::Cursor::goTo( const MapCoordinate& cursorPosition, const MapCoordinate& upperLeftScreenCorner )
01766 {
01767 bool redraw = false;
01768
01769 if ( upperLeftScreenCorner.valid() )
01770 if ( upperLeftScreenCorner != mapDisplay->offset ) {
01771 redraw = true;
01772 mapDisplay->offset = upperLeftScreenCorner;
01773 }
01774
01775 MapCoordinate oldpos = pos();
01776 if ( !mapDisplay->fieldInView( cursorPosition) )
01777 mapDisplay->centerOnField(cursorPosition);
01778
01779 pos()=cursorPosition;
01780
01781 if ( pos() != oldpos || redraw) {
01782 invisible = 0;
01783 mapDisplay->dirty = MapDisplayPG::Curs;
01784 mapDisplay->Update();
01785
01786 }
01787 }
01788
01789 void MapDisplayPG::Cursor::goTo( const MapCoordinate& position )
01790 {
01791 MapCoordinate oldpos = pos();
01792 if ( !mapDisplay->fieldInView( position) )
01793 mapDisplay->centerOnField(position);
01794 pos()=position;
01795
01796 if ( pos() != oldpos ) {
01797 invisible = 0;
01798 mapDisplay->dirty = MapDisplayPG::Curs;
01799 mapDisplay->Update();
01800
01801 }
01802
01803 }
01804
01805
01806
01807
01808
01809 int lockdisplaymap = 0;
01810
01811
01812
01813 void MapDisplayPG::LockDisplay::raiseLock()
01814 {
01815 if ( theMapDisplay ) {
01816 ++theMapDisplay->lock;
01817 theMapDisplay->dirty = Map;
01818 theMapDisplay->Update();
01819 }
01820 lockMapdisplay();
01821
01822 }
01823
01824
01825 MapDisplayPG::LockDisplay::LockDisplay( bool dummy ) : isDummy( dummy )
01826 {
01827 if ( !dummy )
01828 raiseLock();
01829 }
01830
01831 MapDisplayPG::LockDisplay::~LockDisplay()
01832 {
01833 if ( !isDummy ) {
01834 if ( theMapDisplay ) {
01835 --theMapDisplay->lock;
01836 if ( !theMapDisplay->lock ) {
01837 theMapDisplay->dirty = Map;
01838 theMapDisplay->Update();
01839 }
01840 }
01841 if ( !theMapDisplay->lock )
01842 unlockMapdisplay();
01843 }
01844 }
01845
01846
01847