static void DrawWallsAndThings(DrawBuffer *b, Vec2i offset) { Vec2i pos; Tile *tile = &b->tiles[0][0]; pos.y = b->dy + cWallOffset.dy + offset.y; for (int y = 0; y < Y_TILES; y++, pos.y += TILE_HEIGHT) { CArrayClear(&b->displaylist); pos.x = b->dx + cWallOffset.dx + offset.x; for (int x = 0; x < b->Size.x; x++, tile++, pos.x += TILE_WIDTH) { if (tile->flags & MAPTILE_IS_WALL) { if (!(tile->flags & MAPTILE_DELAY_DRAW)) { DrawWallColumn(y, pos, tile); } } else if (tile->flags & MAPTILE_OFFSET_PIC) { // Drawing doors // Doors may be offset; vertical doors are drawn centered // horizontal doors are bottom aligned Vec2i doorPos = pos; doorPos.x += (TILE_WIDTH - tile->picAlt->pic.size.x) / 2; if (tile->picAlt->pic.size.y > 16) { doorPos.y += TILE_HEIGHT - (tile->picAlt->pic.size.y % TILE_HEIGHT); } BlitMasked( &gGraphicsDevice, &tile->picAlt->pic, doorPos, GetTileLOSMask(tile), 0); } // Draw the items that are in LOS if (tile->flags & MAPTILE_OUT_OF_SIGHT) { continue; } CA_FOREACH(ThingId, tid, tile->things) const TTileItem *ti = ThingIdGetTileItem(tid); // Don't draw debris, they are drawn later if (TileItemIsDebris(ti)) { continue; } CArrayPushBack(&b->displaylist, &ti); CA_FOREACH_END() } DrawBufferSortDisplayList(b); CA_FOREACH(const TTileItem *, tp, b->displaylist) DrawThing(b, *tp, offset); CA_FOREACH_END() tile += X_TILES - b->Size.x; } }
static void DrawEditorTiles(DrawBuffer *b, Vec2i offset) { Vec2i pos; Tile *tile = &b->tiles[0][0]; pos.y = b->dy + offset.y; for (int y = 0; y < Y_TILES; y++, pos.y += TILE_HEIGHT) { pos.x = b->dx + offset.x; for (int x = 0; x < b->Size.x; x++, tile++, pos.x += TILE_WIDTH) { if (gMission.missionData->Type == MAPTYPE_STATIC) { Vec2i start = gMission.missionData->u.Static.Start; if (!Vec2iEqual(start, Vec2iZero()) && Vec2iEqual(start, Vec2iNew(x + b->xStart, y + b->yStart))) { // mission start BlitMasked( &gGraphicsDevice, PicManagerGetPic(&gPicManager, "editor/start"), pos, colorWhite, 1); } } } tile += X_TILES - b->Size.x; } }
static void DrawFloor(DrawBuffer *b, Vec2i offset) { int x, y; Vec2i pos; Tile *tile = &b->tiles[0][0]; for (y = 0, pos.y = b->dy + offset.y; y < Y_TILES; y++, pos.y += TILE_HEIGHT) { for (x = 0, pos.x = b->dx + offset.x; x < b->Size.x; x++, tile++, pos.x += TILE_WIDTH) { if (tile->pic != NULL && PicIsNotNone(tile->pic) && !(tile->flags & MAPTILE_IS_WALL)) { BlitMasked( &gGraphicsDevice, tile->pic, pos, GetTileLOSMask(tile), 0); } } tile += X_TILES - b->Size.x; } }
static void DrawBody(GraphicsDevice *g, const ActorPics *pics, const Vec2i pos) { const Pic *body = pics->Body; const Vec2i drawPos = Vec2iMinus(pos, Vec2iNew( body->size.x / 2, body->size.y / 2 + FOOT_OFFSET)); const color_t mask = pics->Mask != NULL ? *pics->Mask : colorWhite; BlitMasked(g, pics->Body, drawPos, mask, true); }
void DrawActorPics( const ActorPics *pics, const Vec2i picPos, const direction_e d) { if (pics->IsDead) { if (pics->IsDying) { DrawBody(&gGraphicsDevice, pics, picPos); } } else { // Draw shadow if (!pics->IsTransparent) { DrawShadow(&gGraphicsDevice, picPos, Vec2iNew(8, 6)); } for (int i = 0; i < 3; i++) { const Pic *picp = NULL; switch (pics->DrawOrder[i]) { case BODY_PART_HEAD: picp = pics->Head; break; case BODY_PART_BODY: picp = pics->Body; break; case BODY_PART_GUN: picp = pics->Gun; break; } if (picp == NULL) { continue; } const Vec2i drawPos = GetActorDrawOffset( picPos, picp, pics->DrawOrder[i], d); if (pics->IsTransparent) { BlitBackground( &gGraphicsDevice, picp, drawPos, pics->Tint, true); } else if (pics->Mask != NULL) { BlitMasked(&gGraphicsDevice, picp, drawPos, *pics->Mask, true); } else { BlitCharMultichannel( &gGraphicsDevice, picp, drawPos, pics->Colors); } } } }
void DrawWallColumn(int y, Vec2i pos, Tile *tile) { while (y >= 0 && (tile->flags & MAPTILE_IS_WALL)) { BlitMasked( &gGraphicsDevice, tile->pic, pos, GetTileLOSMask(tile), 0); pos.y -= TILE_HEIGHT; tile -= X_TILES; y--; } }
void CPicDraw( GraphicsDevice *g, const CPic *p, const Vec2i pos, const CPicDrawContext *context) { const Pic *pic = CPicGetPic(p, context->Dir); if (pic == NULL) { return; } const Vec2i picPos = Vec2iAdd(pos, context->Offset); if (p->UseMask) { BlitMasked(g, pic, picPos, p->u1.Mask, true); } else { BlitBackground(g, pic, picPos, &p->u1.Tint, true); } }
void DrawActorPics(const ActorPics *pics, const Vec2i pos) { if (pics->IsDead) { if (pics->IsDying) { DrawDyingBody(&gGraphicsDevice, pics, pos); } } else { // Draw shadow if (!pics->IsTransparent) { DrawShadow(&gGraphicsDevice, pos, Vec2iNew(8, 6)); } for (int i = 0; i < BODY_PART_COUNT; i++) { const Pic *pic = pics->OrderedPics[i]; if (pic == NULL) { continue; } const Vec2i drawPos = Vec2iAdd(pos, pics->OrderedOffsets[i]); if (pics->IsTransparent) { BlitBackground( &gGraphicsDevice, pic, drawPos, pics->Tint, true); } else if (pics->Mask != NULL) { BlitMasked(&gGraphicsDevice, pic, drawPos, *pics->Mask, true); } else { BlitCharMultichannel( &gGraphicsDevice, pic, drawPos, pics->Colors); } } } }
static void DrawFloor(DrawBuffer *b, Vec2i offset) { int x, y; Vec2i pos; const Tile *tile = &b->tiles[0][0]; const bool useFog = ConfigGetBool(&gConfig, "Game.Fog"); for (y = 0, pos.y = b->dy + offset.y; y < Y_TILES; y++, pos.y += TILE_HEIGHT) { for (x = 0, pos.x = b->dx + offset.x; x < b->Size.x; x++, tile++, pos.x += TILE_WIDTH) { if (tile->pic != NULL && tile->pic->pic.Data != NULL && !(tile->flags & MAPTILE_IS_WALL)) { switch (GetTileLOS(tile, useFog)) { case TILE_LOS_NORMAL: Blit(&gGraphicsDevice, &tile->pic->pic, pos); break; case TILE_LOS_FOG: BlitMasked( &gGraphicsDevice, &tile->pic->pic, pos, colorFog, false); break; case TILE_LOS_NONE: default: // don't draw break; } } } tile += X_TILES - b->Size.x; } }
void DrawWallColumn(int y, Vec2i pos, Tile *tile) { const bool useFog = ConfigGetBool(&gConfig, "Game.Fog"); while (y >= 0 && (tile->flags & MAPTILE_IS_WALL)) { switch (GetTileLOS(tile, useFog)) { case TILE_LOS_NORMAL: Blit(&gGraphicsDevice, &tile->pic->pic, pos); break; case TILE_LOS_FOG: BlitMasked(&gGraphicsDevice, &tile->pic->pic, pos, colorFog, false); break; case TILE_LOS_NONE: default: // don't draw anything break; } pos.y -= TILE_HEIGHT; tile -= X_TILES; y--; } }
static void DrawCompassArrow( GraphicsDevice *g, Rect2i r, Vec2i pos, Vec2i playerPos, color_t mask, const char *label) { Vec2i compassV = Vec2iMinus(pos, playerPos); // Don't draw if objective is on screen if (abs(pos.x - playerPos.x) < r.Size.x / 2 && abs(pos.y - playerPos.y) < r.Size.y / 2) { return; } Vec2i textPos = Vec2iZero(); // Find which edge of screen is the best bool hasDrawn = false; if (compassV.x != 0) { double sx = r.Size.x / 2.0 / compassV.x; int yInt = (int)floor(fabs(sx) * compassV.y + 0.5); if (yInt >= -r.Size.y / 2 && yInt <= r.Size.y / 2) { // Intercepts either left or right side hasDrawn = true; if (compassV.x > 0) { // right edge textPos = Vec2iNew( r.Pos.x + r.Size.x, r.Pos.y + r.Size.y / 2 + yInt); const Pic *p = PicManagerGetPic(&gPicManager, "arrow_right"); Vec2i drawPos = Vec2iNew( textPos.x - p->size.x, textPos.y - p->size.y / 2); BlitMasked(g, p, drawPos, mask, true); } else if (compassV.x < 0) { // left edge textPos = Vec2iNew(r.Pos.x, r.Pos.y + r.Size.y / 2 + yInt); const Pic *p = PicManagerGetPic(&gPicManager, "arrow_left"); Vec2i drawPos = Vec2iNew(textPos.x, textPos.y - p->size.y / 2); BlitMasked(g, p, drawPos, mask, true); } } } if (!hasDrawn && compassV.y != 0) { double sy = r.Size.y / 2.0 / compassV.y; int xInt = (int)floor(fabs(sy) * compassV.x + 0.5); if (xInt >= -r.Size.x / 2 && xInt <= r.Size.x / 2) { // Intercepts either top or bottom side if (compassV.y > 0) { // bottom edge textPos = Vec2iNew( r.Pos.x + r.Size.x / 2 + xInt, r.Pos.y + r.Size.y); const Pic *p = PicManagerGetPic(&gPicManager, "arrow_down"); Vec2i drawPos = Vec2iNew( textPos.x - p->size.x / 2, textPos.y - p->size.y); BlitMasked(g, p, drawPos, mask, true); } else if (compassV.y < 0) { // top edge textPos = Vec2iNew(r.Pos.x + r.Size.x / 2 + xInt, r.Pos.y); const Pic *p = PicManagerGetPic(&gPicManager, "arrow_up"); Vec2i drawPos = Vec2iNew(textPos.x - p->size.x / 2, textPos.y); BlitMasked(g, p, drawPos, mask, true); } } } if (label && strlen(label) > 0) { Vec2i textSize = FontStrSize(label); // Center the text around the target position textPos.x -= textSize.x / 2; textPos.y -= textSize.y / 2; // Make sure the text is inside the screen int padding = 8; textPos.x = MAX(textPos.x, r.Pos.x + padding); textPos.x = MIN(textPos.x, r.Pos.x + r.Size.x - textSize.x - padding); textPos.y = MAX(textPos.y, r.Pos.y + padding); textPos.y = MIN(textPos.y, r.Pos.y + r.Size.y - textSize.y - padding); FontStrMask(label, textPos, mask); } }
static void UIObjectDrawAndAddChildren( UIObject *o, GraphicsDevice *g, Vec2i pos, Vec2i mouse, CArray *objs) { if (!o) { return; } if (o->CheckVisible) { o->CheckVisible(o, o->Data); } if (!o->IsVisible) { return; } int isHighlighted = UIObjectIsHighlighted(o); Vec2i oPos = Vec2iAdd(pos, o->Pos); switch (o->Type) { case UITYPE_LABEL: { const char *text = LabelGetText(o); if (!text) { break; } color_t textMask = isHighlighted ? colorRed : colorWhite; FontStrMaskWrap(text, oPos, textMask, o->Size.x); } break; case UITYPE_TEXTBOX: { int isText = !!o->u.Textbox.TextLinkFunc; const char *text = isText ? o->u.Textbox.TextLinkFunc(o, o->Data) : NULL; int isEmptyText = !isText || !text || strlen(text) == 0; color_t bracketMask = isHighlighted ? colorRed : colorWhite; color_t textMask = isEmptyText ? colorGray : colorWhite; int oPosX = oPos.x; if (isEmptyText) { text = o->u.Textbox.Hint; } if (!o->u.Textbox.IsEditable) { textMask = bracketMask; } if (o->u.Textbox.IsEditable) { oPos = FontChMask('>', oPos, bracketMask); } oPos = FontStrMaskWrap( text, oPos, textMask, o->Pos.x + o->Size.x - oPosX); if (o->u.Textbox.IsEditable) { oPos = FontChMask('<', oPos, bracketMask); } oPos.x = oPosX; } break; case UITYPE_TAB: if (o->Children.size > 0) { color_t textMask = isHighlighted ? colorRed : colorWhite; char **labelp = CArrayGet(&o->u.Tab.Labels, o->u.Tab.Index); UIObject **objp = CArrayGet(&o->Children, o->u.Tab.Index); FontStrMaskWrap( *labelp, Vec2iAdd(pos, o->Pos), textMask, o->Size.x); if (!((*objp)->Flags & UI_ENABLED_WHEN_PARENT_HIGHLIGHTED_ONLY) || isHighlighted) { UIObjectDrawAndAddChildren(*objp, g, oPos, mouse, objs); } } break; case UITYPE_BUTTON: { int isDown = o->u.Button.IsDownFunc && o->u.Button.IsDownFunc(o->Data); BlitMasked( g, o->u.Button.Pic, oPos, isDown ? colorGray : colorWhite, 1); } break; case UITYPE_CONTEXT_MENU: { // Draw background DrawRectangle( g, Vec2iAdd(oPos, Vec2iScale(Vec2iUnit(), -TOOLTIP_PADDING)), Vec2iAdd(o->Size, Vec2iScale(Vec2iUnit(), 2 * TOOLTIP_PADDING)), menuBGColor, 0); // Find if mouse over any children, and draw highlight for (int i = 0; i < (int)o->Children.size; i++) { UIObject *child = *(UIObject **)CArrayGet(&o->Children, i); if (IsInside(mouse, Vec2iAdd(oPos, child->Pos), child->Size)) { DrawRectangle( g, Vec2iAdd(oPos, child->Pos), child->Size, hiliteColor, 0); } } } break; case UITYPE_CUSTOM: o->u.CustomDrawFunc(o, g, pos, o->Data); break; default: // do nothing break; } // add children // Note: tab type draws its own children (one) if (o->Type != UITYPE_TAB && objs != NULL) { size_t i; UIObject **childPtr = o->Children.data; for (i = 0; i < o->Children.size; i++, childPtr++) { if (!((*childPtr)->Flags & UI_ENABLED_WHEN_PARENT_HIGHLIGHTED_ONLY) || isHighlighted) { UIObjectDrawContext c; c.obj = *childPtr; c.pos = oPos; CArrayPushBack(objs, &c); } } } }
static void DrawWallsAndThings(DrawBuffer *b, Vec2i offset) { Vec2i pos; Tile *tile = &b->tiles[0][0]; pos.y = b->dy + cWallOffset.dy + offset.y; for (int y = 0; y < Y_TILES; y++, pos.y += TILE_HEIGHT) { TTileItem *displayList = NULL; pos.x = b->dx + cWallOffset.dx + offset.x; for (int x = 0; x < b->Size.x; x++, tile++, pos.x += TILE_WIDTH) { if (tile->flags & MAPTILE_IS_WALL) { if (!(tile->flags & MAPTILE_DELAY_DRAW)) { DrawWallColumn(y, pos, tile); } } else if (tile->flags & MAPTILE_OFFSET_PIC) { // Drawing doors BlitMasked( &gGraphicsDevice, &tile->picAlt, pos, GetTileLOSMask(tile), 0); } if (!(tile->flags & MAPTILE_OUT_OF_SIGHT)) { // Draw the items that are in LOS for (int i = 0; i < (int)tile->things.size; i++) { TTileItem *ti = ThingIdGetTileItem(CArrayGet(&tile->things, i)); if (!(ti->flags & TILEITEM_IS_WRECK)) { AddItemToDisplayList(ti, &displayList); } } } } for (TTileItem *t = displayList; t; t = t->nextToDisplay) { Vec2i picPos = Vec2iNew( t->x - b->xTop + offset.x, t->y - b->yTop + offset.y); if (t->getPicFunc) { Vec2i picOffset; const Pic *pic = t->getPicFunc(t->id, &picOffset); Blit(&gGraphicsDevice, pic, Vec2iAdd(picPos, picOffset)); } else if (t->getActorPicsFunc) { ActorPics pics = t->getActorPicsFunc(t->id); if (pics.IsDead) { if (pics.IsDying) { int pic = pics.OldPics[0]; if (pic == 0) { continue; } if (pics.IsTransparent) { DrawBTPic( &gGraphicsDevice, PicManagerGetFromOld(&gPicManager, pic), Vec2iAdd(picPos, pics.Pics[0].offset), pics.Tint); } else { DrawTTPic( picPos.x + pics.Pics[0].offset.x, picPos.y + pics.Pics[0].offset.y, PicManagerGetOldPic(&gPicManager, pic), pics.Table); } } } else if (pics.IsTransparent) { for (int i = 0; i < 3; i++) { Pic *oldPic = PicManagerGetFromOld( &gPicManager, pics.OldPics[i]); if (oldPic == NULL) { continue; } DrawBTPic( &gGraphicsDevice, oldPic, Vec2iAdd(picPos, pics.Pics[i].offset), pics.Tint); } } else { DrawShadow(&gGraphicsDevice, picPos, Vec2iNew(8, 6)); for (int i = 0; i < 3; i++) { PicPaletted *oldPic = PicManagerGetOldPic( &gPicManager, pics.OldPics[i]); if (oldPic == NULL) { continue; } BlitOld( picPos.x + pics.Pics[i].offset.x, picPos.y + pics.Pics[i].offset.y, oldPic, pics.Table, BLIT_TRANSPARENT); } } } else { (*(t->drawFunc))(picPos, &t->drawData); } } tile += X_TILES - b->Size.x; } }
static void DrawWallsAndThings(DrawBuffer *b, Vec2i offset) { Vec2i pos; Tile *tile = &b->tiles[0][0]; pos.y = b->dy + WALL_OFFSET_Y + offset.y; const bool useFog = ConfigGetBool(&gConfig, "Game.Fog"); for (int y = 0; y < Y_TILES; y++, pos.y += TILE_HEIGHT) { CArrayClear(&b->displaylist); pos.x = b->dx + offset.x; for (int x = 0; x < b->Size.x; x++, tile++, pos.x += TILE_WIDTH) { if (tile->flags & MAPTILE_IS_WALL) { if (!(tile->flags & MAPTILE_DELAY_DRAW)) { DrawWallColumn(y, pos, tile); } } else if (tile->flags & MAPTILE_OFFSET_PIC) { // Drawing doors // Doors may be offset; vertical doors are drawn centered // horizontal doors are bottom aligned Vec2i doorPos = pos; doorPos.x += (TILE_WIDTH - tile->picAlt->pic.size.x) / 2; if (tile->picAlt->pic.size.y > 16) { doorPos.y += TILE_HEIGHT - (tile->picAlt->pic.size.y % TILE_HEIGHT); } switch (GetTileLOS(tile, useFog)) { case TILE_LOS_NORMAL: Blit(&gGraphicsDevice, &tile->picAlt->pic, doorPos); break; case TILE_LOS_FOG: BlitMasked( &gGraphicsDevice, &tile->picAlt->pic, doorPos, colorFog, false); break; case TILE_LOS_NONE: default: // don't draw anything break; } } // Draw the items that are in LOS if (tile->flags & MAPTILE_OUT_OF_SIGHT) { continue; } CA_FOREACH(ThingId, tid, tile->things) const TTileItem *ti = ThingIdGetTileItem(tid); // Drawn later if (TileItemDrawLast(ti)) { continue; } CArrayPushBack(&b->displaylist, &ti); CA_FOREACH_END() } DrawBufferSortDisplayList(b); CA_FOREACH(const TTileItem *, tp, b->displaylist) DrawThing(b, *tp, offset); CA_FOREACH_END() tile += X_TILES - b->Size.x; } }