美文网首页
UE4封装Skia

UE4封装Skia

作者: qlaiaqu | 来源:发表于2019-02-20 17:48 被阅读0次

UE4在蓝图里面是没有2D绘图引擎的(或者我没找到),所以需要另外找一个第三方的2D引擎。
Skia和Cairo都用了一下。Cairo是C接口,里面很多参数得实验才知道怎么用,很多功能的封装必须多个函数搭配使用才能完成,用起来颇为蛋疼,试了几天就放弃了。Skia使用C++,有Bitmap,Paint,Canvas,Path的等概念,OOP的思想和UE4接口封装适配的很好。试了几天,终于封装了Skia的部分接口.
尽量保持了UE4和Skia在接口上的一致性,自己还是颇为满意的。
基本图形


Snipaste_2019-02-20_17-47-29.png

正旋曲线,和螺旋曲线


Snipaste_2019-02-20_17-43-56.png

SkiaBPLibrary.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Kismet/BlueprintFunctionLibrary.h"
#include "Runtime/Core/Public/Math/Color.h"
#include "Runtime/Engine/Classes/Engine/Texture2D.h"
#include <memory>
#include "SkiaBPLibrary.generated.h"

class SkBitmap;
class SkCanvas;
class SkPaint;
class SkPath;

#pragma region Struct
USTRUCT(BlueprintType, Blueprintable)
struct FSkiaBitmap
{
    GENERATED_USTRUCT_BODY()
    std::shared_ptr<SkBitmap> bitmap = nullptr;

    UPROPERTY(BlueprintReadOnly)
    float imageWidth = 0.0;

