HoviTron Video Pipeline
RenderingParameters.cpp
1/* ----------------------
2* Copyright 2023 Université Libre de Bruxelles(ULB), Universidad Politécnica de Madrid(UPM), CREAL, Deutsches Zentrum für Luft - und Raumfahrt(DLR)
3
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at < http://www.apache.org/licenses/LICENSE-2.0>
7
8* Unless required by applicable law or agreed to in writing, software
9* distributed under the License is distributed on an "AS IS" BASIS,
10* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11* See the License for the specific language governing permissionsand
12* limitations under the License.
13---------------------- */
14
15
16#include "RenderingParameters.h"
17#include"../WindowAbstract.h"
18
20#include "VulkanWrapper.h"
21
22#ifdef HVT_UDP_CONTROL
23void RenderingParameters::init(int viewNum, WindowAbstract* wind, VulkanWrapper* wraps, unsigned short portNumber)
24{
25 this->portNumber = portNumber;
26#else
28{
29#endif
30 window = wind;
31 wrapper = wraps;
32
33 virtualExtrinsics.resize(viewNum);
34 virtualIntrasics.resize(viewNum);
35 virtualViewDef.resize(viewNum);
36
37 staticPosition.resize(staticPoses);
38 staticQuaternion.resize(staticPoses);
39
40 for (int i = 0; i < viewNum; i++) {
41 auto ext = window->getSwapchainExtent(i);
42 virtualViewDef[i] = glm::vec2(ext.width, ext.height);
43 virtualExtrinsics[i].position = glm::vec3(0, 0, 0);
44 virtualExtrinsics[i].rotation = glm::vec3(0, 0, 0);
45 projectionType = InputProvider::ProjectionType::PROJECTION_PERSPECTIVE;
47 virtualIntrasics[i] = intra;
48 std::get<InputProvider::PerspectiveIntrinsics>(virtualIntrasics[i]).principle = glm::vec2(ext.width, ext.height) / 2.0f;
49 std::get<InputProvider::PerspectiveIntrinsics>(virtualIntrasics[i]).focals = glm::vec2(ext.width, ext.width) / 2.0f;
50 virtualIntrasics.push_back(intra);
51 }
52#ifdef HVT_UDP_CONTROL
53 setupUDPServer();
54#endif // HVT_UDP_CONTROL
55
56}
57
59{
60#ifdef HVT_UDP_CONTROL
61 serverIsActive = false;
62 serverThread.join();
63#endif
64}
65
66void RenderingParameters::updateSpaceTransform(glm::vec3 translation, glm::vec3 rotation)
67{
68 for (int i = 0; i < virtualExtrinsics.size(); i++) {
69 virtualExtrinsics[i].position = translation;//glm::vec3(translation[0], translation[1], translation[2]);
70 virtualExtrinsics[i].rotation = rotation;//glm::vec3(rotation[0], rotation[1], rotation[2]);
71 }
72}
73
74void RenderingParameters::updateSpaceTransform(glm::vec3 translation, glm::vec3 rotation, glm::vec4 fov, int view)
75{
76 virtualExtrinsics[view].position = translation;// glm::vec3(translation[0], translation[1], translation[2]);
77 virtualExtrinsics[view].rotation = rotation;//glm::vec3(rotation[0], rotation[1], rotation[2]);
78
79 auto tl = std::tan(fov[0]); //left
80 auto tr = std::tan(fov[1]); //right
81 auto tt = std::tan(fov[2]); //top
82 auto tb = std::tan(fov[3]); //down
83
84 auto tw = tr - tl;
85 auto th = tt - tb;
86
87 auto x0 = (-tl) / tw;
88 auto y0 = (-tb) / th;
89
90 if (projectionType == InputProvider::ProjectionType::PROJECTION_PERSPECTIVE) {
91 std::get<InputProvider::PerspectiveIntrinsics>(virtualIntrasics[view]).focals.x = virtualViewDef[view].x / tw;
92 std::get<InputProvider::PerspectiveIntrinsics>(virtualIntrasics[view]).focals.y = virtualViewDef[view].y / th;
93
94
95 std::get<InputProvider::PerspectiveIntrinsics>(virtualIntrasics[view]).principle.x = x0 * virtualViewDef[view].x;
96 std::get<InputProvider::PerspectiveIntrinsics>(virtualIntrasics[view]).principle.y = (1 - y0) * virtualViewDef[view].y;
97 }
98 else {
99 throw std::runtime_error("Unsupported projection type for virtual parameter"); //TODO support this (Should not be complicated since fov are already the angle that we need for ver_range and hor_range)
100 }
101}
102
104{
105 InputProvider::Extrinsics pose = { .position = {0,0,0}, .rotation = {0,0,0} };
106
107 //TODO move that at a better place
108 glm::vec3 averagePos = { 0,0,0 };
109 for (int i = 0; i < virtualExtrinsics.size(); i++) {
110 averagePos += virtualExtrinsics[i].position;
111 }
112 averagePos /= virtualExtrinsics.size();
113
114 if (virtualMode == VirtualMode::Static1) {
115#ifdef HVT_UDP_CONTROL
116 mutex.lock();
117#endif
118 pose.position = staticPosition[0] + (virtualExtrinsics[view].position - averagePos );
119 pose.rotation = quatToEuler(staticQuaternion[0]);
120#ifdef HVT_UDP_CONTROL
121 mutex.unlock();
122#endif
123 //pose.rotation = static[0];
124 }
125 else if (virtualMode == VirtualMode::Static2) {
126#ifdef HVT_UDP_CONTROL
127 mutex.lock();
128#endif
129 pose.position = staticPosition[1] + (virtualExtrinsics[view].position - averagePos );
130 pose.rotation = quatToEuler(staticQuaternion[1]);
131#ifdef HVT_UDP_CONTROL
132 mutex.unlock();
133#endif
134 }
135 else {
136 assert(virtualExtrinsics.size() > view);
137 pose = virtualExtrinsics[view];
138 }
139 return pose;
140}
141
143{
144 assert(virtualIntrasics.size() > view);
145 return virtualIntrasics[view];
146}
147
148void RenderingParameters::setStartingPt(glm::vec3 startPos, glm::vec3 startRot)
149{
150#ifdef HVT_UDP_CONTROL
151 startPosMut.lock();
152#endif
153 startingPosition = startPos;
154 startingRotation = startRot;
155#ifdef HVT_UDP_CONTROL
156 startPosMut.unlock();
157#endif
158}
159
161{
162#ifdef HVT_UDP_CONTROL
163 startPosMut.lock();
164#endif
165 const glm::vec3 res = glm::vec3(startingPosition);
166#ifdef HVT_UDP_CONTROL
167 startPosMut.unlock();
168#endif
169 return res;
170}
171
173{
174#ifdef HVT_UDP_CONTROL
175 startPosMut.lock();
176#endif
177 const glm::vec3 res = glm::vec3(startingRotation);
178#ifdef HVT_UDP_CONTROL
179 startPosMut.unlock();
180#endif
181 return res;
182}
183
184#ifdef HVT_UDP_CONTROL
185void RenderingParameters::setupUDPServer()
186{
187
188#ifndef WIN32
189 struct sockaddr_in client, server;
190#endif
191
192
193
194#ifdef WIN32
195 // Initialize Winsock
196 WSADATA wsaData;
197 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
198 if (iResult != 0) {
199 printf("WSAStartup failed with error: %d\n", iResult);
200 throw std::runtime_error("WSAStartup");
201 }
202#endif // WIN32
203
204
205 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
206 {
207#ifdef WIN32
208 auto dw = GetLastError();
209 LPSTR messageBuffer = nullptr;
210
211 //Ask Win32 to give us the string version of that message ID.
212 //The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
213 size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
214 NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
215
216 //Copy the error message into a std::string.
217 std::string message(messageBuffer, size);
218 WSACleanup();
219 throw std::runtime_error("socket error" + message);
220 //Free the Win32's string's buffer.
221 LocalFree(messageBuffer);
222
223
224#else
225 tcperror("socket()");
226 throw std::runtime_error("socket error");
227#endif
228 }
229
230 server.sin_family = AF_INET; /* Server is in Internet Domain */
231 server.sin_port = htons(portNumber); /* Use specified port */
232 server.sin_addr.s_addr = INADDR_ANY;/* Server's Internet Address */
233
234 if (bind(s, (struct sockaddr*)&server, sizeof(server)) < 0)
235 {
236#ifdef WIN32
237 WSACleanup();
238 throw std::runtime_error("bind error");
239#else
240 tcperror("bind()");
241 throw std::runtime_error("bind error");
242#endif
243
244 }
245
246
247 DWORD tv = 1000;
248 if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*) &tv, sizeof(tv)) < 0) {
249 perror("Error");
250 }
251
252 /* Find out what port was really assigned and print it */
253 namelen = sizeof(server);
254 if (getsockname(s, (struct sockaddr*)&server, &namelen) < 0)
255 {
256#ifdef WIN32
257 WSACleanup();
258 throw std::runtime_error("error sockName");
259#else
260 tcperror("getsockname()");
261 throw std::runtime_error("error sockName");
262#endif
263
264 }
265
266 PRINT("Port assigned is %d\n", ntohs(server.sin_port));
267
268 serverThread = std::thread([this] { this->mainLoop(); });
269
270}
271void RenderingParameters::mainLoop()
272{
273 while (serverIsActive) {
274 client_address_size = sizeof(client);
275
276 if (recvfrom(s, (char*)&udpMsg, sizeof(UDPMessage), 0, (struct sockaddr*)&client,
277 &client_address_size) < 0)
278 {
279#ifdef WIN32
280 auto dw = GetLastError();
281 LPSTR messageBuffer = nullptr;
282 //Ask Win32 to give us the string version of that message ID.
283 //The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
284 size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
285 NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
286 //Copy the error message into a std::string.
287 std::string message(messageBuffer, size);
288
289 if (!message.empty() > 0) {
290 D(PRINT("On port %d message: %s", ntohs(server.sin_port), message.c_str());)
291 }
292 //
293 //throw std::runtime_error("rcv from error" + message);
294#else
295 tcperror("recvfrom()");
296 //throw std::runtime_error("rcv from error");
297#endif
298
299 }
300 else {
301 assert(udpMsg.magic == magicNb);
302
303 PRINT("Requested mode: %f", udpMsg.mode);
304 PRINT("Received position: %f,%f,%f", udpMsg.viewTransx, udpMsg.viewTransy, udpMsg.viewTransz);
305 PRINT("Received rotation: %f,%f,%f,%f", udpMsg.viewRotx, udpMsg.viewRoty, udpMsg.viewRotz, udpMsg.viewRotw);
306
307 mutex.lock();
308
309 if (udpMsg.mode == 0) {
310 virtualMode = VirtualMode::Tracking;
311 }
312 else if (udpMsg.mode == 1) {
313 virtualMode = VirtualMode::Static1;
314 staticPosition[0] = { udpMsg.viewTransx, udpMsg.viewTransy, udpMsg.viewTransz };
315 staticQuaternion[0] = { udpMsg.viewRotx, udpMsg.viewRoty, udpMsg.viewRotz, udpMsg.viewRotw };
316
317 }
318 else if (udpMsg.mode == 2) {
319 virtualMode = VirtualMode::Static2;
320 staticPosition[1] = { udpMsg.viewTransx, udpMsg.viewTransy, udpMsg.viewTransz };
321 staticQuaternion[1] = { udpMsg.viewRotx, udpMsg.viewRoty, udpMsg.viewRotz, udpMsg.viewRotw };
322 }
323 else {
324 PRINT("UDP MESSAGE: Invalid mode requested");
325 }
326
327 mutex.unlock();
328
329 PRINT("Camera Activation %f", udpMsg.cameras);
330
331 auto actVector = wrapper->getCameraActivation();
332
333 //note that it probably will be better to use base 2 here but ok ..
334 const auto nbCam = actVector.size();
335
336 std::vector<bool> activations;
337 bool update = false;
338 for (int i = 0; i < nbCam; i++) {
339 bool cam = int(udpMsg.cameras / std::pow(10, nbCam - i - 1)) % 2;
340 activations.push_back(cam);
341 if (cam != actVector[i]) {
342 // the enabling/disabling of camera is not a light operation, it's better to do it only when needed
343 //wrapper->toggleCamera(i);
344 update = true;
345 }
346 }
347
348 if (update) {
349 wrapper->setCameraActivation(activations);
350 }
351
352 PRINT("Value for reset: %f", udpMsg.reset);
353
354 if (udpMsg.reset == 1) {
355
356 glm::vec3 startP = {udpMsg.initTransx,udpMsg.initTransy,udpMsg.initTransz};
357 glm::quat startQ = {udpMsg.initRotx,udpMsg.initRoty, udpMsg.initRotz,udpMsg.initRotw};
358
359 PRINT("Received reset position: %f,%f,%f", udpMsg.initTransx, udpMsg.initTransy, udpMsg.initTransz);
360 PRINT("Received reset rotation: %f,%f,%f,%f", udpMsg.initRotx, udpMsg.initRoty, udpMsg.initRotz, udpMsg.initRotw);
361
362 startPosMut.lock();
363
364 startingPosition = startP;
365 startingRotation = quatToEuler(startQ);
366
367 startPosMut.unlock();
368
369 window->resetOrigin();
370
371
372
373 }
374 }
375
376 }
377
378#ifdef WIN32
379 WSACleanup();
380 closesocket(s);
381#else
382 close(s);
383#endif //
384}
385#endif
Class that contains helper functions for Vulkan.
file that contains the VulkanWrapper class that manages the classes related to Vulkan code and ease t...
std::variant< PerspectiveIntrinsics, EquirectangularIntrinsics > Intrinsics
Union of possible intrinsics types data.
Definition: InputProvider.h:67
void setStartingPt(glm::vec3 startPos, glm::vec3 startRot)
const InputProvider::Extrinsics getVirtualExtrinsics(int view)
const glm::vec3 getStartingPosition()
const glm::vec3 getStartingRotation()
std::vector< glm::vec2 > virtualViewDef
void updateSpaceTransform(glm::vec3 translation, glm::vec3 rotation)
InputProvider::ProjectionType projectionType
void init(int view, WindowAbstract *window, VulkanWrapper *wraps)
const InputProvider::Intrinsics getVirtualIntrinsics(int view)
Class that manages the classes related to Vulkan code and act as a wrapper around them.
Definition: VulkanWrapper.h:66
std::vector< bool > getCameraActivation()
void setCameraActivation(std::vector< bool > activation)
Abstraction of the way of the result is displayed (screen or HMD).
virtual void resetOrigin()=0
virtual vk::Extent2D getSwapchainExtent(int view)
Intrinsics parameters of a perspective projection.
Definition: InputProvider.h:59