From 0de861b2b90367ee48621dafb233a9917bbb3775 Mon Sep 17 00:00:00 2001 From: sz Date: Fri, 19 Feb 2021 20:50:10 -0600 Subject: [PATCH 01/26] quick WIP for GLSL transpose for the shakycam effect --- src/lib/gui/gl_2d_display.h | 32 +++++++++++++++++++++++++++----- src/lib/gui/window_glfw.h | 6 ++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/lib/gui/gl_2d_display.h b/src/lib/gui/gl_2d_display.h index 3a4cf5e5..c806500b 100644 --- a/src/lib/gui/gl_2d_display.h +++ b/src/lib/gui/gl_2d_display.h @@ -60,8 +60,13 @@ class gl_2d_display // pass in rotation matrix GLuint rotateUniform = glGetUniformLocation(prog, "rot"); - std::array vals = rotation_matrix(); - glUniformMatrix2fv(rotateUniform, 1, false, vals.data()); + std::array rot = rotation_matrix(); + glUniformMatrix2fv(rotateUniform, 1, false, rot.data()); + + // pass in transform vector + GLuint transformUniform = glGetUniformLocation(prog, "tform"); + std::pair tform = shake_transform(); + glUniform2f(transformUniform, tform.first, tform.second); // Draw glDrawArrays(GL_TRIANGLES, 0, 6); @@ -87,6 +92,12 @@ class gl_2d_display _rotation = 0; } + void shake(unsigned i=1) + { + if (i == 0 or ++_shake >= 8) + _shake = 0; + } + std::array rotation_matrix() const { // just using sin and cos is probably better? @@ -95,15 +106,23 @@ class gl_2d_display default: case 0: return {-1, 0, 0, 1}; - case 1: // right 90 - return {0, 1, 1, 0}; - case 2: // right 180 + case 1: // right 180 return {1, 0, 0, -1}; + case 2: // right 90 + return {0, 1, 1, 0}; case 3: // right 270 return {0, -1, -1, 0}; } } + std::pair shake_transform() const + { + static constexpr std::array, 8> SHAKE_POS = {{ + {0, 0}, {-.008, -.008}, {0, 0}, {.008, .008}, {0, 0}, {-.008, .008}, {0, 0}, {.008, -.008} + }}; + return SHAKE_POS[_shake]; + } + protected: static std::shared_ptr create() { @@ -116,6 +135,7 @@ class gl_2d_display */ static const std::string VERTEX_SHADER_SRC = R"(#version 300 es uniform mat2 rot; + uniform vec2 tform; in vec4 vert; out vec2 texCoord; void main() { @@ -123,6 +143,7 @@ class gl_2d_display vec2 ori = vec2(vert.x, vert.y); ori *= rot; texCoord = vec2(1.0f - ori.x, 1.0f - ori.y) / 2.0; + texCoord += tform; })"; static const std::string FRAGMENT_SHADER_SRC = R"(#version 300 es @@ -145,6 +166,7 @@ class gl_2d_display GLuint _vao; unsigned _i = 0; unsigned _rotation = 0; + unsigned _shake = 0; }; } diff --git a/src/lib/gui/window_glfw.h b/src/lib/gui/window_glfw.h index d3cb358b..57a4df6a 100644 --- a/src/lib/gui/window_glfw.h +++ b/src/lib/gui/window_glfw.h @@ -61,6 +61,12 @@ class window_glfw : public window_interface _display->rotate(i); } + void shake(unsigned i=1) + { + if (_display) + _display->shake(i); + } + void clear() { if (_display) From cb84a5924fbf5636d351730c105dced88173311a Mon Sep 17 00:00:00 2001 From: sz Date: Fri, 19 Feb 2021 21:18:55 -0600 Subject: [PATCH 02/26] hmm (still using the shaky_cam object, though its days are likely numbered) --- src/exe/cimbar_send/send.cpp | 10 ++++------ src/lib/gui/gl_2d_display.h | 3 ++- src/lib/gui/window_glfw.h | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/exe/cimbar_send/send.cpp b/src/exe/cimbar_send/send.cpp index f20aeb51..3c9ded5c 100644 --- a/src/exe/cimbar_send/send.cpp +++ b/src/exe/cimbar_send/send.cpp @@ -60,11 +60,7 @@ int main(int argc, char** argv) bool use_shakycam = result.count("shakycam"); cimbar::shaky_cam cam(cimbar::Config::image_size(), 1080, 1080, dark); - // if we don't need the shakycam, we'll just turn it off - // we could use a separate code path (just do a mat copyTo), - // but this is fine. - if (!use_shakycam) - cam.toggle(); + cam.toggle(); cimbar::window w(cam.width(), cam.height(), "cimbar_send"); if (!w.is_good()) @@ -76,7 +72,7 @@ int main(int argc, char** argv) bool running = true; bool start = true; - auto draw = [&w, &cam, use_rotatecam, delay, &running, &start] (const cv::Mat& frame, unsigned) { + auto draw = [&w, &cam, use_rotatecam, use_shakycam, delay, &running, &start] (const cv::Mat& frame, unsigned) { if (!start and w.should_close()) return running = false; start = false; @@ -85,6 +81,8 @@ int main(int argc, char** argv) w.show(windowImg, delay); if (use_rotatecam) w.rotate(); + if (use_shakycam) + w.shake(); return true; }; diff --git a/src/lib/gui/gl_2d_display.h b/src/lib/gui/gl_2d_display.h index c806500b..5f62a48d 100644 --- a/src/lib/gui/gl_2d_display.h +++ b/src/lib/gui/gl_2d_display.h @@ -117,8 +117,9 @@ class gl_2d_display std::pair shake_transform() const { + const float step = .007407407f; // 8 / 1080 static constexpr std::array, 8> SHAKE_POS = {{ - {0, 0}, {-.008, -.008}, {0, 0}, {.008, .008}, {0, 0}, {-.008, .008}, {0, 0}, {.008, -.008} + {0, 0}, {-step, -step}, {0, 0}, {step, step}, {0, 0}, {-step, step}, {0, 0}, {step, -step} }}; return SHAKE_POS[_shake]; } diff --git a/src/lib/gui/window_glfw.h b/src/lib/gui/window_glfw.h index 57a4df6a..9529a2bf 100644 --- a/src/lib/gui/window_glfw.h +++ b/src/lib/gui/window_glfw.h @@ -30,6 +30,7 @@ class window_glfw : public window_interface return; } glfwMakeContextCurrent(_w); + glfwSwapInterval(1); _display = std::make_shared(); glGenTextures(1, &_texid); From d869656f072ba8d1683a66922def80739beee185 Mon Sep 17 00:00:00 2001 From: sz Date: Fri, 19 Feb 2021 21:43:15 -0600 Subject: [PATCH 03/26] use loop_iterator? Not sure where the magical "shake" calculation should live -- it's tied to the shader, but feels weird to prop out into the window_* classes. Might pass in the dimensions to gl_2d_display(), it kinda makes sense for it to have them --- src/lib/gui/gl_2d_display.h | 62 ++++++++++++++++--------------------- src/lib/gui/window_glfw.h | 3 +- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/lib/gui/gl_2d_display.h b/src/lib/gui/gl_2d_display.h index 5f62a48d..8570b7c7 100644 --- a/src/lib/gui/gl_2d_display.h +++ b/src/lib/gui/gl_2d_display.h @@ -3,6 +3,7 @@ #include "gl_program.h" #include "gl_shader.h" +#include "util/loop_iterator.h" #include #include @@ -23,9 +24,20 @@ class gl_2d_display -1.0f, 1.0f, 0.0f }; + // just using sin and cos is probably better? + static constexpr std::array, 4> ROTATIONS = {{ + {-1, 0, 0, 1}, + {1, 0, 0, -1}, // right 180 + {0, 1, 1, 0}, // right 90 + {0, -1, -1, 0} // right 270 + }}; + public: - gl_2d_display() + gl_2d_display(float shake=0) : _p(create()) + , _shakePos{{ {0, 0}, {-shake, -shake}, {0, 0}, {shake, shake}, {0, 0}, {-shake, shake}, {0, 0}, {shake, -shake} }} + , _shake(_shakePos) + , _rotation(ROTATIONS) { glGenBuffers(3, _vbo.data()); glGenVertexArrays(1, &_vao); @@ -60,12 +72,12 @@ class gl_2d_display // pass in rotation matrix GLuint rotateUniform = glGetUniformLocation(prog, "rot"); - std::array rot = rotation_matrix(); + std::array rot = *_rotation; glUniformMatrix2fv(rotateUniform, 1, false, rot.data()); // pass in transform vector GLuint transformUniform = glGetUniformLocation(prog, "tform"); - std::pair tform = shake_transform(); + std::pair tform = *_shake; glUniform2f(transformUniform, tform.first, tform.second); // Draw @@ -88,40 +100,18 @@ class gl_2d_display void rotate(unsigned i=1) { - if (i == 0 or ++_rotation >= 4) - _rotation = 0; + if (i == 0) + _rotation.reset(); + else + ++_rotation; } void shake(unsigned i=1) { - if (i == 0 or ++_shake >= 8) - _shake = 0; - } - - std::array rotation_matrix() const - { - // just using sin and cos is probably better? - switch (_rotation) - { - default: - case 0: - return {-1, 0, 0, 1}; - case 1: // right 180 - return {1, 0, 0, -1}; - case 2: // right 90 - return {0, 1, 1, 0}; - case 3: // right 270 - return {0, -1, -1, 0}; - } - } - - std::pair shake_transform() const - { - const float step = .007407407f; // 8 / 1080 - static constexpr std::array, 8> SHAKE_POS = {{ - {0, 0}, {-step, -step}, {0, 0}, {step, step}, {0, 0}, {-step, step}, {0, 0}, {step, -step} - }}; - return SHAKE_POS[_shake]; + if (i == 0) + _shake.reset(); + else + ++_shake; } protected: @@ -166,8 +156,10 @@ class gl_2d_display std::array _vbo; GLuint _vao; unsigned _i = 0; - unsigned _rotation = 0; - unsigned _shake = 0; + + std::array, 8> _shakePos; + loop_iterator _shake; + loop_iterator _rotation; }; } diff --git a/src/lib/gui/window_glfw.h b/src/lib/gui/window_glfw.h index 9529a2bf..1085a1e8 100644 --- a/src/lib/gui/window_glfw.h +++ b/src/lib/gui/window_glfw.h @@ -32,7 +32,8 @@ class window_glfw : public window_interface glfwMakeContextCurrent(_w); glfwSwapInterval(1); - _display = std::make_shared(); + float shake = 8.0 / std::min(width, height); + _display = std::make_shared(shake); glGenTextures(1, &_texid); init_opengl(width, height); } From 355ef7c90e1fbf811cf2bfb416139f20511c32f2 Mon Sep 17 00:00:00 2001 From: sz Date: Fri, 19 Feb 2021 21:52:39 -0600 Subject: [PATCH 04/26] Is this better? --- src/lib/gui/gl_2d_display.h | 10 ++++++++-- src/lib/gui/window_glfw.h | 3 +-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/lib/gui/gl_2d_display.h b/src/lib/gui/gl_2d_display.h index 8570b7c7..3386f33c 100644 --- a/src/lib/gui/gl_2d_display.h +++ b/src/lib/gui/gl_2d_display.h @@ -32,10 +32,16 @@ class gl_2d_display {0, -1, -1, 0} // right 270 }}; + static std::array, 8> computeShakePos(unsigned dim) + { + float shake = 8.0f / dim; + return {{ {0, 0}, {-shake, -shake}, {0, 0}, {shake, shake}, {0, 0}, {-shake, shake}, {0, 0}, {shake, -shake} }}; + } + public: - gl_2d_display(float shake=0) + gl_2d_display(unsigned width, unsigned height) : _p(create()) - , _shakePos{{ {0, 0}, {-shake, -shake}, {0, 0}, {shake, shake}, {0, 0}, {-shake, shake}, {0, 0}, {shake, -shake} }} + , _shakePos(computeShakePos(std::min(width, height))) , _shake(_shakePos) , _rotation(ROTATIONS) { diff --git a/src/lib/gui/window_glfw.h b/src/lib/gui/window_glfw.h index 1085a1e8..03091224 100644 --- a/src/lib/gui/window_glfw.h +++ b/src/lib/gui/window_glfw.h @@ -32,8 +32,7 @@ class window_glfw : public window_interface glfwMakeContextCurrent(_w); glfwSwapInterval(1); - float shake = 8.0 / std::min(width, height); - _display = std::make_shared(shake); + _display = std::make_shared(width, height); glGenTextures(1, &_texid); init_opengl(width, height); } From f6b64960499129fbe10ce97b02e3b23b9d840063 Mon Sep 17 00:00:00 2001 From: sz Date: Sat, 20 Feb 2021 00:46:24 -0600 Subject: [PATCH 05/26] I don't know about this one chief --- src/exe/cimbar_send/send.cpp | 10 +++------- src/lib/gui/gl_2d_display.h | 30 ++++++++++++++++++++++++------ src/wasm/cimbar_js/wasm.cpp | 2 +- web/main.js | 6 +++--- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/exe/cimbar_send/send.cpp b/src/exe/cimbar_send/send.cpp index 3c9ded5c..7cdcf87b 100644 --- a/src/exe/cimbar_send/send.cpp +++ b/src/exe/cimbar_send/send.cpp @@ -59,10 +59,7 @@ int main(int argc, char** argv) bool use_rotatecam = result.count("rotatecam"); bool use_shakycam = result.count("shakycam"); - cimbar::shaky_cam cam(cimbar::Config::image_size(), 1080, 1080, dark); - cam.toggle(); - - cimbar::window w(cam.width(), cam.height(), "cimbar_send"); + cimbar::window w(1080, 1080, "cimbar_send"); if (!w.is_good()) { std::cerr << "failed to create window :(" << std::endl; @@ -72,13 +69,12 @@ int main(int argc, char** argv) bool running = true; bool start = true; - auto draw = [&w, &cam, use_rotatecam, use_shakycam, delay, &running, &start] (const cv::Mat& frame, unsigned) { + auto draw = [&w, use_rotatecam, use_shakycam, delay, &running, &start] (const cv::Mat& frame, unsigned) { if (!start and w.should_close()) return running = false; start = false; - cv::Mat& windowImg = cam.draw(frame); - w.show(windowImg, delay); + w.show(frame, delay); if (use_rotatecam) w.rotate(); if (use_shakycam) diff --git a/src/lib/gui/gl_2d_display.h b/src/lib/gui/gl_2d_display.h index 3386f33c..1969ad25 100644 --- a/src/lib/gui/gl_2d_display.h +++ b/src/lib/gui/gl_2d_display.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace cimbar { @@ -32,16 +33,27 @@ class gl_2d_display {0, -1, -1, 0} // right 270 }}; - static std::array, 8> computeShakePos(unsigned dim) + static std::array, 8> computeShakePos(float dim) { - float shake = 8.0f / dim; - return {{ {0, 0}, {-shake, -shake}, {0, 0}, {shake, shake}, {0, 0}, {-shake, shake}, {0, 0}, {shake, -shake} }}; + float shake = 8.0f / dim; // 1080 + float zero = (dim - 1000.0) / (dim*2); + return {{ + {zero, zero}, + {zero-shake, zero-shake}, + {zero, zero}, + {zero+shake, zero+shake}, + {zero, zero}, + {zero-shake, zero+shake}, + {zero, zero}, + {zero+shake, zero-shake} + }}; } public: gl_2d_display(unsigned width, unsigned height) : _p(create()) - , _shakePos(computeShakePos(std::min(width, height))) + , _dimension(std::min(width, height)) + , _shakePos(computeShakePos(_dimension)) , _shake(_shakePos) , _rotation(ROTATIONS) { @@ -76,6 +88,10 @@ class gl_2d_display glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(textureUniform, 0); + // scaling + GLuint scalingUniform = glGetUniformLocation(prog, "scaling"); + glUniform1f(scalingUniform, 2 * (1008 / _dimension)); + // pass in rotation matrix GLuint rotateUniform = glGetUniformLocation(prog, "rot"); std::array rot = *_rotation; @@ -133,14 +149,15 @@ class gl_2d_display static const std::string VERTEX_SHADER_SRC = R"(#version 300 es uniform mat2 rot; uniform vec2 tform; + uniform float scaling; in vec4 vert; out vec2 texCoord; void main() { gl_Position = vec4(vert.x, vert.y, 0.0f, 1.0f); vec2 ori = vec2(vert.x, vert.y); ori *= rot; - texCoord = vec2(1.0f - ori.x, 1.0f - ori.y) / 2.0; - texCoord += tform; + texCoord = vec2(1.0f - ori.x, 1.0f - ori.y) / scaling; + texCoord -= tform; })"; static const std::string FRAGMENT_SHADER_SRC = R"(#version 300 es @@ -162,6 +179,7 @@ class gl_2d_display std::array _vbo; GLuint _vao; unsigned _i = 0; + float _dimension; std::array, 8> _shakePos; loop_iterator _shake; diff --git a/src/wasm/cimbar_js/wasm.cpp b/src/wasm/cimbar_js/wasm.cpp index ce6a958b..5c33dd96 100644 --- a/src/wasm/cimbar_js/wasm.cpp +++ b/src/wasm/cimbar_js/wasm.cpp @@ -65,7 +65,7 @@ int render() } _window->show(*img, 0); - _window->rotate(); + _window->shake(); return ++_renders; } diff --git a/web/main.js b/web/main.js index eaca534c..6f7894d1 100644 --- a/web/main.js +++ b/web/main.js @@ -33,7 +33,7 @@ return { { console.log("init for canvas " + canvas); - Module._initialize_GL(1024, 1024); + Module._initialize_GL(1040, 1040); Main.scaleCanvas(canvas, width, height); Main.alignInvisibleClick(canvas); }, @@ -45,8 +45,8 @@ return { dim = height; } console.log(dim); - if (dim > 1024) { - dim = 1024; + if (dim > 1040) { + dim = 1040; } canvas.style.width = dim + "px"; canvas.style.height = dim + "px"; From 396939a90853f0c319baac26027473d53167adaf Mon Sep 17 00:00:00 2001 From: sz Date: Sat, 20 Feb 2021 02:10:05 -0600 Subject: [PATCH 06/26] It's something like this, but... --- src/lib/gui/gl_2d_display.h | 18 ++++++++++-------- src/lib/gui/window_glfw.h | 2 +- src/wasm/cimbar_js/wasm.cpp | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/lib/gui/gl_2d_display.h b/src/lib/gui/gl_2d_display.h index 1969ad25..9acb9910 100644 --- a/src/lib/gui/gl_2d_display.h +++ b/src/lib/gui/gl_2d_display.h @@ -33,10 +33,10 @@ class gl_2d_display {0, -1, -1, 0} // right 270 }}; - static std::array, 8> computeShakePos(float dim) + static std::array, 8> computeShakePos(float src_dim, float target_dim) { - float shake = 8.0f / dim; // 1080 - float zero = (dim - 1000.0) / (dim*2); + float shake = 8.0f / target_dim; + float zero = (target_dim - src_dim + 3) / (target_dim*2); return {{ {zero, zero}, {zero-shake, zero-shake}, @@ -50,10 +50,11 @@ class gl_2d_display } public: - gl_2d_display(unsigned width, unsigned height) + gl_2d_display(unsigned src_dim, unsigned target_dim) : _p(create()) - , _dimension(std::min(width, height)) - , _shakePos(computeShakePos(_dimension)) + , _srcDim(src_dim) + , _targetDim(target_dim) + , _shakePos(computeShakePos(_srcDim, _targetDim)) , _shake(_shakePos) , _rotation(ROTATIONS) { @@ -90,7 +91,7 @@ class gl_2d_display // scaling GLuint scalingUniform = glGetUniformLocation(prog, "scaling"); - glUniform1f(scalingUniform, 2 * (1008 / _dimension)); + glUniform1f(scalingUniform, 2 * (_srcDim / _targetDim)); // pass in rotation matrix GLuint rotateUniform = glGetUniformLocation(prog, "rot"); @@ -179,7 +180,8 @@ class gl_2d_display std::array _vbo; GLuint _vao; unsigned _i = 0; - float _dimension; + float _srcDim; + float _targetDim; std::array, 8> _shakePos; loop_iterator _shake; diff --git a/src/lib/gui/window_glfw.h b/src/lib/gui/window_glfw.h index 03091224..c45d2a45 100644 --- a/src/lib/gui/window_glfw.h +++ b/src/lib/gui/window_glfw.h @@ -32,7 +32,7 @@ class window_glfw : public window_interface glfwMakeContextCurrent(_w); glfwSwapInterval(1); - _display = std::make_shared(width, height); + _display = std::make_shared(1024, std::min(width, height)); glGenTextures(1, &_texid); init_opengl(width, height); } diff --git a/src/wasm/cimbar_js/wasm.cpp b/src/wasm/cimbar_js/wasm.cpp index 5c33dd96..8beb92ba 100644 --- a/src/wasm/cimbar_js/wasm.cpp +++ b/src/wasm/cimbar_js/wasm.cpp @@ -51,7 +51,7 @@ int render() if (_fes->block_count() > required) { _fes->reset(); - _window->rotate(0); + _window->shake(0); } SimpleEncoder enc(_ecc, cimbar::Config::symbol_bits(), _colorBits); @@ -102,7 +102,7 @@ int configure(unsigned color_bits) _fes = nullptr; _window->clear(); } - _window->rotate(0); + _window->shake(0); } } return 0; From a2ffe08ccdbfae654191c28763dc661f66bc88c2 Mon Sep 17 00:00:00 2001 From: sz Date: Sat, 20 Feb 2021 01:48:21 -0600 Subject: [PATCH 07/26] maybe this instead -- variable canvas size for CimbWriter It's slightly more data to copy to the GPU (1040x1040px vs 1024x1024), but everything else is much more sane... --- src/exe/cimbar_send/send.cpp | 5 +-- src/lib/cimb_translator/CimbWriter.cpp | 42 +++++++++++++++----------- src/lib/cimb_translator/CimbWriter.h | 6 +++- src/lib/encoder/Encoder.h | 6 ++-- src/lib/encoder/SimpleEncoder.h | 8 +++-- src/lib/gui/gl_2d_display.h | 23 +++++--------- src/lib/gui/window_glfw.h | 10 ++++-- src/lib/gui/window_interface.h | 5 +++ src/wasm/cimbar_js/wasm.cpp | 6 ++-- 9 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/exe/cimbar_send/send.cpp b/src/exe/cimbar_send/send.cpp index 7cdcf87b..7730ca7c 100644 --- a/src/exe/cimbar_send/send.cpp +++ b/src/exe/cimbar_send/send.cpp @@ -58,8 +58,9 @@ int main(int argc, char** argv) bool dark = true; bool use_rotatecam = result.count("rotatecam"); bool use_shakycam = result.count("shakycam"); + int window_size = 1080; - cimbar::window w(1080, 1080, "cimbar_send"); + cimbar::window w(window_size, window_size, "cimbar_send"); if (!w.is_good()) { std::cerr << "failed to create window :(" << std::endl; @@ -85,6 +86,6 @@ int main(int argc, char** argv) Encoder en(ecc, cimbar::Config::symbol_bits(), colorBits); while (running) for (const string& f : infiles) - en.encode_fountain(f, draw, compressionLevel); + en.encode_fountain(f, draw, compressionLevel, 8.0, window_size); return 0; } diff --git a/src/lib/cimb_translator/CimbWriter.cpp b/src/lib/cimb_translator/CimbWriter.cpp index c5f87a0b..bb021ef7 100644 --- a/src/lib/cimb_translator/CimbWriter.cpp +++ b/src/lib/cimb_translator/CimbWriter.cpp @@ -33,39 +33,45 @@ namespace { string name = dark? "guide-vertical-dark" : "guide-vertical-light"; return cimbar::load_img(fmt::format("bitmap/{}.png", name)); } - - void paste(cv::Mat& canvas, const cv::Mat& img, int x, int y) - { - img.copyTo(canvas(cv::Rect(x, y, img.cols, img.rows))); - } } -CimbWriter::CimbWriter(unsigned symbol_bits, unsigned color_bits, bool dark) +CimbWriter::CimbWriter(unsigned symbol_bits, unsigned color_bits, bool dark, int size) : _positions(Config::cell_spacing(), Config::num_cells(), Config::cell_size(), Config::corner_padding(), Config::interleave_blocks(), Config::interleave_partitions()) , _encoder(symbol_bits, color_bits) { - unsigned size = cimbar::Config::image_size(); + if (size > cimbar::Config::image_size()) + _offset = (size - cimbar::Config::image_size()) / 2; + else + size = cimbar::Config::image_size(); cv::Scalar bgcolor = dark? cv::Scalar(0, 0, 0) : cv::Scalar(0xFF, 0xFF, 0xFF); _image = cv::Mat(size, size, CV_8UC3, bgcolor); + // from here on, we only care about the internal size + size = cimbar::Config::image_size(); + cv::Mat anchor = getAnchor(dark); - paste(_image, anchor, 0, 0); - paste(_image, anchor, 0, size - anchor.cols); - paste(_image, anchor, size - anchor.rows, 0); + paste(anchor, 0, 0); + paste(anchor, 0, size - anchor.cols); + paste(anchor, size - anchor.rows, 0); cv::Mat secondaryAnchor = getSecondaryAnchor(dark); - paste(_image, secondaryAnchor, size - anchor.rows, size - anchor.cols); + paste(secondaryAnchor, size - anchor.rows, size - anchor.cols); cv::Mat hg = getHorizontalGuide(dark); - paste(_image, hg, (size/2) - (hg.cols/2), 2); - paste(_image, hg, (size/2) - (hg.cols/2), size-4); - paste(_image, hg, (size/2) - (hg.cols/2) - hg.cols, size-4); - paste(_image, hg, (size/2) - (hg.cols/2) + hg.cols, size-4); + paste(hg, (size/2) - (hg.cols/2), 2); + paste(hg, (size/2) - (hg.cols/2), size-4); + paste(hg, (size/2) - (hg.cols/2) - hg.cols, size-4); + paste(hg, (size/2) - (hg.cols/2) + hg.cols, size-4); cv::Mat vg = getVerticalGuide(dark); - paste(_image, vg, 2, (size/2) - (vg.rows/2)); - paste(_image, vg, size-4, (size/2) - (vg.rows/2)); + paste(vg, 2, (size/2) - (vg.rows/2)); + paste(vg, size-4, (size/2) - (vg.rows/2)); +} + +void CimbWriter::paste(const cv::Mat& img, int x, int y) +{ + img.copyTo(_image(cv::Rect(x+_offset, y+_offset, img.cols, img.rows))); } bool CimbWriter::write(unsigned bits) @@ -77,7 +83,7 @@ bool CimbWriter::write(unsigned bits) CellPositions::coordinate xy = _positions.next(); cv::Mat cell = _encoder.encode(bits); - paste(_image, cell, xy.first, xy.second); + paste(cell, xy.first, xy.second); return true; } diff --git a/src/lib/cimb_translator/CimbWriter.h b/src/lib/cimb_translator/CimbWriter.h index b76321f2..9af71d9c 100644 --- a/src/lib/cimb_translator/CimbWriter.h +++ b/src/lib/cimb_translator/CimbWriter.h @@ -7,15 +7,19 @@ class CimbWriter { public: - CimbWriter(unsigned symbol_bits, unsigned color_bits, bool dark=true); + CimbWriter(unsigned symbol_bits, unsigned color_bits, bool dark=true, int size=0); bool write(unsigned bits); bool done() const; cv::Mat image() const; +protected: + void paste(const cv::Mat& img, int x, int y); + protected: cv::Mat _image; CellPositions _positions; CimbEncoder _encoder; + unsigned _offset = 0; }; diff --git a/src/lib/encoder/Encoder.h b/src/lib/encoder/Encoder.h index a296d7f9..1ac9e8fe 100644 --- a/src/lib/encoder/Encoder.h +++ b/src/lib/encoder/Encoder.h @@ -16,7 +16,7 @@ class Encoder : public SimpleEncoder unsigned encode(const std::string& filename, std::string output_prefix); unsigned encode_fountain(const std::string& filename, std::string output_prefix, int compression_level=6, double redundancy=1.2); - unsigned encode_fountain(const std::string& filename, const std::function& on_frame, int compression_level=6, double redundancy=4.0); + unsigned encode_fountain(const std::string& filename, const std::function& on_frame, int compression_level=6, double redundancy=4.0, int canvas_size=0); }; inline unsigned Encoder::encode(const std::string& filename, std::string output_prefix) @@ -39,7 +39,7 @@ inline unsigned Encoder::encode(const std::string& filename, std::string output_ return i; } -inline unsigned Encoder::encode_fountain(const std::string& filename, const std::function& on_frame, int compression_level, double redundancy) +inline unsigned Encoder::encode_fountain(const std::string& filename, const std::function& on_frame, int compression_level, double redundancy, int canvas_size) { std::ifstream infile(filename); fountain_encoder_stream::ptr fes = create_fountain_encoder(infile, compression_level); @@ -56,7 +56,7 @@ inline unsigned Encoder::encode_fountain(const std::string& filename, const std: unsigned i = 0; while (i < requiredFrames) { - auto frame = encode_next(*fes); + auto frame = encode_next(*fes, canvas_size); if (!frame) break; diff --git a/src/lib/encoder/SimpleEncoder.h b/src/lib/encoder/SimpleEncoder.h index f3b2cb26..2139c8c8 100644 --- a/src/lib/encoder/SimpleEncoder.h +++ b/src/lib/encoder/SimpleEncoder.h @@ -19,7 +19,7 @@ class SimpleEncoder void set_encode_id(uint8_t encode_id); // [0-127] -- the high bit is ignored. template - std::optional encode_next(STREAM& stream); + std::optional encode_next(STREAM& stream, int canvas_size=0); template fountain_encoder_stream::ptr create_fountain_encoder(STREAM& stream, int compression_level=6); @@ -28,6 +28,7 @@ class SimpleEncoder unsigned _eccBytes; unsigned _bitsPerSymbol; unsigned _bitsPerColor; + bool _dark; uint8_t _encodeId = 0; }; @@ -35,6 +36,7 @@ inline SimpleEncoder::SimpleEncoder(int ecc_bytes, unsigned bits_per_symbol, int : _eccBytes(ecc_bytes >= 0? ecc_bytes : cimbar::Config::ecc_bytes()) , _bitsPerSymbol(bits_per_symbol? bits_per_symbol : cimbar::Config::symbol_bits()) , _bitsPerColor(bits_per_color >= 0? bits_per_color : cimbar::Config::color_bits()) + , _dark(cimbar::Config::dark()) { } @@ -56,13 +58,13 @@ inline void SimpleEncoder::set_encode_id(uint8_t encode_id) * */ template -inline std::optional SimpleEncoder::encode_next(STREAM& stream) +inline std::optional SimpleEncoder::encode_next(STREAM& stream, int canvas_size) { if (!stream.good()) return std::nullopt; unsigned bits_per_op = _bitsPerColor + _bitsPerSymbol; - CimbWriter writer(_bitsPerSymbol, _bitsPerColor); + CimbWriter writer(_bitsPerSymbol, _bitsPerColor, _dark, canvas_size); reed_solomon_stream rss(stream, _eccBytes); bitreader br; diff --git a/src/lib/gui/gl_2d_display.h b/src/lib/gui/gl_2d_display.h index 9acb9910..57151ec9 100644 --- a/src/lib/gui/gl_2d_display.h +++ b/src/lib/gui/gl_2d_display.h @@ -33,10 +33,10 @@ class gl_2d_display {0, -1, -1, 0} // right 270 }}; - static std::array, 8> computeShakePos(float src_dim, float target_dim) + static std::array, 8> computeShakePos(float dim) { - float shake = 8.0f / target_dim; - float zero = (target_dim - src_dim + 3) / (target_dim*2); + float shake = 8.0f / dim; // 1080 + float zero = 0.0f; return {{ {zero, zero}, {zero-shake, zero-shake}, @@ -50,11 +50,10 @@ class gl_2d_display } public: - gl_2d_display(unsigned src_dim, unsigned target_dim) + gl_2d_display(unsigned width, unsigned height) : _p(create()) - , _srcDim(src_dim) - , _targetDim(target_dim) - , _shakePos(computeShakePos(_srcDim, _targetDim)) + , _dimension(std::min(width, height)) + , _shakePos(computeShakePos(_dimension)) , _shake(_shakePos) , _rotation(ROTATIONS) { @@ -89,10 +88,6 @@ class gl_2d_display glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(textureUniform, 0); - // scaling - GLuint scalingUniform = glGetUniformLocation(prog, "scaling"); - glUniform1f(scalingUniform, 2 * (_srcDim / _targetDim)); - // pass in rotation matrix GLuint rotateUniform = glGetUniformLocation(prog, "rot"); std::array rot = *_rotation; @@ -150,14 +145,13 @@ class gl_2d_display static const std::string VERTEX_SHADER_SRC = R"(#version 300 es uniform mat2 rot; uniform vec2 tform; - uniform float scaling; in vec4 vert; out vec2 texCoord; void main() { gl_Position = vec4(vert.x, vert.y, 0.0f, 1.0f); vec2 ori = vec2(vert.x, vert.y); ori *= rot; - texCoord = vec2(1.0f - ori.x, 1.0f - ori.y) / scaling; + texCoord = vec2(1.0f - ori.x, 1.0f - ori.y) / 2.0; texCoord -= tform; })"; @@ -180,8 +174,7 @@ class gl_2d_display std::array _vbo; GLuint _vao; unsigned _i = 0; - float _srcDim; - float _targetDim; + float _dimension; std::array, 8> _shakePos; loop_iterator _shake; diff --git a/src/lib/gui/window_glfw.h b/src/lib/gui/window_glfw.h index c45d2a45..64c183ae 100644 --- a/src/lib/gui/window_glfw.h +++ b/src/lib/gui/window_glfw.h @@ -16,6 +16,7 @@ class window_glfw : public window_interface { public: window_glfw(unsigned width, unsigned height, std::string title) + : _width(width) { if (!glfwInit()) { @@ -32,7 +33,7 @@ class window_glfw : public window_interface glfwMakeContextCurrent(_w); glfwSwapInterval(1); - _display = std::make_shared(1024, std::min(width, height)); + _display = std::make_shared(width, height); glGenTextures(1, &_texid); init_opengl(width, height); } @@ -95,6 +96,11 @@ class window_glfw : public window_interface std::this_thread::sleep_for(std::chrono::milliseconds(delay-millis)); } + unsigned width() const + { + return _width; + } + protected: void init_opengl(int width, int height) { @@ -117,8 +123,8 @@ class window_glfw : public window_interface GLFWwindow* _w; GLuint _texid; std::shared_ptr _display; + unsigned _width; bool _good = true; }; } - diff --git a/src/lib/gui/window_interface.h b/src/lib/gui/window_interface.h index 1728626a..d61fc4ab 100644 --- a/src/lib/gui/window_interface.h +++ b/src/lib/gui/window_interface.h @@ -27,6 +27,11 @@ struct window_interface { static_cast(this)->show(img, delay); } + + unsigned width() const + { + return static_cast(this)->width(); + } }; } diff --git a/src/wasm/cimbar_js/wasm.cpp b/src/wasm/cimbar_js/wasm.cpp index 8beb92ba..9529aad8 100644 --- a/src/wasm/cimbar_js/wasm.cpp +++ b/src/wasm/cimbar_js/wasm.cpp @@ -44,10 +44,10 @@ int render() if (!_window or !_fes) return 0; - // we generate 2x the amount of required blocks -- unless everything fits in a single frame. + // we generate 8x the amount of required blocks -- unless everything fits in a single frame. unsigned required = _fes->blocks_required(); if (required > cimbar::Config::fountain_chunks_per_frame()) - required = required*4; + required = required*8; if (_fes->block_count() > required) { _fes->reset(); @@ -57,7 +57,7 @@ int render() SimpleEncoder enc(_ecc, cimbar::Config::symbol_bits(), _colorBits); enc.set_encode_id(_encodeId); - std::optional img = enc.encode_next(*_fes); + std::optional img = enc.encode_next(*_fes, _window->width()); if (!img) { std::cerr << "no image :(" << std::endl; From 87338c47d7277c8a46a11f6e9334b1edc7e9f7b4 Mon Sep 17 00:00:00 2001 From: sz Date: Mon, 1 Mar 2021 22:28:37 -0600 Subject: [PATCH 08/26] Reimplement shakycam for opencv_highgui I kinda want to leave rotate as not implemented? Maybe I'll add a todo --- src/lib/gui/shaky_cam.h | 13 +++++++++---- src/lib/gui/window_cvhighgui.h | 18 +++++++++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/lib/gui/shaky_cam.h b/src/lib/gui/shaky_cam.h index 61847234..10a0be5c 100644 --- a/src/lib/gui/shaky_cam.h +++ b/src/lib/gui/shaky_cam.h @@ -10,13 +10,13 @@ class shaky_cam { public: static constexpr std::array, 8> SHAKE_POS = {{ - {0, 0}, {-8, -8}, {0, 0}, {8, 8}, {0, 0}, {-8, 8}, {0, 0}, {8, -8} + {0, 0}, {-8, -8}, {0, 0}, {8, 8}, {0, 0}, {-8, 8}, {0, 0}, {8, -8} }}; public: shaky_cam(unsigned img_size, unsigned w, unsigned h, bool dark) - : _shakycam(true) - , _shakePos(SHAKE_POS) + : _shakycam(true) + , _shakePos(SHAKE_POS) { unsigned minFrameSize = img_size + 16; w = std::max(w, minFrameSize); @@ -45,6 +45,12 @@ class shaky_cam _shakePos.reset(); } + void shake() + { + if (_shakycam) + ++_shakePos; + } + cv::Mat& draw(const cv::Mat& img) { _frame = _bgcolor; @@ -59,7 +65,6 @@ class shaky_cam offsetX += (*_shakePos).first; offsetY += (*_shakePos).second; } - ++_shakePos; } img.copyTo(_frame(cv::Rect(offsetX, offsetY, img.cols, img.rows))); diff --git a/src/lib/gui/window_cvhighgui.h b/src/lib/gui/window_cvhighgui.h index e5be7e35..bf8db4a4 100644 --- a/src/lib/gui/window_cvhighgui.h +++ b/src/lib/gui/window_cvhighgui.h @@ -3,12 +3,16 @@ #include "window_interface.h" +#include "shaky_cam.h" + namespace cimbar { class window_cvhighgui : public window_interface { public: - window_cvhighgui(unsigned, unsigned, std::string) + window_cvhighgui(unsigned width, unsigned height, std::string title) + : _cam(std::min(width, height), width, height, true) + , _title(title) {} bool is_good() const @@ -18,20 +22,28 @@ class window_cvhighgui : public window_interface bool should_close() const { - return cv::getWindowProperty("image", cv::WND_PROP_AUTOSIZE) < 0; + return cv::getWindowProperty(_title, cv::WND_PROP_AUTOSIZE) < 0; } void rotate(unsigned i=1) { } + void shake(unsigned i=1) + { + if (i > 0) + _cam.shake(); + } + void show(const cv::Mat& img, unsigned delay) { - cv::imshow("image", img); + cv::imshow(_title, _cam.draw(img)); cv::waitKey(delay); // functions as the frame delay... you can hold down a key to make it go faster } protected: + cimbar::shaky_cam _cam; + std::string _title; }; } From a49fe7f2e2647c70509edf94224bb0fa5d2b0089 Mon Sep 17 00:00:00 2001 From: sz Date: Mon, 1 Mar 2021 22:30:10 -0600 Subject: [PATCH 09/26] Only dark mode for now --- src/exe/cimbar_send/send.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/exe/cimbar_send/send.cpp b/src/exe/cimbar_send/send.cpp index 7730ca7c..a65e12ae 100644 --- a/src/exe/cimbar_send/send.cpp +++ b/src/exe/cimbar_send/send.cpp @@ -55,7 +55,6 @@ int main(int argc, char** argv) fps = defaultFps; unsigned delay = 1000 / fps; - bool dark = true; bool use_rotatecam = result.count("rotatecam"); bool use_shakycam = result.count("shakycam"); int window_size = 1080; From c15ac29ddedc34fc334fa8ae89822b85080de3c8 Mon Sep 17 00:00:00 2001 From: sz Date: Tue, 2 Mar 2021 20:52:13 -0600 Subject: [PATCH 10/26] The motivation of the shaky_cam is to detect cross-frame overlap, ... not an interpretive barcode dance. Less snarkily, I'm trying to find the right balance between "decoder can discard bad frames" and "user gets a headache looking at the barcode". --- src/lib/gui/gl_2d_display.h | 10 +++------- src/lib/gui/shaky_cam.h | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/lib/gui/gl_2d_display.h b/src/lib/gui/gl_2d_display.h index 57151ec9..1d80400a 100644 --- a/src/lib/gui/gl_2d_display.h +++ b/src/lib/gui/gl_2d_display.h @@ -33,7 +33,7 @@ class gl_2d_display {0, -1, -1, 0} // right 270 }}; - static std::array, 8> computeShakePos(float dim) + static std::array, 4> computeShakePos(float dim) { float shake = 8.0f / dim; // 1080 float zero = 0.0f; @@ -41,11 +41,7 @@ class gl_2d_display {zero, zero}, {zero-shake, zero-shake}, {zero, zero}, - {zero+shake, zero+shake}, - {zero, zero}, - {zero-shake, zero+shake}, - {zero, zero}, - {zero+shake, zero-shake} + {zero+shake, zero+shake} }}; } @@ -176,7 +172,7 @@ class gl_2d_display unsigned _i = 0; float _dimension; - std::array, 8> _shakePos; + std::array, 4> _shakePos; loop_iterator _shake; loop_iterator _rotation; }; diff --git a/src/lib/gui/shaky_cam.h b/src/lib/gui/shaky_cam.h index 10a0be5c..4101b5ea 100644 --- a/src/lib/gui/shaky_cam.h +++ b/src/lib/gui/shaky_cam.h @@ -9,8 +9,8 @@ namespace cimbar { class shaky_cam { public: - static constexpr std::array, 8> SHAKE_POS = {{ - {0, 0}, {-8, -8}, {0, 0}, {8, 8}, {0, 0}, {-8, 8}, {0, 0}, {8, -8} + static constexpr std::array, 4> SHAKE_POS = {{ + {0, 0}, {-8, -8}, {0, 0}, {8, 8} }}; public: From 6933d3e0a6a0af64c1a85ca559a4d0dfb8e7aef1 Mon Sep 17 00:00:00 2001 From: sz Date: Tue, 2 Mar 2021 20:59:51 -0600 Subject: [PATCH 11/26] fix color bug with highgui It'd be nice to have a test to catch this :thinking: --- src/lib/gui/shaky_cam.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/gui/shaky_cam.h b/src/lib/gui/shaky_cam.h index 4101b5ea..69ab785c 100644 --- a/src/lib/gui/shaky_cam.h +++ b/src/lib/gui/shaky_cam.h @@ -68,6 +68,7 @@ class shaky_cam } img.copyTo(_frame(cv::Rect(offsetX, offsetY, img.cols, img.rows))); + cv::cvtColor(_frame, _frame, cv::COLOR_BGR2RGB); return _frame; } From 21e39dbada3af55b59095d29e599f220d776cb80 Mon Sep 17 00:00:00 2001 From: sz Date: Tue, 2 Mar 2021 21:02:47 -0600 Subject: [PATCH 12/26] Update help --- src/exe/cimbar/cimbar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exe/cimbar/cimbar.cpp b/src/exe/cimbar/cimbar.cpp index 1990a60e..8f8c91e1 100644 --- a/src/exe/cimbar/cimbar.cpp +++ b/src/exe/cimbar/cimbar.cpp @@ -74,7 +74,7 @@ int main(int argc, char** argv) unsigned ecc = cimbar::Config::ecc_bytes(); options.add_options() ("i,in", "Encoded pngs/jpgs/etc (for decode), or file to encode", cxxopts::value>()) - ("o,out", "Output file or directory.", cxxopts::value()) + ("o,out", "Output file prefix (encoding) or directory (decoding).", cxxopts::value()) ("c,color-bits", "Color bits. [0-3]", cxxopts::value()->default_value(turbo::str::str(colorBits))) ("e,ecc", "ECC level", cxxopts::value()->default_value(turbo::str::str(ecc))) ("f,fountain", "Attempt fountain encode/decode", cxxopts::value()) From 0626afca7dc3443684c909f4a20477e4ebd79b14 Mon Sep 17 00:00:00 2001 From: sz Date: Wed, 3 Mar 2021 20:19:14 -0600 Subject: [PATCH 13/26] Tired of the mouse cursor getting in the way... --- web/index.html | 3 +++ web/main.js | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/web/index.html b/web/index.html index f7e14d16..599d93b8 100644 --- a/web/index.html +++ b/web/index.html @@ -57,6 +57,9 @@ opacity: 0; pointer-events: auto; } +#invisible_click.active { + cursor: none; +} #nav-container:focus-within + #invisible_click { pointer-events: none; display: none; diff --git a/web/main.js b/web/main.js index 6f7894d1..d620b21c 100644 --- a/web/main.js +++ b/web/main.js @@ -68,6 +68,7 @@ return { var res = Module._encode(data.byteOffset, data.length); console.log(res); Main.setTitle(filename); + Main.setActive(true); }, dragDrop : function(event) @@ -121,6 +122,14 @@ return { } }, + setActive : function(active) + { + // hide cursor when there's a barcode active + var invisi = document.getElementById("invisible_click"); + invisi.classList.remove("active"); + invisi.classList.add("active"); + }, + setColorBits : function(color_bits) { Module._configure(color_bits); From f979012d38e02db64071471fd862f966acd707b1 Mon Sep 17 00:00:00 2001 From: sz Date: Wed, 3 Mar 2021 21:13:55 -0600 Subject: [PATCH 14/26] :thinking: --- src/wasm/cimbar_js/wasm.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/wasm/cimbar_js/wasm.cpp b/src/wasm/cimbar_js/wasm.cpp index 9529aad8..f9eddb2e 100644 --- a/src/wasm/cimbar_js/wasm.cpp +++ b/src/wasm/cimbar_js/wasm.cpp @@ -15,6 +15,8 @@ namespace { std::shared_ptr _window; std::shared_ptr _fes; + std::optional _next; + int _renders = 0; uint8_t _encodeId = 0; @@ -44,6 +46,13 @@ int render() if (!_window or !_fes) return 0; + // render frame first to minimize frame pacing issues + if (_next) + { + _window->show(*_next, 0); + _window->shake(); + } + // we generate 8x the amount of required blocks -- unless everything fits in a single frame. unsigned required = _fes->blocks_required(); if (required > cimbar::Config::fountain_chunks_per_frame()) @@ -57,15 +66,7 @@ int render() SimpleEncoder enc(_ecc, cimbar::Config::symbol_bits(), _colorBits); enc.set_encode_id(_encodeId); - std::optional img = enc.encode_next(*_fes, _window->width()); - if (!img) - { - std::cerr << "no image :(" << std::endl; - return 0; - } - - _window->show(*img, 0); - _window->shake(); + _next = enc.encode_next(*_fes, _window->width()); return ++_renders; } @@ -84,6 +85,8 @@ int encode(uint8_t* buffer, size_t size) if (!_fes) return 0; + + _next.reset(); return 1; } @@ -101,6 +104,7 @@ int configure(unsigned color_bits) // if the data is too small, we should throw out _fes -- and clear the canvas. _fes = nullptr; _window->clear(); + _next.reset(); } _window->shake(0); } From 4c5f8266c146489c16adbc1de63fe68cc27f72d9 Mon Sep 17 00:00:00 2001 From: sz Date: Wed, 3 Mar 2021 21:31:17 -0600 Subject: [PATCH 15/26] I like this interface slightly more. The idea here is to improve frame pacing. --- src/wasm/cimbar_js/CMakeLists.txt | 2 +- src/wasm/cimbar_js/wasm.cpp | 12 ++++++++++-- web/main.js | 5 +++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/wasm/cimbar_js/CMakeLists.txt b/src/wasm/cimbar_js/CMakeLists.txt index 42dead63..b1746cbf 100644 --- a/src/wasm/cimbar_js/CMakeLists.txt +++ b/src/wasm/cimbar_js/CMakeLists.txt @@ -47,7 +47,7 @@ set (LINK_WASM_LIST -s USE_GLFW=3 -s FILESYSTEM=0 -s TOTAL_MEMORY=134217728 - -s EXPORTED_FUNCTIONS='["_render","_initialize_GL","_encode","_configure"]' + -s EXPORTED_FUNCTIONS='["_render","_next_frame","_initialize_GL","_encode","_configure"]' ) string(REPLACE ";" " " LINK_WASM_FLAGS "${LINK_WASM_LIST}") diff --git a/src/wasm/cimbar_js/wasm.cpp b/src/wasm/cimbar_js/wasm.cpp index f9eddb2e..d8179a1b 100644 --- a/src/wasm/cimbar_js/wasm.cpp +++ b/src/wasm/cimbar_js/wasm.cpp @@ -17,7 +17,7 @@ namespace { std::shared_ptr _fes; std::optional _next; - int _renders = 0; + int _numFrames = 0; uint8_t _encodeId = 0; // settings @@ -51,7 +51,15 @@ int render() { _window->show(*_next, 0); _window->shake(); + return 1; } + return 0; +} + +int next_frame() +{ + if (!_window or !_fes) + return 0; // we generate 8x the amount of required blocks -- unless everything fits in a single frame. unsigned required = _fes->blocks_required(); @@ -67,7 +75,7 @@ int render() enc.set_encode_id(_encodeId); _next = enc.encode_next(*_fes, _window->width()); - return ++_renders; + return ++_numFrames; } int encode(uint8_t* buffer, size_t size) diff --git a/web/main.js b/web/main.js index d620b21c..e4f0b6e8 100644 --- a/web/main.js +++ b/web/main.js @@ -110,7 +110,8 @@ return { nextFrame : function() { var start = performance.now(); - var renderCount = Module._render(); + Module._render(); + var frameCount = Module._next_frame(); var elapsed = performance.now() - start; var nextInterval = _interval>elapsed? _interval-elapsed : 0; @@ -118,7 +119,7 @@ return { if (_showStats && renderCount) { _renderTime += elapsed; - Main.setHTML( "status", elapsed + " : " + renderCount + " : " + Math.ceil(_renderTime/renderCount)); + Main.setHTML( "status", elapsed + " : " + frameCount + " : " + Math.ceil(_renderTime/frameCount)); } }, From 5b86c29a881111093835eecf93166ef0fafc1b65 Mon Sep 17 00:00:00 2001 From: sz Date: Wed, 3 Mar 2021 22:22:52 -0600 Subject: [PATCH 16/26] WIP: having more light (white) helps the camera = cleaner frames = better transfer rates. Checking in a cool gradient, because I can't resist --- web/index.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/index.html b/web/index.html index 599d93b8..e8596887 100644 --- a/web/index.html +++ b/web/index.html @@ -14,7 +14,8 @@ } body { - background-color: black; + background-color: white; + background-image: linear-gradient(187deg, rgba(16,16,16, 0.07) 0%, rgba(16,16,16, 0.07) 50%,rgba(246,239,239, 0.07) 50%, rgba(246,239,239, 0.07) 100%),linear-gradient(255deg, rgba(255,255,255, 0.09) 0%, rgba(255,255,255, 0.09) 50%,rgba(209,186,186, 0.09) 50%, rgba(209,186,186, 0.09) 100%),linear-gradient(191deg, rgba(170,156,156, 0.08) 0%, rgba(170,156,156, 0.08) 50%,rgba(255,255,255, 0.08) 50%, rgba(255,255,255, 0.08) 100%),linear-gradient(339deg, rgba(255,255,255, 0.04) 0%, rgba(255,255,255, 0.04) 50%,rgba(76,189,219, 0.04) 50%, rgba(76,189,219, 0.04) 100%),linear-gradient(173deg, rgba(125,119,119, 0.09) 0%, rgba(125,119,119, 0.09) 50%,rgba(250,246,246, 0.09) 50%, rgba(250,246,246, 0.09) 100%),linear-gradient(317deg, rgba(255,255,255, 0.01) 0%, rgba(255,255,255, 0.01) 50%,rgba(249,249,249, 0.01) 50%, rgba(249,249,249, 0.01) 100%),linear-gradient(173deg, rgba(138,123,123, 0.07) 0%, rgba(138,123,123, 0.07) 50%,rgba(251,251,251, 0.07) 50%, rgba(251,251,251, 0.07) 100%),linear-gradient(222deg, rgba(243,243,243, 0.05) 0%, rgba(243,243,243, 0.05) 50%,rgba(35,31,31, 0.05) 50%, rgba(35,31,31, 0.05) 100%),linear-gradient(232deg, rgba(251,246,246, 0.01) 0%, rgba(251,246,246, 0.01) 50%,rgba(249,249,249, 0.01) 50%, rgba(249,249,249, 0.01) 100%),linear-gradient(90deg, rgb(0,0,0),rgb(255,255,255),rgb(255,255,255)); color: gray; height: 100vh; display: grid; @@ -39,6 +40,7 @@ margin: 0 auto; z-index: -1; color: #F0F0F0; + outline: 10px solid black; } #dragdrop::before { @@ -113,6 +115,7 @@ pointer-events: auto; touch-action: manipulation; outline: 0; + background-image: linear-gradient(180deg, rgb(0,0,0,0) 20%, rgb(0,0,0) 40%, rgb(0,0,0) 60%, rgb(0,0,0,0) 80%); } .icon-bar { display: block; @@ -276,7 +279,7 @@ - +