    UPROPERTY(BlueprintReadOnly)
    float imageHeight = 0.0;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaCanvas
{
    GENERATED_USTRUCT_BODY()
    std::shared_ptr<SkCanvas> canvas = nullptr;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaPaint
{
    GENERATED_USTRUCT_BODY()
    std::shared_ptr<SkPaint> paint = nullptr;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaContext
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(BlueprintReadOnly)
    FSkiaBitmap bitmap;

    UPROPERTY(BlueprintReadOnly)
    FSkiaCanvas canvas;

    UPROPERTY(BlueprintReadOnly)
    UTexture2D* texture = nullptr;

    std::shared_ptr<FUpdateTextureRegion2D> region = nullptr;
    std::shared_ptr<TArray<FColor>> data;

    UPROPERTY(BlueprintReadOnly)
    float imageWidth = 0.0;

    UPROPERTY(BlueprintReadOnly)
    float imageHeight = 0.0;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaPath
{
    GENERATED_USTRUCT_BODY()
    std::shared_ptr<SkPath> path = nullptr;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaGradient
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    float offset;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    FLinearColor color;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaLine
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    FVector2D p0;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    FVector2D p1;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaRect
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    FVector2D point;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    FVector2D size;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaCircle
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    FVector2D center;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    float radius;
};

USTRUCT(BlueprintType, Blueprintable)
struct FSkiaArc
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    FVector2D point;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    FVector2D size;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    float startAngle;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skia")
    float sweepAngle;
};
#pragma endregion

#pragma region Enum
UENUM(BlueprintType)
enum class EPaintStyle :uint8
{
    Paint_kFill_Style UMETA(DisplayName = "Fill"),
    Paint_kStroke_Style UMETA(DisplayName = "Stroke"),
    Paint_kStrokeAndFill_Style UMETA(DisplayName = "Stroke And Fill"),
};

UENUM(BlueprintType)
enum class ECanvasPointMode :uint8
{
    Canvas_kPoints_PointMode UMETA(DisplayName = "Points"),
    Canvas_kLines_PointMode UMETA(DisplayName = "Lines"),
    Canvas_kPolygon_PointMode UMETA(DisplayName = "Polygon"),
};

UENUM(BlueprintType)
enum class EPaintAlign :uint8
{
    Paint_kLeft_Align UMETA(DisplayName = "Left"),
    Paint_kCenter_Align UMETA(DisplayName = "Center"),
    Paint_kRight_Align UMETA(DisplayName = "Right"),
};

UENUM(BlueprintType)
enum class EPaintCap :uint8
{
    Paint_kButt_Cap UMETA(DisplayName = "Butt"),
    Paint_kRound_Cap UMETA(DisplayName = "Round"),
    Paint_kSquare_Cap UMETA(DisplayName = "Square"),
    Paint_kLast_Cap = Paint_kSquare_Cap UMETA(DisplayName = "Last"),
    Paint_kDefault_Cap = Paint_kButt_Cap UMETA(DisplayName = "Default"),
};

UENUM(BlueprintType)
enum class EPaintJoin :uint8
{
    Paint_kMiter_Join UMETA(DisplayName = "Miter"),
    Paint_kRound_Join UMETA(DisplayName = "Round"),
    Paint_kBevel_Join UMETA(DisplayName = "Bevel"),
    Paint_kLast_Join = Paint_kBevel_Join UMETA(DisplayName = "Last"),
    Paint_kDefault_Join = Paint_kMiter_Join UMETA(DisplayName = "Default"),
};

UENUM(BlueprintType)
enum class EPaintTileMode :uint8
{
    Paint_kClamp_TileMode UMETA(DisplayName = "Clamp"),
    Paint_kRepeat_TileMode UMETA(DisplayName = "Repeat"),
    Paint_kMirror_TileMode UMETA(DisplayName = "Mirror"),
    Paint_kDecal_TileMode UMETA(DisplayName = "Decal"),
    Paint_kLast_TileMode = Paint_kDecal_TileMode UMETA(DisplayName = "Last")
};

UENUM(BlueprintType)
enum class EPathFillType :uint8
{
    Path_kWinding_FillType UMETA(DisplayName = "Winding"),
    Path_kEvenOdd_FillType UMETA(DisplayName = "EvenOdd"),
    Path_kInverseWinding_FillType UMETA(DisplayName = "InverseWinding"),
    Path_kInverseEvenOdd_FillType UMETA(DisplayName = "InverseEvenOdd"),
};

UENUM(BlueprintType)
enum class EFontType :uint8
{
    Font_Normal UMETA(DisplayName = "Normal"),
    Font_Bold UMETA(DisplayName = "Bold"),
    Font_Italic UMETA(DisplayName = "Italic"),
    Font_BoldItalic UMETA(DisplayName = "BoldItalic"),
};

UENUM(BlueprintType)
enum class EClipOp :uint8
{
    ClipOp_kDifference UMETA(DisplayName = "Difference"),
    ClipOp_kIntersect UMETA(DisplayName = "Intersect"),
    ClipOp_kExtraEnumNeedInternallyPleaseIgnoreWillGoAway2 UMETA(DisplayName = "Ignore2"),
    ClipOp_kExtraEnumNeedInternallyPleaseIgnoreWillGoAway3 UMETA(DisplayName = "Ignore3"),
    ClipOp_kExtraEnumNeedInternallyPleaseIgnoreWillGoAway4 UMETA(DisplayName = "Ignore4"),
    ClipOp_kExtraEnumNeedInternallyPleaseIgnoreWillGoAway5 UMETA(DisplayName = "Ignore5"),
    ClipOp_kMax_EnumValue UMETA(DisplayName = "Max"),
};


UENUM(BlueprintType)
enum class ECanvasBlendMode :uint8
{
    Canvas_kClear,    //!< [0, 0]
    Canvas_kSrc,      //!< [Sa, Sc]
    Canvas_kDst,      //!< [Da, Dc]
    Canvas_kSrcOver,  //!< [Sa + Da * (1 - Sa), Sc + Dc * (1 - Sa)]
    Canvas_kDstOver,  //!< [Da + Sa * (1 - Da), Dc + Sc * (1 - Da)]
    Canvas_kSrcIn,    //!< [Sa * Da, Sc * Da]
    Canvas_kDstIn,    //!< [Da * Sa, Dc * Sa]
    Canvas_kSrcOut,   //!< [Sa * (1 - Da), Sc * (1 - Da)]
    Canvas_kDstOut,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]
    Canvas_kSrcATop,  //!< [Da, Sc * Da + Dc * (1 - Sa)]
    Canvas_kDstATop,  //!< [Sa, Dc * Sa + Sc * (1 - Da)]
    Canvas_kXor,      //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + Dc * (1 - Sa)]
    Canvas_kPlus,     //!< [Sa + Da, Sc + Dc]
    Canvas_kModulate, // multiplies all components (= alpha and color)

    Canvas_kScreen,
    Canvas_kLastCoeffMode = Canvas_kScreen,

    Canvas_kOverlay,
    Canvas_kDarken,
    Canvas_kLighten,
    Canvas_kColorDodge,
    Canvas_kColorBurn,
    Canvas_kHardLight,
    Canvas_kSoftLight,
    Canvas_kDifference,
    Canvas_kExclusion,
    Canvas_kMultiply,
    Canvas_kLastSeparableMode = Canvas_kMultiply,

    Canvas_kHue,
    Canvas_kSaturation,
    Canvas_kColor,
    Canvas_kLuminosity,
    Canvas_kLastMode = Canvas_kLuminosity,
};
#pragma endregion

UCLASS()
class EXCHANGELIBRARY_API USkiaBPLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_UCLASS_BODY()

public:
    UFUNCTION(BlueprintCallable, Category = "Skia")
    static void CreateContext(float imageWidth, float imageHeight, FSkiaContext& context, FLinearColor color = FLinearColor::Transparent, bool createTexture = true);

