1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 12 мая 2019 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <ui/tk/tk.h>
23 
24 namespace lsp
25 {
26     namespace tk
27     {
28         #define V3(x, y, z) { x, y, z, 1.0f }
29 
30         static const point3d_t tk_capture_vertices[] =
31         {
32             V3(0, 0, 0),
33             V3(0.30, 0, 0),
34             V3(0.22, 0.06, 0),
35             V3(0.22, -0.06, 0),
36             V3(0.22, 0, 0.06),
37             V3(0.22, 0, -0.06)
38         };
39 //
40 //        static const point3d_t tk_capture_capsule[] =
41 //        {
42 //            V3(0, 0, 1), V3(1, 0, 0), V3(0, 1, 0),
43 //            V3(0, 0, 1), V3(0, 1, 0), V3(-1, 0, 0),
44 //            V3(0, 0, 1), V3(-1, 0, 0), V3(0, -1, 0),
45 //            V3(0, 0, 1), V3(0, -1, 0), V3(1, 0, 0),
46 //
47 //            V3(0, 0, -1), V3(0, 1, 0), V3(1, 0, 0),
48 //            V3(0, 0, -1), V3(-1, 0, 0), V3(0, 1, 0),
49 //            V3(0, 0, -1), V3(0, -1, 0), V3(-1, 0, 0),
50 //            V3(0, 0, -1), V3(1, 0, 0), V3(0, -1, 0),
51 //        };
52 
53         static const uint32_t tk_arrow_indexes[] =
54         {
55             0, 1,
56             1, 2,
57             1, 3,
58             1, 4,
59             1, 5
60         };
61 
62         const w_class_t LSPCapture3D::metadata = { "LSPCapture3D", &LSPObject3D::metadata };
63 
LSPCapture3D(LSPDisplay * dpy)64         LSPCapture3D::LSPCapture3D(LSPDisplay *dpy):
65             LSPObject3D(dpy),
66             sColor(this),
67             sAxisColor(this)
68         {
69             pClass          = &metadata;
70         }
71 
~LSPCapture3D()72         LSPCapture3D::~LSPCapture3D()
73         {
74         }
75 
init()76         status_t LSPCapture3D::init()
77         {
78             status_t res = LSPObject3D::init();
79             if (res != STATUS_OK)
80                 return res;
81 
82             init_color(C_RED, &sColor);
83             init_color(C_YELLOW, &sAxisColor);
84             return STATUS_OK;
85         }
86 
destroy()87         void LSPCapture3D::destroy()
88         {
89             LSPObject3D::destroy();
90         }
91 
get_position(point3d_t * dst,size_t id)92         status_t LSPCapture3D::get_position(point3d_t *dst, size_t id)
93         {
94             v_capture_t *cap = vItems.get(id);
95             if (cap == NULL)
96                 return STATUS_NOT_FOUND;
97             dsp::init_point_xyz(dst, 0.0f, 0.0f, 0.0f);
98             dsp::apply_matrix3d_mp1(dst, &cap->pos);
99             return STATUS_OK;
100         }
101 
get_direction(vector3d_t * dst,size_t id)102         status_t LSPCapture3D::get_direction(vector3d_t *dst, size_t id)
103         {
104             v_capture_t *cap = vItems.get(id);
105             if (cap == NULL)
106                 return STATUS_NOT_FOUND;
107             dsp::init_vector_dxyz(dst, 1.0f, 0.0f, 0.0f);
108             dsp::apply_matrix3d_mv1(dst, &cap->pos);
109             return STATUS_OK;
110         }
111 
get_location(ray3d_t * dst,size_t id)112         status_t LSPCapture3D::get_location(ray3d_t *dst, size_t id)
113         {
114             v_capture_t *cap = vItems.get(id);
115             if (cap == NULL)
116                 return STATUS_NOT_FOUND;
117             dsp::init_point_xyz(&dst->z, 0.0f, 0.0f, 0.0f);
118             dsp::init_vector_dxyz(&dst->v, 1.0f, 0.0f, 0.0f);
119             dsp::apply_matrix3d_mp1(&dst->z, &cap->pos);
120             dsp::apply_matrix3d_mv1(&dst->v, &cap->pos);
121             return STATUS_OK;
122         }
123 
enabled(size_t id) const124         bool LSPCapture3D::enabled(size_t id) const
125         {
126             LSPCapture3D *_this = const_cast<LSPCapture3D *>(this);
127             v_capture_t *cap = _this->vItems.get(id);
128             return (cap != NULL) ? cap->bEnabled : false;
129         }
130 
radius(size_t id) const131         float LSPCapture3D::radius(size_t id) const
132         {
133             LSPCapture3D *_this = const_cast<LSPCapture3D *>(this);
134             v_capture_t *cap = _this->vItems.get(id);
135             return (cap != NULL) ? cap->radius : false;
136         }
137 
clear()138         void LSPCapture3D::clear()
139         {
140             if (vItems.size() > 0)
141             {
142                 vItems.clear();
143                 query_draw();
144             }
145         }
146 
set_items(size_t items)147         status_t LSPCapture3D::set_items(size_t items)
148         {
149             if (vItems.size() == items)
150                 return STATUS_OK;
151 
152             while (vItems.size() < items)
153             {
154                 v_capture_t *cap = vItems.add();
155                 if (cap == NULL)
156                     return STATUS_NO_MEM;
157 
158                 dsp::init_matrix3d_identity(&cap->pos);
159                 cap->radius     = 1.0f;
160                 cap->bEnabled   = false;
161             }
162 
163             while (vItems.size() > items)
164                 vItems.remove_last();
165 
166             query_draw();
167             return STATUS_OK;
168         }
169 
set_transform(size_t id,const matrix3d_t * matrix)170         status_t LSPCapture3D::set_transform(size_t id, const matrix3d_t *matrix)
171         {
172             v_capture_t *cap = vItems.get(id);
173             if (cap == NULL)
174                 return STATUS_NOT_FOUND;
175             cap->pos        = *matrix;
176             query_draw();
177             return STATUS_OK;
178         }
179 
set_enabled(size_t id,bool enabled)180         status_t LSPCapture3D::set_enabled(size_t id, bool enabled)
181         {
182             v_capture_t *cap = vItems.get(id);
183             if (cap == NULL)
184                 return STATUS_NOT_FOUND;
185             if (cap->bEnabled == enabled)
186                 return STATUS_OK;
187             cap->bEnabled  = enabled;
188             query_draw();
189             return STATUS_OK;
190         }
191 
set_radius(size_t id,float radius)192         void LSPCapture3D::set_radius(size_t id, float radius)
193         {
194             v_capture_t *cap = vItems.get(id);
195             if ((cap == NULL) || (cap->radius == radius))
196                 return;
197             cap->radius     = radius;
198             if (cap->bEnabled)
199                 query_draw();
200         }
201 
render(IR3DBackend * r3d)202         void LSPCapture3D::render(IR3DBackend *r3d)
203         {
204             if (!is_visible())
205                 return;
206 
207             r3d_buffer_t buf;
208             cstorage<raw_triangle_t> mesh;
209             cstorage<ray3d_t> vertices;
210 
211             // Draw all elements of the capture
212             for (size_t id=0, nid=vItems.size(); id < nid; ++id)
213             {
214                 v_capture_t *cap = vItems.get(id);
215                 if ((cap == NULL) || (!cap->bEnabled))
216                     continue;
217 
218                 // Update mesh data for lines
219                 for (size_t i=0; i<6; ++i)
220                     dsp::apply_matrix3d_mp2(&sLines[i], &tk_capture_vertices[i], &cap->pos);
221 
222                 // Call draw of lines
223                 buf.type            = R3D_PRIMITIVE_LINES;
224                 buf.width           = 2.0f;
225                 buf.count           = sizeof(tk_arrow_indexes) / (sizeof(uint32_t) * 2);
226                 buf.flags           = 0;
227 
228                 buf.vertex.data     = sLines;
229                 buf.vertex.stride   = sizeof(point3d_t);
230                 buf.normal.data     = NULL;
231                 buf.normal.stride   = sizeof(point3d_t);
232                 buf.color.data      = NULL;
233                 buf.color.stride    = sizeof(point3d_t);
234                 buf.color.dfl.r     = sAxisColor.red();
235                 buf.color.dfl.g     = sAxisColor.green();
236                 buf.color.dfl.b     = sAxisColor.blue();
237                 buf.color.dfl.a     = 1.0f;
238                 buf.index.data      = tk_arrow_indexes;
239 
240                 r3d->draw_primitives(&buf);
241 
242                 // Update mesh data for body
243                 status_t res = rt_gen_capture_mesh(mesh, cap);
244                 if (res != STATUS_OK)
245                     continue;
246 
247                 vertices.clear();
248                 if (!vertices.append_n(mesh.size() * 3))
249                     continue;
250 
251                 raw_triangle_t *tv  = mesh.get_array();
252                 ray3d_t *tr         = vertices.get_array();
253                 for (size_t i=0, n=mesh.size(); i<n; ++i, tr += 3)
254                 {
255                     dsp::apply_matrix3d_mp2(&tr[0].z, &tv[i].v[0], &cap->pos);
256                     dsp::apply_matrix3d_mp2(&tr[1].z, &tv[i].v[1], &cap->pos);
257                     dsp::apply_matrix3d_mp2(&tr[2].z, &tv[i].v[2], &cap->pos);
258 
259                     dsp::calc_normal3d_p3(&tr[0].v, &tr[0].z, &tr[1].z, &tr[2].z);
260                     tr[1].v             = tr[0].v;
261                     tr[2].v             = tr[0].v;
262                 }
263                 tr                  = vertices.get_array();
264 
265                 // Call draw of capsule
266                 buf.type            = R3D_PRIMITIVE_TRIANGLES;
267                 buf.flags           = R3D_BUFFER_LIGHTING;
268                 buf.width           = 1.0f;
269                 buf.count           = mesh.size();
270                 buf.color.dfl.r     = sColor.red();
271                 buf.color.dfl.g     = sColor.green();
272                 buf.color.dfl.b     = sColor.blue();
273                 buf.color.dfl.a     = 1.0f;
274 
275                 buf.vertex.data     = &tr[0].z;
276                 buf.vertex.stride   = sizeof(ray3d_t);
277                 buf.normal.data     = &tr[0].v;
278                 buf.normal.stride   = sizeof(ray3d_t);
279                 buf.index.data      = NULL;
280 
281                 r3d->draw_primitives(&buf);
282             }
283         }
284 
285     } /* namespace tk */
286 } /* namespace lsp */
287