2025-08-31 16:10:56 +08:00
|
|
|
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "Thumbnail/BagConfigThumbnailRenderer.h"
|
|
|
|
|
|
|
|
|
|
#include "CanvasItem.h"
|
|
|
|
|
#include "CanvasTypes.h"
|
|
|
|
|
#include "ProjectFish/DataAsset/BagConfigAsset.h"
|
2025-10-15 18:25:31 +08:00
|
|
|
#include "ProjectFish/DataAsset/ShapeAsset.h"
|
2025-08-31 16:10:56 +08:00
|
|
|
|
|
|
|
|
bool UBagConfigThumbnailRenderer::CanVisualizeAsset(UObject* Object)
|
|
|
|
|
{
|
|
|
|
|
return Cast<UBagConfigAsset>(Object) != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UBagConfigThumbnailRenderer::Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height,
|
|
|
|
|
FRenderTarget* RenderTarget, FCanvas* Canvas, bool bAdditionalViewFamily)
|
|
|
|
|
{
|
|
|
|
|
UBagConfigAsset* BagConfig= Cast<UBagConfigAsset>(Object);
|
|
|
|
|
if (!BagConfig || !Canvas)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DrawBag(BagConfig, Canvas, X, Y, Width, Height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UBagConfigThumbnailRenderer::DrawBag(UBagConfigAsset* BagConfig, FCanvas* Canvas, int32 X, int32 Y,
|
|
|
|
|
uint32 Width, uint32 Height)
|
|
|
|
|
{
|
|
|
|
|
if (!BagConfig || !Canvas)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查是否有背包形状资源
|
|
|
|
|
if (!BagConfig->BagShapeAsset)
|
|
|
|
|
{
|
|
|
|
|
// 绘制错误状态
|
|
|
|
|
FCanvasBoxItem ErrorBox(FVector2D(X, Y), FVector2D(Width, Height));
|
|
|
|
|
ErrorBox.SetColor(FLinearColor(0.5f, 0.1f, 0.1f, 1.0f));
|
|
|
|
|
Canvas->DrawItem(ErrorBox);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-15 18:25:31 +08:00
|
|
|
UShapeAsset* BagShapeAsset = BagConfig->BagShapeAsset;
|
2025-08-31 16:10:56 +08:00
|
|
|
|
|
|
|
|
// Clear the background
|
|
|
|
|
FCanvasBoxItem BackgroundBox(FVector2D(X, Y), FVector2D(Width, Height));
|
|
|
|
|
BackgroundBox.SetColor(FLinearColor(0.1f, 0.1f, 0.1f, 1.0f));
|
|
|
|
|
Canvas->DrawItem(BackgroundBox);
|
|
|
|
|
|
|
|
|
|
// Calculate the best fit scale with spacing for separators
|
|
|
|
|
float SeparatorWidth = 2.0f; // White separator width
|
2025-10-15 18:25:31 +08:00
|
|
|
float Scale = GetBestFitScale(BagShapeAsset->ShapeWidth, BagShapeAsset->ShapeHeight, Width, Height);
|
2025-08-31 16:10:56 +08:00
|
|
|
float CellSize = Scale - SeparatorWidth; // Reduce cell size to make room for separators
|
|
|
|
|
|
|
|
|
|
// Calculate starting position to center the grid (including separators)
|
2025-10-15 18:25:31 +08:00
|
|
|
float GridWidth = BagShapeAsset->ShapeWidth * Scale - SeparatorWidth;
|
|
|
|
|
float GridHeight = BagShapeAsset->ShapeHeight * Scale - SeparatorWidth;
|
2025-08-31 16:10:56 +08:00
|
|
|
float StartX = X + (Width - GridWidth) * 0.5f;
|
|
|
|
|
float StartY = Y + (Height - GridHeight) * 0.5f;
|
|
|
|
|
|
|
|
|
|
// Draw the bag slots (background) with separators
|
2025-10-15 18:25:31 +08:00
|
|
|
for (int32 GridY = 0; GridY < BagShapeAsset->ShapeHeight; GridY++)
|
2025-08-31 16:10:56 +08:00
|
|
|
{
|
2025-10-15 18:25:31 +08:00
|
|
|
for (int32 GridX = 0; GridX < BagShapeAsset->ShapeWidth; GridX++)
|
2025-08-31 16:10:56 +08:00
|
|
|
{
|
|
|
|
|
float CellStartX = StartX + GridX * Scale;
|
|
|
|
|
float CellStartY = StartY + GridY * Scale;
|
|
|
|
|
|
|
|
|
|
bool bIsActive = BagShapeAsset->IsSlotActive(GridX, GridY);
|
|
|
|
|
|
|
|
|
|
// Draw filled cell (smaller to leave space for separators)
|
|
|
|
|
FCanvasTileItem CellTile(FVector2D(CellStartX, CellStartY), FVector2D(CellSize, CellSize),
|
|
|
|
|
bIsActive ? FLinearColor(0.3f, 0.3f, 0.3f, 1.0f) : FLinearColor(0.15f, 0.15f, 0.15f, 1.0f));
|
|
|
|
|
CellTile.BlendMode = SE_BLEND_Opaque;
|
|
|
|
|
Canvas->DrawItem(CellTile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw white separators
|
|
|
|
|
// Vertical separators
|
2025-10-15 18:25:31 +08:00
|
|
|
for (int32 GridX = 1; GridX < BagShapeAsset->ShapeWidth; GridX++)
|
2025-08-31 16:10:56 +08:00
|
|
|
{
|
|
|
|
|
float SeparatorX = StartX + GridX * Scale - SeparatorWidth;
|
|
|
|
|
FCanvasTileItem VerticalSeparator(FVector2D(SeparatorX, StartY), FVector2D(SeparatorWidth, GridHeight), FLinearColor::White);
|
|
|
|
|
VerticalSeparator.BlendMode = SE_BLEND_Opaque;
|
|
|
|
|
Canvas->DrawItem(VerticalSeparator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Horizontal separators
|
2025-10-15 18:25:31 +08:00
|
|
|
for (int32 GridY = 1; GridY < BagShapeAsset->ShapeHeight; GridY++)
|
2025-08-31 16:10:56 +08:00
|
|
|
{
|
|
|
|
|
float SeparatorY = StartY + GridY * Scale - SeparatorWidth;
|
|
|
|
|
FCanvasTileItem HorizontalSeparator(FVector2D(StartX, SeparatorY), FVector2D(GridWidth, SeparatorWidth), FLinearColor::White);
|
|
|
|
|
HorizontalSeparator.BlendMode = SE_BLEND_Opaque;
|
|
|
|
|
Canvas->DrawItem(HorizontalSeparator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw skills on top
|
|
|
|
|
for (const FPlacedSkillInfo& PlacedSkill : BagConfig->PlacedSkills)
|
|
|
|
|
{
|
|
|
|
|
DrawSkill(PlacedSkill, Canvas, StartX, StartY, Scale, SeparatorWidth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw outer border
|
|
|
|
|
FCanvasBoxItem OuterBorder(FVector2D(StartX, StartY), FVector2D(GridWidth, GridHeight));
|
|
|
|
|
OuterBorder.SetColor(FLinearColor::White);
|
|
|
|
|
OuterBorder.LineThickness = 3.0f;
|
|
|
|
|
Canvas->DrawItem(OuterBorder);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-15 18:25:31 +08:00
|
|
|
float UBagConfigThumbnailRenderer::GetBestFitScale(int32 ShapeWidth, int32 ShapeHeight, uint32 CanvasWidth,
|
2025-08-31 16:10:56 +08:00
|
|
|
uint32 CanvasHeight) const
|
|
|
|
|
{
|
2025-10-15 18:25:31 +08:00
|
|
|
if (ShapeWidth == 0 || ShapeHeight == 0)
|
2025-08-31 16:10:56 +08:00
|
|
|
{
|
|
|
|
|
return 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Leave some padding
|
|
|
|
|
float PaddedWidth = CanvasWidth * 0.85f;
|
|
|
|
|
float PaddedHeight = CanvasHeight * 0.85f;
|
|
|
|
|
|
2025-10-15 18:25:31 +08:00
|
|
|
float ScaleX = PaddedWidth / ShapeWidth;
|
|
|
|
|
float ScaleY = PaddedHeight / ShapeHeight;
|
2025-08-31 16:10:56 +08:00
|
|
|
|
|
|
|
|
// Use the smaller scale to ensure everything fits
|
|
|
|
|
float Scale = FMath::Min(ScaleX, ScaleY);
|
|
|
|
|
|
|
|
|
|
// Ensure minimum cell size for visibility
|
|
|
|
|
Scale = FMath::Max(Scale, 3.0f);
|
|
|
|
|
|
|
|
|
|
return Scale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UBagConfigThumbnailRenderer::DrawSkill(const struct FPlacedSkillInfo& PlacedSkill, FCanvas* Canvas, float StartX,
|
|
|
|
|
float StartY, float Scale, float SeparatorWidth)
|
|
|
|
|
{
|
|
|
|
|
if (!PlacedSkill.SkillAsset)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
USkillAsset* SkillObject = PlacedSkill.SkillAsset;
|
|
|
|
|
float CellSize = Scale - SeparatorWidth;
|
|
|
|
|
|
|
|
|
|
float SkillStartX = StartX + PlacedSkill.PositionX * Scale;
|
|
|
|
|
float SkillStartY = StartY + PlacedSkill.PositionY * Scale;
|
|
|
|
|
|
|
|
|
|
float SkillWidth = GetSkillSizeValue(SkillObject->SkillSize).X * Scale - SeparatorWidth;
|
|
|
|
|
float SkillHeight = GetSkillSizeValue(SkillObject->SkillSize).Y * Scale - SeparatorWidth;
|
|
|
|
|
|
|
|
|
|
// Draw skill background
|
|
|
|
|
FCanvasTileItem SkillTile(FVector2D(SkillStartX, SkillStartY), FVector2D(SkillWidth, SkillHeight), FLinearColor::Blue);
|
|
|
|
|
SkillTile.BlendMode = SE_BLEND_Opaque;
|
|
|
|
|
Canvas->DrawItem(SkillTile);
|
|
|
|
|
|
|
|
|
|
// Draw skill border
|
|
|
|
|
FCanvasBoxItem SkillBorder(FVector2D(SkillStartX, SkillStartY), FVector2D(SkillWidth, SkillHeight));
|
|
|
|
|
SkillBorder.SetColor(FLinearColor::White);
|
|
|
|
|
SkillBorder.LineThickness = 2.0f;
|
|
|
|
|
Canvas->DrawItem(SkillBorder);
|
|
|
|
|
|
|
|
|
|
// Draw skill name (if there's enough space)
|
|
|
|
|
if (CellSize >= 12.0f && !SkillObject->SkillName.ToString().IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
FString DisplayName = SkillObject->SkillName.ToString();
|
|
|
|
|
if (DisplayName.Len() > 8)
|
|
|
|
|
{
|
|
|
|
|
DisplayName = DisplayName.Left(6) + TEXT("..");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FCanvasTextItem TextItem(FVector2D(SkillStartX + 2, SkillStartY + 2), FText::FromString(DisplayName), GEngine->GetSmallFont(), FLinearColor::White);
|
|
|
|
|
TextItem.Scale = FVector2D(0.7f, 0.7f);
|
|
|
|
|
Canvas->DrawItem(TextItem);
|
|
|
|
|
}
|
|
|
|
|
}
|