    UFUNCTION(BlueprintCallable, Category = "Skia")
    static void UpdateTexture(const FSkiaContext& context);

    //////////////////////////////////////Paint//////////////////////////////////////
    UFUNCTION(BlueprintCallable, Category = "Skia|Paint")
    static void CreatePaint(FSkiaPaint& paint);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint")
    static const FSkiaPaint& SetPaintStyle(const FSkiaPaint& paint, EPaintStyle style, EPaintCap cap = EPaintCap::Paint_kDefault_Cap, EPaintJoin join = EPaintJoin::Paint_kDefault_Join);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint")
    static const FSkiaPaint& SetPaintColor(const FSkiaPaint& paint, FLinearColor color);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint")
    static const FSkiaPaint& SetPaintStrokeWidth(const FSkiaPaint& paint, int width);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint")
    static const FSkiaPaint& SetPathEffect(const FSkiaPaint& paint, const TArray<float>& intervals, float phase);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Text")
    static const FSkiaPaint& SetTypeFace(const FSkiaPaint& paint, FString familyName, EFontType fontType = EFontType::Font_Normal);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Text")
    static const FSkiaPaint& SetPaintTextAlign(const FSkiaPaint& paint, EPaintAlign textAlign);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Text")
    static const FSkiaPaint& SetPaintTextSize(const FSkiaPaint& paint, float textSize);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Text")
    static const FSkiaPaint& SetPaintAntiAlias(const FSkiaPaint& paint, bool antiAlias);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Text")
    static const FSkiaPaint& SetPaintTextScaleX(const FSkiaPaint& paint, float scale);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Text")
    static const FSkiaPaint& SetPaintTextSkewX(const FSkiaPaint& paint, float skew);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Text")
    static const FSkiaPaint& MeasureText(const FSkiaPaint& paint, const FString& text, FSkiaRect& rect);

    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Gradient")
    static const FSkiaPaint& SetPaintGradientLiner(const FSkiaPaint& paint, FVector2D start, FVector2D end, TArray<FSkiaGradient> gradients, EPaintTileMode mode);
    
    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Gradient")
    static const FSkiaPaint& SetPaintGradientRadial(const FSkiaPaint& paint, FVector2D center, float radius, TArray<FSkiaGradient> gradients, EPaintTileMode mode);
    
    UFUNCTION(BlueprintCallable, Category = "Skia|Paint|Gradient")
    static const FSkiaPaint& SetPaintGradientSweep(const FSkiaPaint& paint, FVector2D center, TArray<FSkiaGradient> gradients);

