Skip to content

Instantly share code, notes, and snippets.

@OlegJakushkin
Created May 6, 2017 04:28
Show Gist options
  • Save OlegJakushkin/0489c48928f0790d62f8523bcf5fba24 to your computer and use it in GitHub Desktop.
Save OlegJakushkin/0489c48928f0790d62f8523bcf5fba24 to your computer and use it in GitHub Desktop.
#include<time.h>
#include <string>
#include <vector>
#include <atomic>
#include <thread>
#include <SDL.h>
#include <GLFW/glfw3.h>
#include <imgui/imgui.h>
#include <imgui/imgui_impl_glfw.h>
#include <pico.h>
#include <zmq_addon.hpp>
using namespace std;
using namespace zmq;
// Model
struct Point : ImVec2 {
int _x, _y;
template<class Archive>
void json(Archive & ar) {
_x = x;
_y = y;
ar & picojson::convert::member("x", _x);
ar & picojson::convert::member("y", _y);
x = _x;
y = _y;
}
void operator+=(const ImVec2 &other) {
x += other.x;
y += other.y;
}
void operator=(const ImVec2 &other) {
x = other.x;
y = other.y;
}
};
struct Line {
Point from, to;
int color;
template<class Archive>
void json(Archive & ar) {
ar & picojson::convert::member("color", color);
ar & picojson::convert::member("from.x", from);
ar & picojson::convert::member("to", to);
}
};
struct Image {
std::vector<Line> lines;
template<class Archive>
void json(Archive & ar) {
ar & picojson::convert::member("lines", lines);
}
Image operator-(const Image & other) const {
Image result;
set_difference(lines.begin(),
lines.end(),
other.lines.begin(),
other.lines.end(),
back_inserter(result.lines),
[](Line l1, Line l2) {
return l1.color == l2.color &&
l1.from == l2.from &&
l1.to == l2.to;
});
return result;
}
};
Image publicImage;
Image myImage;
context_t ctx;
string url= "127.0.0.1";
string userId;
atomic<bool> stop = false;
atomic<bool> updating = false;
void ReceiveUpdates() {
Image syncedImage;
socket_t socket(ctx, ZMQ_SUB);
socket.connect("tcp://"+url+":5566");
string topic = "img";
socket.setsockopt(ZMQ_SUBSCRIBE, topic.c_str(), topic.size());
while(!socket.connected() && !stop) {
this_thread::sleep_for(chrono::milliseconds(100));
}
cout << "connected reader" << endl;
while(!stop) {
this_thread::sleep_for(chrono::milliseconds(50));
message_t img;
socket.recv(&img);
socket.recv(&img);
auto imgStr = string(img.data<char>(), img.size());
updating = true;
picojson::convert::from_string(imgStr, publicImage);
updating = false;
cout << "updated image!" << endl;
}
}
void SendUpdates() {
Image syncedImage;
socket_t socket(ctx, ZMQ_REQ);
socket.setsockopt(ZMQ_IDENTITY, userId.c_str(), userId.length());
socket.connect("tcp://"+url+":5555");
while(!socket.connected() && !stop) {
this_thread::sleep_for(chrono::milliseconds(100));
}
cout << "connected poster" << endl;
while(!stop) {
this_thread::sleep_for(chrono::milliseconds(50));
auto diff = syncedImage - myImage;
auto requestContent = picojson::convert::to_string(diff);
message_t msg(requestContent.data(), requestContent.size());
socket.send(msg);
cout << "sent frame" << endl;
message_t rep;
socket.recv(&rep);
string reply(rep.data<char>(), rep.size());
cout << "syncronised with: " << reply << endl;
}
}
//UI
int main(int, char**) {
srand(time(0));
auto myColor = ImColor(rand()%255, rand()%200, rand()%200);
unsigned int c = myColor ;
userId = to_string(c);
cout << userId << endl;
//Start networking
thread post(ReceiveUpdates);
thread read(SendUpdates);
// Setup window
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
exit(1);
}
auto w=1280, h=720;
auto window = glfwCreateWindow(w, h, "ImGui OpenGL2 example", NULL, NULL);
glfwMakeContextCurrent(window);
// Setup ImGui binding
ImGui_ImplGlfw_Init(window, true);
ImVec4 clear_color = ImColor(114, 144, 154);
auto opened = true;
Line current;
current.color = myColor;
auto adding_line = false;
// Main loop
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
ImGui_ImplGlfw_NewFrame();
ImGui::SetNextWindowSize(ImVec2(w-30,h-30), ImGuiSetCond_FirstUseEver);
if (!ImGui::Begin("Example: Custom Rendering",&opened)) {
ImGui::End();
break;
}
if (myImage.lines.size() > 0) {
ImGui::SameLine();
if (ImGui::Button("Undo")) {
myImage.lines.pop_back();
}
}
ImGui::Text("Your Color");
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, myColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, myColor);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, myColor);
ImGui::Button("------");
ImGui::PopStyleColor(3);
ImGui::Text("Left-click and drag to add lines");
ImGui::SameLine();
ImGui::Text("Right-click to undo");
auto draw_list = ImGui::GetWindowDrawList();
auto canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
auto canvas_size = ImVec2(ImMax(50.0f,ImGui::GetWindowContentRegionMax().x-ImGui::GetCursorPos().x),
ImMax(50.0f,ImGui::GetWindowContentRegionMax().y-ImGui::GetCursorPos().y)); // Resize canvas what's available
draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), 0xFFFFFFFF);
auto adding_preview = false;
ImGui::InvisibleButton("canvas", canvas_size);
if (ImGui::IsItemHovered()) {
auto mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
if (!adding_line && ImGui::GetIO().MouseClicked[0]) {
current.from = mouse_pos_in_canvas;
adding_line = true;
}
if (adding_line) {
adding_preview = true;
current.to = mouse_pos_in_canvas;
myImage.lines.push_back(current); // will be removed if preview_mode before next frame
if (!ImGui::GetIO().MouseDown[0]) {
adding_line = adding_preview = false;
}
}
if (ImGui::GetIO().MouseClicked[1] && !myImage.lines.empty()) {
adding_line = false;
myImage.lines.pop_back();
}
}
draw_list->PushClipRect(ImVec4(canvas_pos.x,
canvas_pos.y,
canvas_pos.x+canvas_size.x,
canvas_pos.y+canvas_size.y)); // clip lines within the canvas (if we resize it, etc.)
for (auto l : myImage.lines) {
draw_list->AddLine(canvas_pos + l.from,
canvas_pos + l.to, l.color);
}
//Network data
if(!updating) {
for (auto l : publicImage.lines) {
draw_list->AddLine(canvas_pos + l.from,
canvas_pos + l.to, l.color);
}
}
draw_list->PopClipRect();
if (adding_preview) {
myImage.lines.pop_back();
}
ImGui::End();
// Rendering
glViewport(0, 0, static_cast<int>(ImGui::GetIO().DisplaySize.x),
static_cast<int>(ImGui::GetIO().DisplaySize.y));
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui::Render();
glfwSwapBuffers(window);
}
// Cleanup
ImGui_ImplGlfw_Shutdown();
glfwTerminate();
//Stop networking
stop = true;
read.join();
post.join();
return 0;
}
#include<time.h>
#include <string>
#include <vector>
#include <atomic>
#include <thread>
#include <SDL.h>
#include <GLFW/glfw3.h>
#include <imgui/imgui.h>
#include <imgui/imgui_impl_glfw.h>
#include <pico.h>
#include <zmq_addon.hpp>
#include <mutex>
using namespace std;
using namespace zmq;
// Model
struct Point : ImVec2 {
int _x, _y;
template<class Archive>
void json(Archive & ar) {
_x = x;
_y = y;
ar & picojson::convert::member("x", _x);
ar & picojson::convert::member("y", _y);
x = _x;
y = _y;
}
void operator+=(const ImVec2 &other) {
x += other.x;
y += other.y;
}
};
struct Line {
Point from, to;
int color;
template<class Archive>
void json(Archive & ar) {
ar & picojson::convert::member("color", color);
ar & picojson::convert::member("from.x", from);
ar & picojson::convert::member("to", to);
}
};
struct Image {
std::vector<Line> lines;
template<class Archive>
void json(Archive & ar) {
ar & picojson::convert::member("lines", lines);
}
Image operator-(const Image & other) const {
Image result;
set_difference(lines.begin(),
lines.end(),
other.lines.begin(),
other.lines.end(),
back_inserter(result.lines),
[](Line l1, Line l2) {
return l1.color == l2.color &&
l1.from == l2.from &&
l1.to == l2.to;
});
return result;
}
};
Image publicImage;
context_t ctx;
string url= "127.0.0.1";
atomic<bool> stop = false;
mutex m;
void BroadcastUpdates() {
socket_t socket(ctx, ZMQ_PUB);
socket.connect("tcp://"+url+":5566");
while(!stop) {
string requestContent;
{
lock_guard<mutex> l(m);
requestContent = picojson::convert::to_string(publicImage);
}
string topicStr = "img";
message_t topic(topicStr.data(), topicStr.size());
socket.send(topic, ZMQ_SNDMORE);
message_t img(requestContent.data(), requestContent.size());
socket.send(img);
cout << "broadcasted image!" << endl;
this_thread::sleep_for(chrono::milliseconds(50));
}
}
void ReceiveUpdates() {
Image syncedImage;
socket_t socket(ctx, ZMQ_ROUTER);
socket.bind("tcp://"+url+":5555");
while(!stop) {
message_t identity;
message_t msg;
socket.recv(&identity);
string id(identity.data<char>(), identity.size());
socket.recv(&msg);
socket.recv(&msg);
cout << "r uid+frame" << endl;
Image diff;
string diffStr(msg.data<char>(), msg.size());
picojson::convert::from_string(diffStr, diff);
{
lock_guard<mutex> l(m);
copy (diff.lines.begin(), diff.lines.end(), back_inserter(publicImage.lines));
}
socket.send(identity, ZMQ_SNDMORE);
socket.send(message_t(), ZMQ_SNDMORE);
string ok = "Ok";
socket.send(message_t(ok.data(), ok.size()));
cout << "syncronised with: " << id << endl;
}
}
//UI
int main(int, char**) {
//Start networking
thread post(BroadcastUpdates);
thread read(ReceiveUpdates);
//Server loop`
string exit;
while(!stop) {
cin >> exit;
if(exit == "quit") {
stop = true;
} else {
cout << "enter 'quit' to stop!" << endl;
}
}
//Stop networking
stop = true;
read.join();
post.join();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment