diff --git a/src/doompanning.cc b/src/doompanning.cc index 694a059..1a5681c 100644 --- a/src/doompanning.cc +++ b/src/doompanning.cc @@ -44,7 +44,7 @@ struct ControllerContext std::vector dooms; bool quit = false; ExampleAppLog appLog; - int columns = 1; + int columns = 4; std::array pixelBuffer; }; @@ -54,22 +54,24 @@ struct ControllerActions bool endAllDooms = false; }; +#define DOOM_EXECUTABLE "dp_doom" + void spawn_doom(ControllerContext &ctx) { DoomState ds; - const char *const argv[] = { "doomsim", nullptr }; + const char *const argv[] = { DOOM_EXECUTABLE, nullptr }; // TODO: Close stdin and stdout? Leave them open for now to see the logging // output. - if (auto err = posix_spawn(&ds.id, "doomsim", nullptr, nullptr, + if (auto err = posix_spawn(&ds.id, DOOM_EXECUTABLE, nullptr, nullptr, const_cast(argv), nullptr)) { log_error("Could not spawn doom: %s", strerror(err)); return; } - ds.texture = SDL_CreateTexture(ctx.renderer, SDL_PIXELFORMAT_ARGB8888, + ds.texture = SDL_CreateTexture(ctx.renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, DoomScreenWidth, DoomScreenHeight); if (!ds.texture) @@ -131,18 +133,19 @@ void check_on_dooms(ControllerContext &ctx) if (pid = waitpid(0, &wstatus, WNOHANG); pid > 0) { - auto dit = find_in_container(ctx.dooms, [pid] (const auto &ds) { return ds.id == pid; }); + auto ds = find_in_container(ctx.dooms, [pid] (const auto &ds) { return ds.id == pid; }); - assert(dit != std::end(ctx.dooms)); + assert(ds != std::end(ctx.dooms)); - if (dit != std::end(ctx.dooms)) + if (ds != std::end(ctx.dooms)) { if (WIFEXITED(wstatus)) log_info("doom(%d) exited with status %d", pid, WEXITSTATUS(wstatus)); else if (WIFSIGNALED(wstatus)) log_warn("doom#(%d) got killed by signal %d", pid, WTERMSIG(wstatus)); - ctx.dooms.erase(dit); + SDL_DestroyTexture(ds->texture); // TODO: use the destructor to do this + ctx.dooms.erase(ds); } } } while (pid > 0); @@ -150,7 +153,52 @@ void check_on_dooms(ControllerContext &ctx) void do_networking(ControllerContext &ctx) { - // FIXME: test code. spam RunDoom + bool sendRunDoom = false; + auto tStart = std::chrono::steady_clock::now(); + + while (true) + { + if (auto elapsed = std::chrono::steady_clock::now() - tStart; + elapsed >= std::chrono::milliseconds(10)) + { + break; + } + + nng_msg *msg = nullptr; + + if (auto res = dp_recv_new_msg_nonblock(ctx.sub, &msg)) + { + if (!dp_nng_is_timeout(res)) + dp_nng_fatal("ctrl/recvmsg", res); + break; // timeout + } + + auto msgBase = DP_NNG_BODY_AS(msg, MessageBase); + + if (msgBase->msgType == DP_MT_DoomState) + { + auto msgDoomState = DP_NNG_BODY_AS(msg, MsgDoomState); + + if (msgDoomState->doomState == DP_DS_Ready) + sendRunDoom = true; + } + else if (msgBase->msgType == DP_MT_DoomFrame) + { + auto msgDoomFrame = DP_NNG_BODY_AS(msg, MsgDoomFrame); + auto pid = msgDoomFrame->doomId; + auto dit = find_in_container(ctx.dooms, [pid] (const auto &ds) { return ds.id == pid; }); + + if (dit != std::end(ctx.dooms)) + { + auto &ds = *dit; + SDL_UpdateTexture(ds.texture, nullptr, msgDoomFrame->frame, DoomFramePitch); + } + } + + nng_msg_free(msg); + } + + if (sendRunDoom) { nng_msg *msg = nullptr; int res = 0; @@ -317,7 +365,7 @@ void render_dooms(ControllerContext &ctx) auto &ds = ctx.dooms.at(i); auto texture = ds.texture; assert(texture); - SDL_UpdateTexture(texture, nullptr, buffer.pixels, buffer.width * buffer.BytesPerPixel); + //SDL_UpdateTexture(texture, nullptr, buffer.pixels, buffer.width * buffer.BytesPerPixel); SDL_RenderCopy(ctx.renderer, texture, nullptr, &destRect); destRect.x += buffer.width; diff --git a/src/dp_common.h b/src/dp_common.h index b5ab0d4..0927104 100644 --- a/src/dp_common.h +++ b/src/dp_common.h @@ -17,8 +17,10 @@ typedef pid_t doomid_t; // unique id for each doom instance typedef u16 dmt_t; // for DP_MessageType values #define DoomScreenWidth 320u -#define DoomScreenHeight 200u -#define DoomBytesPerPixel 4u +#define DoomScreenHeight 240u +#define DoomBytesPerPixel 3u +#define DoomFrameSize (DoomScreenWidth * DoomScreenHeight * DoomBytesPerPixel) +#define DoomFramePitch (DoomScreenWidth * DoomBytesPerPixel) typedef enum DP_MessageType { @@ -63,6 +65,7 @@ typedef struct __attribute__((packed, aligned(4))) typedef struct __attribute__((packed, aligned(4))) { MessageBase head; + doomid_t doomId; u8 frame[DoomScreenWidth * DoomScreenHeight * DoomBytesPerPixel]; } MsgDoomFrame; @@ -87,7 +90,7 @@ typedef struct __attribute__((packed, aligned(4))) void dp_errno_fatal(const char *const msg); void dp_nng_fatal(const char *const msg, int rv); void dp_nng_init_limits(int ncpu_max, int pool_thread_limit_max, int resolv_thread_limit); -inline bool dp_nng_is_timeout(int res) +static inline bool dp_nng_is_timeout(int res) { return res == NNG_ETIMEDOUT || res == NNG_EAGAIN; } @@ -104,7 +107,7 @@ int dp_recv_new_msg(nng_socket sock, nng_msg **msg_ptr); int dp_recv_new_msg_nonblock(nng_socket sock, nng_msg **msg_ptr); int dp_recv_new_msg_flags(nng_socket sock, nng_msg **msg_ptr, int flags); -inline void *dp_nng_msg_body_if_size_ge(nng_msg *msg, size_t size, bool isFatal) +static inline void *dp_nng_msg_body_if_size_ge(nng_msg *msg, size_t size, bool isFatal) { if (nng_msg_len(msg) >= size) return nng_msg_body(msg);