    //////////////////////////////////////Transfor//////////////////////////////////////
    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas|Transfor")
    static void Translate(const FSkiaCanvas& canvas, float dx, float dy);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas|Transfor")
    static void Scale(const FSkiaCanvas& canvas, float sx, float sy);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas|Transfor")
    static void Rotate(const FSkiaCanvas& canvas, float angle);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas|Transfor")
    static void Rotate2(const FSkiaCanvas& canvas, float angle, float px, float py);
     
    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas|Transfor")
    static void Skew(const FSkiaCanvas& canvas, float sx, float sy);

    //////////////////////////////////////Canvas//////////////////////////////////////
    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawColor(const FSkiaCanvas& canvas, FLinearColor color, ECanvasBlendMode mode = ECanvasBlendMode::Canvas_kSrcOver);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void Clear(const FSkiaCanvas& canvas, FLinearColor color);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawPaint(const FSkiaCanvas& canvas, const FSkiaPaint& paint);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawPoint(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawPoints(const FSkiaCanvas& canvas, const FSkiaPaint& paint, ECanvasPointMode mode, TArray<FVector2D> points);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawLine(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D p0, FVector2D p1);
    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawLine2(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaLine& line);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawPolyline(const FSkiaCanvas& canvas, const FSkiaPaint& paint, TArray<FVector2D> points, bool closed = false);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawRect(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FVector2D size);
    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawRect2(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaRect& rect);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawRoundRect(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FVector2D size, float rx, float ry);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawArc(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FVector2D size, float startAngle, float sweepAngle, bool useCenter);
    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawArc2(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaArc& arc, bool useCenter);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawOval(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FVector2D size);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawCircle(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D center, float radius);
    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void DrawCircle2(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaCircle& circle);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static FSkiaRect DrawText(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FString text);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void ClipRect(const FSkiaCanvas& canvas,  FVector2D point, FVector2D size, EClipOp op = EClipOp::ClipOp_kIntersect, bool doAntiAlias = false);

    UFUNCTION(BlueprintCallable, Category = "Skia|Canvas")
    static void ClipPath(const FSkiaCanvas& canvas, const FSkiaPath& path, EClipOp op = EClipOp::ClipOp_kIntersect, bool doAntiAlias = false);

    UFUNCTION(BlueprintCallable, Category = "Skia|Bitmap")
    static void CreateBitmap(FString filePath, FSkiaBitmap& bitmap);

    UFUNCTION(BlueprintCallable, Category = "Skia|Bitmap")
    static void DrawBitmap(const FSkiaCanvas& canvas, const FSkiaBitmap& bitmap, FVector2D point);

    //////////////////////////////////////Path//////////////////////////////////////
    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void CreatePath(FSkiaPath& path);

    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void MoveTo(const FSkiaPath& path, FVector2D point);

    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void LineTo(const FSkiaPath& path, FVector2D point);

    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void QuadTo(const FSkiaPath& path, FVector2D pt1, FVector2D pt2);

    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void ConicTo(const FSkiaPath& path, FVector2D pt1, FVector2D pt2, float w);
    
    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void CubicTo(const FSkiaPath& path, FVector2D pt1, FVector2D pt2, FVector2D pt3);
    
    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void ArcTo(const FSkiaPath& path, FVector2D point, FVector2D size, float startAngle, float sweepAngle, bool forceMoveTo);

    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void ArcTo2(const FSkiaPath& path, FVector2D pt1, FVector2D pt2, float radius);

    UFUNCTION(BlueprintCallable, Category = "Skia|Path")
    static void DrawPath(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaPath& path, bool closed = false, EPathFillType fillType = EPathFillType::Path_kWinding_FillType);

    //////////////////////////////////////Algorithm//////////////////////////////////////

};

SkiaBPLibrary.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "SkiaBPLibrary.h"
#include "Runtime/Engine/Classes/Engine/Texture2D.h"
#include "Runtime/Engine/Classes/Engine/TextureDefines.h"

#include "SkString.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkImage.h"
#include "SkDevice.h"
#include "SkPath.h"
#include "SkPoint.h"
#include "SkRect.h"
#include "SkTypeface.h"
#include "SkImageEncoder.h"
#include "SkPngCodec.h"
#include "SkDashPathEffect.h"
#include "SkGradientShader.h"

const bool IS_SRGB = false;

USkiaBPLibrary::USkiaBPLibrary(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{

}

void USkiaBPLibrary::CreateContext(float imageWidth, float imageHeight, FSkiaContext& context, FLinearColor color, bool createTexture)
{
    if ((imageWidth <= 0) || (imageHeight <= 0)) return;

    //w & h
    context.imageWidth = imageWidth;
    context.imageHeight = imageHeight;

    //bitmap
    context.bitmap.bitmap = std::make_shared<SkBitmap>();
    SkImageInfo image_info = SkImageInfo::Make((int)imageWidth, imageHeight, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
    context.bitmap.bitmap->allocPixels(image_info, image_info.minRowBytes());

    //canvas
    context.canvas.canvas = std::make_shared<SkCanvas>(*context.bitmap.bitmap);
    context.canvas.canvas->clear(color.ToFColor(IS_SRGB).DWColor());

    if (createTexture)
    {
        //texture
        context.texture = UTexture2D::CreateTransient(context.imageWidth, context.imageHeight, EPixelFormat::PF_B8G8R8A8);
        context.texture->UpdateResource();

        //data
        context.region = std::make_shared<FUpdateTextureRegion2D>(0, 0, 0, 0, imageWidth, imageHeight);
        context.data = std::make_shared<TArray<FColor>>();
        context.data->Init(FColor(0, 0, 0, 255), imageWidth *imageHeight);
    }
}

void USkiaBPLibrary::UpdateTexture(const FSkiaContext& context)
{
    if (context.bitmap.bitmap && context.texture)
    {
        TArray<FColor>& Data = *context.data;
        FMemory::Memcpy(Data.GetData(), context.bitmap.bitmap->getPixels(), context.bitmap.bitmap->computeByteSize());

        // Update texture 2D
        context.texture->UpdateTextureRegions(0, 1, context.region.get(), (uint32)(context.imageWidth * sizeof(uint32)), sizeof(uint32), (uint8*)Data.GetData(), 
            [](uint8*, const FUpdateTextureRegion2D*){});
    }
}

#pragma region Convert
SkRect MakeRect(FVector2D position, FVector2D size)
{
    SkRect rect;
    rect.fLeft = position.X;
    rect.fTop = position.Y;
    rect.fRight = position.X + size.X;
    rect.fBottom = position.Y + size.Y;

    return rect;
}

SkPoint MakePoint(FVector2D point)
{
    return SkPoint::Make(point.X, point.Y);
}
#pragma endregion

#pragma region Paint
void USkiaBPLibrary::CreatePaint(FSkiaPaint& paint)
{
    paint.paint = std::make_shared<SkPaint>();
    //paint.paint->setLCDRenderText(true);
}

const FSkiaPaint& USkiaBPLibrary::SetPaintStyle(const FSkiaPaint& paint, EPaintStyle style, EPaintCap cap, EPaintJoin join)
{
    paint.paint->setStyle((SkPaint::Style)style);
    paint.paint->setStrokeCap((SkPaint::Cap)cap);
    paint.paint->setStrokeJoin((SkPaint::Join)join);

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintColor(const FSkiaPaint& paint, FLinearColor color)
{
    paint.paint->setColor(color.ToFColor(IS_SRGB).DWColor());

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintStrokeWidth(const FSkiaPaint& paint, int width)
{
    paint.paint->setStrokeWidth(width);

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPathEffect(const FSkiaPaint& paint, const TArray<float>& intervals, float phase)
{
    paint.paint->setPathEffect(SkDashPathEffect::Make(intervals.GetData(), intervals.Num(), phase));
    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetTypeFace(const FSkiaPaint& paint, FString familyName, EFontType fontType)
{
    switch (fontType)
    {
    case EFontType::Font_Normal:
        paint.paint->setTypeface(SkTypeface::MakeFromName(TCHAR_TO_UTF8(*familyName), SkFontStyle::Normal()));
        break;
    case EFontType::Font_Bold:
        paint.paint->setTypeface(SkTypeface::MakeFromName(TCHAR_TO_UTF8(*familyName), SkFontStyle::Bold()));
        break;
    case EFontType::Font_Italic:
        paint.paint->setTypeface(SkTypeface::MakeFromName(TCHAR_TO_UTF8(*familyName), SkFontStyle::Italic()));
        break;
    case EFontType::Font_BoldItalic:
        paint.paint->setTypeface(SkTypeface::MakeFromName(TCHAR_TO_UTF8(*familyName), SkFontStyle::BoldItalic()));
        break;
    default:
        break;
    }
    
    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintTextAlign(const FSkiaPaint& paint, EPaintAlign textAlign)
{
    paint.paint->setTextAlign((SkPaint::Align)textAlign);
    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintTextSize(const FSkiaPaint& paint, float textSize)
{
    paint.paint->setTextSize(textSize);

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintAntiAlias(const FSkiaPaint& paint, bool antiAlias)
{
    paint.paint->setAntiAlias(antiAlias);

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintTextScaleX(const FSkiaPaint& paint, float scale)
{
    paint.paint->setTextScaleX(scale);

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintTextSkewX(const FSkiaPaint& paint, float scale)
{
    paint.paint->setTextSkewX(scale);

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::MeasureText(const FSkiaPaint& paint, const FString& text, FSkiaRect& rect)
{
    std::string str = TCHAR_TO_UTF8(*text);

    SkRect r;
    paint.paint->measureText(str.c_str(), str.length(), &r);

    rect.point = FVector2D(r.left(), r.top());
    rect.size = FVector2D(r.width(), r.height());

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintGradientLiner(const FSkiaPaint& paint, FVector2D start, FVector2D end, TArray<FSkiaGradient> gradients, EPaintTileMode mode)
{
    SkPoint pts[2]{ MakePoint(start), MakePoint(end) };
    TArray<SkColor> colors;
    TArray<SkScalar> pos;
    for (size_t i = 0; i < gradients.Num(); i++)
    {
        colors.Add(gradients[i].color.ToFColor(IS_SRGB).DWColor());
        pos.Add(gradients[i].offset);
    }

    sk_sp<SkShader> shade = SkGradientShader::MakeLinear(pts, colors.GetData(), pos.GetData(), colors.Num(), (SkShader::TileMode)mode);
    paint.paint->setShader(shade);

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintGradientRadial(const FSkiaPaint& paint, FVector2D center, float radius, TArray<FSkiaGradient> gradients, EPaintTileMode mode)
{
    TArray<SkColor> colors;
    TArray<SkScalar> pos;
    for (size_t i = 0; i < gradients.Num(); i++)
    {
        colors.Add(gradients[i].color.ToFColor(IS_SRGB).DWColor());
        pos.Add(gradients[i].offset);
    }

    sk_sp<SkShader> shade = SkGradientShader::MakeRadial(MakePoint(center), radius, colors.GetData(), pos.GetData(), colors.Num(), (SkShader::TileMode)mode);
    paint.paint->setShader(shade);

    return paint;
}

const FSkiaPaint& USkiaBPLibrary::SetPaintGradientSweep(const FSkiaPaint& paint, FVector2D center, TArray<FSkiaGradient> gradients)
{
    TArray<SkColor> colors;
    TArray<SkScalar> pos;
    for (size_t i = 0; i < gradients.Num(); i++)
    {
        colors.Add(gradients[i].color.ToFColor(IS_SRGB).DWColor());
        pos.Add(gradients[i].offset);
    }

    sk_sp<SkShader> shade = SkGradientShader::MakeSweep(center.X, center.Y, colors.GetData(), pos.GetData(), colors.Num());
    paint.paint->setShader(shade);

    return paint;
}
#pragma endregion

#pragma region Drawing
void USkiaBPLibrary::Translate(const FSkiaCanvas& canvas, float dx, float dy)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->translate(dx, dy);
    }
}

void USkiaBPLibrary::Scale(const FSkiaCanvas& canvas, float sx, float sy)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->scale(sx, sy);
    }
}

void USkiaBPLibrary::Rotate(const FSkiaCanvas& canvas, float angle)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->rotate(angle * PI / 180);
    }
}

void USkiaBPLibrary::Rotate2(const FSkiaCanvas& canvas, float angle, float px, float py)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->rotate(angle * PI / 180, px, py);
    }
}

void USkiaBPLibrary::Skew(const FSkiaCanvas& canvas, float sx, float sy)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->skew(sx, sy);
    }
}

void USkiaBPLibrary::DrawColor(const FSkiaCanvas& canvas, FLinearColor color, ECanvasBlendMode mode)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawColor(color.ToFColor(IS_SRGB).DWColor(), (SkBlendMode)mode);
    }
}

void USkiaBPLibrary::Clear(const FSkiaCanvas& canvas, FLinearColor color)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->clear(color.ToFColor(IS_SRGB).DWColor());
    }
}

void USkiaBPLibrary::DrawPaint(const FSkiaCanvas& canvas, const FSkiaPaint& paint)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawPaint(*paint.paint);
    }
}

