← 과제 목록

[과제] 2주차) Basic Programming 김창완

@Saususge
  • #과제
목차

제출 브랜치

https://github.com/Saususge/thorvg.example/tree/example/custom

과제 코드

/*
 * Copyright (c) 2020 - 2026 ThorVG project. All rights reserved.

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "Example.h"

/************************************************************************/
/* ThorVG Drawing Contents                                              */
/************************************************************************/

struct UserExample : tvgexam::Example
{
    bool content(tvg::Canvas* canvas, uint32_t w, uint32_t h) override
    {
        //White background
        auto bg = tvg::Shape::gen();
        bg->appendRect(0, 0, w, h);
        bg->fill(255, 255, 255);
        canvas->add(bg);

        auto scene = tvg::Scene::gen();

        float cx = float(w) * 0.5f;

        //Blade — tapered path, pointed tip
        float y_tip = 40.0f;
        float y_blade_base = 200.0f;
        float blade_half_base = 12.0f;

        auto blade = tvg::Shape::gen();
        blade->moveTo(cx - blade_half_base, y_blade_base);
        blade->lineTo(cx, y_tip);
        blade->lineTo(cx + blade_half_base, y_blade_base);
        blade->close();
        blade->fill(220, 220, 230);
        blade->strokeFill(120, 120, 130);
        blade->strokeWidth(1.5f);
        scene->add(blade);

        //Blade edge highlight
        auto edge = tvg::Shape::gen();
        edge->moveTo(cx, y_tip);
        edge->lineTo(cx + blade_half_base, y_blade_base);
        edge->strokeFill(255, 255, 255);
        edge->strokeWidth(1.0f);
        scene->add(edge);

        //Guard (crossguard)
        auto guard = tvg::Shape::gen();
        guard->appendRect(cx - 55, y_blade_base - 5, 110, 16, 4, 4);
        guard->fill(139, 90, 43);
        guard->strokeFill(80, 50, 20);
        guard->strokeWidth(1.5f);
        scene->add(guard);

        //Grip (handle)
        auto grip = tvg::Shape::gen();
        grip->appendRect(cx - 8, y_blade_base + 15, 16, 100, 4, 4);
        grip->fill(101, 67, 33);
        grip->strokeFill(60, 30, 10);
        grip->strokeWidth(1.5f);
        scene->add(grip);

        //Grip wrapping lines
        for (int i = 0; i < 5; i++) {
            auto wrap = tvg::Shape::gen();
            float wy = y_blade_base + 25 + i * 18;
            wrap->moveTo(cx - 10, wy);
            wrap->lineTo(cx + 10, wy);
            wrap->strokeFill(80, 50, 20);
            wrap->strokeWidth(1.0f);
            scene->add(wrap);
        }

        //Pommel
        auto pommel = tvg::Shape::gen();
        pommel->appendCircle(cx, y_blade_base + 125, 14, 14);
        pommel->fill(180, 160, 50);
        pommel->strokeFill(100, 80, 20);
        pommel->strokeWidth(1.5f);
        scene->add(pommel);

        canvas->add(scene);

        return true;
    }
};

/************************************************************************/
/* Entry Point                                                          */
/************************************************************************/

int main(int argc, char **argv)
{
    return tvgexam::main(new UserExample, argc, argv, false, 400, 600);
}

주요 구현 내용

  • 일단 판타지 스타일의 검을 tutorial에 나와있는 shape drawing으로만 구현해보려 했습니다.
  • 캔버스는 큰게 필요없을거같아 main에서 400x600으로 윈도우 크기를 override했습니다
  • 각 도형에 맞게 path, move, appendRect, appendCircle등을 이용하여 물체를 만들었습니다.
  • grip은 반복문을 이용해 일정거리에 그려서 깔끔하게 처리하도록 했습니다.
  • Example 구조체가 윈도우 생성과 같은 반복 작업을 추상화해줘서, 도형 구성에만 집중할 수 있었습니다.
  • 좌표는 가로 중심을 기준으로 잡고, 도형 크기를 조정해가며 배치했습니다.
  • SVG나 Skia처럼 벡터 도형을 조립하는 스타일과 비슷해서, 다른 예제를 참고하기도 쉬웠습니다.
  • 과제의 코드는 src/CustomExample.cpp에 위치해 있습니다.

댓글

Discussion 원문