2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
#include "gui/imgui/imgui.h"
|
|
|
|
#include "types.hpp"
|
|
|
|
#include "ig001.hpp"
|
|
|
|
#include "gui/imgui/imgui_stdlib.h"
|
2024-04-11 21:19:24 +08:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <iterator>
|
2024-04-11 17:00:40 +08:00
|
|
|
#include <string>
|
2024-04-22 07:03:25 +08:00
|
|
|
#include <vector>
|
2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
|
|
|
|
class EntityBase {
|
|
|
|
public:
|
2024-04-11 21:19:24 +08:00
|
|
|
virtual ~EntityBase() {}
|
2024-04-11 17:00:40 +08:00
|
|
|
virtual std::string type() = 0;
|
|
|
|
|
2024-04-11 21:19:24 +08:00
|
|
|
virtual std::string to_file() = 0;
|
|
|
|
virtual void from_strtok() = 0;
|
2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
// Pointer to the entity base is pushed outside
|
2024-04-11 21:19:24 +08:00
|
|
|
virtual void imgui() {}
|
2024-04-16 19:34:36 +08:00
|
|
|
virtual void draw_prev(Vec2 offset, bool selected) {}
|
2024-04-11 21:19:24 +08:00
|
|
|
virtual void draw(Vec2 offset, bool selected) {}
|
|
|
|
virtual EntityBase *setpos(Vec2 pos) { return this; }
|
2024-04-11 17:00:40 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
inline static void draw_box2(Box2 box, bool selected, ImU32 color) {
|
|
|
|
ImDrawList *list = ig::GetBackgroundDrawList();
|
|
|
|
list->AddRect(box.lefttop.im(), (box.lefttop + box.size).im(), color);
|
|
|
|
if (selected) {
|
|
|
|
list->AddLine(box.lefttop.im(), (box.lefttop + box.size).im(), color);
|
|
|
|
list->AddLine((box.lefttop + Vec2(box.size.x, 0)).im(), (box.lefttop + Vec2(0, box.size.y)).im(), color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void draw_vec2(Vec2 vec, bool selected, ImU32 color) {
|
|
|
|
ImDrawList *list = ig::GetBackgroundDrawList();
|
|
|
|
list->AddLine((vec + Vec2(-10, -10)).im(), (vec + Vec2(10, 10)).im(), color);
|
|
|
|
list->AddLine((vec + Vec2(-10, 10)).im(), (vec + Vec2(10, -10)).im(), color);
|
|
|
|
if (selected)
|
|
|
|
list->AddCircle(vec.im(), 7.0f, color);
|
|
|
|
}
|
|
|
|
|
2024-04-11 21:19:24 +08:00
|
|
|
#define TOKEN (strtok(NULL, " "))
|
|
|
|
#define TOKEN_INT (atoi(TOKEN))
|
|
|
|
#define TOKEN_DOUBLE (strtod(TOKEN, NULL))
|
|
|
|
|
2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
// Defined in bundle.cpp
|
|
|
|
extern char buf[1024];
|
|
|
|
|
|
|
|
class Hitbox: public EntityBase {
|
|
|
|
public:
|
|
|
|
std::string type() override { return "hitbox"; }
|
|
|
|
std::string to_file() override {
|
2024-04-11 21:19:24 +08:00
|
|
|
snprintf(buf, sizeof(buf), "HITBOX %.0lf %.0lf %.0lf %.0lf\n", box.lefttop.x, box.lefttop.y, box.size.x, box.size.y);
|
2024-04-11 17:00:40 +08:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2024-04-11 21:19:24 +08:00
|
|
|
void from_strtok() override {
|
|
|
|
double a, b, c, d;
|
|
|
|
a = TOKEN_DOUBLE;
|
|
|
|
b = TOKEN_DOUBLE;
|
|
|
|
c = TOKEN_DOUBLE;
|
|
|
|
d = TOKEN_DOUBLE;
|
|
|
|
box = Box2(a, b, c, d);
|
|
|
|
}
|
|
|
|
|
|
|
|
void imgui() override { DragBox2("", &box); }
|
|
|
|
void draw(Vec2 offset, bool selected) override { draw_box2(box.offset(offset), selected, IM_COL32(0, 255, 0, 255)); }
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
box.lefttop = pos;
|
|
|
|
return this;
|
|
|
|
}
|
2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
Box2 box;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Player: public EntityBase {
|
|
|
|
public:
|
|
|
|
std::string type() override { return "player"; }
|
|
|
|
std::string to_file() override {
|
2024-04-11 21:19:24 +08:00
|
|
|
snprintf(buf, sizeof(buf), "PLAYER %.0lf %.0lf\n", pos.x, pos.y);
|
2024-04-11 17:00:40 +08:00
|
|
|
return buf;
|
|
|
|
}
|
2024-04-11 21:19:24 +08:00
|
|
|
void from_strtok() override {
|
|
|
|
double a, b, c, d;
|
|
|
|
a = TOKEN_DOUBLE;
|
|
|
|
b = TOKEN_DOUBLE;
|
|
|
|
pos = Vec2(a, b);
|
|
|
|
}
|
2024-04-11 17:00:40 +08:00
|
|
|
|
2024-04-11 21:19:24 +08:00
|
|
|
void imgui() override { DragVec2("Player Spawn", &pos); }
|
|
|
|
void draw(Vec2 offset, bool selected) override { draw_vec2(pos + offset, selected, IM_COL32_WHITE); }
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
this->pos = pos;
|
|
|
|
return this;
|
|
|
|
}
|
2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
Vec2 pos;
|
|
|
|
};
|
|
|
|
|
|
|
|
class HazardRespawn: public EntityBase {
|
|
|
|
public:
|
|
|
|
std::string type() override { return "hazard_respawn"; }
|
|
|
|
std::string to_file() override {
|
2024-04-11 21:19:24 +08:00
|
|
|
snprintf(buf, sizeof(buf), "HAZARD_RESPAWN %.0lf %.0lf %.0lf %.0lf %.0lf %.0lf\n", box.lefttop.x, box.lefttop.y, box.size.x, box.size.y, pos.x, pos.y);
|
2024-04-11 17:00:40 +08:00
|
|
|
return buf;
|
|
|
|
}
|
2024-04-11 21:19:24 +08:00
|
|
|
void from_strtok() override {
|
|
|
|
double a, b, c, d, e, f;
|
|
|
|
a = TOKEN_DOUBLE;
|
|
|
|
b = TOKEN_DOUBLE;
|
|
|
|
c = TOKEN_DOUBLE;
|
|
|
|
d = TOKEN_DOUBLE;
|
|
|
|
e = TOKEN_DOUBLE;
|
|
|
|
f = TOKEN_DOUBLE;
|
|
|
|
box = Box2(a, b, c, d);
|
|
|
|
pos = Vec2(e, f);
|
|
|
|
}
|
2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
void imgui() override {
|
|
|
|
DragBox2("", &box);
|
|
|
|
DragVec2("Respawn", &pos);
|
|
|
|
}
|
|
|
|
void draw(Vec2 offset, bool selected) override {
|
2024-04-11 21:19:24 +08:00
|
|
|
draw_box2(box.offset(offset), selected, IM_COL32(255, 0, 255, 255));
|
|
|
|
draw_vec2(pos + offset, selected, IM_COL32(255, 0, 255, 255));
|
|
|
|
}
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
box.lefttop = pos;
|
|
|
|
this->pos = pos;
|
|
|
|
return this;
|
2024-04-11 17:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Box2 box;
|
|
|
|
Vec2 pos;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Hazard: public EntityBase {
|
|
|
|
public:
|
|
|
|
std::string type() override { return "hazard"; }
|
|
|
|
std::string to_file() override {
|
2024-04-11 21:19:24 +08:00
|
|
|
snprintf(buf, sizeof(buf), "HAZARD %.0lf %.0lf %.0lf %.0lf\n", box.lefttop.x, box.lefttop.y, box.size.x, box.size.y);
|
2024-04-11 17:00:40 +08:00
|
|
|
return buf;
|
|
|
|
}
|
2024-04-11 21:19:24 +08:00
|
|
|
void from_strtok() override {
|
|
|
|
double a, b, c, d;
|
|
|
|
a = TOKEN_DOUBLE;
|
|
|
|
b = TOKEN_DOUBLE;
|
|
|
|
c = TOKEN_DOUBLE;
|
|
|
|
d = TOKEN_DOUBLE;
|
|
|
|
box = Box2(a, b, c, d);
|
|
|
|
}
|
2024-04-11 17:00:40 +08:00
|
|
|
|
2024-04-11 21:19:24 +08:00
|
|
|
void imgui() override { DragBox2("", &box); }
|
|
|
|
void draw(Vec2 offset, bool selected) override { draw_box2(box.offset(offset), selected, IM_COL32(255, 0, 0, 255)); }
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
box.lefttop = pos;
|
|
|
|
return this;
|
|
|
|
}
|
2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
Box2 box;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Textbox: public EntityBase {
|
|
|
|
public:
|
|
|
|
std::string type() override { return "textbox"; }
|
|
|
|
std::string to_file() override {
|
|
|
|
std::string str;
|
2024-04-11 21:19:24 +08:00
|
|
|
snprintf(buf, sizeof(buf), "TEXTBOX %.0lf %.0lf %.0lf %.0lf %s ", box.lefttop.x, box.lefttop.y, box.size.x, box.size.y, render_bundle.c_str());
|
2024-04-11 17:00:40 +08:00
|
|
|
str += buf;
|
|
|
|
|
|
|
|
// Escape all the whitespaces
|
|
|
|
for (char c: text) {
|
|
|
|
switch (c) {
|
|
|
|
case '\t':
|
|
|
|
str += "\\t";
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
str += "\\s";
|
|
|
|
break;
|
|
|
|
case '\n':
|
|
|
|
str += "\\n";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
str.push_back(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
str += "\n";
|
|
|
|
return str;
|
|
|
|
}
|
2024-04-11 21:19:24 +08:00
|
|
|
void from_strtok() override {
|
|
|
|
double a, b, c, d;
|
|
|
|
a = TOKEN_DOUBLE;
|
|
|
|
b = TOKEN_DOUBLE;
|
|
|
|
c = TOKEN_DOUBLE;
|
|
|
|
d = TOKEN_DOUBLE;
|
|
|
|
box = Box2(a, b, c, d);
|
|
|
|
|
|
|
|
char *t = TOKEN;
|
|
|
|
render_bundle = (t ? t : "");
|
|
|
|
t = TOKEN;
|
|
|
|
std::string temp = (t ? t : "");
|
|
|
|
text.clear();
|
|
|
|
for (int i = 0; i < temp.size(); i++) {
|
|
|
|
if (temp[i] == '\\') {
|
|
|
|
if (i == temp.size() - 1)
|
|
|
|
text.push_back('\\'); // Weird case
|
|
|
|
else {
|
|
|
|
if (temp[i + 1] == 's')
|
|
|
|
text.push_back(' ');
|
|
|
|
else if (temp[i + 1] == 'n')
|
|
|
|
text.push_back('\n');
|
|
|
|
else if (temp[i + 1] == 't')
|
|
|
|
text.push_back('\t');
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
text.push_back(temp[i]);
|
|
|
|
}
|
|
|
|
}
|
2024-04-11 17:00:40 +08:00
|
|
|
|
|
|
|
void imgui() override {
|
|
|
|
DragBox2("", &box);
|
2024-04-11 21:19:24 +08:00
|
|
|
ig::InputText("Render Bundle", &render_bundle);
|
2024-04-11 17:00:40 +08:00
|
|
|
ig::InputTextMultiline("##Text", &text, ImVec2(-1, 0));
|
|
|
|
}
|
|
|
|
void draw(Vec2 offset, bool selected) override {
|
2024-04-11 21:19:24 +08:00
|
|
|
draw_box2(box.offset(offset), selected, IM_COL32(0, 0, 255, 255));
|
2024-04-11 17:00:40 +08:00
|
|
|
// Draw text
|
|
|
|
ImDrawList *list = ig::GetBackgroundDrawList();
|
2024-04-11 21:19:24 +08:00
|
|
|
list->AddText((box.lefttop + offset).im(), IM_COL32_WHITE, text.c_str());
|
|
|
|
list->AddText((box.lefttop + offset + Vec2(0, box.size.y)).im(), IM_COL32_WHITE, render_bundle.c_str());
|
|
|
|
}
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
box.lefttop = pos;
|
|
|
|
return this;
|
2024-04-11 17:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string text;
|
2024-04-11 21:19:24 +08:00
|
|
|
std::string render_bundle;
|
|
|
|
Box2 box;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class LevelTransition: public EntityBase {
|
|
|
|
public:
|
|
|
|
std::string type() override { return "level_transition"; }
|
|
|
|
std::string to_file() override {
|
|
|
|
snprintf(buf, sizeof(buf), "LEVEL_TRANSITION %.0lf %.0lf %.0lf %.0lf %s\n", box.lefttop.x, box.lefttop.y, box.size.x, box.size.y, next_level.c_str());
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void from_strtok() override {
|
|
|
|
double a, b, c, d;
|
|
|
|
a = TOKEN_DOUBLE;
|
|
|
|
b = TOKEN_DOUBLE;
|
|
|
|
c = TOKEN_DOUBLE;
|
|
|
|
d = TOKEN_DOUBLE;
|
|
|
|
box = Box2(a, b, c, d);
|
|
|
|
|
|
|
|
char *t = TOKEN;
|
|
|
|
if (t != NULL)
|
|
|
|
next_level = t;
|
|
|
|
else
|
|
|
|
next_level.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void imgui() override {
|
|
|
|
DragBox2("", &box);
|
|
|
|
ig::InputText("Next Level", &next_level);
|
|
|
|
}
|
|
|
|
void draw(Vec2 offset, bool selected) override {
|
|
|
|
draw_box2(box.offset(offset), selected, IM_COL32(255, 255, 0, 255));
|
|
|
|
// Draw text
|
|
|
|
ImDrawList *list = ig::GetBackgroundDrawList();
|
|
|
|
list->AddText((box.lefttop + offset).im(), IM_COL32_WHITE, next_level.c_str());
|
|
|
|
}
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
box.lefttop = pos;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2024-04-11 17:00:40 +08:00
|
|
|
Box2 box;
|
2024-04-11 21:19:24 +08:00
|
|
|
std::string next_level;
|
2024-04-11 17:00:40 +08:00
|
|
|
};
|
2024-04-15 14:18:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
class CameraFocus: public EntityBase {
|
|
|
|
public:
|
|
|
|
std::string type() override { return "camera_focus"; }
|
|
|
|
std::string to_file() override {
|
|
|
|
snprintf(buf, sizeof(buf), "CAMERA_FOCUS %.0lf %.0lf %.0lf %.0lf\n", box.lefttop.x, box.lefttop.y, box.size.x, box.size.y);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
void from_strtok() override {
|
|
|
|
double a, b, c, d;
|
|
|
|
a = TOKEN_DOUBLE;
|
|
|
|
b = TOKEN_DOUBLE;
|
|
|
|
c = TOKEN_DOUBLE;
|
|
|
|
d = TOKEN_DOUBLE;
|
|
|
|
box = Box2(a, b, c, d);
|
|
|
|
}
|
|
|
|
|
|
|
|
void imgui() override { DragBox2("", &box); }
|
|
|
|
void draw(Vec2 offset, bool selected) override { draw_box2(box.offset(offset), selected, IM_COL32(0, 255, 255, 255)); }
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
box.lefttop = pos;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Box2 box;
|
|
|
|
};
|
2024-04-16 19:34:36 +08:00
|
|
|
|
|
|
|
class FillBox: public EntityBase {
|
|
|
|
public:
|
2024-04-16 19:36:02 +08:00
|
|
|
std::string type() override { return "fill"; }
|
2024-04-16 19:34:36 +08:00
|
|
|
std::string to_file() override {
|
2024-04-16 19:36:02 +08:00
|
|
|
snprintf(buf, sizeof(buf), "FILL %.0f %.0f %.0f %.0lf %.0lf %.0lf %.0lf\n", color[0] * 255, color[1] * 255, color[2] * 255, box.lefttop.x, box.lefttop.y, box.size.x, box.size.y);
|
2024-04-16 19:34:36 +08:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
void from_strtok() override {
|
|
|
|
color[0] = TOKEN_DOUBLE / 255.0;
|
|
|
|
color[1] = TOKEN_DOUBLE / 255.0;
|
|
|
|
color[2] = TOKEN_DOUBLE / 255.0;
|
|
|
|
double a, b, c, d;
|
|
|
|
a = TOKEN_DOUBLE;
|
|
|
|
b = TOKEN_DOUBLE;
|
|
|
|
c = TOKEN_DOUBLE;
|
|
|
|
d = TOKEN_DOUBLE;
|
|
|
|
box = Box2(a, b, c, d);
|
|
|
|
}
|
|
|
|
|
|
|
|
void imgui() override {
|
|
|
|
ig::ColorEdit3("Fill", color, ImGuiColorEditFlags_PickerHueWheel);
|
|
|
|
DragBox2("", &box);
|
|
|
|
}
|
|
|
|
void draw_prev(Vec2 offset, bool selected) override {
|
|
|
|
ImDrawList *d = ig::GetBackgroundDrawList();
|
|
|
|
Box2 world = box.offset(offset);
|
|
|
|
d->AddRectFilled(world.lefttop.im(), (world.lefttop + world.size).im(), ImColor(color[0], color[1], color[2]));
|
|
|
|
}
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
box.lefttop = pos;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Box2 box;
|
|
|
|
float color[3];
|
|
|
|
};
|
2024-04-22 07:03:25 +08:00
|
|
|
|
|
|
|
class FillPoly: public EntityBase {
|
|
|
|
public:
|
|
|
|
std::string type() override { return "fillpoly"; }
|
|
|
|
std::string to_file() override {
|
|
|
|
std::string ans;
|
|
|
|
snprintf(buf, sizeof(buf), "FILLPOLY %.0f %.0f %.0f %d", color[0] * 255, color[1] * 255, color[2] * 255, (int)points.size());
|
|
|
|
ans += buf;
|
|
|
|
|
|
|
|
for (const Vec2 &p: points) {
|
|
|
|
snprintf(buf, sizeof(buf), " %.0lf %.0lf", p.x, p.y);
|
|
|
|
ans += buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
ans += "\n";
|
|
|
|
return ans;
|
|
|
|
}
|
|
|
|
void from_strtok() override {
|
|
|
|
color[0] = TOKEN_DOUBLE / 255.0;
|
|
|
|
color[1] = TOKEN_DOUBLE / 255.0;
|
|
|
|
color[2] = TOKEN_DOUBLE / 255.0;
|
|
|
|
int n = TOKEN_INT;
|
|
|
|
points.resize(n);
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
double x = TOKEN_DOUBLE;
|
|
|
|
double y = TOKEN_DOUBLE;
|
|
|
|
points[i] = Vec2(x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void imgui() override {
|
|
|
|
ig::ColorEdit3("Fill", color, ImGuiColorEditFlags_PickerHueWheel);
|
|
|
|
ig::SameLine();
|
|
|
|
if (ig::Button("Add Point")) {
|
|
|
|
if (points.empty())
|
|
|
|
points.push_back(pos0);
|
|
|
|
else
|
|
|
|
points.push_back(points.back());
|
|
|
|
}
|
|
|
|
for (int i = 0; i < points.size(); i++) {
|
|
|
|
ig::PushID(i);
|
|
|
|
DragVec2("", &points[i]);
|
|
|
|
ig::PopID();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void draw_prev(Vec2 offset, bool selected) override {
|
|
|
|
if (points.size() < 3)
|
|
|
|
return;
|
|
|
|
ImDrawList *d = ig::GetBackgroundDrawList();
|
|
|
|
static std::vector<ImVec2> screen;
|
|
|
|
screen.clear();
|
|
|
|
for (const Vec2 &p: points)
|
|
|
|
screen.push_back((p + offset).im());
|
|
|
|
d->AddConvexPolyFilled(screen.data(), screen.size(), ImColor(color[0], color[1], color[2]));
|
|
|
|
}
|
|
|
|
EntityBase *setpos(Vec2 pos) override {
|
|
|
|
pos0 = pos;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Vec2> points;
|
|
|
|
float color[3];
|
|
|
|
Vec2 pos0;
|
|
|
|
};
|