void USkiaBPLibrary::DrawPoint(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawPoint(MakePoint(point), *paint.paint);
    }
}

void USkiaBPLibrary::DrawPoints(const FSkiaCanvas& canvas, const FSkiaPaint& paint, ECanvasPointMode mode, TArray<FVector2D> points)
{
    if (canvas.canvas != nullptr)
    {
        TArray<SkPoint> pts;
        for (size_t i = 0; i < points.Num(); i++)
        {
            pts.Add(MakePoint(points[i]));
        }

        canvas.canvas->drawPoints((SkCanvas::PointMode)mode, pts.Num(), pts.GetData(), *paint.paint);
    }
}

void USkiaBPLibrary::DrawLine(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D p0, FVector2D p1)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawLine(MakePoint(p0), MakePoint(p1), *paint.paint);
    }
}

void USkiaBPLibrary::DrawLine2(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaLine& line)
{
    DrawLine(canvas, paint, line.p0, line.p1);
}

void USkiaBPLibrary::DrawPolyline(const FSkiaCanvas& canvas, const FSkiaPaint& paint, TArray<FVector2D> points, bool closed)
{
    if (canvas.canvas != nullptr)
    {
        TArray<SkPoint> pts;
        for (size_t i = 0; i < points.Num(); i++)
        {
            pts.Add(MakePoint(points[i]));
        }

        SkPath path;
        path.addPoly(pts.GetData(), pts.Num(), closed);
        canvas.canvas->drawPath(path, *paint.paint);
    }
}

