5
3

More than 3 years have passed since last update.

SkiaとC++でデスクトップアプリを作る(Windows) その2

Posted at

目次

SkiaとC++でデスクトップアプリを作る(Windows) その1
SkiaとC++でデスクトップアプリを作る(Windows) その2

環境

  • Windows 10 64bit 2004
  • VisualStudio2019
  • CMake version 3.17.20032601-MSVC_2

諸々のプロダクトは2020年8月時点の最新版です(多分)

VisualStudioのプロジェクト(CMake)でSkiaを使う

クロスプラットフォームも見据えてCMakeでプロジェクトを作ります。

VisualStudioを開き、[CMake プロジェクト]を選択して作成しましょう。この先プロジェクト名は[SkiaDesktopSample]として書きます。

image.png

GLFWの導入

Skia単体では画面出力ができないため、OpenGLのユーティリティライブラリであるGLFWの助けを借ります。

glfw.orgの右上のボタンからGLFWの最新版をダウンロードします。Zipファイルを解凍したら先程作ったプロジェクトの{ProjectRoot}/SkiaDesktopSample/third/glfw 辺りに入れておきましょう。
これによりCMakeで読み込めるようになります。

CMakeLists.txtの書き換え

CMakeListsを書いてskiaとglfwをリンクしましょう。

{ProjectRoot}/SkiaDesktopSample/CMakeLists.txt
# CMakeList.txt : SkiaDesktopSample の CMake プロジェクト。ソースを含めて、次を定義します:
# プロジェクト専用ロジックはこちらです。
#
cmake_minimum_required (VERSION 3.8)

# ソースをこのプロジェクトの実行可能ファイルに追加します。
add_executable (SkiaDesktopSample "SkiaDesktopSample.cpp" "SkiaDesktopSample.h")

# TODO: テストを追加し、必要な場合は、ターゲットをインストールします。

include_directories("C:/src/skia")
include_directories("C:/src/skia/tools/sk_app")
link_directories("C:/src/skia/out/release")
target_link_libraries(SkiaDesktopSample opengl32)
target_link_libraries(SkiaDesktopSample "C:/src/skia/out/release/skia.lib")

add_subdirectory("third/glfw")
include_directories("third/glfw/include")
target_link_libraries(SkiaDesktopSample glfw)

set_property(TARGET SkiaDesktopSample PROPERTY CXX_STANDARD 17)

include_directoriesでskiaの2箇所をincludeパスに指定します。もっと深い階層でincludeすることもできるのですが、内部ファイルのインクルードの指定の影響でこの書き方でないとコンパイルできません。
あまり行儀よくないですが、target_link_librariesにその1で作ったskia.libファイルをリンクします。openglも必要なので一緒にリンクしましょう。

またGLFWはsubdirectoryとして追加します。

Skiaは現時点ではC++20に対応していないため、C++17を指定します。

ファイルをこれで書き換え、保存してエラーが出ないことを確認してください。

コードを書く

プロジェクト作成時に作られているcppファイルを以下の内容で置き換えます。

SkiaDesktopSample.cpp
// SkiaDesktopSample.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "SkiaDesktopSample.h"

#define SK_GL

#include "GLFW/glfw3.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrContext.h"
#include "include/gpu/gl/GrGLInterface.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkSurface.h"
#include "include/core/SkFont.h"
#include <stdio.h>
#include <stdlib.h>
#include "include/effects/Sk2DPathEffect.h"


using namespace std;

GrContext* sContext = nullptr;
SkSurface* sSurface = nullptr;

void errorCallback(int error, const char* description) {
    fputs(description, stderr);
}

void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
}

void initSkia(int w, int h) {
    GrContextOptions options;
    sContext = GrContext::MakeGL(nullptr, options).release();

    GrGLFramebufferInfo framebufferInfo;
    framebufferInfo.fFBOID = 0;
    framebufferInfo.fFormat = GL_RGBA8;

    SkColorType colorType;
    colorType = kRGBA_8888_SkColorType;
    GrBackendRenderTarget backendRenderTarget(w, h, 0, 0, framebufferInfo);

    sSurface = SkSurface::MakeFromBackendRenderTarget(
        sContext, backendRenderTarget, kBottomLeft_GrSurfaceOrigin, colorType, nullptr, nullptr
    ).release();
    if (sSurface == nullptr) abort();
}

void cleanupSkia() {
    delete sSurface;
    delete sContext;
}

const int kWidth = 960;
const int kHeight = 640;

int main(int argc, char* argv[])
{
    cout << "Hello CMake." << endl;
    GLFWwindow* window;
    glfwSetErrorCallback(errorCallback);
    if (!glfwInit()) {
        exit(EXIT_FAILURE);
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    glfwWindowHint(GLFW_STENCIL_BITS, 0);
    glfwWindowHint(GLFW_DEPTH_BITS, 0);

    window = glfwCreateWindow(kWidth, kHeight, "Simple Example", NULL, NULL);
    if (!window) {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    glfwMakeContextCurrent(window);

    initSkia(kWidth, kHeight);

    glfwSwapInterval(1);
    glfwSetKeyCallback(window, keyCallback);

    SkCanvas* canvas = sSurface->getCanvas();

    const char message[] = "Hello, Skia!";

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        SkPaint paint;
        canvas->clear(SK_ColorWHITE);
        paint.setColor(SK_ColorBLUE);
        canvas->drawRect({ 100,200,300,500 }, paint);
        paint.setColor(SK_ColorRED);
        SkFont font;
        font.setSubpixel(true);
        font.setSize(72);
        canvas->drawSimpleText(message, strlen(message), SkTextEncoding::kUTF8, kWidth / 2, kHeight / 2, font, paint);
        sContext->flush();

        glfwSwapBuffers(window);
    }

    cleanupSkia();
    glfwDestroyWindow(window);
    glfwTerminate();
    exit(EXIT_SUCCESS);
    return 0;
}

CMakeの設定を変更

少し設定を弄ります。[プロジェクト]>[SkiaDesktopSampleのCMakeの設定]>[CMake変数とキャッシュ]で、[高度な変数を表示]にチェックを入れます。
すると複数の変数が表示されるのでCMAKE_CXX_FLAGS_DEBUGを探し出し、最初の/MDd/MTdに変更し、保存します。

image.png

またUSE_MSVC_RUNTIME_LIBRARY_DLLのチェックを外します。

image.png

ビルドして実行

[デバッグ]>[デバッグの開始]を選択すると、ウィンドウが表示されます!!!!!!!

image.png

参考

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3