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
00029 #include "pgeventsupplier.h"
00030
00031 #include "global.h"
00032 #include "typen.h"
00033 #include "mapdisplay.h"
00034 #include "vehicletype.h"
00035 #include "buildingtype.h"
00036 #include "spfst.h"
00037 #include "dialog.h"
00038 #include "loaders.h"
00039 #include "gameoptions.h"
00040 #include "loadbi3.h"
00041 #include "mapalgorithms.h"
00042 #include "graphicset.h"
00043 #include "graphics/blitter.h"
00044 #include "graphics/drawing.h"
00045 #include "loadpcx.h"
00046 #include "iconrepository.h"
00047 #include "mainscreenwidget.h"
00048 #include "sdl/sound.h"
00049
00050 #ifndef karteneditor
00051 #include "dialogs/attackpanel.h"
00052 #endif
00053
00054
00055 #ifdef debugmapdisplay
00056 #include <iostream>
00057 #endif
00058
00059
00060 MapRenderer::Icons MapRenderer::icons;
00061
00062 bool tempsvisible = true;
00063
00064
00065 SigC::Signal0<void> lockMapdisplay;
00066 SigC::Signal0<void> unlockMapdisplay;
00067
00068
00069 class ContainerInfoLayer : public MapLayer {
00070 Surface& marker;
00071 bool hasCargo( const ContainerBase* c ) {
00072 for ( ContainerBase::Cargo::const_iterator i = c->getCargo().begin(); i != c->getCargo().end(); ++i )
00073 if ( *i )
00074 return true;
00075 return false;
00076 };
00077
00078 bool hasOwnCargo( const ContainerBase* c, int viewingPlayer ) {
00079 for ( ContainerBase::Cargo::const_iterator i = c->getCargo().begin(); i != c->getCargo().end(); ++i )
00080 if ( *i ) {
00081 if ( (*i)->getOwner() == viewingPlayer )
00082 return true;
00083 else
00084 if ( hasOwnCargo( *i, viewingPlayer ))
00085 return true;
00086 }
00087 return false;
00088 };
00089 public:
00090 ContainerInfoLayer() : marker( IconRepository::getIcon("fieldcontainermarker.png") ) {};
00091
00092 bool onLayer( int layer ) { return layer == 17; };
00093 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00094 };
00095
00096 void ContainerInfoLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00097 {
00098 if ( fieldInfo.visibility >= visible_ago) {
00099 if ( fieldInfo.fld->vehicle || (fieldInfo.fld->building && fieldInfo.fld->bdt.test(cbbuildingentry) )) {
00100 ContainerBase* c = fieldInfo.fld->getContainer();
00101 if ( hasCargo(c) ) {
00102 if ( c->getOwner() == fieldInfo.playerView )
00103 fieldInfo.surface.Blit( marker, pos );
00104 else
00105 if ( hasOwnCargo(c, fieldInfo.playerView ))
00106 fieldInfo.surface.Blit( marker, pos );
00107 }
00108 }
00109 }
00110 }
00111
00112
00113
00114 class ResourceGraphLayer : public MapLayer {
00115 void paintBar( const MapRenderer::FieldRenderInfo& fieldInfo, const SPoint& pos, int row, int amount, int color ) {
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 int length = amount * 28 / 255;
00126 int maxlength = 28;
00127 if ( amount )
00128 paintFilledRectangle<4>( fieldInfo.surface, SPoint( pos.x + 10, pos.y + 12 + row*15), length, 8, ColorMerger_ColoredOverwrite<4>( color ));
00129 if ( length < maxlength )
00130 paintFilledRectangle<4>( fieldInfo.surface, SPoint( pos.x + 10 + length, pos.y + 12 + row*15), maxlength-length, 8, ColorMerger_ColoredOverwrite<4>( 0 ));
00131
00132 };
00133 public:
00134 bool onLayer( int layer ) { return layer == 17; };
00135 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00136 };
00137
00138 void ResourceGraphLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00139 {
00140 #ifndef karteneditor
00141 if ( fieldInfo.visibility >= visible_ago) {
00142 bool visible = false;
00143
00144 if ( fieldInfo.playerView == -1 )
00145 visible = true;
00146
00147 if ( fieldInfo.playerView >= 0 )
00148 if ( fieldInfo.fld->resourceview && (fieldInfo.fld->resourceview->visible & ( 1 << fieldInfo.playerView) ) )
00149 visible = true;
00150
00151 if ( visible ) {
00152 if ( fieldInfo.playerView>=0 && fieldInfo.gamemap->getPlayer(fieldInfo.playerView).stat == Player::supervisor ) {
00153 paintBar( fieldInfo, pos, 0, fieldInfo.fld->material, Resources::materialColor );
00154 paintBar( fieldInfo, pos, 1, fieldInfo.fld->fuel, Resources::fuelColor );
00155 } else {
00156 paintBar( fieldInfo, pos, 0, fieldInfo.fld->resourceview->materialvisible[max(fieldInfo.playerView,0)], Resources::materialColor );
00157 paintBar( fieldInfo, pos, 1, fieldInfo.fld->resourceview->fuelvisible[max(fieldInfo.playerView,0)], Resources::fuelColor );
00158 }
00159 }
00160 }
00161 #else
00162 paintBar( fieldInfo, pos, 0, fieldInfo.fld->material, Resources::materialColor );
00163 paintBar( fieldInfo, pos, 1, fieldInfo.fld->fuel, Resources::fuelColor );
00164 #endif
00165 }
00166
00167
00168
00169
00170 class PipeLayer : public MapLayer {
00171 ObjectType* buried_pipeline;
00172 ObjectType* pipeline;
00173 bool isPipe( const ContainerBase* c ) {
00174 for ( ContainerBase::Cargo::const_iterator i = c->getCargo().begin(); i != c->getCargo().end(); ++i )
00175 if ( *i )
00176 return true;
00177 return false;
00178 };
00179
00180 bool isObjectPipeline( const ObjectType* obj )
00181 {
00182 if ( !obj )
00183 return false;
00184 return (obj->displayMethod <= 1 ) && obj->fieldModification[0].terrain_or.test( cbpipeline );
00185 }
00186
00187 public:
00188 PipeLayer() : buried_pipeline( NULL ), pipeline ( NULL )
00189 {
00190 pipeline = objectTypeRepository.getObject_byID( 3 );
00191 if ( !isObjectPipeline( pipeline ))
00192 pipeline = NULL;
00193
00194 for ( int i = 0; i < objectTypeRepository.getNum(); ++i ) {
00195 ObjectType* obj = objectTypeRepository.getObject_byPos( i );
00196 if (obj->displayMethod == 1 && obj->fieldModification[0].terrain_or.test( cbpipeline )) {
00197 buried_pipeline = obj;
00198 }
00199 if (obj->displayMethod == 0 && obj->fieldModification[0].terrain_or.test( cbpipeline ) && !pipeline) {
00200 pipeline = obj;
00201 }
00202 }
00203 }
00204
00205 bool onLayer( int layer ) { return layer == 17; };
00206 void paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos );
00207 };
00208
00209 void PipeLayer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00210 {
00211 if ( !pipeline )
00212 return;
00213
00214 if ( fieldInfo.visibility > visible_ago) {
00215 if ( fieldInfo.fld->building ) {
00216 pipeline->display( fieldInfo.surface, pos, 63, 0 );
00217 } else {
00218 if ( fieldInfo.fld->bdt.test( cbpipeline )) {
00219 Object* o = fieldInfo.fld->checkforobject( buried_pipeline );
00220 if ( o )
00221 pipeline->display( fieldInfo.surface, pos, o->dir, 0 );
00222 else {
00223 bool objfound = false;
00224 for ( tfield::ObjectContainer::iterator i = fieldInfo.fld->objects.begin(); i != fieldInfo.fld->objects.end(); ++i )
00225 if ( i->typ->fieldModification[0].terrain_or.test( cbpipeline ) ) {
00226 pipeline->display( fieldInfo.surface, pos, i->dir, 0 );
00227 objfound = true;
00228 break;
00229 }
00230
00231 if ( !objfound )
00232 pipeline->display( fieldInfo.surface, pos, 63, 0 );
00233
00234 }
00235 }
00236 }
00237 }
00238 }
00239
00240
00241 class WeaponRange : public SearchFields
00242 {
00243 public:
00244 int run ( const Vehicle* veh );
00245 void testfield ( const MapCoordinate& mc )
00246 {
00247 gamemap->getField( mc )->tempw = 1;
00248 };
00249 WeaponRange ( GameMap* _gamemap ) : SearchFields ( _gamemap )
00250 {}
00251 ;
00252 };
00253
00254 int WeaponRange :: run ( const Vehicle* veh )
00255 {
00256 int found = 0;
00257 if ( fieldvisiblenow ( getfield ( veh->xpos, veh->ypos )))
00258 for ( int i = 0; i < veh->typ->weapons.count; i++ ) {
00259 if ( veh->typ->weapons.weapon[i].shootable() ) {
00260 initsearch ( veh->getPosition(), veh->typ->weapons.weapon[i].maxdistance/minmalq, (veh->typ->weapons.weapon[i].mindistance+maxmalq-1)/maxmalq );
00261 startsearch();
00262 found++;
00263 }
00264 }
00265 return found;
00266 }
00267
00268
00269
00270
00271
00272 MapRenderer::ViewPort::ViewPort( int x1, int y1, int x2, int y2 )
00273 {
00274 this->x1 = x1;
00275 this->y1 = y1;
00276 this->x2 = x2;
00277 this->y2 = y2;
00278 };
00279
00280 MapRenderer::ViewPort::ViewPort()
00281 {
00282 };
00283
00284 MapRenderer :: MapRenderer()
00285 {
00286 readData();
00287 };
00288
00289
00290 void MapRenderer::readData()
00291 {
00292 if ( !icons.mapBackground.valid() ) {
00293 icons.mapBackground = IconRepository::getIcon("mapbkgr.raw");
00294 icons.notVisible = IconRepository::getIcon("hexinvis.raw");
00295 icons.markField = IconRepository::getIcon("markedfield.pcx");
00296 icons.markField.detectColorKey();
00297 icons.markFieldDark = IconRepository::getIcon("markedfielddark.png");
00298 }
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 int MapRenderer::bitmappedHeight2pass( int height )
00326 {
00327 return log2(height) * 2 + 2;
00328 }
00329
00330
00331 void MapRenderer::paintSingleField( const MapRenderer::FieldRenderInfo& fieldInfo, int layer, const SPoint& pos )
00332 {
00333
00334 int binaryUnitHeight = 0;
00335 if ( layer > 1 )
00336 if ( !(layer & 1 ))
00337 binaryUnitHeight = 1 << (( layer-2)/2);
00338
00339 tfield* fld = fieldInfo.fld;
00340
00341 if ( layer == 0 && fieldInfo.visibility >= visible_ago )
00342 fld->typ->paint ( fieldInfo.surface, pos );
00343
00344
00345 if ( fieldInfo.visibility > visible_ago ) {
00346
00347
00348 if ( fld->building && (fld->building->typ->buildingheight & binaryUnitHeight) && fld->building->visible )
00349 if ((fieldInfo.visibility == visible_all) || (fld->building->typ->buildingheight >= chschwimmend) || ( fld->building->getOwner() == fieldInfo.playerView ))
00350 fld->building->paintSingleField( fieldInfo.surface, pos, fld->building->getLocalCoordinate( fieldInfo.pos ));
00351
00352
00353
00354 if ( fld->vehicle && (fld->vehicle->height == binaryUnitHeight))
00355 if ( ( fld->vehicle->getOwner() == fieldInfo.playerView ) || (fieldInfo.visibility == visible_all) || ((fld->vehicle->height >= chschwimmend) && (fld->vehicle->height <= chhochfliegend)))
00356 fld->vehicle->paint( fieldInfo.surface, pos );
00357
00358 }
00359
00360
00361 if ( layer & 1 )
00362 for ( tfield::ObjectContainer::iterator o = fld->objects.begin(); o != fld->objects.end(); o++ ) {
00363 int h = o->typ->imageHeight;
00364 if ( fieldInfo.visibility > visible_ago || (o->typ->visibleago && fieldInfo.visibility >= visible_ago ))
00365 if ( h >= ((layer-1)/2)*30 && h < (layer-1)/2*30+30 )
00366 o->display ( fieldInfo.surface, pos, fld->getweather() );
00367 }
00368
00369
00370
00371
00372 if ( fieldInfo.visibility > visible_ago ) {
00373
00374
00375 if ( fieldInfo.visibility == visible_all )
00376 if ( !fld->mines.empty() && layer == 7 )
00377 fld->mines.begin()->paint( fieldInfo.surface, pos );
00378
00379
00380
00381
00382
00383 if ( layer == 18 ) {
00384 if ( fld->a.temp && tempsvisible )
00385 fieldInfo.surface.Blit( icons.markField, pos );
00386 else
00387 if ( fld->a.temp2 && tempsvisible )
00388 fieldInfo.surface.Blit( icons.markFieldDark, pos );
00389 }
00390
00391
00392 } else {
00393 if (fieldInfo.visibility == visible_ago ) {
00394 if ( fld->building && (fld->building->typ->buildingheight & binaryUnitHeight) && fld->building->visible )
00395 if ((fieldInfo.visibility == visible_all) || (fld->building->typ->buildingheight >= chschwimmend) || ( fld->building->getOwner() == fieldInfo.playerView ))
00396 fld->building->paintSingleField( fieldInfo.surface, pos, fld->building->getLocalCoordinate( fieldInfo.pos ));
00397
00398 }
00399 }
00400
00401
00402
00403 if ( layer == 18 ) {
00404 if ( fieldInfo.visibility == visible_ago) {
00405 MegaBlitter<1,colorDepth,ColorTransform_None,ColorMerger_AlphaShadow> blitter;
00406
00407 blitter.blit( icons.notVisible, fieldInfo.surface, pos);
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 } else
00419 if ( fieldInfo.visibility == visible_not) {
00420 fieldInfo.surface.Blit( icons.notVisible, pos );
00421
00422
00423
00424
00425
00426 }
00427
00428 }
00429
00430 for ( LayerRenderer::iterator i = layerRenderer.begin(); i != layerRenderer.end(); ++i )
00431 if ( (*i)->isActive() && (*i)->onLayer(layer))
00432 (*i)->paintSingleField( fieldInfo , layer, pos );
00433
00434 }
00435
00436
00437 void MapRenderer::paintBackground( Surface& surf, const ViewPort& viewPort )
00438 {
00439 for (int y= viewPort.y1; y < viewPort.y2; ++y )
00440 for ( int x=viewPort.x1; x < viewPort.x2; ++x )
00441 paintBackgroundField( surf, getFieldPos(x,y) );
00442 }
00443
00444 void MapRenderer::paintBackgroundField( Surface& surf, SPoint pos )
00445 {
00446 surf.Blit( icons.mapBackground, pos );
00447 }
00448
00449
00450
00451 void MapRenderer::paintTerrain( Surface& surf, GameMap* actmap, int playerView, const ViewPort& viewPort, const MapCoordinate& offset )
00452 {
00453 FieldRenderInfo fieldRenderInfo( surf, actmap );
00454 fieldRenderInfo.playerView = playerView;
00455
00456 GraphicSetManager::Instance().setActive ( actmap->graphicset );
00457
00458 for (int pass = 0; pass <= 18 ;pass++ ) {
00459 for (int y= viewPort.y1; y < viewPort.y2; ++y )
00460 for ( int x=viewPort.x1; x < viewPort.x2; ++x ) {
00461 fieldRenderInfo.pos = MapCoordinate( offset.x + x, offset.y + y );
00462 fieldRenderInfo.fld = actmap->getField ( fieldRenderInfo.pos );
00463 SPoint pos = getFieldPos(x,y);
00464 if ( fieldRenderInfo.fld ) {
00465 fieldRenderInfo.visibility = fieldVisibility ( fieldRenderInfo.fld, playerView );
00466 paintSingleField( fieldRenderInfo, pass, pos );
00467 } else
00468 if ( pass == 0 )
00469 paintBackgroundField( surf, pos );
00470
00471 }
00472 additionalItemDisplayHook( surf, pass );
00473 }
00474
00475 }
00476
00477
00478
00479 void benchMapDisplay()
00480 {
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 }
00497
00498
00499 MapDisplayPG* MapDisplayPG::theMapDisplay = NULL;
00500 MapDisplayPG* theGlobalMapDisplay = NULL;
00501
00502 MapDisplayPG::MapDisplayPG ( MainScreenWidget *parent, const PG_Rect r )
00503 : PG_Widget ( parent, r, false ) ,
00504 zoom(-1),
00505 surface(NULL),
00506 lastDisplayedMap(NULL),
00507 offset(0,0),
00508 dirty(Map),
00509 additionalUnit(NULL),
00510 disableKeyboardCursorMovement(false),
00511 signalPrio(0),
00512 cursor(this),
00513 lock(0)
00514 {
00515 SetDirtyUpdate(true);
00516 dataLoaderTicker();
00517
00518 readData();
00519
00520 dataLoaderTicker();
00521
00522 setNewZoom( CGameOptions::Instance()->mapzoom );
00523
00524 repaintMap.connect( SigC::slot( *this, &MapDisplayPG::updateWidget ));
00525
00526 PG_Application::GetApp()->sigKeyDown.connect( SigC::slot( *this, &MapDisplayPG::keyboardHandler ));
00527
00528 SetName( "THEMapDisplay");
00529
00530 dataLoaderTicker();
00531 SDL_Surface* ws = GetWidgetSurface ();
00532 if ( ws ) {
00533 Surface s = Surface::Wrap( ws );
00534 s.assignDefaultPalette();
00535 }
00536
00537 MapRenderer::additionalItemDisplayHook.connect( SigC::slot( *this, &MapDisplayPG::displayAddons ));
00538
00539 upperLeftSourceBlitCorner = SPoint( getFieldPosX(0,0), getFieldPosY(0,0));
00540
00541 theMapDisplay = this;
00542 theGlobalMapDisplay = this;
00543 dataLoaderTicker();
00544
00545 addMapLayer( new ResourceGraphLayer(), "resources" );
00546 addMapLayer( new ContainerInfoLayer(), "container" );
00547 addMapLayer( new PipeLayer() , "pipes" );
00548
00549 parent->lockOptionsChanged.connect( SigC::slot( *this, &MapDisplayPG::lockOptionsChanged ));
00550 GameMap::sigMapDeletion.connect( SigC::slot( *this, &MapDisplayPG::sigMapDeleted ));
00551 }
00552
00553
00554
00555 void MapDisplayPG::lockOptionsChanged( int options )
00556 {
00557 if ( options & MainScreenWidget::LockOptions::MapControl )
00558 EnableReceiver(false);
00559 else
00560 EnableReceiver(true);
00561 }
00562
00563 void MapDisplayPG::sigMapDeleted( GameMap& deletedMap )
00564 {
00565 if ( &deletedMap == lastDisplayedMap ) {
00566 paintBackground();
00567 Update();
00568 }
00569 }
00570
00571
00572 MapDisplayPG::~MapDisplayPG ()
00573 {
00574 if ( surface ) {
00575 delete surface;
00576 surface = NULL;
00577 }
00578 }
00579
00580
00581 MapDisplayPG::Icons MapDisplayPG::icons;
00582
00583
00584 void MapDisplayPG::readData()
00585 {
00586 if ( !icons.cursor.valid() ) {
00587 icons.cursor = IconRepository::getIcon( "curshex.raw" );
00588 icons.fieldShape = IconRepository::getIcon("hexinvis.raw");
00589 }
00590 }
00591
00592
00593 void MapDisplayPG::setNewZoom( int zoom )
00594 {
00595 if ( zoom > 100 )
00596 zoom = 100;
00597 if ( zoom < 20 )
00598 zoom = 20;
00599
00600 if ( zoom == this->zoom )
00601 return;
00602
00603 this->zoom = zoom;
00604
00605 field.numx = int( ceil(float(Width()) * 100 / zoom / fielddistx) );
00606 field.numy = int( ceil(float(Height()) * 100 / zoom / fielddisty) );
00607
00608 field.viewPort.x1 = -1;
00609 field.viewPort.y1 = -1;
00610 field.viewPort.x2 = field.numx + 1;
00611 field.viewPort.y2 = field.numy + 1;
00612
00613 if ( field.numy & 1 )
00614 field.numy += 1;
00615
00616 delete surface;
00617 surface = new Surface( Surface::createSurface ( field.numx * fielddistx + 2 * surfaceBorder, (field.numy - 1) * fielddisty + fieldysize + 2 * surfaceBorder, colorDepth*8 ));
00618
00619 dirty = Map;
00620 if ( zoom != CGameOptions::Instance()->mapzoom ) {
00621 CGameOptions::Instance()->mapzoom = zoom;
00622 CGameOptions::Instance()->setChanged();
00623 }
00624 newZoom( zoom );
00625 }
00626
00627
00628 void MapDisplayPG::fillSurface( int playerView )
00629 {
00630 checkViewPosition( offset );
00631 if ( !lock ) {
00632 paintTerrain( *surface, actmap, playerView, field.viewPort, offset );
00633 lastDisplayedMap = actmap;
00634 }
00635 else
00636 paintBackground();
00637 dirty = Curs;
00638 }
00639
00640 void MapDisplayPG::paintBackground( )
00641 {
00642 MapRenderer::paintBackground( *surface, field.viewPort );
00643 lastDisplayedMap = NULL;
00644 }
00645
00646
00647
00648 void MapDisplayPG::checkViewPosition( MapCoordinate& offset )
00649 {
00650 if ( offset.x + field.numx >= actmap->xsize +1 )
00651 offset.x = max(0,actmap->xsize - field.numx +1 );
00652
00653 if ( offset.y + field.numy >= actmap->ysize +4)
00654 offset.y = max(0,actmap->ysize - field.numy +4);
00655
00656 if ( offset.y & 1 )
00657 offset.y -= 1;
00658
00659 if ( offset.x < 0 )
00660 offset.x = 0;
00661
00662 if ( offset.y < 0 )
00663 offset.y = 0;
00664 }
00665
00666
00667
00668
00669 template<int pixelSize>
00670 class PixSel : public SourcePixelSelector_CacheZoom<pixelSize, SourcePixelSelector_DirectRectangle<pixelSize> >
00671 {}
00672 ;
00673
00674
00675 void MapDisplayPG::updateMap(bool force )
00676 {
00677 if ( !actmap )
00678 return;
00679
00680 if ( dirty > Curs || force )
00681 fillSurface( actmap->getPlayerView() );
00682 }
00683
00684 void MapDisplayPG::updateWidget()
00685 {
00686 updateMap(true);
00687 Update(true);
00688 }
00689
00690
00691
00692 void MapDisplayPG::blitInternalSurface( SDL_Surface* dest, const SPoint& pnt, const PG_Rect& dstClip )
00693 {
00694 if ( zoom != 100 ) {
00695 float fzoom = float(zoom) / 100.0;
00696 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,PixSel,TargetPixelSelector_Rect> blitter;
00697 blitter.setZoom( fzoom );
00698 blitter.initSource( *surface );
00699
00700
00701 blitter.setSrcRectangle( upperLeftSourceBlitCorner, int(float(Width()) / fzoom), int(float(Height()) / fzoom));
00702
00703 PG_Rect clip= dstClip.IntersectRect( dest->clip_rect );
00704 blitter.setTargetRect( clip );
00705
00706 Surface s = Surface::Wrap( dest );
00707 blitter.blit( *surface, s, SPoint(pnt.x, pnt.y ));
00708 } else {
00709 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_DirectRectangle,TargetPixelSelector_Rect> blitter;
00710 blitter.initSource( *surface );
00711
00712
00713 blitter.setSrcRectangle( upperLeftSourceBlitCorner, Width(), Height() );
00714
00715 PG_Rect clip= dstClip.IntersectRect( dest->clip_rect );
00716 blitter.setTargetRect( clip );
00717
00718 Surface s = Surface::Wrap( dest );
00719 blitter.blit( *surface, s, SPoint(pnt.x, pnt.y ));
00720 }
00721
00722 }
00723
00724
00725 void MapDisplayPG::displayCursor()
00726 {
00727 displayCursor( *this );
00728 }
00729
00730 void MapDisplayPG::displayCursor( const PG_Rect& dst )
00731 {
00732 if ( !actmap )
00733 return;
00734
00735 if ( dst.w <= 0 || dst.h <= 0 )
00736 return;
00737
00738 int x = cursor.pos().x - offset.x;
00739 int y = cursor.pos().y - offset.y;
00740 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 ) {
00741
00742 MegaBlitter<1,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_DirectZoom,TargetPixelSelector_Rect> blitter;
00743 blitter.setZoom( float(zoom) / 100.0 );
00744
00745 PG_Rect clip= dst.IntersectRect( PG_Application::GetScreen()->clip_rect );
00746
00747 if ( clip.w && clip.h ) {
00748 blitter.setTargetRect ( clip );
00749
00750 Surface s = Surface::Wrap( PG_Application::GetScreen() );
00751 SPoint pos = widget2screen ( internal2widget( mapViewPos2internalPos( MapCoordinate(x,y))));
00752 blitter.blit( icons.cursor, s, pos );
00753 }
00754 }
00755 }
00756
00757
00758 void MapDisplayPG::UpdateRect( const PG_Rect& rect )
00759 {
00760 SPoint p = widget2screen ( SPoint( rect.x, rect.y));
00761 PG_Rect sc ( p.x, p.y, rect.w, rect.h );
00762 sc = sc.IntersectRect( *this );
00763 eventBlit( GetWidgetSurface (), rect, sc );
00764 if ( sc.w && sc.h )
00765 PG_Application::UpdateRect(PG_Application::GetScreen(), sc.x, sc.y, sc.w, sc.h );
00766 }
00767
00768
00769 void MapDisplayPG::eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst)
00770 {
00771 if ( !GetWidgetSurface ()) {
00772 if ( dirty > Nothing )
00773 updateMap();
00774
00775 PG_Point pnt = ClientToScreen( 0,0 );
00776 blitInternalSurface( PG_Application::GetScreen(), SPoint(pnt.x,pnt.y), dst );
00777 } else {
00778 PG_Widget::eventBlit(srf,src,dst);
00779 }
00780
00781 if ( !cursor.invisible )
00782 displayCursor( dst );
00783
00784
00785 }
00786
00787
00788 SPoint MapDisplayPG::mapGlobalPos2internalPos ( const MapCoordinate& pos )
00789 {
00790 return getFieldPos( pos.x - offset.x, pos.y - offset.y );
00791 }
00792
00793 SPoint MapDisplayPG::mapViewPos2internalPos ( const MapCoordinate& pos )
00794 {
00795 return getFieldPos( pos.x, pos.y );
00796 }
00797
00798
00799 SPoint MapDisplayPG::internal2widget( const SPoint& pos )
00800 {
00801 return SPoint( int(ceil(float(pos.x - surfaceBorder) * zoom / 100.0)), int(ceil(float(pos.y - surfaceBorder) * zoom / 100.0)));
00802 }
00803
00804 SPoint MapDisplayPG::widget2screen( const SPoint& pos )
00805 {
00806 PG_Point p = ClientToScreen ( pos.x, pos.y );
00807 return SPoint ( p.x, p.y );
00808 }
00809
00810
00811 MapCoordinate MapDisplayPG::screenPos2mapPos( const SPoint& pos )
00812 {
00813 PG_Point pnt = ScreenToClient( pos.x, pos.y );
00814 if ( pnt.x >= 0 && pnt.y >= 0 && pnt.x < Width() && pnt.y < Height() )
00815 return widgetPos2mapPos ( SPoint( pnt.x, pnt.y ));
00816 else
00817 return MapCoordinate();
00818 }
00819
00820 MapCoordinate MapDisplayPG::widgetPos2mapPos( const SPoint& pos )
00821 {
00822 int x = int( float(pos.x) * 100 / zoom ) + surfaceBorder;
00823 int y = int( float(pos.y) * 100 / zoom ) + surfaceBorder;
00824
00825 for (int yy= field.viewPort.y1; yy < field.viewPort.y2; ++yy )
00826 for ( int xx=field.viewPort.x1; xx < field.viewPort.x2; ++xx ) {
00827 int x1 = getFieldPosX(xx,yy);
00828 int y1 = getFieldPosY(xx,yy);
00829 if ( x >= x1 && x < x1+ fieldsizex && y >= y1 && y < y1+fieldsizey )
00830 if ( icons.fieldShape.GetPixel(x-x1,y-y1) != 255 )
00831 return MapCoordinate(xx+offset.x,yy+offset.y);
00832 }
00833
00834 return MapCoordinate();
00835 }
00836
00837 MapCoordinate MapDisplayPG::upperLeftCorner()
00838 {
00839 return offset;
00840 }
00841
00842 MapCoordinate MapDisplayPG::lowerRightCorner()
00843 {
00844 return MapCoordinate( offset.x + field.numx , offset.y + field.numy );
00845 }
00846
00847
00848 bool MapDisplayPG::centerOnField( const MapCoordinate& mc )
00849 {
00850 if ( !(mc.valid() && mc.x < actmap->xsize && mc.y < actmap->ysize ))
00851 return false;
00852
00853 MapCoordinate newpos ( mc.x - field.numx / 2, mc.y - field.numy / 2 );
00854
00855 checkViewPosition( newpos );
00856
00857 if ( newpos != offset ) {
00858 offset = newpos;
00859 dirty = Map;
00860 Redraw();
00861 viewChanged();
00862 }
00863 return true;
00864
00865 }
00866
00867 void MapDisplayPG::redrawMapAtCursor ( const MapCoordinate& oldpos )
00868 {
00869 if ( oldpos.valid() ) {
00870 SPoint p = internal2widget( mapGlobalPos2internalPos( oldpos ));
00871 UpdateRect( PG_Rect( p.x, p.y, fieldsizex, fieldsizey ) );
00872 }
00873
00874 SPoint p = internal2widget( mapGlobalPos2internalPos( cursor.pos() ));
00875 UpdateRect( PG_Rect( p.x, p.y, fieldsizex, fieldsizey ) );
00876 }
00877
00878
00879 int MapDisplayPG::setSignalPriority( int priority )
00880 {
00881 int old = signalPrio;
00882 signalPrio = priority;
00883 return old;
00884 }
00885
00886 void filterQueuedZoomEvents()
00887 {
00888 SDL_Event event;
00889 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 ))
00890 PG_Application::GetEventSupplier()->PollEvent ( &event );
00891 }
00892
00893 bool MapDisplayPG::eventMouseButtonDown (const SDL_MouseButtonEvent *button)
00894 {
00895 MapCoordinate mc = screenPos2mapPos( SPoint(button->x, button->y));
00896
00897 if ( button->type == SDL_MOUSEBUTTONDOWN && button->button == CGameOptions::Instance()->mouse.zoomoutbutton ) {
00898 changeZoom( 10 );
00899
00900 MapCoordinate newpos = screenPos2mapPos( SPoint(button->x, button->y));
00901 MapCoordinate newOffset ( offset.x - ( newpos.x - mc.x ), offset.y - ( newpos.y - mc.y ));
00902 checkViewPosition( newOffset );
00903 offset = newOffset;
00904
00905 viewChanged();
00906 repaintMap();
00907 filterQueuedZoomEvents();
00908 return true;
00909 }
00910
00911 if ( button->type == SDL_MOUSEBUTTONDOWN && button->button == CGameOptions::Instance()->mouse.zoominbutton ) {
00912 changeZoom( -10 );
00913
00914 MapCoordinate newpos = screenPos2mapPos( SPoint(button->x, button->y));
00915 MapCoordinate newOffset ( offset.x - ( newpos.x - mc.x ), offset.y - ( newpos.y - mc.y ));
00916 checkViewPosition( newOffset );
00917 offset = newOffset;
00918
00919 viewChanged();
00920 repaintMap();
00921 filterQueuedZoomEvents();
00922 return true;
00923 }
00924
00925
00926 if ( !(mc.valid() && mc.x < actmap->xsize && mc.y < actmap->ysize ))
00927 return false;
00928
00929 if ( button->type == SDL_MOUSEBUTTONDOWN && button->button == CGameOptions::Instance()->mouse.fieldmarkbutton ) {
00930 MapCoordinate oldpos = cursor.pos();
00931 bool changed = cursor.pos() != mc;
00932 cursor.pos() = mc;
00933 cursor.invisible = 0;
00934 dirty = Curs;
00935
00936 updateFieldInfo();
00937
00938 if ( changed )
00939 redrawMapAtCursor( oldpos );
00940
00941 mouseButtonOnField( mc, SPoint(button->x, button->y), changed, button->button, signalPrio );
00942 return true;
00943
00944 }
00945
00946 if ( button->type == SDL_MOUSEBUTTONDOWN && button->button == CGameOptions::Instance()->mouse.centerbutton ) {
00947 return centerOnField( mc );
00948 }
00949
00950 mouseButtonOnField( mc, SPoint(button->x, button->y), false, button->button, signalPrio );
00951
00952 return false;
00953 }
00954
00955 bool MapDisplayPG::eventMouseMotion (const SDL_MouseMotionEvent *button)
00956 {
00957 MapCoordinate mc = screenPos2mapPos( SPoint(button->x, button->y));
00958 if ( !(mc.valid() && mc.x < actmap->xsize && mc.y < actmap->ysize ))
00959 return false;
00960
00961 if ( button->type == SDL_MOUSEMOTION && (button->state == SDL_BUTTON( CGameOptions::Instance()->mouse.fieldmarkbutton) )) {
00962 bool changed = cursor.pos() != mc;
00963 if ( changed ) {
00964 MapCoordinate oldpos = cursor.pos();
00965 cursor.pos() = mc;
00966 cursor.invisible = 0;
00967 dirty = Curs;
00968
00969 redrawMapAtCursor( oldpos );
00970 cursorMoved();
00971
00972 mouseDraggedToField( mc, SPoint(button->x, button->y), changed, signalPrio );
00973
00974 return true;
00975 }
00976 }
00977 return false;
00978 }
00979
00980
00981 bool MapDisplayPG::eventMouseButtonUp (const SDL_MouseButtonEvent *button)
00982 {
00983 return false;
00984 }
00985
00986
00987 bool MapDisplayPG::fieldCompletelyInViewX( const MapCoordinate& pos )
00988 {
00989 SPoint internal = mapGlobalPos2internalPos( pos);
00990 SPoint s = widget2screen( internal2widget( internal ));
00991 SPoint s2 = widget2screen( internal2widget( internal + SPoint(fieldsizex,fieldsizey) ));
00992 return s.x >= my_xpos && s2.x < my_xpos + my_width;
00993 }
00994
00995 bool MapDisplayPG::fieldCompletelyInViewY( const MapCoordinate& pos )
00996 {
00997 SPoint internal = mapGlobalPos2internalPos( pos);
00998 SPoint s = widget2screen( internal2widget( internal ));
00999 SPoint s2 = widget2screen( internal2widget( internal + SPoint(fieldsizex,fieldsizey) ));
01000 return s.y >= my_ypos && s2.y < my_ypos + my_height;
01001 }
01002
01003 bool MapDisplayPG::fieldCompletelyInView( const MapCoordinate& pos )
01004 {
01005
01006 SPoint internal = mapGlobalPos2internalPos( pos);
01007 SPoint s = widget2screen( internal2widget( internal ));
01008 SPoint s2 = widget2screen( internal2widget( internal + SPoint(fieldsizex,fieldsizey) ));
01009 return (s.y >= my_ypos && s2.y < my_ypos + my_height) && (s.x >= my_xpos && s2.x < my_xpos + my_width);
01010
01011 }
01012
01013
01014 bool MapDisplayPG::fieldInView(const MapCoordinate& mc )
01015 {
01016 if ( mc.x < offset.x || mc.y < offset.y || mc.x >= offset.x + field.numx || mc.y >= offset.y + field.numy || !fieldCompletelyInView(mc) )
01017 return false;
01018 else
01019 return true;
01020 }
01021
01022
01023
01024 Surface MapDisplayPG::createMovementBufferSurface()
01025 {
01026 Surface s = Surface::createSurface( 2*surfaceBorder + effectiveMovementSurfaceWidth, 2*surfaceBorder + effectiveMovementSurfaceHeight, 8*colorDepth, 0x00ffffff ) ;
01027 s.SetColorKey( SDL_SRCCOLORKEY, 0xffffff);
01028 return s;
01029 }
01030
01031
01032 void MapDisplayPG::initMovementStructure()
01033 {
01034 if ( !movementMask[0].mask.valid() )
01035 for ( int dir = 0; dir < sidenum; ++dir ) {
01036 movementMask[dir].mask = createMovementBufferSurface();
01037 MapCoordinate start;
01038 if ( dir >= 2 && dir <= 4 )
01039 start = MapCoordinate( 1, 2 );
01040 else
01041 start = MapCoordinate( 1, 4 );
01042
01043 MapCoordinate dest = getNeighbouringFieldCoordinate( start, dir );
01044
01045 for ( int i = 0; i < sidenum; ++i)
01046 movementMask[dir].mask.Blit( icons.fieldShape, getFieldPos2( getNeighbouringFieldCoordinate( start, i )));
01047 for ( int i = 0; i < sidenum; ++i)
01048 movementMask[dir].mask.Blit( icons.fieldShape, getFieldPos2( getNeighbouringFieldCoordinate( dest, i )));
01049
01050 SPoint pix = getFieldPos2( start );
01051 movementMask[dir].startFieldPos = pix;
01052
01053 pix.x += fieldsizex/2;
01054 pix.y += fieldsizey/2;
01055 movementMask[dir].mask.SetColorKey( SDL_SRCCOLORKEY, movementMask[dir].mask.GetPixel( pix ) & ~movementMask[dir].mask.GetPixelFormat().Amask());
01056 }
01057 }
01058
01059
01060 template<int pixelsize>
01061 class SourcePixelSelector_DirectSubRectangle
01062 {
01063 typedef typename PixelSize2Type<pixelsize>::PixelType PixelType;
01064 int x,y,x1,y1;
01065 int w,h;
01066 PG_Rect innerRect;
01067 int outerwidth;
01068
01069 const PixelType* pointer;
01070 const PixelType* startPointer;
01071 int pitch;
01072 int linelength;
01073 const Surface* surface;
01074 protected:
01075 SourcePixelSelector_DirectSubRectangle() : x(0),y(0),x1(0),y1(0),w(0),h(0),outerwidth(0),pointer(NULL), surface(NULL)
01076 {}
01077 ;
01078
01079 int getWidth()
01080 {
01081 return min(w, surface->w() -x1 );
01082 };
01083 int getHeight()
01084 {
01085 return min(h, surface->h()-y1 );
01086 };
01087
01088
01089 void init ( const Surface& srv )
01090 {
01091 surface = &srv;
01092 startPointer = pointer = (const PixelType*)(srv.pixels());
01093 linelength = srv.pitch()/sizeof(PixelType);
01094 pitch = linelength - w -1 ;
01095 y = y1;
01096 x = x1;
01097 pointer += x1 + y1 * linelength;
01098 outerwidth = getWidth();
01099 };
01100
01101 PixelType getPixel(int x, int y)
01102 {
01103 x += x1;
01104 y += y1;
01105 if ( x >= 0 && y >= 0 && x < surface->w() && y < surface->h() )
01106 return surface->GetPixel(SPoint(x,y));
01107 else
01108 return surface->GetPixelFormat().colorkey();
01109 };
01110
01111
01112 PixelType nextPixel()
01113 {
01114 ++x;
01115 return *(pointer++);
01116 };
01117
01118
01119 void skipWholeLine()
01120 {
01121 pointer += linelength;
01122 ++y;
01123 };
01124
01125 void skipPixels( int pixNum )
01126 {
01127 pointer += pixNum;
01128 x += pixNum;
01129 };
01130
01131 int getSourcePixelSkip()
01132 {
01133 if ( y < innerRect.y )
01134 return outerwidth - (x - x1);
01135 else
01136 if ( y >= innerRect.y + innerRect.h )
01137 return outerwidth - (x - x1);
01138 else
01139 if ( x < innerRect.x )
01140 return innerRect.x - x;
01141 else
01142 if ( x >= innerRect.x + innerRect.w )
01143 return outerwidth - (x - x1);
01144 else
01145 return 0;
01146
01147 };
01148
01149 void nextLine()
01150 {
01151 pointer = startPointer + x1 + (y++) * linelength;
01152 x = x1;
01153 };
01154
01155 public:
01156 void setSrcRectangle( SPoint pos, int width, int height )
01157 {
01158 x1 = pos.x;
01159 y1 = pos.y;
01160 w = width;
01161 h = height;
01162 };
01163 void setInnerSrcRectangle( const PG_Rect& rect )
01164 {
01165 innerRect = rect;
01166 };
01167
01168 };
01169
01170 template<int pixelSize>
01171 class MovePixSel : public SourcePixelSelector_CacheZoom<pixelSize, SourcePixelSelector_DirectSubRectangle<pixelSize> >
01172 {}
01173 ;
01174
01175
01176 void MapDisplayPG::displayMovementStep( Movement& movement, int percentage )
01177 {
01178 #ifdef debugmapdisplay
01179 surface->Fill( 0xff00ff00);
01180 #endif
01181
01182 FieldRenderInfo fieldRenderInfo( *surface, movement.veh->getMap() );
01183 fieldRenderInfo.playerView = movement.playerView;
01184 for (int pass = 0; pass <= 18 ;pass++ ) {
01185 for ( int i = 0; i < movement.actualFieldNum; ++i ) {
01186 SPoint pos = movement.touchedFields[i].surfPos;
01187 fieldRenderInfo.pos = movement.touchedFields[i].mapPos;
01188 fieldRenderInfo.fld = movement.actmap->getField ( fieldRenderInfo.pos );
01189 if ( fieldRenderInfo.fld ) {
01190 fieldRenderInfo.visibility = fieldVisibility ( fieldRenderInfo.fld, fieldRenderInfo.playerView );
01191
01192 paintSingleField( fieldRenderInfo, pass, pos );
01193 }
01194 }
01195
01196 if ( pass >= 2 && pass < 18 )
01197 if ( !(pass & 1 ))
01198 if ( movement.veh->height & (1 << (( pass-2)/2))) {
01199 SPoint pos;
01200 pos.x = movement.from.x + (movement.to.x - movement.from.x) * percentage/100;
01201 pos.y = movement.from.y + (movement.to.y - movement.from.y) * percentage/100;
01202 int shadow = 0;
01203 if ( movement.fromShadow >= 0 && movement.toShadow >= 0 )
01204 shadow = movement.fromShadow + (movement.toShadow - movement.fromShadow) * percentage/100;
01205 movement.veh->paint( *surface, pos, false, shadow );
01206 }
01207 }
01208
01209 #ifdef debugmapdisplay
01210 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_Plain,TargetPixelSelector_Valid> alphaBlitter;
01211 alphaBlitter.blit( *movement.mask, *surface, movement.maskPosition);
01212 #endif
01213
01214 PG_Rect targetArea ( widget2screen( SPoint( 0, 0 )).x, widget2screen( SPoint( 0, 0 )).y, Width(), Height() );
01215 Surface s = Surface::Wrap( PG_Application::GetScreen() );
01216
01217 #ifdef debugmapdisplay
01218 s.Fill( 0xff00ff );
01219 #endif
01220
01221 if ( zoom != 100 ) {
01222 float fzoom = float(zoom) / 100.0;
01223 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,MovePixSel,TargetPixelSelector_Rect> blitter;
01224 blitter.setZoom( fzoom );
01225 blitter.initSource( *surface );
01226
01227 blitter.setSrcRectangle( SPoint( getFieldPosX(0,0), getFieldPosY(0,0)), int(float(Width()) / fzoom), int(float(Height()) / fzoom));
01228 blitter.setInnerSrcRectangle( movement.blitViewPortInternal );
01229
01230 blitter.setTargetRect( targetArea );
01231 blitter.blit( *surface, s, movement.targetBlitPos );
01232 } else {
01233 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_DirectSubRectangle,TargetPixelSelector_Rect> blitter;
01234 blitter.initSource( *surface );
01235
01236 blitter.setSrcRectangle( SPoint( getFieldPosX(0,0), getFieldPosY(0,0)), Width(), Height() );
01237 blitter.setInnerSrcRectangle( movement.blitViewPortInternal );
01238
01239 blitter.setTargetRect( targetArea );
01240 blitter.blit( *surface, s, movement.targetBlitPos );
01241 }
01242
01243 #ifdef debugmapdisplay
01244 rectangle<4>( s, SPoint(targetArea.x, targetArea.y), targetArea.w, targetArea.h, ColorMerger_ColoredOverwrite<4>( 0x00ffff ), ColorMerger_ColoredOverwrite<4>( 0x00ffff ) );
01245 rectangle<4>( s, SPoint(movement.blitViewPortScreen.x, movement.blitViewPortScreen.y), movement.blitViewPortScreen.w, movement.blitViewPortScreen.h, ColorMerger_ColoredOverwrite<4>( 0x0000ff ), ColorMerger_ColoredOverwrite<4>( 0x0000ff ) );
01246 PG_Application::UpdateRect(PG_Application::GetScreen(), 0, 0, PG_Application::GetScreen()->w, PG_Application::GetScreen()->h );
01247 #else
01248 PG_Application::UpdateRect(PG_Application::GetScreen(), movement.blitViewPortScreen.x, movement.blitViewPortScreen.y, movement.blitViewPortScreen.w, movement.blitViewPortScreen.h );
01249 #endif
01250 }
01251
01252
01253
01254
01255
01256 bool ccompare( const MapCoordinate& a, const MapCoordinate& b )
01257 {
01258 return a.y < b.y || (a.y == b.y && a.x < b.x);
01259 }
01260
01261
01262 void MapDisplayPG::displayUnitMovement( GameMap* actmap, Vehicle* veh, const MapCoordinate3D& from, const MapCoordinate3D& to )
01263 {
01264 static int col = 0xff;
01265
01266 #ifdef debugmapdisplay
01267 col += 30;
01268 if ( col > 255 )
01269 col -= 255;
01270 #endif
01271
01272 surface->Fill( col << 8 );
01273
01274 if ( !fieldInView( from ) && !fieldInView( to ))
01275 return;
01276
01277 if ( from.x == to.x && from.y == to.y && from.getBitmappedHeight() <= chschwimmend && to.getBitmappedHeight() <=