void USkiaBPLibrary::DrawRect(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FVector2D size)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawRect(MakeRect(point, size), *paint.paint);
    }
}

void USkiaBPLibrary::DrawRect2(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaRect& rect)
{
    DrawRect(canvas, paint, rect.point, rect.size);
}

void USkiaBPLibrary::DrawRoundRect(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FVector2D size, float rx, float ry)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawRoundRect(MakeRect(point, size), rx, ry, *paint.paint);
    }
}

void USkiaBPLibrary::DrawArc(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FVector2D size, float startAngle, float sweepAngle, bool useCenter)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawArc(MakeRect(point, size), startAngle, sweepAngle, useCenter, *paint.paint);
    }
}

void USkiaBPLibrary::DrawArc2(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaArc& arc, bool useCenter)
{
    DrawArc(canvas, paint, arc.point, arc.size, arc.startAngle, arc.sweepAngle, useCenter);
}

void USkiaBPLibrary::DrawOval(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FVector2D size)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawOval(MakeRect(point, size), *paint.paint);
    }
}

void USkiaBPLibrary::DrawCircle(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D center, float radius)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->drawCircle(MakePoint(center), radius, *paint.paint);
    }
}

void USkiaBPLibrary::DrawCircle2(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaCircle& circle)
{
    DrawCircle(canvas, paint, circle.center, circle.radius);
}

