void STileLayerList::MergeLayerDown() { if (UPaperTileMap* TileMap = TileMapPtr.Get()) { const int32 SourceIndex = GetSelectionIndex(); const int32 TargetIndex = SourceIndex + 1; if ((SourceIndex != INDEX_NONE) && (TargetIndex != INDEX_NONE)) { const FScopedTransaction Transaction(LOCTEXT("TileMapMergeLayerDown", "Merge Layer Down")); TileMap->SetFlags(RF_Transactional); TileMap->Modify(); UPaperTileLayer* SourceLayer = TileMap->TileLayers[SourceIndex]; UPaperTileLayer* TargetLayer = TileMap->TileLayers[TargetIndex]; TargetLayer->SetFlags(RF_Transactional); TargetLayer->Modify(); // Copy the non-empty tiles from the source to the target layer for (int32 Y = 0; Y < SourceLayer->LayerWidth; ++Y) { for (int32 X = 0; X < SourceLayer->LayerWidth; ++X) { FPaperTileInfo TileInfo = SourceLayer->GetCell(X, Y); if (TileInfo.IsValid()) { TargetLayer->SetCell(X, Y, TileInfo); } } } // Remove the source layer TileMap->TileLayers.RemoveAt(SourceIndex); // Update viewers PostEditNotfications(); } } }
void UPaperTileMapComponent::RebuildRenderData(FPaperTileMapRenderSceneProxy* Proxy) { TArray<FSpriteDrawCallRecord> BatchedSprites; if (TileMap == nullptr) { return; } FVector CornerOffset; FVector OffsetYFactor; FVector StepPerTileX; FVector StepPerTileY; TileMap->GetTileToLocalParameters(/*out*/ CornerOffset, /*out*/ StepPerTileX, /*out*/ StepPerTileY, /*out*/ OffsetYFactor); UTexture2D* LastSourceTexture = nullptr; FVector TileSetOffset = FVector::ZeroVector; FVector2D InverseTextureSize(1.0f, 1.0f); FVector2D SourceDimensionsUV(1.0f, 1.0f); FVector2D TileSizeXY(0.0f, 0.0f); for (int32 Z = 0; Z < TileMap->TileLayers.Num(); ++Z) { UPaperTileLayer* Layer = TileMap->TileLayers[Z]; if (Layer == nullptr) { continue; } FLinearColor DrawColor = FLinearColor::White; #if WITH_EDITORONLY_DATA if (Layer->bHiddenInEditor) { continue; } DrawColor.A = Layer->LayerOpacity; #endif FSpriteDrawCallRecord* CurrentBatch = nullptr; for (int32 Y = 0; Y < TileMap->MapHeight; ++Y) { // In pixels FVector EffectiveTopLeftCorner; switch (TileMap->ProjectionMode) { case ETileMapProjectionMode::Orthogonal: default: EffectiveTopLeftCorner = CornerOffset; break; case ETileMapProjectionMode::IsometricDiamond: EffectiveTopLeftCorner = CornerOffset - StepPerTileX; break; case ETileMapProjectionMode::IsometricStaggered: case ETileMapProjectionMode::HexagonalStaggered: EffectiveTopLeftCorner = CornerOffset + (Y & 1) * OffsetYFactor; break; } for (int32 X = 0; X < TileMap->MapWidth; ++X) { const FPaperTileInfo TileInfo = Layer->GetCell(X, Y); // do stuff const float TotalSeparation = (TileMap->SeparationPerLayer * Z) + (TileMap->SeparationPerTileX * X) + (TileMap->SeparationPerTileY * Y); FVector TopLeftCornerOfTile = (StepPerTileX * X) + (StepPerTileY * Y) + EffectiveTopLeftCorner; TopLeftCornerOfTile += TotalSeparation * PaperAxisZ; const int32 TileWidth = TileMap->TileWidth; const int32 TileHeight = TileMap->TileHeight; { UTexture2D* SourceTexture = nullptr; FVector2D SourceUV = FVector2D::ZeroVector; if (Layer->bCollisionLayer) { if (TileInfo.PackedTileIndex == 0) { continue; } SourceTexture = UCanvas::StaticClass()->GetDefaultObject<UCanvas>()->DefaultTexture; } else { if (TileInfo.TileSet == nullptr) { continue; } if (!TileInfo.TileSet->GetTileUV(TileInfo.PackedTileIndex, /*out*/ SourceUV)) { continue; } SourceTexture = TileInfo.TileSet->TileSheet; if (SourceTexture == nullptr) { continue; } } if ((SourceTexture != LastSourceTexture) || (CurrentBatch == nullptr)) { CurrentBatch = (new (BatchedSprites) FSpriteDrawCallRecord()); CurrentBatch->Texture = SourceTexture; CurrentBatch->Color = DrawColor; CurrentBatch->Destination = TopLeftCornerOfTile.ProjectOnTo(PaperAxisZ); } if (SourceTexture != LastSourceTexture) { InverseTextureSize = FVector2D(1.0f / SourceTexture->GetSizeX(), 1.0f / SourceTexture->GetSizeY()); if (TileInfo.TileSet != nullptr) { SourceDimensionsUV = FVector2D(TileInfo.TileSet->TileWidth * InverseTextureSize.X, TileInfo.TileSet->TileHeight * InverseTextureSize.Y); TileSizeXY = FVector2D(TileInfo.TileSet->TileWidth, TileInfo.TileSet->TileHeight); TileSetOffset = (TileInfo.TileSet->DrawingOffset.X * PaperAxisX) + (TileInfo.TileSet->DrawingOffset.Y * PaperAxisY); } else { SourceDimensionsUV = FVector2D(TileWidth * InverseTextureSize.X, TileHeight * InverseTextureSize.Y); TileSizeXY = FVector2D(TileWidth, TileHeight); TileSetOffset = FVector::ZeroVector; } LastSourceTexture = SourceTexture; } TopLeftCornerOfTile += TileSetOffset; SourceUV.X *= InverseTextureSize.X; SourceUV.Y *= InverseTextureSize.Y; FSpriteDrawCallRecord& NewTile = *CurrentBatch; const float WX0 = FVector::DotProduct(TopLeftCornerOfTile, PaperAxisX); const float WY0 = FVector::DotProduct(TopLeftCornerOfTile, PaperAxisY); const FVector4 BottomLeft(WX0, WY0 - TileSizeXY.Y, SourceUV.X, SourceUV.Y + SourceDimensionsUV.Y); const FVector4 BottomRight(WX0 + TileSizeXY.X, WY0 - TileSizeXY.Y, SourceUV.X + SourceDimensionsUV.X, SourceUV.Y + SourceDimensionsUV.Y); const FVector4 TopRight(WX0 + TileSizeXY.X, WY0, SourceUV.X + SourceDimensionsUV.X, SourceUV.Y); const FVector4 TopLeft(WX0, WY0, SourceUV.X, SourceUV.Y); new (NewTile.RenderVerts) FVector4(BottomLeft); new (NewTile.RenderVerts) FVector4(TopRight); new (NewTile.RenderVerts) FVector4(BottomRight); new (NewTile.RenderVerts) FVector4(BottomLeft); new (NewTile.RenderVerts) FVector4(TopLeft); new (NewTile.RenderVerts) FVector4(TopRight); } } } } Proxy->SetBatchesHack(BatchedSprites); }