/** This function Draws the Window on the Output Screen */ void Window::DrawWindow() { if (!Visible) return; // no point in drawing invisible windows Video* video = core->GetVideoDriver(); Region clip( XPos, YPos, Width, Height ); //Frame && Changed if ( (Flags & (WF_FRAME|WF_CHANGED) ) == (WF_FRAME|WF_CHANGED) ) { Region screen( 0, 0, core->Width, core->Height ); video->SetScreenClip( NULL ); //removed this? video->DrawRect( screen, ColorBlack ); if (core->WindowFrames[0]) video->BlitSprite( core->WindowFrames[0], 0, 0, true ); if (core->WindowFrames[1]) video->BlitSprite( core->WindowFrames[1], core->Width - core->WindowFrames[1]->Width, 0, true ); if (core->WindowFrames[2]) video->BlitSprite( core->WindowFrames[2], (core->Width - core->WindowFrames[2]->Width) / 2, 0, true ); if (core->WindowFrames[3]) video->BlitSprite( core->WindowFrames[3], (core->Width - core->WindowFrames[3]->Width) / 2, core->Height - core->WindowFrames[3]->Height, true ); } video->SetScreenClip( &clip ); //Float || Changed bool bgRefreshed = false; if (BackGround && (Flags & (WF_FLOAT|WF_CHANGED) ) ) { DrawBackground(NULL); bgRefreshed = true; } std::vector< Control*>::iterator m; for (m = Controls.begin(); m != Controls.end(); ++m) { Control* c = *m; // FIXME: drawing BG in the same loop as controls can produce incorrect results with overlapping controls. the only case I know of this occuring it is ok due to no BG drawing // furthermore, overlapping controls are still a problem when NeedsDraw() returns false for the top control, but true for the bottom (see the level up icon on char portraits) // we will fix both issues later by refactoring with the concept of views and subviews if (BackGround && !bgRefreshed && !c->IsOpaque() && c->NeedsDraw()) { const Region& fromClip = c->ControlFrame(); DrawBackground(&fromClip); } if (Flags & (WF_FLOAT)) { // FIXME: this is a total hack. Required for anything drawing over GameControl (nothing really at all to do with floating) c->MarkDirty(); } c->Draw( XPos, YPos ); } if ( (Flags&WF_CHANGED) && (Visible == WINDOW_GRAYED) ) { Color black = { 0, 0, 0, 128 }; video->DrawRect(clip, black); } video->SetScreenClip( NULL ); Flags &= ~WF_CHANGED; }
/** This function Draws the Window on the Output Screen */ void Window::DrawWindow() { Video* video = core->GetVideoDriver(); Region clip( XPos, YPos, Width, Height ); //Frame && Changed if ( (Flags & (WF_FRAME|WF_CHANGED) )== (WF_FRAME|WF_CHANGED) ) { Region screen( 0, 0, core->Width, core->Height ); video->SetClipRect( NULL ); //removed this? Color black = { 0, 0, 0, 255 }; video->DrawRect( screen, black ); if (core->WindowFrames[0]) video->BlitSprite( core->WindowFrames[0], 0, 0, true ); if (core->WindowFrames[1]) video->BlitSprite( core->WindowFrames[1], core->Width - core->WindowFrames[1]->Width, 0, true ); if (core->WindowFrames[2]) video->BlitSprite( core->WindowFrames[2], (core->Width - core->WindowFrames[2]->Width) / 2, 0, true ); if (core->WindowFrames[3]) video->BlitSprite( core->WindowFrames[3], (core->Width - core->WindowFrames[3]->Width) / 2, core->Height - core->WindowFrames[3]->Height, true ); } else if (clip_regions.size()) { // clip drawing (we only do Background right now) for InvalidateForControl for (unsigned int i = 0; i < clip_regions.size(); i++) { Region to_clip = clip_regions[i]; to_clip.x += XPos; to_clip.y += YPos; video->SetClipRect(&to_clip); if (BackGround) { video->BlitSprite( BackGround, XPos, YPos, true ); } } } clip_regions.clear(); video->SetClipRect( &clip ); //Float || Changed if (BackGround && (Flags & (WF_FLOAT|WF_CHANGED) ) ) { video->BlitSprite( BackGround, XPos, YPos, true ); } std::vector< Control*>::iterator m; for (m = Controls.begin(); m != Controls.end(); ++m) { ( *m )->Draw( XPos, YPos ); } if ( (Flags&WF_CHANGED) && (Visible == WINDOW_GRAYED) ) { Color black = { 0, 0, 0, 128 }; video->DrawRect(clip, black); } video->SetClipRect( NULL ); Flags &= ~WF_CHANGED; }
// Draw fog on the small bitmap void MapControl::DrawFog(unsigned short XWin, unsigned short YWin) { Video *video = core->GetVideoDriver(); Region old_clip; video->GetClipRect(old_clip); Region r( XWin + XPos, YWin + YPos, Width, Height ); video->SetClipRect(&r); // FIXME: this is ugly, the knowledge of Map and ExploredMask // sizes should be in Map.cpp int w = MyMap->GetWidth() / 2; int h = MyMap->GetHeight() / 2; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { Point p( (short) (MAP_MULT * x), (short) (MAP_MULT * y) ); bool visible = MyMap->IsVisible( p, true ); if (! visible) { Region rgn = Region ( MAP_TO_SCREENX(MAP_DIV * x), MAP_TO_SCREENY(MAP_DIV * y), MAP_DIV, MAP_DIV ); video->DrawRect( rgn, colors[black] ); } } } video->SetClipRect(&old_clip); }
/** Draws the Control on the Output Display */ void TextEdit::DrawInternal(Region& rgn) { ieWord yOff = FontPosY; ieWord xOff = FontPosX; Video* video = core->GetVideoDriver(); if (Back) { // FIXME: temporary hack for PST map labels. // once subviews branch is merged this is not needed video->DrawRect(rgn, ColorBlack); video->BlitSprite( Back, rgn.x, rgn.y, true ); xOff += Back->XPos; yOff += Back->YPos; } else if (Text != L"") { // FIXME: temporary hack for PST map labels. // once subviews branch is merged this is not needed video->DrawRect(rgn, ColorBlack); } if (!font) { // no font was specified; happens with cheat input edits return; } //The aligning of textedit fields is done by absolute positioning (FontPosX, FontPosY) font->Print( Region( rgn.x + xOff, rgn.y + yOff, Width, Height ), Text, palette, Alignment ); if (hasFocus) { int w = font->StringSize(Text.substr(0, CurPos)).w; ieWord vcenter = (rgn.h / 2) + (Cursor->Height / 2); if (w > rgn.w) { int rows = (w / rgn.w); vcenter += rows * font->LineHeight; w = w - (rgn.w * rows); } video->BlitSprite(Cursor, w + rgn.x + xOff, yOff + vcenter + rgn.y, true); } }
void Picture::Draw( int relx, int rely ){ // DEBUG lines to see the difference between the Picture and the Image. Video* vid = Video::Instance(); // The Picture size vid->DrawRect( GetX()+relx, GetY()+rely, w,h, color.r,color.g,color.b,alpha ); /* // The Image if(bitmap!=NULL) vid->DrawRect( GetX()+relx+w/2 - bitmap->GetWidth()/2, GetY()+rely+h/2 - bitmap->GetHeight()/2, bitmap->GetWidth(), bitmap->GetHeight(), 1.0,1.0,1.0,0.1 ); */ if(bitmap!=NULL) bitmap->DrawFit( this->x+relx, this->y+rely, w, h, static_cast<float>(rotation)); }
/** Draws the Control on the Output Display */ void Button::DrawInternal(Region& rgn) { Video * video = core->GetVideoDriver(); // Button image if (!( Flags & IE_GUI_BUTTON_NO_IMAGE )) { Sprite2D* Image = NULL; switch (State) { case IE_GUI_BUTTON_UNPRESSED: case IE_GUI_BUTTON_LOCKED: case IE_GUI_BUTTON_LOCKED_PRESSED: Image = buttonImages[BUTTON_IMAGE_UNPRESSED]; break; case IE_GUI_BUTTON_FAKEPRESSED: case IE_GUI_BUTTON_PRESSED: Image = buttonImages[BUTTON_IMAGE_PRESSED]; break; case IE_GUI_BUTTON_SELECTED: Image = buttonImages[BUTTON_IMAGE_SELECTED]; break; case IE_GUI_BUTTON_DISABLED: case IE_GUI_BUTTON_FAKEDISABLED: Image = buttonImages[BUTTON_IMAGE_DISABLED]; break; } if (!Image) { Image = buttonImages[BUTTON_IMAGE_UNPRESSED]; } if (Image) { // FIXME: maybe it's useless... int xOffs = ( Width / 2 ) - ( Image->Width / 2 ); int yOffs = ( Height / 2 ) - ( Image->Height / 2 ); video->BlitSprite( Image, rgn.x + xOffs, rgn.y + yOffs, true ); } } if (State == IE_GUI_BUTTON_PRESSED) { //shift the writing/border a bit rgn.x += PushOffset.x; rgn.y += PushOffset.y; } // Button picture if (AnimPicture) { int xOffs = ( Width / 2 ) - ( AnimPicture->Width / 2 ); int yOffs = ( Height / 2 ) - ( AnimPicture->Height / 2 ); Region r( rgn.x + xOffs, rgn.y + yOffs, (int)(AnimPicture->Width * Clipping), AnimPicture->Height ); if (Flags & IE_GUI_BUTTON_CENTER_PICTURES) { video->BlitSprite( AnimPicture, rgn.x + xOffs + AnimPicture->XPos, rgn.y + yOffs + AnimPicture->YPos, true, &r ); } else { video->BlitSprite( AnimPicture, rgn.x + xOffs, rgn.y + yOffs, true, &r ); } } // Button picture int picXPos = 0, picYPos = 0; if (Picture && (Flags & IE_GUI_BUTTON_PICTURE) ) { // Picture is drawn centered picXPos = ( rgn.w / 2 ) - ( Picture->Width / 2 ) + rgn.x; picYPos = ( rgn.h / 2 ) - ( Picture->Height / 2 ) + rgn.y; if (Flags & IE_GUI_BUTTON_HORIZONTAL) { picXPos += Picture->XPos; picYPos += Picture->YPos; // Clipping: 0 = overlay over full button, 1 = no overlay int overlayHeight = Picture->Height * (1.0 - Clipping); if (overlayHeight < 0) overlayHeight = 0; if (overlayHeight >= Picture->Height) overlayHeight = Picture->Height; int buttonHeight = Picture->Height - overlayHeight; Region rb = Region(picXPos, picYPos, Picture->Width, buttonHeight); Region ro = Region(picXPos, picYPos + buttonHeight, Picture->Width, overlayHeight); video->BlitSprite( Picture, picXPos, picYPos, true, &rb ); // TODO: Add an option to add BLIT_GREY to the flags video->BlitGameSprite( Picture, picXPos, picYPos, BLIT_TINTED, SourceRGB, 0, 0, &ro, true); // do NOT uncomment this, you can't change Changed or invalidate things from // the middle of Window::DrawWindow() -- it needs moving to somewhere else //CloseUpColor(); } else { Region r( picXPos, picYPos, (int)(Picture->Width * Clipping), Picture->Height ); video->BlitSprite( Picture, picXPos + Picture->XPos, picYPos + Picture->YPos, true, &r ); } } // Composite pictures (paperdolls/description icons) if (!PictureList.empty() && (Flags & IE_GUI_BUTTON_PICTURE) ) { std::list<Sprite2D*>::iterator iter = PictureList.begin(); int xOffs = 0, yOffs = 0; if (Flags & IE_GUI_BUTTON_CENTER_PICTURES) { // Center the hotspots of all pictures xOffs = Width/2; yOffs = Height/2; } else if (Flags & IE_GUI_BUTTON_BG1_PAPERDOLL) { // Display as-is xOffs = 0; yOffs = 0; } else { // Center the first picture, and align the rest to that xOffs = Width/2 - (*iter)->Width/2 + (*iter)->XPos; yOffs = Height/2 - (*iter)->Height/2 + (*iter)->YPos; } for (; iter != PictureList.end(); ++iter) { video->BlitSprite( *iter, rgn.x + xOffs, rgn.y + yOffs, true ); } } // Button label if (hasText && ! ( Flags & IE_GUI_BUTTON_NO_TEXT )) { Palette* ppoi = normal_palette; int align = 0; if (State == IE_GUI_BUTTON_DISABLED) ppoi = disabled_palette; // FIXME: hopefully there's no button which sinks when selected // AND has text label //else if (State == IE_GUI_BUTTON_PRESSED || State == IE_GUI_BUTTON_SELECTED) { if (Flags & IE_GUI_BUTTON_ALIGN_LEFT) align |= IE_FONT_ALIGN_LEFT; else if (Flags & IE_GUI_BUTTON_ALIGN_RIGHT) align |= IE_FONT_ALIGN_RIGHT; else align |= IE_FONT_ALIGN_CENTER; if (Flags & IE_GUI_BUTTON_ALIGN_TOP) align |= IE_FONT_ALIGN_TOP; else if (Flags & IE_GUI_BUTTON_ALIGN_BOTTOM) align |= IE_FONT_ALIGN_BOTTOM; else align |= IE_FONT_ALIGN_MIDDLE; if (! (Flags & IE_GUI_BUTTON_MULTILINE)) { align |= IE_FONT_SINGLE_LINE; } Region r; if (Picture && (Flags & IE_GUI_BUTTON_PORTRAIT) == IE_GUI_BUTTON_PORTRAIT) { // constrain the label (status icons) to the picture bounds // FIXME: we are subtracting IE_FONT_PADDING because Font indents 5px, but we dont want that here r = Region(picXPos - IE_FONT_PADDING, picYPos + IE_FONT_PADDING, Picture->Width + IE_FONT_PADDING, Picture->Height); } else { r = Region( rgn.x, rgn.y, rgn.w - 2, rgn.h - 2); } font->Print( r, ( unsigned char * ) Text, ppoi, (ieByte) align, true ); } if (! (Flags&IE_GUI_BUTTON_NO_IMAGE)) { for (int i = 0; i < MAX_NUM_BORDERS; i++) { ButtonBorder *fr = &borders[i]; if (! fr->enabled) continue; Region r = Region( rgn.x + fr->dx1, rgn.y + fr->dy1, rgn.w - (fr->dx1 + fr->dx2 + 1), rgn.h - (fr->dy1 + fr->dy2 + 1) ); video->DrawRect( r, fr->color, fr->filled ); } } }
/** Draws the Control on the Output Display */ void MapControl::Draw(unsigned short XWin, unsigned short YWin) { if (!Width || !Height) { return; } if (Owner->Visible!=WINDOW_VISIBLE) { return; } if (Changed) { Realize(); Changed = false; } // we're going to paint over labels/etc, so they need to repaint! bool seen_this = false; unsigned int i; for (i = 0; i < Owner->GetControlCount(); i++) { Control *ctrl = Owner->GetControl(i); if (!ctrl) continue; // we could try working out which controls overlap, // but the later controls are cheap to paint.. if (ctrl == this) { seen_this = true; continue; } if (!seen_this) continue; ctrl->Changed = true; } Video* video = core->GetVideoDriver(); Region r( XWin + XPos, YWin + YPos, Width, Height ); if (MapMOS) { video->BlitSprite( MapMOS, MAP_TO_SCREENX(0), MAP_TO_SCREENY(0), true, &r ); } if (core->FogOfWar&FOG_DRAWFOG) DrawFog(XWin, YWin); Region vp = video->GetViewport(); vp.x = GAME_TO_SCREENX(vp.x); vp.y = GAME_TO_SCREENY(vp.y); vp.w = ViewWidth; vp.h = ViewHeight; if ((vp.x + vp.w) >= MAP_TO_SCREENX( Width )) vp.w = MAP_TO_SCREENX( Width ) - vp.x; if ((vp.y + vp.h) >= MAP_TO_SCREENY( Height )) vp.h = MAP_TO_SCREENY( Height ) - vp.y; video->DrawRect( vp, colors[green], false, false ); // Draw PCs' ellipses Game *game = core->GetGame(); i = game->GetPartySize(true); while (i--) { Actor* actor = game->GetPC( i, true ); if (MyMap->HasActor(actor) ) { video->DrawEllipse( (short) GAME_TO_SCREENX(actor->Pos.x), (short) GAME_TO_SCREENY(actor->Pos.y), 3, 2, actor->Selected ? colors[green] : colors[darkgreen], false ); } } // Draw Map notes, could be turned off in bg2 // we use the common control value to handle it, because then we // don't need another interface if (Value!=MAP_NO_NOTES) { i = MyMap -> GetMapNoteCount(); while (i--) { MapNote * mn = MyMap -> GetMapNote(i); Sprite2D *anim = Flag[mn->color&7]; Point pos = mn->Pos; if (convertToGame) { vp.x = GAME_TO_SCREENX(mn->Pos.x); vp.y = GAME_TO_SCREENY(mn->Pos.y); } else { //pst style vp.x = MAP_TO_SCREENX(mn->Pos.x); vp.y = MAP_TO_SCREENY(mn->Pos.y); pos.x = pos.x * MAP_MULT / MAP_DIV; pos.y = pos.y * MAP_MULT / MAP_DIV; } //Skip unexplored map notes bool visible = MyMap->IsVisible( pos, true ); if (!visible) continue; if (anim) { video->BlitSprite( anim, vp.x - anim->Width/2, vp.y - anim->Height/2, true, &r ); } else { video->DrawEllipse( (short) vp.x, (short) vp.y, 6, 5, colors[mn->color&7], false ); } } } }
/** Draws the Control on the Output Display */ void Button::Draw(unsigned short x, unsigned short y) { if (!Changed && !(Owner->Flags&WF_FLOAT) ) { return; } Changed = false; if (XPos == 65535 || Width == 0) { return; } Video * video = core->GetVideoDriver(); // Button image if (!( Flags & IE_GUI_BUTTON_NO_IMAGE )) { Sprite2D* Image = NULL; switch (State) { case IE_GUI_BUTTON_UNPRESSED: case IE_GUI_BUTTON_LOCKED: case IE_GUI_BUTTON_LOCKED_PRESSED: Image = Unpressed; break; case IE_GUI_BUTTON_SECOND: case IE_GUI_BUTTON_PRESSED: Image = Pressed; if (! Image) Image = Unpressed; break; case IE_GUI_BUTTON_SELECTED: Image = Selected; if (! Image) Image = Unpressed; break; case IE_GUI_BUTTON_DISABLED: case IE_GUI_BUTTON_THIRD: Image = Disabled; if (! Image) Image = Unpressed; break; } if (Image) { // FIXME: maybe it's useless... int xOffs = ( Width / 2 ) - ( Image->Width / 2 ); int yOffs = ( Height / 2 ) - ( Image->Height / 2 ); video->BlitSprite( Image, x + XPos + xOffs, y + YPos + yOffs, true ); } } if (State == IE_GUI_BUTTON_PRESSED) { //shift the writing/border a bit x+= 2; y+= 2; } // Button picture if (Picture && (Flags & IE_GUI_BUTTON_PICTURE) ) { // Picture is drawn centered int xOffs = ( Width / 2 ) - ( Picture->Width / 2 ); int yOffs = ( Height / 2 ) - ( Picture->Height / 2 ); if (Flags & IE_GUI_BUTTON_HORIZONTAL) { xOffs += x + XPos + Picture->XPos; yOffs += y + YPos + Picture->YPos; video->BlitSprite( Picture, xOffs, yOffs, true ); Region r = Region( xOffs, yOffs + (int) (Picture->Height * Clipping), Picture->Width, (int) (Picture->Height*(1.0 - Clipping)) ); video->DrawRect( r, SourceRGB, true ); // do NOT uncomment this, you can't change Changed or invalidate things from // the middle of Window::DrawWindow() -- it needs moving to somewhere else //CloseUpColor(); } else { Region r( x + XPos + xOffs, y + YPos + yOffs, (int)(Picture->Width * Clipping), Picture->Height ); video->BlitSprite( Picture, x + XPos + xOffs + Picture->XPos, y + YPos + yOffs + Picture->YPos, true, &r ); } } // Composite pictures (paperdolls/description icons) if (!PictureList.empty() && (Flags & IE_GUI_BUTTON_PICTURE) ) { std::list<Sprite2D*>::iterator iter = PictureList.begin(); int xOffs = 0, yOffs = 0; if (Flags & IE_GUI_BUTTON_CENTER_PICTURES) { // Center the hotspots of all pictures xOffs = Width/2; yOffs = Height/2; } else if (Flags & IE_GUI_BUTTON_BG1_PAPERDOLL) { // Display as-is xOffs = 0; yOffs = 0; } else { // Center the first picture, and align the rest to that xOffs = Width/2 - (*iter)->Width/2 + (*iter)->XPos; yOffs = Height/2 - (*iter)->Height/2 + (*iter)->YPos; } for (; iter != PictureList.end(); ++iter) { video->BlitSprite( *iter, x + XPos + xOffs, y + YPos + yOffs, true ); } } // Button picture if (AnimPicture) { int xOffs = ( Width / 2 ) - ( AnimPicture->Width / 2 ); int yOffs = ( Height / 2 ) - ( AnimPicture->Height / 2 ); Region r( x + XPos + xOffs, y + YPos + yOffs, (int)(AnimPicture->Width * Clipping), AnimPicture->Height ); if (Flags & IE_GUI_BUTTON_CENTER_PICTURES) { video->BlitSprite( AnimPicture, x + XPos + xOffs + AnimPicture->XPos, y + YPos + yOffs + AnimPicture->YPos, true, &r ); } else { video->BlitSprite( AnimPicture, x + XPos + xOffs, y + YPos + yOffs, true, &r ); } } // Button label if (hasText && ! ( Flags & IE_GUI_BUTTON_NO_TEXT )) { Palette* ppoi = normal_palette; int align = 0; if (State == IE_GUI_BUTTON_DISABLED) ppoi = disabled_palette; // FIXME: hopefully there's no button which sinks when selected // AND has text label //else if (State == IE_GUI_BUTTON_PRESSED || State == IE_GUI_BUTTON_SELECTED) { if (Flags & IE_GUI_BUTTON_ALIGN_LEFT) align |= IE_FONT_ALIGN_LEFT; else if (Flags & IE_GUI_BUTTON_ALIGN_RIGHT) align |= IE_FONT_ALIGN_RIGHT; else align |= IE_FONT_ALIGN_CENTER; if (Flags & IE_GUI_BUTTON_ALIGN_TOP) align |= IE_FONT_ALIGN_TOP; else if (Flags & IE_GUI_BUTTON_ALIGN_BOTTOM) align |= IE_FONT_ALIGN_BOTTOM; else align |= IE_FONT_ALIGN_MIDDLE; if (! (Flags & IE_GUI_BUTTON_MULTILINE)) { align |= IE_FONT_SINGLE_LINE; } font->Print( Region( x + XPos, y + YPos, Width - 2, Height - 2), ( unsigned char * ) Text, ppoi, (ieByte) align, true ); } if (! (Flags&IE_GUI_BUTTON_NO_IMAGE)) { for (int i = 0; i < MAX_NUM_BORDERS; i++) { ButtonBorder *fr = &borders[i]; if (! fr->enabled) continue; Region r = Region( x + XPos + fr->dx1, y + YPos + fr->dy1, Width - (fr->dx1 + fr->dx2 + 1), Height - (fr->dy1 + fr->dy2 + 1) ); video->DrawRect( r, fr->color, fr->filled ); } } }
void TileMap::DrawFogOfWar(ieByte* explored_mask, ieByte* visible_mask, Region viewport) { // viewport - pos & size of the control int w = XCellCount * CELL_RATIO; int h = YCellCount * CELL_RATIO; if (LargeMap) { w++; h++; } Color black = { 0, 0, 0, 255 }; Video* vid = core->GetVideoDriver(); Region vp = vid->GetViewport(); vp.w = viewport.w; vp.h = viewport.h; if (( vp.x + vp.w ) > w * CELL_SIZE) { vp.x = ( w * CELL_SIZE - vp.w ); } if (vp.x < 0) { vp.x = 0; } if (( vp.y + vp.h ) > h * CELL_SIZE) { vp.y = ( h * CELL_SIZE - vp.h ); } if (vp.y < 0) { vp.y = 0; } int sx = ( vp.x ) / CELL_SIZE; int sy = ( vp.y ) / CELL_SIZE; int dx = sx + vp.w / CELL_SIZE + 2; int dy = sy + vp.h / CELL_SIZE + 2; int x0 = sx * CELL_SIZE - vp.x; int y0 = sy * CELL_SIZE - vp.y; if (LargeMap) { x0 -= CELL_SIZE / 2; y0 -= CELL_SIZE / 2; dx++; dy++; } for (int y = sy; y < dy && y < h; y++) { for (int x = sx; x < dx && x < w; x++) { Region r = Region(x0 + viewport.x + ( (x - sx) * CELL_SIZE ), y0 + viewport.y + ( (y - sy) * CELL_SIZE ), CELL_SIZE, CELL_SIZE); if (! IS_EXPLORED( x, y )) { // Unexplored tiles are all black vid->DrawRect(r, black, true, true); continue; // Don't draw 'invisible' fog } else { // If an explored tile is adjacent to an // unexplored one, we draw border sprite // (gradient black <-> transparent) // Tiles in four cardinal directions have these // values. // // 1 // 2 8 // 4 // // Values of those unexplored are // added together, the resulting number being // an index of shadow sprite to use. For now, // some tiles are made 'on the fly' by // drawing two or more tiles int e = ! IS_EXPLORED( x, y - 1); if (! IS_EXPLORED( x - 1, y )) e |= 2; if (! IS_EXPLORED( x, y + 1 )) e |= 4; if (! IS_EXPLORED( x + 1, y )) e |= 8; switch (e) { case 1: case 2: case 3: case 4: case 6: case 8: case 9: case 12: FOG( e ); break; case 5: FOG( 1 ); FOG( 4 ); break; case 7: FOG( 3 ); FOG( 6 ); break; case 10: FOG( 2 ); FOG( 8 ); break; case 11: FOG( 3 ); FOG( 9 ); break; case 13: FOG( 9 ); FOG( 12 ); break; case 14: FOG( 6 ); FOG( 12 ); break; case 15: //this is black too vid->DrawRect(r, black, true, true); break; } } if (! IS_VISIBLE( x, y )) { // Invisible tiles are all gray FOG( 16 ); continue; // Don't draw 'invisible' fog } else { // If a visible tile is adjacent to an // invisible one, we draw border sprite // (gradient gray <-> transparent) // Tiles in four cardinal directions have these // values. // // 1 // 2 8 // 4 // // Values of those invisible are // added together, the resulting number being // an index of shadow sprite to use. For now, // some tiles are made 'on the fly' by // drawing two or more tiles int e = ! IS_VISIBLE( x, y - 1); if (! IS_VISIBLE( x - 1, y )) e |= 2; if (! IS_VISIBLE( x, y + 1 )) e |= 4; if (! IS_VISIBLE( x + 1, y )) e |= 8; switch (e) { case 1: case 2: case 3: case 4: case 6: case 8: case 9: case 12: FOG( 16 + e ); break; case 5: FOG( 16 + 1 ); FOG( 16 + 4 ); break; case 7: FOG( 16 + 3 ); FOG( 16 + 6 ); break; case 10: FOG( 16 + 2 ); FOG( 16 + 8 ); break; case 11: FOG( 16 + 3 ); FOG( 16 + 9 ); break; case 13: FOG( 16 + 9 ); FOG( 16 + 12 ); break; case 14: FOG( 16 + 6 ); FOG( 16 + 12 ); break; case 15: //this is unseen too FOG( 16 ); break; } } } } }