Created
May 6, 2017 04:28
-
-
Save OlegJakushkin/0489c48928f0790d62f8523bcf5fba24 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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