summaryrefslogtreecommitdiffhomepage
path: root/pose-widget/pose-widget.hpp
blob: 1e50b39225c29dd092e890bfe82ae04eff4a5d18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* Copyright (c) 2013, 2015 Stanislaw Halik <sthalik@misaki.pl>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 */

#pragma once

#include "api/plugin-api.hpp"
#include "compat/euler.hpp"

#include "export.hpp"

#include <tuple>
#include <mutex>
#include <atomic>
#include <vector>

#include <QWidget>
#include <QThread>
#include <QImage>

namespace pose_widget_impl {

using num = float;
using vec3 = Mat<num, 3, 1>;
using vec2 = Mat<num, 2, 1>;
using vec2i = Mat<int, 2, 1>;
using vec2u = Mat<int, 2, 1>;

using rmat = Mat<num, 3, 3>;

using namespace euler;

using lock_guard = std::unique_lock<std::mutex>;

class pose_widget;

class Triangle {
    num dot00, dot01, dot11, invDenom;
    vec2 v0, v1, origin;
public:
    Triangle(const vec2& p1, const vec2& p2, const vec2& p3);
    bool barycentric_coords(const vec2& px, vec2& uv, int& i) const;
};

struct pose_transform final : QThread
{
    pose_transform(QWidget* dst, double device_pixel_ratio);
    ~pose_transform() override;

    void rotate_async(double xAngle, double yAngle, double zAngle, double x, double y, double z);
    void rotate_sync(double xAngle, double yAngle, double zAngle, double x, double y, double z);

    template<typename F>
    void with_rotate(F&& fun, double xAngle, double yAngle, double zAngle, double x, double y, double z);

    void run() override;

    vec2 project(const vec3& point);
    vec3 project2(const vec3& point);
    void project_quad_texture();
    std::pair<vec2i, vec2i> get_bounds(const vec2& size);

    template<typename F> inline void with_image_lock(F&& fun);

    rmat rotation, rotation_;
    vec3 translation, translation_;

    std::mutex mtx, mtx2;

    QWidget* dst;

    QImage front{QImage{":/images/side1.png"}.convertToFormat(QImage::Format_ARGB32)};
    QImage back{QImage{":/images/side6.png"}.convertToFormat(QImage::Format_ARGB32)};
    QImage image{w, h, QImage::Format_ARGB32};
    QImage image2{w, h, QImage::Format_ARGB32};

    struct uv_ // NOLINT(cppcoreguidelines-pro-type-member-init)
    {
        vec2 coords;
        int i;
    };

    std::vector<uv_> uv_vec;
    std::atomic<bool> fresh = false;

    static constexpr int w = 320, h = 240;
};

class OTR_POSE_WIDGET_EXPORT pose_widget final : public QWidget
{
public:
    pose_widget(QWidget *parent = nullptr);
    ~pose_widget() override;
    void rotate_async(double xAngle, double yAngle, double zAngle, double x, double y, double z);
    void rotate_sync(double xAngle, double yAngle, double zAngle, double x, double y, double z);

private:
    pose_transform xform;
    void paintEvent(QPaintEvent *event) override;
};

}

using pose_widget = pose_widget_impl::pose_widget;