FSkiaRect USkiaBPLibrary::DrawText(const FSkiaCanvas& canvas, const FSkiaPaint& paint, FVector2D point, FString text)
{
    FSkiaRect rect;
    if (canvas.canvas != nullptr)
    {
        std::string str = TCHAR_TO_UTF8(*text);
        canvas.canvas->drawText(str.c_str(), str.length(), point.X, point.Y, *paint.paint);

        MeasureText(paint, text, rect);
        rect.point += point;
    }

    return rect;
}

void USkiaBPLibrary::ClipRect(const FSkiaCanvas& canvas, FVector2D point, FVector2D size, EClipOp op, bool doAntiAlias)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->clipRect(MakeRect(point, size), (SkClipOp)op, doAntiAlias);
    }
}

void USkiaBPLibrary::ClipPath(const FSkiaCanvas& canvas, const FSkiaPath& path, EClipOp op, bool doAntiAlias)
{
    if (canvas.canvas != nullptr)
    {
        canvas.canvas->clipPath(*path.path, (SkClipOp)op, doAntiAlias);
    }
}

void USkiaBPLibrary::CreateBitmap(FString filePath, FSkiaBitmap& bitmap)
{
    SkCodec::Result result;
    std::unique_ptr<SkCodec> codec = SkPngCodec::MakeFromStream(SkFILEStream::MakeFromFile(TCHAR_TO_UTF8(*filePath)), &result);

    const SkImageInfo& image_info = codec->getInfo();
    std::shared_ptr<SkBitmap> image = std::make_shared<SkBitmap>();
    image->allocPixels(image_info);

    result = codec->getPixels(image_info, image->getPixels(), image->rowBytes());
    if (SkCodec::kSuccess == result)
    {
        bitmap.bitmap = image;
        bitmap.imageWidth = image->width();
        bitmap.imageHeight = image->height();
    }
}

