|
|
|
@ -12,17 +12,12 @@
|
|
|
|
|
to predict the stock market with supernatural accuracy.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "Pudding.hpp"
|
|
|
|
|
|
|
|
|
|
/* Launch the Pudding instance's mainloop */
|
|
|
|
|
int main()
|
|
|
|
|
{
|
|
|
|
|
Pudding pudding = Pudding();
|
|
|
|
|
pudding.run();
|
|
|
|
|
pudding.quit();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#if defined(__ANDROID__) || defined(ANDROID)
|
|
|
|
|
#include <android/asset_manager_jni.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "Pudding.hpp"
|
|
|
|
|
|
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
|
|
|
void flag_frame()
|
|
|
|
@ -39,6 +34,9 @@ void set_heap_offset(int offset)
|
|
|
|
|
/* Initialize a Pudding instance */
|
|
|
|
|
Pudding::Pudding()
|
|
|
|
|
{
|
|
|
|
|
/* Allocate storage for curl error string */
|
|
|
|
|
curl_error.resize(CURL_ERROR_SIZE);
|
|
|
|
|
|
|
|
|
|
#ifndef __EMSCRIPTEN__
|
|
|
|
|
/* Initialize cURL and store result. Initialize the multi request handler. */
|
|
|
|
|
curl_init_result = curl_global_init(CURL_GLOBAL_DEFAULT);
|
|
|
|
@ -54,14 +52,29 @@ Pudding::Pudding()
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(__ANDROID__) || defined(ANDROID)
|
|
|
|
|
/* Copy CA bundle from the APK assets folder to internal storage. */
|
|
|
|
|
if (SDL_AndroidGetInternalStoragePath() != nullptr)
|
|
|
|
|
{
|
|
|
|
|
/* Copy the certificates into the internal storage. If successfully copied, save the path. */
|
|
|
|
|
if (!fs::exists(ca_bundle_path = sb::copy_file(configuration()["scan"]["certificate-authorities-file"], SDL_AndroidGetInternalStoragePath())))
|
|
|
|
|
{
|
|
|
|
|
sb::Log::log("Could not copy certificate authorities file, SSL peer verification will be disabled.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sb::Log::sdl_error("Could not access Android internal storage, SSL peer verification will be disabled.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SDL_SetHint(SDL_HINT_ORIENTATIONS, "Portrait");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* subscribe to command events */
|
|
|
|
|
get_delegate().subscribe(&Pudding::respond, this);
|
|
|
|
|
get_delegate().subscribe(&Pudding::respond, this, SDL_MOUSEMOTION);
|
|
|
|
|
get_delegate().subscribe(&Pudding::respond, this, SDL_MOUSEBUTTONDOWN);
|
|
|
|
|
|
|
|
|
|
/* initialize a zbar image scanner for reading barcodes of any format */
|
|
|
|
|
image_scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
|
|
|
|
|
|
|
|
|
|
/* set up pudding model */
|
|
|
|
|
nlohmann::json pudding = configuration()["pudding"];
|
|
|
|
|
load_pudding_model(pudding["top-radius"], pudding["base-radius"], pudding["ring-vertex-count"], pudding["layer-count"],
|
|
|
|
@ -72,9 +85,14 @@ Pudding::Pudding()
|
|
|
|
|
|
|
|
|
|
/* Add a texture to the camera Plane for storing frame image data */
|
|
|
|
|
camera_view.texture(sb::Texture());
|
|
|
|
|
glm::mat4 flip = glm::mat4(1);
|
|
|
|
|
flip[1][1] = -1;
|
|
|
|
|
camera_view.transformation(flip);
|
|
|
|
|
|
|
|
|
|
/* Flip and rotate the image */
|
|
|
|
|
glm::mat4 transform = glm::mat4(1);
|
|
|
|
|
transform[1][1] = -1;
|
|
|
|
|
#if defined(__ANDROID__) || defined(ANDROID)
|
|
|
|
|
transform = glm::rotate(3.0f * glm::half_pi<float>(), glm::vec3(0.0f, 0.0f, 1.0f)) * transform;
|
|
|
|
|
#endif
|
|
|
|
|
camera_view.transformation(transform);
|
|
|
|
|
|
|
|
|
|
/* Load background tiles */
|
|
|
|
|
load_tiles();
|
|
|
|
@ -267,7 +285,7 @@ void Pudding::load_gl_context()
|
|
|
|
|
/* Read every jpg in the folder at tile path into a GL texture and associate with the background object. */
|
|
|
|
|
void Pudding::load_tiles()
|
|
|
|
|
{
|
|
|
|
|
for (fs::path path : sb::glob(configuration()["resource"]["tile-path"].get<fs::path>() / ".*.jpg"))
|
|
|
|
|
for (fs::path path : configuration()["textures"]["tiles"])
|
|
|
|
|
{
|
|
|
|
|
sb::Texture texture {path};
|
|
|
|
|
texture.load();
|
|
|
|
@ -278,7 +296,7 @@ void Pudding::load_tiles()
|
|
|
|
|
/* Load every png in the button path as a Texture and add to a map. */
|
|
|
|
|
void Pudding::load_pads()
|
|
|
|
|
{
|
|
|
|
|
for (fs::path path : sb::glob(configuration()["resource"]["button-path"].get<fs::path>() / ".*.png"))
|
|
|
|
|
for (fs::path path : configuration()["textures"]["buttons"])
|
|
|
|
|
{
|
|
|
|
|
labels[path.stem()] = sb::Texture(path);
|
|
|
|
|
labels[path.stem()].load();
|
|
|
|
@ -327,8 +345,11 @@ void Pudding::open_camera()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate a texture the size of the camera's resolution. */
|
|
|
|
|
camera_view.texture().generate({capture.get(cv::CAP_PROP_FRAME_WIDTH), capture.get(cv::CAP_PROP_FRAME_HEIGHT)});
|
|
|
|
|
/* This is necessary for Android */
|
|
|
|
|
capture.set(cv::CAP_PROP_FOURCC, (('R' & 0x000000FF) | (('G' << 8) & 0x0000FF00) | (('B' << 16) & 0x00FF0000) | (('3' << 24) & 0xFF000000)));
|
|
|
|
|
|
|
|
|
|
/* Generate a texture the size of the camera's resolution. Using GL_RGB8 (instead of GL_RGBA8) seems to be necessary on Android. */
|
|
|
|
|
camera_view.texture().generate({capture.get(cv::CAP_PROP_FRAME_WIDTH), capture.get(cv::CAP_PROP_FRAME_HEIGHT)}, GL_RGB8);
|
|
|
|
|
|
|
|
|
|
/* Create and detach a thread which will read frame data */
|
|
|
|
|
std::thread camera_thread(&Pudding::capture_frame, this);
|
|
|
|
@ -873,6 +894,38 @@ void Pudding::web_get_bytes(std::string url, const web_callback& callback, const
|
|
|
|
|
}
|
|
|
|
|
curl_easy_setopt(curl_easy_handle, CURLOPT_HTTPHEADER, list);
|
|
|
|
|
|
|
|
|
|
/* Add error string buffer */
|
|
|
|
|
curl_easy_setopt(curl_easy_handle, CURLOPT_ERRORBUFFER, curl_error.data());
|
|
|
|
|
|
|
|
|
|
#if defined(__ANDROID__) || defined(ANDROID)
|
|
|
|
|
/* CA certificates bundle path must be specified in Android. */
|
|
|
|
|
CURLcode res;
|
|
|
|
|
bool success = false;
|
|
|
|
|
std::ostringstream message;
|
|
|
|
|
if (fs::exists(ca_bundle_path))
|
|
|
|
|
{
|
|
|
|
|
res = curl_easy_setopt(curl_easy_handle, CURLOPT_CAINFO, ca_bundle_path.c_str());
|
|
|
|
|
if (res == CURLE_OK)
|
|
|
|
|
{
|
|
|
|
|
message << "Set curl handle's CURLOPT_CAINFO to " << ca_bundle_path;
|
|
|
|
|
sb::Log::log(message);
|
|
|
|
|
success = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
message << "Setting curl handle's CURLOPT_CAINFO failed " << curl_easy_strerror(res);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fallback to turning off SSL peer verification if the certificates file isn't available. */
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
message << "Turning off SSL peer verification";
|
|
|
|
|
sb::Log::log(message, sb::Log::WARN);
|
|
|
|
|
curl_easy_setopt(curl_easy_handle, CURLOPT_SSL_VERIFYPEER, 0);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Add the easy handle to the multi handle, so it can be processed asynchronously in the update loop */
|
|
|
|
|
curl_multi_add_handle(curl_multi_handle.get(), curl_easy_handle);
|
|
|
|
|
}
|
|
|
|
@ -1113,6 +1166,9 @@ void Pudding::update()
|
|
|
|
|
|
|
|
|
|
/* Pixels from Emscripten are RGBA */
|
|
|
|
|
GLenum pixel_format = GL_RGBA;
|
|
|
|
|
#elif defined(__ANDROID__) || defined(ANDROID)
|
|
|
|
|
/* Pixels from cv::VideoCapture are RGB on Android */
|
|
|
|
|
GLenum pixel_format = GL_RGB;
|
|
|
|
|
#else
|
|
|
|
|
/* Pixels from cv::VideoCapture are BGR */
|
|
|
|
|
GLenum pixel_format = GL_BGR;
|
|
|
|
@ -1174,12 +1230,15 @@ void Pudding::update()
|
|
|
|
|
color_components = configuration()["scan"]["contour-color-undecodable"].get<std::vector<std::uint8_t>>();
|
|
|
|
|
}
|
|
|
|
|
cv::Scalar color = cv::Scalar(color_components[0], color_components[1], color_components[2], 255);
|
|
|
|
|
/* GL_BGR is not available on Android */
|
|
|
|
|
#if !defined(__ANDROID__) && !defined(ANDROID)
|
|
|
|
|
if (pixel_format == GL_BGR)
|
|
|
|
|
{
|
|
|
|
|
std::uint8_t save = color[0];
|
|
|
|
|
color[0] = color[2];
|
|
|
|
|
color[2] = save;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
cv::drawContours(camera_frame, input, 0, color, 2);
|
|
|
|
|
for (const cv::Point& point : contours)
|
|
|
|
|
{
|
|
|
|
@ -1361,8 +1420,17 @@ void Pudding::update()
|
|
|
|
|
message_queue = curl_multi_info_read(curl_multi_handle.get(), &message_count);
|
|
|
|
|
if (message_queue && (message_queue->msg == CURLMSG_DONE))
|
|
|
|
|
{
|
|
|
|
|
std::uint32_t response_code;
|
|
|
|
|
Request* request;
|
|
|
|
|
curl_easy_getinfo(message_queue->easy_handle, CURLINFO_RESPONSE_CODE, &response_code);
|
|
|
|
|
curl_easy_getinfo(message_queue->easy_handle, CURLINFO_PRIVATE, &request);
|
|
|
|
|
std::ostringstream message;
|
|
|
|
|
message << request->url() << " returned HTTP response " << response_code;
|
|
|
|
|
if (response_code != 200)
|
|
|
|
|
{
|
|
|
|
|
message << ": " << curl_error;
|
|
|
|
|
}
|
|
|
|
|
sb::Log::log(message);
|
|
|
|
|
request->respond();
|
|
|
|
|
curl_multi_remove_handle(curl_multi_handle.get(), message_queue->easy_handle);
|
|
|
|
|
curl_easy_cleanup(message_queue->easy_handle);
|
|
|
|
@ -1411,6 +1479,9 @@ void Pudding::update()
|
|
|
|
|
camera_button.translation({-1.0f * interface["main-button-double-x"].get<float>(), interface["main-button-y"]});
|
|
|
|
|
}
|
|
|
|
|
incoming_item = Item();
|
|
|
|
|
|
|
|
|
|
/* Close camera view */
|
|
|
|
|
camera_switch.disconnect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1569,3 +1640,12 @@ EMSCRIPTEN_BINDINGS(my_module)
|
|
|
|
|
function("set_heap_offset", &set_heap_offset);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Launch the Pudding instance's mainloop */
|
|
|
|
|
int main()
|
|
|
|
|
{
|
|
|
|
|
Pudding pudding = Pudding();
|
|
|
|
|
pudding.run();
|
|
|
|
|
pudding.quit();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|