void USkiaBPLibrary::DrawBitmap(const FSkiaCanvas& canvas, const FSkiaBitmap& bitmap, FVector2D point)
{
    if ((canvas.canvas != nullptr) && (bitmap.bitmap != nullptr))
    {
        canvas.canvas->drawBitmap(*bitmap.bitmap, point.X, point.Y);
    }
}
#pragma endregion

#pragma region Path
void USkiaBPLibrary::CreatePath(FSkiaPath& path)
{
    path.path = std::make_shared<SkPath>();
}

void USkiaBPLibrary::MoveTo(const FSkiaPath& path, FVector2D point)
{
    path.path->moveTo(point.X, point.Y);
}

void USkiaBPLibrary::LineTo(const FSkiaPath& path, FVector2D point)
{
    path.path->lineTo(point.X, point.Y);
}

void USkiaBPLibrary::QuadTo(const FSkiaPath& path, FVector2D pt1, FVector2D pt2)
{
    path.path->quadTo(MakePoint(pt1), MakePoint(pt2));
}

void USkiaBPLibrary::ConicTo(const FSkiaPath& path, FVector2D pt1, FVector2D pt2, float w)
{
    path.path->conicTo(MakePoint(pt1), MakePoint(pt2), w);
}

void USkiaBPLibrary::CubicTo(const FSkiaPath& path, FVector2D pt1, FVector2D pt2, FVector2D pt3)
{
    path.path->cubicTo(MakePoint(pt1), MakePoint(pt2), MakePoint(pt3));
}

void USkiaBPLibrary::ArcTo(const FSkiaPath& path, FVector2D point, FVector2D size, float startAngle, float sweepAngle, bool forceMoveTo)
{
    path.path->arcTo(MakeRect(point, size), startAngle, sweepAngle, forceMoveTo);
}

void USkiaBPLibrary::ArcTo2(const FSkiaPath& path, FVector2D pt1, FVector2D pt2, float radius)
{
    path.path->arcTo(MakePoint(pt1), MakePoint(pt2), radius);
}

void USkiaBPLibrary::DrawPath(const FSkiaCanvas& canvas, const FSkiaPaint& paint, const FSkiaPath& path, bool closed, EPathFillType fillType)
{
    if (canvas.canvas != nullptr)
    {
        if (closed)
        {
            path.path->close();
        }

        path.path->setFillType((SkPath::FillType)fillType);
        canvas.canvas->drawPath(*path.path, *paint.paint);
    }
}


#pragma endregion

相关文章

网友评论

      本文标题:UE4封装Skia

      本文链接:https://www.haomeiwen.com/subject/izahyqtx.html