diff --git a/src/DivaGL/DivaGL.vcxproj b/src/DivaGL/DivaGL.vcxproj
index d08d388..395960d 100644
--- a/src/DivaGL/DivaGL.vcxproj
+++ b/src/DivaGL/DivaGL.vcxproj
@@ -135,8 +135,11 @@ del "$(SolutionDir)bin\$(TargetName).lib"
+
+
+
@@ -207,8 +210,11 @@ del "$(SolutionDir)bin\$(TargetName).lib"
+
+
+
diff --git a/src/DivaGL/bone_database.cpp b/src/DivaGL/bone_database.cpp
new file mode 100644
index 0000000..1ab9fc6
--- /dev/null
+++ b/src/DivaGL/bone_database.cpp
@@ -0,0 +1,9 @@
+/*
+ by korenkonder
+ GitHub/GitLab: korenkonder
+*/
+
+#include "bone_database.hpp"
+
+bone_database_skeleton* (FASTCALL* bone_database_get_skeleton_by_type)(bone_database_skeleton_type type)
+ = (bone_database_skeleton * (FASTCALL*)(bone_database_skeleton_type type))0x00000001401F10C0;
diff --git a/src/DivaGL/bone_database.hpp b/src/DivaGL/bone_database.hpp
new file mode 100644
index 0000000..8ae3e01
--- /dev/null
+++ b/src/DivaGL/bone_database.hpp
@@ -0,0 +1,69 @@
+/*
+ by korenkonder
+ GitHub/GitLab: korenkonder
+*/
+
+#pragma once
+
+#include "../KKdLib/default.hpp"
+#include "../KKdLib/vec.hpp"
+
+
+enum bone_database_skeleton_type : int32_t {
+ BONE_DATABASE_SKELETON_COMMON = 0,
+ BONE_DATABASE_SKELETON_MIKU = 1,
+ BONE_DATABASE_SKELETON_KAITO = 2,
+ BONE_DATABASE_SKELETON_LEN = 3,
+ BONE_DATABASE_SKELETON_LUKA = 4,
+ BONE_DATABASE_SKELETON_MEIKO = 5,
+ BONE_DATABASE_SKELETON_RIN = 6,
+ BONE_DATABASE_SKELETON_HAKU = 7,
+ BONE_DATABASE_SKELETON_NERU = 8,
+ BONE_DATABASE_SKELETON_SAKINE = 9,
+ BONE_DATABASE_SKELETON_TETO = 10,
+ BONE_DATABASE_SKELETON_NONE = -1,
+};
+
+enum bone_database_bone_type : uint8_t {
+ BONE_DATABASE_BONE_ROTATION = 0x00,
+ BONE_DATABASE_BONE_TYPE_1 = 0x01,
+ BONE_DATABASE_BONE_POSITION = 0x02,
+ BONE_DATABASE_BONE_POSITION_ROTATION = 0x03,
+ BONE_DATABASE_BONE_HEAD_IK_ROTATION = 0x04,
+ BONE_DATABASE_BONE_ARM_IK_ROTATION = 0x05,
+ BONE_DATABASE_BONE_LEGS_IK_ROTATION = 0x06,
+};
+
+struct bone_database_bone {
+ bone_database_bone_type type;
+ bool has_parent;
+ uint8_t parent;
+ uint8_t pole_target;
+ uint8_t mirror;
+ uint8_t flags;
+ const char* name;
+};
+
+static_assert(sizeof(bone_database_bone) == 0x10, "\"bone_database_skeleton\" struct should have a size of 0x10");
+
+struct bone_database_skeleton {
+ bone_database_bone* bones;
+ uint32_t posittion_count;
+ vec3* positions;
+ float_t* heel_height;
+ uint32_t object_bone_name_count;
+ const char** object_bone_names;
+ uint32_t motion_bone_name_count;
+ const char** motion_bone_names;
+ uint16_t* parent_indices;
+ int32_t field_48;
+ int32_t field_4C;
+ int32_t field_50;
+ int32_t field_54;
+ int32_t field_58;
+ int32_t field_5C;
+};
+
+static_assert(sizeof(bone_database_skeleton) == 0x60, "\"bone_database_skeleton\" struct should have a size of 0x60");
+
+extern bone_database_skeleton* (FASTCALL* bone_database_get_skeleton_by_type)(bone_database_skeleton_type type);
diff --git a/src/DivaGL/data_test/rob_osage_test.cpp b/src/DivaGL/data_test/rob_osage_test.cpp
new file mode 100644
index 0000000..5d98e38
--- /dev/null
+++ b/src/DivaGL/data_test/rob_osage_test.cpp
@@ -0,0 +1,2785 @@
+/*
+ by korenkonder
+ GitHub/GitLab: korenkonder
+*/
+
+#include "rob_osage_test.hpp"
+#include "../../KKdLib/io/file_stream.hpp"
+#include "../../KKdLib/io/path.hpp"
+#include "../../KKdLib/prj/algorithm.hpp"
+#include "../../KKdLib/key_val.hpp"
+#include "../Glitter/glitter.hpp"
+#include "../rob/rob.hpp"
+#include "../bone_database.hpp"
+#include "../canonical_properties.hpp"
+#include "../dw.hpp"
+#include "../render_context.hpp"
+#include "../resolution_mode.hpp"
+#include
+
+class RobOsageTestDw : public dw::Shell {
+public:
+ struct Rob {
+ dw::ListBox* list_box;
+
+ dw::Button* save_button;
+ dw::Button* load_button;
+ dw::Button* default_button;
+
+ dw::ListBox* object_list_box;
+
+ void Init(dw::Composite* parent);
+
+ static void CharaCallback(dw::Widget* data);
+ static void DefaultCallback(dw::Widget* data);
+ static void LoadCallback(dw::Widget* data);
+ static void ObjectCallback(dw::Widget* data);
+ static void SaveCallback(dw::Widget* data);
+ };
+
+ struct Flags {
+ dw::Button* line_button;
+ dw::Button* lock_button;
+ dw::Button* no_pause_button;
+ dw::Button* coli_button;
+ dw::Button* name_button;
+ dw::Button* init_button;
+
+ void Init(dw::Composite* parent);
+
+ static void ColiCallback(dw::Widget* data);
+ static void InitCallback(dw::Widget* data);
+ static void LineCallback(dw::Widget* data);
+ static void LockCallback(dw::Widget* data);
+ static void NameCallback(dw::Widget* data);
+ static void NoPauseCallback(dw::Widget* data);
+ };
+
+ struct Root {
+ class Force : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ Force(dw::Composite* parent);
+ virtual ~Force() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class Gain : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ Gain(dw::Composite* parent);
+ virtual ~Gain() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class AirRes : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ AirRes(dw::Composite* parent);
+ virtual ~AirRes() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class RootYRot : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ RootYRot(dw::Composite* parent);
+ virtual ~RootYRot() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class RootZRot : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ RootZRot(dw::Composite* parent);
+ virtual ~RootZRot() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class Fric : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ Fric(dw::Composite* parent);
+ virtual ~Fric() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class WindAfc : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ WindAfc(dw::Composite* parent);
+ virtual ~WindAfc() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class ColiType : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::ListBox* list_box;
+
+ ColiType(dw::Composite* parent);
+ virtual ~ColiType() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetItemIndex(size_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class InitYRot : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ InitYRot(dw::Composite* parent);
+ virtual ~InitYRot() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class InitZRot : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ InitZRot(dw::Composite* parent);
+ virtual ~InitZRot() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ dw::ListBox* list_box;
+
+ dw::Button* reset_button;
+ dw::Button* copy_button;
+ dw::Button* paste_button;
+
+ Force* force;
+ Gain* gain;
+ AirRes* air_res;
+ RootYRot* root_y_rot;
+ RootZRot* root_z_rot;
+ Fric* fric;
+ WindAfc* wind_afc;
+ ColiType* coli_type;
+ InitYRot* init_y_rot;
+ InitZRot* init_z_rot;
+
+ void Init(dw::Composite* parent);
+ void Update();
+
+ static void CopyCallback(dw::Widget* data);
+ static void OsageCallback(dw::Widget* data);
+ static void PasteCallback(dw::Widget* data);
+ static void ResetCallback(dw::Widget* data);
+ };
+
+ struct Node {
+ class CollisionRadius : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ CollisionRadius(dw::Composite* parent);
+ virtual ~CollisionRadius() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class Hinge : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* y_min_slider;
+ dw::Slider* y_max_slider;
+ dw::Slider* z_min_slider;
+ dw::Slider* z_max_slider;
+
+ Hinge(dw::Composite* parent);
+ virtual ~Hinge() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(const RobOsageTest::Node::Hinge& value);
+ void Update(bool value);
+
+ static void YMinCallback(dw::Widget* data);
+ static void YMaxCallback(dw::Widget* data);
+ static void ZMinCallback(dw::Widget* data);
+ static void ZMaxCallback(dw::Widget* data);
+ };
+
+ class InertialCancel : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ InertialCancel(dw::Composite* parent);
+ virtual ~InertialCancel() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ class Weight : public dw::SelectionAdapter {
+ public:
+ dw::Composite* comp;
+ dw::Button* button;
+ dw::Slider* slider;
+
+ Weight(dw::Composite* parent);
+ virtual ~Weight() override;
+
+ virtual void Callback(dw::SelectionListener::CallbackData* data) override;
+
+ void SetValue(float_t value);
+ void Update(bool value);
+
+ static void Callback(dw::Widget* data);
+ };
+
+ dw::Group* group;
+
+ CollisionRadius* coli_r;
+ Hinge* hinge;
+ InertialCancel* inertial_cancel;
+ Weight* weight;
+
+ void Init(dw::Composite* parent);
+ void Update();
+ };
+
+ struct BetweenOsageCollision {
+ dw::Button* button;
+
+ void Init(dw::Composite* parent);
+ };
+
+ struct Collision {
+ dw::Group* group;
+
+ dw::Button* reset_button;
+ dw::Button* copy_button;
+ dw::Button* paste_button;
+
+ dw::Composite* element_comp;
+
+ void Init(dw::Composite* parent);
+ void Update();
+
+ static void CopyCallback(dw::Widget* data);
+ static void ElementCallback(dw::Widget* data);
+ static void PasteCallback(dw::Widget* data);
+ static void ResetCallback(dw::Widget* data);
+ };
+
+ struct ColliElement {
+ dw::Group* group;
+
+ dw::Button* reset_button;
+ dw::Button* copy_button;
+ dw::Button* paste_button;
+ dw::Button* flip_button;
+
+ dw::ListBox* type_list_box;
+ dw::Slider* radius_slider;
+ dw::ListBox* bone0_list_box;
+ dw::Slider* bone0_x_slider;
+ dw::Slider* bone0_y_slider;
+ dw::Slider* bone0_z_slider;
+ dw::ListBox* bone1_list_box;
+ dw::Slider* bone1_x_slider;
+ dw::Slider* bone1_y_slider;
+ dw::Slider* bone1_z_slider;
+
+ void Init(dw::Composite* parent);
+ void Update();
+
+ static void BoneCallback(dw::Widget* data);
+ static void BonePosXCallback(dw::Widget* data);
+ static void BonePosYCallback(dw::Widget* data);
+ static void BonePosZCallback(dw::Widget* data);
+ static void CopyCallback(dw::Widget* data);
+ static void FlipCallback(dw::Widget* data);
+ static void PasteCallback(dw::Widget* data);
+ static void RadiusCallback(dw::Widget* data);
+ static void ResetCallback(dw::Widget* data);
+ static void TypeCallback(dw::Widget* data);
+ };
+
+ Rob rob;
+ Flags flags;
+ Root root;
+ Node node;
+ BetweenOsageCollision boc;
+ Collision collision;
+ ColliElement colli_element;
+
+ RobOsageTestDw();
+ virtual ~RobOsageTestDw() override;
+
+ virtual void Hide() override;
+};
+
+const char* collision_type_name_list[] = {
+ "END",
+ "BALL",
+ "CYLINDER",
+ "PLANE",
+ "ELLIPSE",
+ "AABB",
+};
+
+RobOsageTest* rob_osage_test;
+RobOsageTestDw* rob_osage_test_dw;
+
+extern render_context* rctx_ptr;
+
+RobOsageTest::RobOsageTest() : load(), save(), coli(), line(),
+osage_index(), collision_index(), collision_update() {
+ chara_id = -1;
+ load_chara_id = 0;
+ item_id = ITEM_NONE;
+ osage_index = -1;
+ collision_index = -1;
+}
+
+RobOsageTest::~RobOsageTest() {
+
+}
+
+bool RobOsageTest::init() {
+ if (!rob_osage_test_dw) {
+ rob_osage_test_dw = new RobOsageTestDw;
+ rob_osage_test_dw->sub_1402F38B0();
+ }
+ else
+ rob_osage_test_dw->Disp();
+ return true;
+}
+
+bool RobOsageTest::ctrl() {
+ if (load) {
+ load = false;
+
+ chara_id = load_chara_id;
+
+ objects.clear();
+ bocs.clear();
+ nodes.clear();
+ normal_refs.clear();
+
+ rob_osage_test_dw->rob.object_list_box->ClearItems();
+ rob_osage_test_dw->rob.object_list_box->SetItemIndex(-1);
+ rob_osage_test_dw->root.list_box->ClearItems();
+ rob_osage_test_dw->root.list_box->SetItemIndex(-1);
+
+ item_id = ITEM_NONE;
+ obj_info = object_info();
+ osage_index = -1;
+ collision_index = -1;
+
+ rob_chara_item_equip* rob_itm_equip = rob_chara_array_get_item_equip(get_rob_chara_smth(), chara_id);
+ if (!rob_itm_equip)
+ return false;
+
+ for (int32_t i = 0; i < ITEM_MAX; i++) {
+ rob_chara_item_equip_object* itm_eq_obj = rob_itm_equip->get_item_equip_object((::item_id)i);
+ ::obj* obj = object_info_get_object(itm_eq_obj->obj_info);
+ if (!obj || !itm_eq_obj->osage_blocks.size() && !itm_eq_obj->cloth_blocks.size())
+ continue;
+
+ objects.push_back((::item_id)i, itm_eq_obj->obj_info);
+ rob_osage_test_dw->rob.object_list_box->AddItem(object_database_get_object_name(itm_eq_obj->obj_info));
+
+ std::string buf = string_to_lower(sprintf_s_string(
+ "ext_skp_%s.txt", object_database_get_object_name(itm_eq_obj->obj_info)));
+
+ std::string path("ram/skin_param/");
+ path.append(buf);
+
+ key_val kv;
+ {
+ CanonicalProperties can_prop;
+ if (path_check_file_exists(path.c_str())) {
+ file_stream s;
+ s.open(path.c_str(), "rb");
+ if (s.check_not_null()) {
+ char* d = force_malloc(s.length);
+ s.read(d, s.length);
+ can_prop.ParseEscapeSeq((const char*)d, s.length);
+ free_def(d);
+ }
+ }
+ else {
+ path.assign("rom/skin_param/");
+ path.append(buf);
+
+ p_file_handler pfhndl;
+ pfhndl.read_file_path(path.c_str(), prj::HeapCMallocDebug);
+ pfhndl.read_now();
+ if (!pfhndl.check_not_ready())
+ can_prop.ParseEscapeSeq((const char*)pfhndl.get_data(), pfhndl.get_size());
+ }
+ itm_eq_obj->skp_load(&can_prop);
+
+ kv.parse(can_prop.data.data(), can_prop.data.size());
+ }
+
+ prj::vector_pair_alloc ex_nodes;
+ ex_nodes.reserve(itm_eq_obj->osage_blocks.size() + itm_eq_obj->cloth_blocks.size());
+
+ for (ExOsageBlock*& j : itm_eq_obj->osage_blocks) {
+ ExOsageBlock* osg = j;
+ ex_nodes.push_back({ osg->name, osg });
+ }
+
+ for (ExClothBlock*& j : itm_eq_obj->cloth_blocks) {
+ ExClothBlock* cls = j;
+ ex_nodes.push_back({ cls->name, cls });
+ }
+
+ ex_nodes.sort();
+
+ for (ExOsageBlock*& j : itm_eq_obj->osage_blocks) {
+ ExOsageBlock* osg = j;
+ if (!kv.open_scope(osg->name))
+ continue;
+
+ if (!kv.open_scope("node")) {
+ kv.close_scope();
+ continue;
+ }
+
+ nodes.push_back(osg, {});
+ prj::vector& vn = nodes.back().second;
+
+ int32_t node_length = 0;
+ kv.read("length", node_length);
+
+ for (int32_t k = 0; k < node_length; k++) {
+ if (!kv.open_scope_fmt(k))
+ continue;
+
+ vn.push_back({});
+ skin_param_osage_node& n = vn.back();
+
+ float_t coli_r = 0.0f;
+ if (kv.read("coli_r", coli_r))
+ n.coli_r = coli_r;
+
+ float_t weight = 0.0f;
+ if (kv.read("weight", weight))
+ n.weight = weight;
+
+ float_t inertial_cancel = 0.0f;
+ if (kv.read("inertial_cancel", inertial_cancel))
+ n.inertial_cancel = inertial_cancel;
+
+ n.hinge.ymin = -180.0f;
+ n.hinge.ymax = 180.0f;
+ n.hinge.zmin = -180.0f;
+ n.hinge.zmax = 180.0f;
+
+ float_t hinge_ymax = 0.0f;
+ if (kv.read("hinge_ymax", hinge_ymax))
+ n.hinge.ymax = hinge_ymax;
+
+ float_t hinge_ymin = 0.0f;
+ if (kv.read("hinge_ymin", hinge_ymin))
+ n.hinge.ymin = hinge_ymin;
+
+ float_t hinge_zmax = 0.0f;
+ if (kv.read("hinge_zmax", hinge_zmax))
+ n.hinge.zmax = hinge_zmax;
+
+ float_t hinge_zmin = 0.0f;
+ if (kv.read("hinge_zmin", hinge_zmin))
+ n.hinge.zmin = hinge_zmin;
+ kv.close_scope();
+ }
+
+ kv.close_scope();
+
+ if (!kv.open_scope("root")) {
+ kv.close_scope();
+ continue;
+ }
+
+ int32_t count;
+ if (kv.read("boc", "length", count) && count > 0) {
+ bocs.push_back(osg, {});
+ prj::vector& vb = bocs.back().second;
+
+ vb.reserve(count);
+ for (int32_t k = 0; k < count; k++) {
+ if (!kv.open_scope_fmt(k))
+ continue;
+
+ int32_t st_node = 0;
+ std::string ed_root;
+ int32_t ed_node = 0;
+ if (kv.read("st_node", st_node)
+ && st_node < node_length
+ && kv.read("ed_root", ed_root)
+ && kv.read("ed_node", ed_node)
+ && ed_node < node_length) {
+ vb.push_back({});
+ skin_param_osage_root_boc& b = vb.back();
+ b.st_node = st_node;
+ b.ed_root.assign(ed_root.data(), ed_root.size());
+ b.ed_node = ed_node;
+ }
+ kv.close_scope();
+ }
+ kv.close_scope();
+ }
+ kv.close_scope();
+
+ if (kv.read("normal_ref", "length", count)) {
+ normal_refs.push_back(osg, {});
+ prj::vector& vnr = normal_refs.back().second;
+
+ vnr.reserve(count);
+ for (int32_t k = 0; k < count; k++) {
+ if (!kv.open_scope_fmt(k))
+ continue;
+
+ std::string n;
+ if (kv.read("N", n)) {
+ std::string u;
+ std::string d;
+ std::string l;
+ std::string r;
+ kv.read("U", u);
+ kv.read("D", d);
+ kv.read("L", l);
+ kv.read("R", r);
+
+ vnr.push_back({});
+ skin_param_osage_root_normal_ref& nr = vnr.back();
+ nr.n.assign(n.data(), n.size());
+ nr.u.assign(u.data(), u.size());
+ nr.d.assign(d.data(), d.size());
+ nr.l.assign(l.data(), l.size());
+ nr.r.assign(r.data(), r.size());
+ }
+ kv.close_scope();
+ }
+ kv.close_scope();
+ }
+
+ kv.close_scope();
+ kv.close_scope();
+ }
+ }
+
+ bocs.sort();
+ nodes.sort();
+ normal_refs.sort();
+ }
+
+ if (save) {
+ save = false;
+
+ const char* flt_fmt = "%0.6f";
+
+ rob_chara_item_equip* rob_itm_equip = rob_chara_array_get_item_equip(get_rob_chara_smth(), chara_id);
+ if (!rob_itm_equip)
+ return false;
+
+ bone_database_skeleton* skeleton = bone_database_get_skeleton_by_type(BONE_DATABASE_SKELETON_COMMON);
+
+ for (int32_t i = 0; i < ITEM_MAX; i++) {
+ rob_chara_item_equip_object* itm_eq_obj = rob_itm_equip->get_item_equip_object((::item_id)i);
+ ::obj* obj = object_info_get_object(itm_eq_obj->obj_info);
+ if (!obj || !itm_eq_obj->osage_blocks.size() && !itm_eq_obj->cloth_blocks.size())
+ continue;
+
+ path_create_directory("ram/skin_param/");
+
+ std::string buf = string_to_lower(sprintf_s_string(
+ "ext_skp_%s.txt", object_database_get_object_name(itm_eq_obj->obj_info)));
+
+ prj::vector_pair_alloc ex_nodes;
+ ex_nodes.reserve(itm_eq_obj->osage_blocks.size() + itm_eq_obj->cloth_blocks.size());
+
+ for (ExOsageBlock*& i : itm_eq_obj->osage_blocks) {
+ ExOsageBlock* osg = i;
+ ex_nodes.push_back({ osg->name, osg });
+ }
+
+ for (ExClothBlock*& i : itm_eq_obj->cloth_blocks) {
+ ExClothBlock* cls = i;
+ ex_nodes.push_back({ cls->name, cls });
+ }
+
+ ex_nodes.sort();
+
+ std::string path("ram/skin_param/");
+ path.append(buf);
+
+ file_stream s;
+ s.open(path.c_str(), "wb");
+
+ key_val_out kv;
+ s.write("# This file was generated automatically. DO NOT EDIT.\n", 54);
+
+ for (auto& j : ex_nodes) {
+ kv.open_scope(j.first.c_str());
+
+ skin_param* skp = j.second->type == EX_OSAGE
+ ? ((ExOsageBlock*)j.second)->rob.skin_param_ptr
+ : ((ExClothBlock*)j.second)->rob.skin_param_ptr;
+
+ ExOsageBlock* osg = j.second->type == EX_OSAGE
+ ? (ExOsageBlock*)j.second : 0;
+
+ std::vector sort_index;
+ int32_t* sort_index_data = 0;
+
+ auto elem_node = nodes.find(osg);
+ if (elem_node != nodes.end()) {
+ prj::vector& vn = elem_node->second;
+ int32_t node_count = (int32_t)vn.size();
+
+ key_val_out::get_lexicographic_order(sort_index, node_count);
+ sort_index_data = sort_index.data();
+ kv.open_scope("node");
+ for (int32_t k = 0; k < node_count; k++) {
+ kv.open_scope_fmt(sort_index_data[k]);
+ skin_param_osage_node* node = &vn[sort_index_data[k]];
+
+ kv.write(s, "coli_r", node->coli_r, flt_fmt);
+ kv.write(s, "hinge_ymax", node->hinge.ymax, flt_fmt);
+ kv.write(s, "hinge_ymin", node->hinge.ymin, flt_fmt);
+ kv.write(s, "hinge_zmax", node->hinge.zmax, flt_fmt);
+ kv.write(s, "hinge_zmin", node->hinge.zmin, flt_fmt);
+ kv.write(s, "inertial_cancel", node->inertial_cancel, flt_fmt);
+ kv.write(s, "weight", node->weight, flt_fmt);
+
+ kv.close_scope();
+ }
+
+ kv.write(s, "length", node_count);
+ kv.close_scope();
+ }
+ else {
+ kv.open_scope("node");
+ kv.write(s, "length", 0);
+ kv.close_scope();
+ }
+
+ kv.open_scope("root");
+
+ if (skp->air_res != 1.0f)
+ kv.write(s, "air_res", skp->air_res, flt_fmt);
+
+ auto elem_boc = bocs.find(osg);
+ if (elem_boc != bocs.end()) {
+ prj::vector& vb = elem_boc->second;
+ int32_t boc_count = (int32_t)vb.size();
+
+ key_val_out::get_lexicographic_order(sort_index, boc_count);
+ sort_index_data = sort_index.data();
+ kv.open_scope("boc");
+ for (int32_t k = 0; k < boc_count; k++) {
+ kv.open_scope_fmt(sort_index_data[k]);
+ skin_param_osage_root_boc* boc = &vb[sort_index_data[k]];
+
+ kv.write(s, "ed_node", boc->ed_node);
+ kv.write(s, "ed_root", boc->ed_root.c_str());
+ kv.write(s, "st_node", boc->st_node);
+
+ kv.close_scope();
+ }
+
+ kv.write(s, "length", boc_count);
+ kv.close_scope();
+ }
+ else {
+ kv.open_scope("boc");
+ kv.write(s, "length", 0);
+ kv.close_scope();
+ }
+
+ prj::vector& vc = skp->coli;
+
+ int32_t coli_count = 0;
+ for (SkinParam::CollisionParam& k : vc)
+ if (k.type)
+ coli_count++;
+ else
+ break;
+
+ kv.open_scope("coli");
+
+ key_val_out::get_lexicographic_order(sort_index, coli_count);
+ sort_index_data = sort_index.data();
+ for (int32_t k = 0; k < coli_count; k++) {
+ kv.open_scope_fmt(sort_index_data[k]);
+ SkinParam::CollisionParam* cls_param = &vc[sort_index_data[k]];
+
+ kv.write(s, "bone.0.name", skeleton->object_bone_names[cls_param->node_idx[0]]);
+ kv.write(s, "bone.0.posx", cls_param->pos[0].x, flt_fmt);
+ kv.write(s, "bone.0.posy", cls_param->pos[0].y, flt_fmt);
+ kv.write(s, "bone.0.posz", cls_param->pos[0].z, flt_fmt);
+
+ switch (cls_param->type) {
+ case SkinParam::CollisionTypeCapsule:
+ case SkinParam::CollisionTypePlane:
+ case SkinParam::CollisionTypeEllipse:
+ kv.write(s, "bone.1.name", skeleton->object_bone_names[cls_param->node_idx[1]]);
+ kv.write(s, "bone.1.posx", cls_param->pos[1].x, flt_fmt);
+ kv.write(s, "bone.1.posy", cls_param->pos[1].y, flt_fmt);
+ kv.write(s, "bone.1.posz", cls_param->pos[1].z, flt_fmt);
+ break;
+ }
+
+ kv.write(s, "radius", cls_param->radius, flt_fmt);
+ kv.write(s, "type", cls_param->type);
+
+ kv.close_scope();
+ }
+
+ kv.write(s, "length", coli_count);
+ kv.close_scope();
+
+ if (skp->coli_r != 0.0f)
+ kv.write(s, "coli_r", skp->coli_r, flt_fmt);
+
+ kv.write(s, "coli_type", skp->coli_type);
+
+ if (skp->colli_tgt_osg)
+ for (ExOsageBlock*& k : itm_eq_obj->osage_blocks)
+ if (skp->colli_tgt_osg == &k->rob.nodes) {
+ kv.write(s, "colli_tgt_osg", k->name);
+ break;
+ }
+
+ kv.write(s, "force", skp->force, flt_fmt);
+ kv.write(s, "force_gain", skp->force_gain, flt_fmt);
+ kv.write(s, "friction", skp->friction, flt_fmt);
+
+ if (fabsf(skp->hinge.ymax * RAD_TO_DEG_FLOAT - 90.0f) > 0.0001f
+ || fabsf(skp->hinge.zmax * RAD_TO_DEG_FLOAT - 90.0f) > 0.0001f) {
+ kv.write(s, "hinge_y", skp->hinge.ymax, flt_fmt);
+ kv.write(s, "hinge_z", skp->hinge.zmax, flt_fmt);
+ }
+
+ kv.write(s, "init_rot_y", skp->init_rot.y * RAD_TO_DEG_FLOAT, flt_fmt);
+ kv.write(s, "init_rot_z", skp->init_rot.z * RAD_TO_DEG_FLOAT, flt_fmt);
+
+ auto elem_normal_ref = normal_refs.find(osg);
+ if (elem_normal_ref != normal_refs.end()) {
+ prj::vector& vnr = elem_normal_ref->second;
+ int32_t normal_ref_count = (int32_t)vnr.size();
+
+ key_val_out::get_lexicographic_order(sort_index, normal_ref_count);
+ sort_index_data = sort_index.data();
+ kv.open_scope("normal_ref");
+ for (int32_t k = 0; k < normal_ref_count; k++) {
+ kv.open_scope_fmt(sort_index_data[k]);
+ skin_param_osage_root_normal_ref* normal_ref = &vnr[sort_index_data[k]];
+
+ if (normal_ref->d.size())
+ kv.write(s, "D", normal_ref->d.c_str());
+
+ if (normal_ref->l.size())
+ kv.write(s, "L", normal_ref->l.c_str());
+
+ kv.write(s, "N", normal_ref->n.c_str());
+
+ if (normal_ref->r.size())
+ kv.write(s, "R", normal_ref->r.c_str());
+
+ if (normal_ref->u.size())
+ kv.write(s, "U", normal_ref->u.c_str());
+
+ kv.close_scope();
+ }
+
+ kv.write(s, "length", normal_ref_count);
+ kv.close_scope();
+ }
+
+ if (skp->move_cancel != -0.01f)
+ kv.write(s, "move_cancel", skp->move_cancel, flt_fmt);
+
+ kv.write(s, "rot_y", skp->rot.y * RAD_TO_DEG_FLOAT, flt_fmt);
+ kv.write(s, "rot_z", skp->rot.z * RAD_TO_DEG_FLOAT, flt_fmt);
+
+ if (skp->stiffness != 0.0f)
+ kv.write(s, "stiffness", skp->stiffness, flt_fmt);
+
+ kv.write(s, "wind_afc", skp->wind_afc, flt_fmt);
+
+ kv.close_scope();
+
+ kv.close_scope();
+ }
+
+ s.close();
+ }
+ }
+
+ return false;
+}
+
+bool RobOsageTest::dest() {
+ rob_osage_test_dw->SetDisp();
+ return true;
+}
+
+void RobOsageTest::disp() {
+ if (chara_id < 0 || chara_id >= ROB_CHARA_COUNT)
+ return;
+
+ rob_chara* rob_chr = rob_chara_array_get(get_rob_chara_smth(), chara_id);
+ if (rob_chr && !pv_osage_manager_array_get_disp(&chara_id)
+ && rob_chr->is_visible() && !(rob_chr->data.field_3 & 0x80)) {
+ disp_coli();
+ disp_line();
+ }
+}
+
+void RobOsageTest::basic() {
+ if (collision_update) {
+ collision_update = false;
+
+ rob_osage_test_dw->collision.Update();
+ rob_osage_test_dw->colli_element.Update();
+ rob_osage_test_dw->UpdateLayout();
+ }
+
+ rob_chara_item_equip_object* itm_eq_obj = get_item_equip_object();
+ if (!itm_eq_obj)
+ return;
+
+ ExOsageBlock* osg = get_osage_block(itm_eq_obj);
+ if (osg) {
+ osg->rob.SetForce(root.force, root.gain);
+ osg->rob.SetAirRes(root.air_res);
+ osg->rob.SetRot(root.root_y_rot, root.root_z_rot);
+ osg->rob.skin_param_ptr->friction = root.fric;
+ osg->rob.skin_param_ptr->wind_afc = root.wind_afc;
+ osg->rob.skin_param_ptr->coli_type = root.coli_type;
+ osg->rob.SetInitRot(root.init_y_rot, root.init_z_rot);
+ }
+
+ ExClothBlock* cls = get_cloth_block(itm_eq_obj);
+ if (cls) {
+ skin_param* skp = cls->rob.skin_param_ptr;
+ skp->force = root.force;
+ skp->force_gain = root.gain;
+ skp->air_res = root.air_res;
+ skp->rot.y = root.root_y_rot * DEG_TO_RAD_FLOAT;
+ skp->rot.z = root.root_z_rot * DEG_TO_RAD_FLOAT;
+ skp->friction = root.fric;
+ skp->wind_afc = root.wind_afc;
+ skp->coli_type = root.coli_type;
+ skp->init_rot.y = root.init_y_rot * DEG_TO_RAD_FLOAT;
+ skp->init_rot.z = root.init_z_rot * DEG_TO_RAD_FLOAT;
+ }
+}
+
+void RobOsageTest::disp_coli() {
+ if (!coli)
+ return;
+
+ rob_chara_item_equip_object* itm_eq_obj = get_item_equip_object();
+ if (!itm_eq_obj)
+ return;
+
+ prj::vector* cls_list = 0;
+ mat4* transform = 0;
+
+ ExOsageBlock* osg = get_osage_block(itm_eq_obj);
+ ExClothBlock* cls = 0;
+ if (osg) {
+ cls_list = get_cls_list(osg);
+ transform = osg->mats;
+ }
+ else {
+ cls = get_cloth_block(itm_eq_obj);
+ if (cls) {
+ cls_list = get_cls_list(cls);
+ transform = cls->mats;
+ }
+ }
+
+ if (!cls_list || !transform)
+ return;
+
+ static const color4u8 selected_color = 0xCF00EF00;
+ static const color4u8 cls_node_color = 0xCFEFEF00;
+ static const color4u8 osg_node_color = 0xCFEFEF00;
+ static const color4u8 default_color = 0xCFFFFFFF;
+
+ SkinParam::CollisionParam* cls_param = get_cls_param(cls_list);
+ for (const SkinParam::CollisionParam& i : *cls_list)
+ switch (i.type) {
+ case SkinParam::CollisionTypeBall: {
+ mdl::EtcObj etc(mdl::ETC_OBJ_SPHERE);
+ etc.color = cls_param && &i == cls_param ? selected_color : default_color;
+ etc.constant = true;
+
+ etc.data.sphere.radius = i.radius;
+ etc.data.sphere.slices = 16;
+ etc.data.sphere.stacks = 16;
+ etc.data.sphere.wire = false;
+
+ vec3 pos;
+ mat4 mat;
+ mat4_transpose(&transform[i.node_idx[0]], &mat);
+ mat4_transform_point(&mat, &i.pos[0], &pos);
+
+ mat4_translate(&pos, &mat);
+ mat4_transpose(&mat, &mat);
+ disp_manager->entry_obj_etc(&mat, &etc);
+ } break;
+ case SkinParam::CollisionTypeCapsule: {
+ mdl::EtcObj etc(mdl::ETC_OBJ_CAPSULE);
+ etc.color = cls_param && &i == cls_param ? selected_color : default_color;
+ etc.constant = true;
+
+ etc.data.capsule.radius = i.radius;
+ etc.data.capsule.slices = 16;
+ etc.data.capsule.stacks = 16;
+ etc.data.capsule.wire = false;
+
+ mat4 mat;
+ mat4_transpose(&transform[i.node_idx[0]], &mat);
+ mat4_transform_point(&mat, &i.pos[0], &etc.data.capsule.pos[0]);
+ mat4_transpose(&transform[i.node_idx[1]], &mat);
+ mat4_transform_point(&mat, &i.pos[1], &etc.data.capsule.pos[1]);
+ disp_manager->entry_obj_etc(&mat4_identity, &etc);
+ } break;
+ case SkinParam::CollisionTypePlane: {
+ mdl::EtcObj etc(mdl::ETC_OBJ_PLANE);
+ etc.color = cls_param && &i == cls_param ? selected_color : default_color;
+ etc.constant = true;
+
+ etc.data.plane.w = 2;
+ etc.data.plane.h = 2;
+
+ vec3 pos;
+ mat4 mat;
+ mat4_transpose(&transform[i.node_idx[0]], &mat);
+ mat4_transform_point(&mat, &i.pos[0], &pos);
+
+ vec3 dir = vec3::normalize(i.pos[1]);
+ vec3 up = { 0.0f, 1.0f, 0.0f };
+ vec3 axis;
+ float_t angle;
+ Glitter::axis_angle_from_vectors(&axis, &angle, &up, &dir);
+
+ mat4 mat_rot = mat4_identity;
+ mat4_mul_rotation(&mat_rot, &axis, angle, &mat_rot);
+
+ mat4_translate(&pos, &mat);
+ mat4_mul(&mat_rot, &mat, &mat);
+ mat4_scale_rot(&mat, i.radius, &mat);
+ mat4_transpose(&mat, &mat);
+ disp_manager->entry_obj_etc(&mat, &etc);
+ } break;
+ case SkinParam::CollisionTypeEllipse: {
+ mdl::EtcObj etc(mdl::ETC_OBJ_SPHERE);
+ etc.color = cls_param && &i == cls_param ? selected_color : default_color;
+ etc.constant = true;
+
+ etc.data.sphere.radius = 1.0f;
+ etc.data.sphere.slices = 16;
+ etc.data.sphere.stacks = 16;
+ etc.data.sphere.wire = false;
+
+ vec3 pos[2];
+ mat4 mat;
+ mat4_transpose(&transform[i.node_idx[0]], &mat);
+ mat4_transform_point(&mat, &i.pos[0], &pos[0]);
+ mat4_transpose(&transform[i.node_idx[1]], &mat);
+ mat4_transform_point(&mat, &i.pos[1], &pos[1]);
+
+ vec3 origin = (pos[0] + pos[1]) * 0.5f;
+ mat4_translate(&origin, &mat);
+
+ vec3 dir = vec3::normalize(pos[1] - pos[0]);
+ vec3 up = { 0.0f, 1.0f, 0.0f };
+ vec3 axis;
+ float_t angle;
+ Glitter::axis_angle_from_vectors(&axis, &angle, &up, &dir);
+
+ mat4 m = mat4_identity;
+ mat4_mul_rotation(&m, &axis, angle, &m);
+ mat4_mul(&m, &mat, &mat);
+
+ const float_t length = vec3::length((pos[0] - pos[1]) * 0.5f);
+ const float_t scale_y = sqrtf(i.radius * i.radius + length * length);
+
+ mat4_scale_rot(&mat, i.radius, scale_y, i.radius, &mat);
+ mat4_transpose(&mat, &mat);
+ disp_manager->entry_obj_etc(&mat, &etc);
+ } break;
+ case SkinParam::CollisionTypeAABB: {
+ mdl::EtcObj etc(mdl::ETC_OBJ_CUBE);
+ etc.color = cls_param && &i == cls_param ? selected_color : default_color;
+ etc.constant = true;
+
+ vec3 pos;
+ mat4 mat;
+ mat4_transpose(&transform[i.node_idx[0]], &mat);
+ mat4_transform_point(&mat, &i.pos[0], &pos);
+
+ etc.data.cube.size = i.radius;
+ etc.data.cube.wire = false;
+
+ mat4_translate(&pos, &mat);
+ mat4_transpose(&mat, &mat);
+ disp_manager->entry_obj_etc(&mat, &etc);
+ } break;
+ }
+
+ if (osg && osg->rob.nodes.size() > 1) {
+ RobOsageNode* i_begin = osg->rob.nodes.data() + 1;
+ RobOsageNode* i_end = osg->rob.nodes.data() + osg->rob.nodes.size();
+ for (RobOsageNode* i = i_begin; i != i_end; i++) {
+ mdl::EtcObj etc(mdl::ETC_OBJ_CAPSULE);
+ etc.color = osg_node_color;
+ etc.constant = true;
+
+ etc.data.capsule.radius = i->data_ptr->skp_osg_node.coli_r;
+ etc.data.capsule.slices = 16;
+ etc.data.capsule.stacks = 16;
+ etc.data.capsule.wire = false;
+ etc.data.capsule.pos[0] = i[-1].trans;
+ etc.data.capsule.pos[1] = i[ 0].trans;
+ disp_manager->entry_obj_etc(&mat4_identity, &etc);
+ }
+ }
+
+ if (cls && cls->rob.nodes.size() > 1) {
+ CLOTHNode* i_begin = cls->rob.nodes.data() + cls->rob.root_count;
+ CLOTHNode* i_end = cls->rob.nodes.data() + cls->rob.nodes.size();
+ for (CLOTHNode* i = i_begin; i != i_end; i++) {
+ mdl::EtcObj etc(mdl::ETC_OBJ_SPHERE);
+ etc.color = cls_node_color;
+ etc.constant = true;
+
+ etc.data.sphere.radius = max_def(cls->rob.skin_param_ptr->coli_r, 0.005f);
+ etc.data.sphere.slices = 16;
+ etc.data.sphere.stacks = 16;
+ etc.data.sphere.wire = false;
+
+ vec3 pos;
+ mat4 mat;
+ mat4_transpose(&itm_eq_obj->item_equip->mat, &mat);
+ mat4_transform_point(&mat, &i->trans, &pos);
+
+ mat4_translate(&pos, &mat);
+ mat4_transpose(&mat, &mat);
+ disp_manager->entry_obj_etc(&mat, &etc);
+ }
+ }
+}
+
+void RobOsageTest::disp_line() {
+ if (!line)
+ return;
+
+}
+
+inline ExClothBlock* RobOsageTest::get_cloth_block(rob_chara_item_equip_object* itm_eq_obj) const {
+ if (itm_eq_obj && itm_eq_obj->obj_info == obj_info && osage_index >= itm_eq_obj->osage_blocks.size()
+ && osage_index - itm_eq_obj->osage_blocks.size() < itm_eq_obj->cloth_blocks.size())
+ return itm_eq_obj->cloth_blocks[osage_index - itm_eq_obj->osage_blocks.size()];
+ return 0;
+}
+
+inline rob_chara_item_equip_object* RobOsageTest::get_item_equip_object() const {
+ if (chara_id < 0 || chara_id >= ROB_CHARA_COUNT)
+ return 0;
+
+ rob_chara_item_equip* rob_itm_equip = rob_chara_array_get_item_equip(get_rob_chara_smth(), chara_id);
+ if (rob_itm_equip && item_id >= ITEM_BODY && item_id < ITEM_MAX)
+ return rob_itm_equip->get_item_equip_object(item_id);
+ return 0;
+}
+
+inline ExOsageBlock* RobOsageTest::get_osage_block(rob_chara_item_equip_object* itm_eq_obj) const {
+ if (itm_eq_obj && itm_eq_obj->obj_info == obj_info && osage_index < itm_eq_obj->osage_blocks.size())
+ return itm_eq_obj->osage_blocks[osage_index];
+ return 0;
+}
+
+inline prj::vector* RobOsageTest::get_cls_list(ExClothBlock* cls) const {
+ if (cls)
+ return &cls->rob.skin_param_ptr->coli;
+ return 0;
+}
+
+inline prj::vector* RobOsageTest::get_cls_list(ExOsageBlock* osg) const {
+ if (osg)
+ return &osg->rob.skin_param_ptr->coli;
+ return 0;
+}
+
+inline SkinParam::CollisionParam* RobOsageTest::get_cls_param(
+ prj::vector* cls_list) const {
+ if (cls_list && collision_index < cls_list->size())
+ return &cls_list->data()[collision_index];
+ return 0;
+}
+
+void RobOsageTest::set_root(skin_param* skp) {
+ if (!skp)
+ return;
+
+ root.force = skp->force;
+ root.gain = skp->force_gain;
+ root.air_res = skp->air_res;
+ root.root_y_rot = skp->rot.y;
+ root.root_z_rot = skp->rot.z;
+ root.fric = skp->friction;
+ root.wind_afc = skp->wind_afc;
+ root.coli_type = skp->coli_type;
+ root.init_y_rot = skp->init_rot.y;
+ root.init_z_rot = skp->init_rot.z;
+}
+
+HOOK(bool, FASTCALL, SubGameState__DataTestMot__Dest, 0x00000001402871F0) {
+ rob_osage_test->del();
+ return originalSubGameState__DataTestMot__Dest();
+}
+
+HOOK(bool, FASTCALL, SubGameState__DataTestMot__Init, 0x00000001402876B0) {
+ app::TaskWork::add_task(rob_osage_test, "ROB_OSAGE_TEST");
+ return originalSubGameState__DataTestMot__Init();
+}
+
+void rob_osage_test_init() {
+ if (!rob_osage_test)
+ rob_osage_test = new RobOsageTest;
+
+ INSTALL_HOOK(SubGameState__DataTestMot__Dest);
+ INSTALL_HOOK(SubGameState__DataTestMot__Init);
+}
+
+void rob_osage_test_free() {
+ if (rob_osage_test) {
+ delete rob_osage_test;
+ rob_osage_test = 0;
+ }
+}
+
+void RobOsageTestDw::Rob::Init(dw::Composite* parent) {
+ dw::Composite* comp = new dw::Composite(parent);
+
+ dw::Composite* ribbon_comp = new dw::Composite(comp);
+ ribbon_comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ list_box = new dw::ListBox(ribbon_comp);
+ list_box->AddItem("1P");
+ list_box->AddItem("2P");
+ list_box->AddItem("3P");
+ list_box->AddItem("4P");
+ list_box->AddItem("5P");
+ list_box->AddItem("6P");
+ list_box->SetItemIndex(0);
+ list_box->AddSelectionListener(new dw::SelectionListenerOnHook(RobOsageTestDw::Rob::CharaCallback));
+
+ save_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ save_button->SetText(" SAVE ");
+ save_button->callback = RobOsageTestDw::Rob::SaveCallback;
+
+ load_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ load_button->SetText(" LOAD ");
+ load_button->callback = RobOsageTestDw::Rob::LoadCallback;
+
+ default_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ default_button->SetText("DEFAULT");
+ default_button->callback = RobOsageTestDw::Rob::DefaultCallback;
+
+ object_list_box = new dw::ListBox(comp);
+ object_list_box->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Rob::ObjectCallback));
+}
+
+void RobOsageTestDw::Rob::CharaCallback(dw::Widget* data) {
+ dw::ListBox* list_box = dynamic_cast(data);
+ if (list_box)
+ rob_osage_test->load_chara_id = (int32_t)list_box->list->selected_item;
+}
+
+void RobOsageTestDw::Rob::DefaultCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ rob_osage_test->chara_id = -1;
+ rob_osage_test->load_chara_id = 0;
+ rob_osage_test->item_id = ITEM_NONE;
+ rob_osage_test->obj_info = object_info();
+ rob_osage_test->osage_index = -1;
+ rob_osage_test->collision_index = -1;
+ rob_osage_test->collision_update = true;
+
+ rob_osage_test->root = {};
+ rob_osage_test->node = {};
+
+ rob_osage_test_dw->root.Update();
+ rob_osage_test_dw->node.Update();
+ rob_osage_test_dw->colli_element.Update();
+ }
+}
+
+void RobOsageTestDw::Rob::LoadCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button)
+ rob_osage_test->load = true;
+}
+
+void RobOsageTestDw::Rob::ObjectCallback(dw::Widget* data) {
+ dw::ListBox* list_box = dynamic_cast(data);
+ if (list_box && list_box->list->selected_item < rob_osage_test->objects.size()) {
+ auto elem = rob_osage_test->objects.data()[list_box->list->selected_item];
+ rob_osage_test->item_id = elem.first;
+ rob_osage_test->obj_info = elem.second;
+ rob_osage_test->osage_index = -1;
+ rob_osage_test->collision_index = -1;
+ rob_osage_test->set_root();
+
+ rob_osage_test_dw->root.list_box->ClearItems();
+
+ rob_chara_item_equip_object* itm_eq_obj = rob_osage_test->get_item_equip_object();
+ if (itm_eq_obj) {
+ for (ExOsageBlock*& i : itm_eq_obj->osage_blocks)
+ rob_osage_test_dw->root.list_box->AddItem(i->name);
+
+ for (ExClothBlock*& i : itm_eq_obj->cloth_blocks)
+ rob_osage_test_dw->root.list_box->AddItem(i->name);
+ }
+ }
+}
+
+void RobOsageTestDw::Rob::SaveCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button)
+ rob_osage_test->save = true;
+}
+
+void RobOsageTestDw::Flags::Init(dw::Composite* parent) {
+ dw::Composite* comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::GridLayout(3));
+
+ line_button = new dw::Button(comp, dw::CHECKBOX);
+ line_button->SetText("Line ");
+ line_button->SetValue(rob_osage_test->line);
+ line_button->callback = RobOsageTestDw::Flags::LineCallback;
+
+ lock_button = new dw::Button(comp, dw::CHECKBOX);
+ lock_button->SetText("Lock ");
+ lock_button->callback = RobOsageTestDw::Flags::LockCallback;
+
+ no_pause_button = new dw::Button(comp, dw::CHECKBOX);
+ no_pause_button->SetText("NoPause");
+ no_pause_button->callback = RobOsageTestDw::Flags::NoPauseCallback;
+
+ coli_button = new dw::Button(comp, dw::CHECKBOX);
+ coli_button->SetText("Coli ");
+ coli_button->SetValue(rob_osage_test->coli);
+ coli_button->callback = RobOsageTestDw::Flags::ColiCallback;
+
+ name_button = new dw::Button(comp, dw::CHECKBOX);
+ name_button->SetText("Name ");
+ name_button->callback = RobOsageTestDw::Flags::NameCallback;
+
+ init_button = new dw::Button(comp, dw::CHECKBOX);
+ init_button->SetText("Init ");
+ init_button->callback = RobOsageTestDw::Flags::InitCallback;
+}
+
+void RobOsageTestDw::Flags::ColiCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button)
+ rob_osage_test->coli = button->value;
+}
+
+void RobOsageTestDw::Flags::InitCallback(dw::Widget* data) {
+
+}
+
+void RobOsageTestDw::Flags::LineCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button)
+ rob_osage_test->line = button->value;
+}
+
+void RobOsageTestDw::Flags::LockCallback(dw::Widget* data) {
+
+}
+
+void RobOsageTestDw::Flags::NameCallback(dw::Widget* data) {
+
+}
+
+void RobOsageTestDw::Flags::NoPauseCallback(dw::Widget* data) {
+
+}
+
+RobOsageTestDw::Root::Force::Force(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("force ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::Force::~Force() {
+
+}
+
+void RobOsageTestDw::Root::Force::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::Force::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::Force::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 2.3f";
+ slider->SetParams(rob_osage_test->root.force, 0.0f, 0.1f, 0.01f, 0.001f, 0.01f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::Force::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::Force::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.force = slider->scroll_bar->value;
+}
+
+RobOsageTestDw::Root::Gain::Gain(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("gain ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::Gain::~Gain() {
+
+}
+
+void RobOsageTestDw::Root::Gain::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::Gain::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::Gain::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 2.3f";
+ slider->SetParams(rob_osage_test->root.gain, 0.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::Gain::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::Gain::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.gain = slider->scroll_bar->value;
+}
+
+RobOsageTestDw::Root::AirRes::AirRes(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("air res ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::AirRes::~AirRes() {
+
+}
+
+void RobOsageTestDw::Root::AirRes::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::AirRes::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::AirRes::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 2.3f";
+ slider->SetParams(rob_osage_test->root.air_res, 0.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::AirRes::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::AirRes::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.air_res = slider->scroll_bar->value;
+}
+
+RobOsageTestDw::Root::RootYRot::RootYRot(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("rootYrot ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::RootYRot::~RootYRot() {
+
+}
+
+void RobOsageTestDw::Root::RootYRot::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::RootYRot::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::RootYRot::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 6.0f";
+ slider->SetParams(rob_osage_test->root.root_y_rot,
+ -180.0f, 180.0f, 90.0f, 1.0f, 10.0f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::RootYRot::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::RootYRot::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.root_y_rot = slider->scroll_bar->value;
+}
+
+RobOsageTestDw::Root::RootZRot::RootZRot(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("rootZrot ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::RootZRot::~RootZRot() {
+
+}
+
+void RobOsageTestDw::Root::RootZRot::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::RootZRot::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::RootZRot::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 6.0f";
+ slider->SetParams(rob_osage_test->root.root_z_rot,
+ -180.0f, 180.0f, 90.0f, 1.0f, 10.0f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::RootZRot::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::RootZRot::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.root_z_rot = slider->scroll_bar->value;
+}
+
+RobOsageTestDw::Root::Fric::Fric(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("fric ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::Fric::~Fric() {
+
+}
+
+void RobOsageTestDw::Root::Fric::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::Fric::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::Fric::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 2.3f";
+ slider->SetParams(rob_osage_test->root.fric, 0.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::Fric::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::Fric::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.fric = slider->scroll_bar->value;
+}
+
+RobOsageTestDw::Root::WindAfc::WindAfc(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("windAfc ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::WindAfc::~WindAfc() {
+
+}
+
+void RobOsageTestDw::Root::WindAfc::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::WindAfc::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::WindAfc::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 2.3f";
+ slider->SetParams(rob_osage_test->root.wind_afc, 0.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::WindAfc::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::WindAfc::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.wind_afc = slider->scroll_bar->value;
+}
+
+RobOsageTestDw::Root::ColiType::ColiType(dw::Composite* parent) : list_box() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::ColiType::~ColiType() {
+
+}
+
+void RobOsageTestDw::Root::ColiType::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::ColiType::SetItemIndex(size_t value) {
+ if (list_box)
+ list_box->SetItemIndex(value);
+}
+
+void RobOsageTestDw::Root::ColiType::Update(bool value) {
+ if (value) {
+ if (list_box)
+ return;
+
+ list_box = new dw::ListBox(comp, dw::MULTISELECT);
+ list_box->AddItem("coli_type: End");
+ list_box->AddItem("coli_type: Ball");
+ list_box->AddItem("coli_type: Capsule(+root)");
+ list_box->SetItemIndex(rob_osage_test->root.coli_type);
+ list_box->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::ColiType::Callback));
+ }
+ else {
+ if (!list_box)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(list_box));
+ list_box->Reset();
+ list_box = 0;
+ }
+}
+
+void RobOsageTestDw::Root::ColiType::Callback(dw::Widget* data) {
+ dw::ListBox* list_box = dynamic_cast(data);
+ if (list_box)
+ rob_osage_test->root.coli_type = (SkinParam::RootCollisionType)(int32_t)list_box->list->selected_item;
+}
+
+RobOsageTestDw::Root::InitYRot::InitYRot(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("initYrot ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::InitYRot::~InitYRot() {
+
+}
+
+void RobOsageTestDw::Root::InitYRot::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::InitYRot::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::InitYRot::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 6.0f";
+ slider->SetParams(rob_osage_test->root.init_y_rot,
+ -180.0f, 180.0f, 90.0f, 1.0f, 10.0f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::InitYRot::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::InitYRot::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.init_y_rot = slider->scroll_bar->value;
+}
+
+RobOsageTestDw::Root::InitZRot::InitZRot(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("initZrot ");
+ button->SetValue(true);
+ button->AddSelectionListener(this);
+
+ Update(true);
+}
+
+RobOsageTestDw::Root::InitZRot::~InitZRot() {
+
+}
+
+void RobOsageTestDw::Root::InitZRot::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Root::InitZRot::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Root::InitZRot::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 6.0f";
+ slider->SetParams(rob_osage_test->root.init_z_rot,
+ -180.0f, 180.0f, 90.0f, 1.0f, 10.0f);
+ slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Root::InitZRot::Callback));
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Root::InitZRot::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider)
+ rob_osage_test->root.init_z_rot = slider->scroll_bar->value;
+}
+
+void RobOsageTestDw::Root::Init(dw::Composite* parent) {
+ dw::Composite* comp = new dw::Composite(parent);
+
+ list_box = new dw::ListBox(comp);
+ list_box->AddSelectionListener(new dw::SelectionListenerOnHook(RobOsageTestDw::Root::OsageCallback));
+
+ dw::Composite* ribbon_comp = new dw::Composite(comp);
+ ribbon_comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ reset_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ reset_button->SetText(" RESET ");
+ reset_button->callback = RobOsageTestDw::Root::ResetCallback;
+
+ copy_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ copy_button->SetText(" COPY ");
+ copy_button->callback = RobOsageTestDw::Root::CopyCallback;
+
+ paste_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ paste_button->SetText(" PASTE ");
+ paste_button->callback = RobOsageTestDw::Root::PasteCallback;
+
+ force = new Force(comp);
+ gain = new Gain(comp);
+ air_res = new AirRes(comp);
+ root_y_rot = new RootYRot(comp);
+ root_z_rot = new RootZRot(comp);
+ fric = new Fric(comp);
+ wind_afc = new WindAfc(comp);
+ coli_type = new ColiType(comp);
+ init_y_rot = new InitYRot(comp);
+ init_z_rot = new InitZRot(comp);
+}
+
+void RobOsageTestDw::Root::Update() {
+ const RobOsageTest::Root& root = rob_osage_test->root;
+
+ force->SetValue(root.force);
+ gain->SetValue(root.gain);
+ air_res->SetValue(root.air_res);
+ root_y_rot->SetValue(root.root_y_rot);
+ root_z_rot->SetValue(root.root_z_rot);
+ fric->SetValue(root.fric);
+ wind_afc->SetValue(root.wind_afc);
+ coli_type->SetItemIndex(root.coli_type);
+ init_y_rot->SetValue(root.init_y_rot);
+ init_z_rot->SetValue(root.init_z_rot);
+}
+
+void RobOsageTestDw::Root::CopyCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ rob_osage_test->root_temp = rob_osage_test->root;
+ rob_osage_test->node_temp = rob_osage_test->node;
+ }
+}
+
+void RobOsageTestDw::Root::OsageCallback(dw::Widget* data) {
+ dw::ListBox* list_box = dynamic_cast(data);
+ if (list_box) {
+ rob_osage_test->osage_index = list_box->list->selected_item;
+ rob_osage_test->collision_index = -1;
+ rob_osage_test->collision_update = true;
+
+ rob_osage_test->set_root();
+ rob_osage_test_dw->root.Update();
+ rob_osage_test_dw->node.Update();
+ }
+}
+
+void RobOsageTestDw::Root::PasteCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ rob_osage_test->root = rob_osage_test->root_temp;
+ rob_osage_test->node = rob_osage_test->node_temp;
+
+ rob_osage_test_dw->root.Update();
+ }
+}
+
+void RobOsageTestDw::Root::ResetCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ rob_osage_test->root = {};
+ rob_osage_test->node = {};
+
+ rob_osage_test_dw->root.Update();
+ rob_osage_test_dw->node.Update();
+ }
+}
+
+RobOsageTestDw::Node::CollisionRadius::CollisionRadius(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("coli_r ");
+ button->AddSelectionListener(this);
+
+ Update(false);
+}
+
+RobOsageTestDw::Node::CollisionRadius::~CollisionRadius() {
+
+}
+
+void RobOsageTestDw::Node::CollisionRadius::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Node::CollisionRadius::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Node::CollisionRadius::Update(bool value) {
+ if (value) {
+ if (slider)
+ return;
+
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 2.3f";
+ slider->SetParams(rob_osage_test->node.coli_r, 0.0f, 2.0f, 0.01f, 0.001f, 0.01f);
+ }
+ else {
+ if (!slider)
+ return;
+
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Node::CollisionRadius::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+
+ }
+}
+
+RobOsageTestDw::Node::Hinge::Hinge(dw::Composite* parent)
+ : y_min_slider(), y_max_slider(), z_min_slider(), z_max_slider() {
+ comp = new dw::Composite(parent);
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("hinge ");
+ button->AddSelectionListener(this);
+
+ Update(false);
+}
+
+RobOsageTestDw::Node::Hinge::~Hinge() {
+
+}
+
+void RobOsageTestDw::Node::Hinge::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Node::Hinge::SetValue(const RobOsageTest::Node::Hinge& value) {
+ if (y_min_slider)
+ y_min_slider->SetValue(value.ymin);
+
+ if (y_max_slider)
+ y_max_slider->SetValue(value.ymax);
+
+ if (z_min_slider)
+ z_min_slider->SetValue(value.zmin);
+
+ if (z_max_slider)
+ z_max_slider->SetValue(value.zmax);
+}
+
+void RobOsageTestDw::Node::Hinge::Update(bool value) {
+ if (value) {
+ y_min_slider = dw::Slider::Create(comp);
+ y_min_slider->SetText(" Ymin ");
+ y_min_slider->format = "% 6.0f";
+ y_min_slider->SetParams(rob_osage_test->node.hinge.ymin, -179.0f, 0.0f, 89.5f, 0.5f, 5.0f);
+ y_min_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Node::Hinge::YMinCallback));
+
+ y_max_slider = dw::Slider::Create(comp);
+ y_max_slider->SetText(" Ymax ");
+ y_max_slider->format = "% 6.0f";
+ y_max_slider->SetParams(rob_osage_test->node.hinge.ymax, 0.0f, 179.0f, 89.5f, 0.5f, 5.0f);
+ y_max_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Node::Hinge::YMaxCallback));
+
+ z_min_slider = dw::Slider::Create(comp);
+ z_min_slider->SetText(" Zmin ");
+ z_min_slider->format = "% 6.0f";
+ z_min_slider->SetParams(rob_osage_test->node.hinge.zmin, -179.0f, 0.0f, 89.5f, 0.5f, 5.0f);
+ z_min_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Node::Hinge::ZMinCallback));
+
+ z_max_slider = dw::Slider::Create(comp);
+ z_max_slider->SetText(" Zmax ");
+ z_max_slider->format = "% 6.0f";
+ z_max_slider->SetParams(rob_osage_test->node.hinge.zmax, 0.0f, 179.0f, 89.5f, 0.5f, 5.0f);
+ z_max_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::Node::Hinge::ZMaxCallback));
+ }
+ else if (y_min_slider) {
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(y_min_slider));
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(y_max_slider));
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(z_min_slider));
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(z_max_slider));
+
+ y_min_slider->Reset();
+ y_max_slider->Reset();
+ z_min_slider->Reset();
+ z_max_slider->Reset();
+ y_min_slider = 0;
+ y_max_slider = 0;
+ z_min_slider = 0;
+ z_max_slider = 0;
+ }
+}
+
+void RobOsageTestDw::Node::Hinge::YMinCallback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+
+ }
+}
+
+void RobOsageTestDw::Node::Hinge::YMaxCallback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+
+ }
+}
+
+void RobOsageTestDw::Node::Hinge::ZMinCallback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+
+ }
+}
+
+void RobOsageTestDw::Node::Hinge::ZMaxCallback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+
+ }
+}
+
+RobOsageTestDw::Node::InertialCancel::InertialCancel(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("i.c. ");
+ button->AddSelectionListener(this);
+
+ Update(false);
+}
+
+RobOsageTestDw::Node::InertialCancel::~InertialCancel() {
+
+}
+
+void RobOsageTestDw::Node::InertialCancel::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Node::InertialCancel::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Node::InertialCancel::Update(bool value) {
+ if (value) {
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 2.3f";
+ slider->SetParams(rob_osage_test->node.inertial_cancel, 0.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ }
+ else if (slider) {
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Node::InertialCancel::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+
+ }
+}
+
+RobOsageTestDw::Node::Weight::Weight(dw::Composite* parent) : slider() {
+ comp = new dw::Composite(parent);
+ comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("weight ");
+ button->AddSelectionListener(this);
+
+ Update(false);
+}
+
+RobOsageTestDw::Node::Weight::~Weight() {
+
+}
+
+void RobOsageTestDw::Node::Weight::Callback(dw::SelectionListener::CallbackData* data) {
+ dw::Button* button = dynamic_cast(data->widget);
+ if (button) {
+ Update(button->value);
+ rob_osage_test_dw->UpdateLayout();
+ }
+}
+
+void RobOsageTestDw::Node::Weight::SetValue(float_t value) {
+ if (slider)
+ slider->SetValue(value);
+}
+
+void RobOsageTestDw::Node::Weight::Update(bool value) {
+ if (value) {
+ slider = dw::Slider::Create(comp);
+ slider->SetText("");
+ slider->format = "% 2.3f";
+ slider->SetParams(rob_osage_test->node.weight, 0.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ }
+ else if (slider) {
+ comp->controls.erase(comp->controls.begin() + comp->GetControlIndex(slider));
+ slider->Reset();
+ slider = 0;
+ }
+}
+
+void RobOsageTestDw::Node::Weight::Callback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+
+ }
+}
+
+void RobOsageTestDw::Node::Init(dw::Composite* parent) {
+ group = new dw::Group(parent);
+ group->SetText("Node Param");
+
+ coli_r = new CollisionRadius(group);
+ weight = new Weight(group);
+ inertial_cancel = new InertialCancel(group);
+ hinge = new Hinge(group);
+}
+
+void RobOsageTestDw::Node::Update() {
+ const RobOsageTest::Node& node = rob_osage_test->node;
+
+ coli_r->SetValue(node.coli_r);
+ weight->SetValue(node.weight);
+ inertial_cancel->SetValue(node.inertial_cancel);
+ hinge->SetValue(node.hinge);
+}
+
+void RobOsageTestDw::BetweenOsageCollision::Init(dw::Composite* parent) {
+ dw::Composite* comp = new dw::Composite(parent);
+
+ button = new dw::Button(comp, dw::CHECKBOX);
+ button->SetText("Between Osage Collision");
+}
+
+void RobOsageTestDw::Collision::Init(dw::Composite* parent) {
+ group = new dw::Group(parent);
+ group->SetText("COLLISION");
+
+ dw::Composite* ribbon_comp = new dw::Composite(group);
+ ribbon_comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ reset_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ reset_button->SetText(" RESET ");
+ reset_button->callback = RobOsageTestDw::Collision::ResetCallback;
+
+ copy_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ copy_button->SetText(" COPY ");
+ copy_button->callback = RobOsageTestDw::Collision::CopyCallback;
+
+ paste_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ paste_button->SetText(" PASTE ");
+ paste_button->callback = RobOsageTestDw::Collision::PasteCallback;
+
+ element_comp = 0;
+}
+
+void RobOsageTestDw::Collision::Update() {
+ if (element_comp) {
+ Composite* parent_comp = element_comp->parent_comp;
+ auto i_begin = parent_comp->controls.begin();
+ auto i_end = parent_comp->controls.end();
+ for (auto i = i_begin; i != i_end; )
+ if (*i == element_comp) {
+ parent_comp->controls.erase(i);
+ break;
+ }
+ else
+ i++;
+
+ element_comp->Free();
+ element_comp = 0;
+ }
+
+ element_comp = new dw::Composite(group);
+
+ const prj::vector* cls_list = rob_osage_test->get_cls_list();
+ if (!cls_list)
+ return;
+
+ bone_database_skeleton* skeleton = bone_database_get_skeleton_by_type(BONE_DATABASE_SKELETON_COMMON);
+
+ char buf[0x200];
+ int32_t index = 0;
+ for (const SkinParam::CollisionParam& i : *cls_list) {
+ dw::Button* element_button = new dw::Button(element_comp, dw::RADIOBUTTON);
+ switch (i.type) {
+ case SkinParam::CollisionTypeEnd:
+ sprintf_s(buf, sizeof(buf), "%d %s", index, collision_type_name_list[i.type]);
+ break;
+ case SkinParam::CollisionTypeBall:
+ case SkinParam::CollisionTypeCapsule:
+ case SkinParam::CollisionTypePlane:
+ case SkinParam::CollisionTypeEllipse:
+ case SkinParam::CollisionTypeAABB:
+ sprintf_s(buf, sizeof(buf), "%d %s/%s", index,
+ collision_type_name_list[i.type], skeleton->object_bone_names[i.node_idx[0]]);
+ break;
+ default:
+ sprintf_s(buf, sizeof(buf), "%d", index);
+ break;
+ }
+
+ element_button->SetText(buf);
+ element_button->callback_data.i32 = index;
+ element_button->callback = RobOsageTestDw::Collision::ElementCallback;
+ if (index == rob_osage_test->collision_index)
+ element_button->SetValue(true);
+
+ if (i.type == SkinParam::CollisionTypeEnd)
+ break;
+
+ index++;
+ }
+}
+
+void RobOsageTestDw::Collision::CopyCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ prj::vector* cls_list = rob_osage_test->get_cls_list();
+ if (cls_list)
+ rob_osage_test->cls_list_temp.assign(cls_list->begin(), cls_list->end());
+ }
+}
+
+void RobOsageTestDw::Collision::ElementCallback(dw::Widget* data) {
+ int32_t index = data->callback_data.i32;
+ prj::vector* cls_list = rob_osage_test->get_cls_list();
+ if (cls_list) {
+ rob_osage_test->collision_index = index;
+
+ rob_osage_test_dw->colli_element.Update();
+ }
+}
+
+void RobOsageTestDw::Collision::PasteCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+
+ if (button) {
+ prj::vector* cls_list = rob_osage_test->get_cls_list();
+ if (cls_list) {
+ cls_list->assign(
+ rob_osage_test->cls_list_temp.begin(), rob_osage_test->cls_list_temp.end());
+
+ rob_osage_test->collision_index = -1;
+ rob_osage_test->collision_update = true;
+ }
+ }
+}
+
+void RobOsageTestDw::Collision::ResetCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ prj::vector* cls_list = rob_osage_test->get_cls_list();
+ if (cls_list) {
+ cls_list->clear();
+ cls_list->push_back({});
+ rob_osage_test->collision_index = -1;
+ rob_osage_test->collision_update = true;
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::Init(dw::Composite* parent) {
+ group = new dw::Group(parent);
+ group->SetText("COLLI ELEMENT");
+
+ dw::Composite* ribbon_comp = new dw::Composite(group);
+ ribbon_comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ reset_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ reset_button->SetText("RESET ");
+ reset_button->callback = RobOsageTestDw::ColliElement::ResetCallback;
+
+ copy_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ copy_button->SetText(" COPY ");
+ copy_button->callback = RobOsageTestDw::ColliElement::CopyCallback;
+
+ paste_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ paste_button->SetText("PASTE ");
+ paste_button->callback = RobOsageTestDw::ColliElement::PasteCallback;
+
+ flip_button = new dw::Button(ribbon_comp, dw::FLAG_8);
+ flip_button->SetText(" FLIP ");
+ flip_button->callback = RobOsageTestDw::ColliElement::FlipCallback;
+
+ type_list_box = new dw::ListBox(group, dw::MULTISELECT);
+ for (const char*& i : collision_type_name_list)
+ type_list_box->AddItem(i);
+ type_list_box->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::TypeCallback));
+
+ radius_slider = dw::Slider::Create(group);
+ radius_slider->SetText("R");
+ radius_slider->format = "% 2.3f ";
+ radius_slider->SetParams(0.0f, 0.0f, 2.0f, 0.01f, 0.001f, 0.01f);
+ radius_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::RadiusCallback));
+
+ bone_database_skeleton* skeleton = bone_database_get_skeleton_by_type(BONE_DATABASE_SKELETON_COMMON);
+
+ bone0_list_box = new dw::ListBox(group);
+ bone0_list_box->SetMaxItems(20);
+ for (uint32_t i = 0; i < skeleton->object_bone_name_count; i++)
+ bone0_list_box->AddItem(skeleton->object_bone_names[i]);
+ bone0_list_box->callback_data.i32 = 0;
+ bone0_list_box->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::BoneCallback));
+
+ bone0_x_slider = dw::Slider::Create(group);
+ bone0_x_slider->SetText("x");
+ bone0_x_slider->format = "% 2.3f ";
+ bone0_x_slider->SetParams(0.0f, -1.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ bone0_x_slider->callback_data.i32 = 0;
+ bone0_x_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::BonePosXCallback));
+
+ bone0_y_slider = dw::Slider::Create(group);
+ bone0_y_slider->SetText("y");
+ bone0_y_slider->format = "% 2.3f ";
+ bone0_y_slider->SetParams(0.0f, -1.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ bone0_y_slider->callback_data.i32 = 0;
+ bone0_y_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::BonePosYCallback));
+
+ bone0_z_slider = dw::Slider::Create(group);
+ bone0_z_slider->SetText("z");
+ bone0_z_slider->format = "% 2.3f ";
+ bone0_z_slider->SetParams(0.0f, -1.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ bone0_z_slider->callback_data.i32 = 0;
+ bone0_z_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::BonePosZCallback));
+
+ bone1_list_box = new dw::ListBox(group);
+ bone1_list_box->SetMaxItems(20);
+ for (uint32_t i = 0; i < skeleton->object_bone_name_count; i++)
+ bone1_list_box->AddItem(skeleton->object_bone_names[i]);
+ bone1_list_box->callback_data.i32 = 1;
+ bone1_list_box->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::BoneCallback));
+
+ bone1_x_slider = dw::Slider::Create(group);
+ bone1_x_slider->SetText("x");
+ bone1_x_slider->format = "% 2.3f ";
+ bone1_x_slider->SetParams(0.0f, -1.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ bone1_x_slider->callback_data.i32 = 1;
+ bone1_x_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::BonePosXCallback));
+
+ bone1_y_slider = dw::Slider::Create(group);
+ bone1_y_slider->SetText("y");
+ bone1_y_slider->format = "% 2.3f ";
+ bone1_y_slider->SetParams(0.0f, -1.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ bone1_y_slider->callback_data.i32 = 1;
+ bone1_y_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::BonePosYCallback));
+
+ bone1_z_slider = dw::Slider::Create(group);
+ bone1_z_slider->SetText("z");
+ bone1_z_slider->format = "% 2.3f ";
+ bone1_z_slider->SetParams(0.0f, -1.0f, 1.0f, 0.1f, 0.01f, 0.1f);
+ bone1_z_slider->callback_data.i32 = 1;
+ bone1_z_slider->AddSelectionListener(new dw::SelectionListenerOnHook(
+ RobOsageTestDw::ColliElement::BonePosZCallback));
+}
+
+void RobOsageTestDw::ColliElement::Update() {
+ const SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (!cls_param)
+ return;
+
+ type_list_box->SetItemIndex(cls_param->type);
+
+ radius_slider->SetValue(cls_param->radius);
+
+ bone0_list_box->SetItemIndex(cls_param->node_idx[0]);
+
+ bone0_x_slider->SetValue(cls_param->pos[0].x);
+ bone0_y_slider->SetValue(cls_param->pos[0].y);
+ bone0_z_slider->SetValue(cls_param->pos[0].z);
+
+ bone1_list_box->SetItemIndex(cls_param->node_idx[1]);
+
+ bone1_x_slider->SetValue(cls_param->pos[1].x);
+ bone1_y_slider->SetValue(cls_param->pos[1].y);
+ bone1_z_slider->SetValue(cls_param->pos[1].z);
+}
+
+void RobOsageTestDw::ColliElement::BoneCallback(dw::Widget* data) {
+ dw::ListBox* list_box = dynamic_cast(data);
+ if (list_box) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ cls_param->type = (SkinParam::CollisionType)(int32_t)rob_osage_test_dw->
+ colli_element.type_list_box->list->selected_item;
+ cls_param->node_idx[list_box->callback_data.i32] = (int32_t)list_box->list->selected_item;
+
+ rob_osage_test->collision_update = true;
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::BonePosXCallback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ cls_param->type = (SkinParam::CollisionType)(int32_t)rob_osage_test_dw->
+ colli_element.type_list_box->list->selected_item;
+ cls_param->pos[slider->callback_data.i32].x = slider->scroll_bar->value;
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::BonePosYCallback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ cls_param->type = (SkinParam::CollisionType)(int32_t)rob_osage_test_dw->
+ colli_element.type_list_box->list->selected_item;
+ cls_param->pos[slider->callback_data.i32].y = slider->scroll_bar->value;
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::BonePosZCallback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ cls_param->type = (SkinParam::CollisionType)(int32_t)rob_osage_test_dw->
+ colli_element.type_list_box->list->selected_item;
+ cls_param->pos[slider->callback_data.i32].z = slider->scroll_bar->value;
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::CopyCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param)
+ rob_osage_test->cls_param_temp = *cls_param;
+ }
+}
+
+void RobOsageTestDw::ColliElement::FlipCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ int32_t node_idx = cls_param->node_idx[0];
+ vec3 pos = cls_param->pos[0];
+ cls_param->node_idx[0] = cls_param->node_idx[1];
+ cls_param->pos[0] = cls_param->pos[1];
+ cls_param->node_idx[1] = node_idx;
+ cls_param->pos[1] = pos;
+
+ rob_osage_test->collision_update = true;
+ rob_osage_test_dw->colli_element.Update();
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::PasteCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ *cls_param = rob_osage_test->cls_param_temp;
+
+ rob_osage_test->collision_update = true;
+ rob_osage_test_dw->colli_element.Update();
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::RadiusCallback(dw::Widget* data) {
+ dw::Slider* slider = dynamic_cast(data);
+ if (slider) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ cls_param->type = (SkinParam::CollisionType)(int32_t)rob_osage_test_dw->
+ colli_element.type_list_box->list->selected_item;
+ cls_param->radius = slider->scroll_bar->value;
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::ResetCallback(dw::Widget* data) {
+ dw::Button* button = dynamic_cast(data);
+ if (button) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ *cls_param = {};
+
+ rob_osage_test->collision_update = true;
+ rob_osage_test_dw->colli_element.Update();
+ }
+ }
+}
+
+void RobOsageTestDw::ColliElement::TypeCallback(dw::Widget* data) {
+ dw::ListBox* list_box = dynamic_cast(data);
+ if (list_box) {
+ SkinParam::CollisionParam* cls_param = rob_osage_test->get_cls_param();
+ if (cls_param) {
+ cls_param->type = (SkinParam::CollisionType)(int32_t)list_box->list->selected_item;
+
+ rob_osage_test->collision_update = true;
+ }
+ }
+}
+
+RobOsageTestDw::RobOsageTestDw() : rob(), flags(), root(), node(), boc(), collision(), colli_element() {
+ SetText("RobOsage TEST");
+
+ dw::Composite* main_comp = new dw::Composite(this);
+ main_comp->SetLayout(new dw::RowLayout(dw::HORIZONTAL));
+
+ dw::Composite* left_comp = new dw::Composite(main_comp);
+
+ rob.Init(left_comp);
+ flags.Init(left_comp);
+ root.Init(left_comp);
+ node.Init(left_comp);
+ boc.Init(left_comp);
+
+ dw::Composite* right_comp = new dw::Composite(main_comp);
+
+ collision.Init(right_comp);
+ colli_element.Init(right_comp);
+
+ UpdateLayout();
+
+ rect.pos.x = (float_t)res_window_get()->width - rect.size.x;
+ rect.pos.y = 160.0f;
+
+ SetSize(rect.size);
+}
+
+RobOsageTestDw::~RobOsageTestDw() {
+
+}
+
+void RobOsageTestDw::Hide() {
+ SetDisp();
+}
diff --git a/src/DivaGL/data_test/rob_osage_test.hpp b/src/DivaGL/data_test/rob_osage_test.hpp
new file mode 100644
index 0000000..b674515
--- /dev/null
+++ b/src/DivaGL/data_test/rob_osage_test.hpp
@@ -0,0 +1,147 @@
+/*
+ by korenkonder
+ GitHub/GitLab: korenkonder
+*/
+
+#pragma once
+
+#include "../../KKdLib/default.hpp"
+#include "../../KKdLib/prj/vector_pair.hpp"
+#include "../rob/rob.hpp"
+#include "../task.hpp"
+#include "../types.hpp"
+
+class RobOsageTest : public app::Task {
+public:
+ struct Node {
+ struct Hinge {
+ float_t ymin;
+ float_t ymax;
+ float_t zmin;
+ float_t zmax;
+
+ inline Hinge() {
+ ymin = -90.0f;
+ ymax = 90.0f;
+ zmin = -90.0f;
+ zmax = 90.0f;
+ }
+ };
+
+ float_t coli_r;
+ float_t weight;
+ float_t inertial_cancel;
+ Hinge hinge;
+
+ inline Node() {
+ coli_r = 0.0f;
+ weight = 1.0f;
+ inertial_cancel = 0.0f;
+ }
+ };
+
+ struct Root {
+ float_t force;
+ float_t gain;
+ float_t air_res;
+ float_t root_y_rot;
+ float_t root_z_rot;
+ float_t fric;
+ float_t wind_afc;
+ SkinParam::RootCollisionType coli_type;
+ float_t init_y_rot;
+ float_t init_z_rot;
+
+ inline Root() {
+ force = 0.0f;
+ gain = 0.0f;
+ air_res = 0.5f;
+ root_y_rot = 0.0f;
+ root_z_rot = 0.0f;
+ fric = 1.0f;
+ wind_afc = 0.5f;
+ coli_type = SkinParam::RootCollisionTypeEnd;
+ init_y_rot = 0.0f;
+ init_z_rot = 0.0f;
+ }
+ };
+
+ bool load;
+ bool save;
+ bool coli;
+ bool line;
+
+ int32_t chara_id;
+ int32_t load_chara_id;
+ ::item_id item_id;
+ object_info obj_info;
+ size_t osage_index;
+ size_t collision_index;
+
+ prj::vector_pair_alloc<::item_id, object_info> objects;
+ prj::vector_pair_alloc> bocs;
+ prj::vector_pair_alloc> nodes;
+ prj::vector_pair_alloc> normal_refs;
+
+ Root root;
+ Node node;
+
+ Root root_temp;
+ Node node_temp;
+ prj::vector cls_list_temp;
+ SkinParam::CollisionParam cls_param_temp;
+
+ bool collision_update;
+
+ RobOsageTest();
+ virtual ~RobOsageTest() override;
+
+ virtual bool init() override;
+ virtual bool ctrl() override;
+ virtual bool dest() override;
+ virtual void disp() override;
+ virtual void basic() override;
+
+ void disp_coli();
+ void disp_line();
+
+ ExClothBlock* get_cloth_block(rob_chara_item_equip_object* itm_eq_obj) const;
+ rob_chara_item_equip_object* get_item_equip_object() const;
+ ExOsageBlock* get_osage_block(rob_chara_item_equip_object* itm_eq_obj) const;
+ prj::vector* get_cls_list(ExClothBlock* cls) const;
+ prj::vector* get_cls_list(ExOsageBlock* osg) const;
+ SkinParam::CollisionParam* get_cls_param(prj::vector* cls_list) const;
+ void set_root(skin_param* skp);
+
+ inline prj::vector* get_cls_list() const {
+ rob_chara_item_equip_object* itm_eq_obj = get_item_equip_object();
+ ExOsageBlock* osg = get_osage_block(itm_eq_obj);
+ return osg ? get_cls_list(osg) : get_cls_list(get_cloth_block(itm_eq_obj));
+ }
+
+ inline SkinParam::CollisionParam* get_cls_param() const {
+ return get_cls_param(get_cls_list());
+ }
+
+ inline skin_param* get_skin_param() const {
+ rob_chara_item_equip_object* itm_eq_obj = get_item_equip_object();
+ ExOsageBlock* osg = get_osage_block(itm_eq_obj);
+ if (osg)
+ return osg->rob.skin_param_ptr;
+ else {
+ ExClothBlock* cls = get_cloth_block(itm_eq_obj);
+ if (cls)
+ return cls->rob.skin_param_ptr;
+ }
+ return 0;
+ }
+
+ inline void set_root() {
+ return set_root(get_skin_param());
+ }
+};
+
+extern RobOsageTest* rob_osage_test;
+
+extern void rob_osage_test_init();
+extern void rob_osage_test_free();
diff --git a/src/DivaGL/dw.cpp b/src/DivaGL/dw.cpp
new file mode 100644
index 0000000..c986c06
--- /dev/null
+++ b/src/DivaGL/dw.cpp
@@ -0,0 +1,3168 @@
+/*
+ by korenkonder
+ GitHub/GitLab: korenkonder
+*/
+
+#include "dw.hpp"
+#include "print_work.hpp"
+
+class PrintWorkDebug : public PrintWork {
+public:
+ PrintWorkDebug();
+};
+
+namespace dw {
+ struct Print {
+ p_Font* font;
+ PrintWorkDebug* print_work;
+ color4u8 field_10;
+ color4u8 field_14;
+ rectangle field_18;
+ rectangle clip_data;
+ float_t field_38;
+
+ Print(float_t width, float_t height);
+ ~Print();
+
+ void FillRectangle(rectangle rect);
+ vec2 GetTextSize(prj::string& str);
+ vec2 GetTextSize(prj::wstring& str);
+ vec2 GetTextSize(const wchar_t* str, size_t length);
+ void PrintText(prj::string& str, float_t pos_x, float_t pos_y);
+ void PrintText(prj::wstring& str, float_t pos_x, float_t pos_y);
+ void SetClipData(rectangle rect);
+ void SetFillColor(color4u8 value);
+ void SetFont(p_Font* value);
+ void SetColor(color4u8 value);
+
+ void sub_140301390(rectangle rect, float_t a3);
+ void sub_140302800();
+
+ inline vec2 GetTextSize(prj::string&& str) {
+ return GetTextSize(str);
+ }
+
+ inline vec2 GetTextSize(prj::wstring&& str) {
+ return GetTextSize(str);
+ }
+
+ inline void PrintText(prj::string&& str, float_t pos_x, float_t pos_y) {
+ PrintText(str, pos_x, pos_y);
+ }
+
+ inline void PrintText(prj::wstring&& str, float_t pos_x, float_t pos_y) {
+ PrintText(str, pos_x, pos_y);
+ }
+ };
+
+ struct Colors {
+ color4u8 background;
+ color4u8 foreground;
+ color4u8 selection_background;
+ color4u8 selection_foreground;
+ color4u8 selection_inactive_background;
+ color4u8 selection_inactive_foreground;
+ color4u8 disable_background;
+ color4u8 disable_foreground;
+ color4u8 title_background;
+ color4u8 title_foreground;
+ color4u8 title_inactive_background;
+ color4u8 title_inactive_foreground;
+ color4u8 active_border_color;
+ color4u8 inactive_border_color;
+ color4u8 focus_border_color;
+ color4u8 border_color;
+ color4u8 border_light_color;
+ color4u8 border_dark_color;
+ color4u8 popup_background;
+ color4u8 popup_foreground;
+ color4u8 popup_selection_background;
+ color4u8 popup_selection_foreground;
+ color4u8 menu_background;
+ color4u8 menu_foreground;
+ color4u8 menu_selection_background;
+ color4u8 menu_selection_foreground;
+ color4u8 button_background;
+ color4u8 button_foreground;
+ color4u8 button_disable_background;
+ color4u8 button_disable_foreground;
+ };
+}
+
+struct struc_751 {
+ vec2 mouse_pos;
+ vec2 mouse_delta;
+ int32_t mouse_input;
+ int32_t modifier;
+ int32_t field_18;
+ int8_t field_1C;
+ int8_t field_1D;
+ int64_t field_20;
+ uint8_t field_28;
+ int32_t key_input[2];
+};
+
+namespace dw_gui_detail {
+ struct Display {
+ class RootKeySelection : public dw::KeyAdapter {
+ public:
+ };
+
+ void* __vftable;
+ dw::Shell* selected_shell;
+ dw::Menu* opened_menu;
+ dw::Widget* howered_shell;
+ dw::Widget* move_resize_shell;
+ dw::Widget* howered_widget;
+ dw::Widget* selected_widget;
+ dw::Shell* focused_shell;
+ bool set_focus;
+ bool find_focus;
+ prj::vector shells;
+ prj::vector menus;
+ dw::Widget::MouseCallbackData mouse_callback_data;
+ dw::Widget::KeyCallbackData key_callback_data;
+ prj::vector free_widgets;
+ struc_751 field_C0;
+ dw::init_data init_data;
+ int64_t field_118;
+ vec2 field_120;
+ float_t field_128;
+ struct DragBoundsControl* drag_bounds_control;
+ prj::wstring name;
+ RootKeySelection root_key_selection;
+
+ dw::Shell* GetHoveredShell();
+ void MakeShellFirst(dw::Shell* value);
+ void MakeShellLast(dw::Shell* value);
+ void RemoveShell(dw::Shell* value);
+ };
+}
+
+static_assert(sizeof(dw_gui_detail::Display) == 0x160, "\"dw_gui_detail::Display\" struct should have a size of 0x160");
+
+dw_gui_detail::Display*& dw_gui_detail_display = *(dw_gui_detail::Display**)0x0000000141190108;
+
+int32_t& dword_140EDA6B8 = *(int32_t*)0x0000000140EDA6B8;
+
+static void dw_gui_detail_display_set_selected_widget(dw::Widget* widget, bool set);
+
+static void sub_1402EE3C0(rectangle rect, float_t border, int32_t type, color4u8* fill_color);
+
+namespace dw {
+ const dw::Colors& colors_default = *(dw::Colors*)0x000000141190130;
+
+ static RowLayout* row_layout_vertical = new RowLayout(VERTICAL);
+
+ DropDownListScrollBarSelectionListener& drop_down_list_scroll_bar_selection_listener
+ = *(DropDownListScrollBarSelectionListener*)0x0000000140C987E8;
+ ScrollBarTestSelectionListener& scroll_bar_test_Selection_listener
+ = *(ScrollBarTestSelectionListener*)0x0000000140C987F0;
+
+ Print*& print = *(Print**)0x00000001411900C8;
+
+ dw::Colors& colors_current = *(dw::Colors*)0x00000001411901B0;
+
+ p_Font& current_font = *(p_Font*)0x00000141190128;
+
+ Font*& font_type_6x12 = *(Font**)0x00000001411902A0;
+ Font*& font_type_8x12 = *(Font**)0x00000001411902A8;
+ Font*& font_type_8x16 = *(Font**)0x00000001411902B0;
+ Font*& font_type_10x16 = *(Font**)0x00000001411902B8;
+ Font*& font_type_10x20 = *(Font**)0x00000001411902C0;
+ Font*& font_type_12x24 = *(Font**)0x00000001411902C8;
+ Font*& font_type_scroll_bar = *(Font**)0x00000001411902D0;
+
+ p_Font& p_font_type_6x12 = *(p_Font*)0x00000001411901A8;
+ p_Font& p_font_type_8x12 = *(p_Font*)0x0000000141190238;
+ p_Font& p_font_type_8x16 = *(p_Font*)0x0000000141190240;
+ p_Font& p_font_type_10x16 = *(p_Font*)0x0000000141190248;
+ p_Font& p_font_type_10x20 = *(p_Font*)0x0000000141190250;
+ p_Font& p_font_type_12x24 = *(p_Font*)0x0000000141190258;
+ p_Font& p_font_type_scroll_bar = *(p_Font*)0x0000000141190260;
+
+ prj::map& font_collection = *(prj::map*)0x00000001403024BE;
+
+ Font::Font(int32_t font_handler_index, prj::string& name, bool half_width) {
+ font = font_info(font_handler_index);
+ this->name.assign(name);
+ this->half_width = half_width;
+ }
+
+ Font::Font(int32_t font_handler_index, prj::string& name) {
+ font = font_info(font_handler_index);
+ this->name.assign(name);
+ this->half_width = 0;
+ }
+
+ Font::~Font() {
+
+ }
+
+ float_t Font::GetFontGlyphHeight() {
+ return font.glyph.y;
+ }
+
+ vec2 Font::GetFontGlyphSize() {
+ vec2 size;
+ size.x = GetFontGlyphWidth();
+ size.y = GetFontGlyphHeight();
+ return size;
+ }
+
+ float_t Font::GetFontGlyphWidth() {
+ float_t glyph_height = font.glyph.x;
+ if (half_width)
+ return glyph_height * 0.5f;
+ return glyph_height;
+ }
+
+ prj::string Font::GetName() {
+ return name;
+ }
+
+ void Font::SetGlyphSize(float_t glyph_width, float_t glyph_height) {
+ if (half_width)
+ glyph_width *= 2.0f;
+ font.set_glyph_size(glyph_width, glyph_height);
+ }
+
+ p_Font::p_Font() : ptr() {
+
+ }
+
+ p_Font::~p_Font() {
+
+ }
+
+ float_t p_Font::GetFontGlyphHeight() {
+ return ptr->GetFontGlyphHeight();
+ }
+
+ vec2 p_Font::GetFontGlyphSize() {
+ return ptr->GetFontGlyphSize();
+ }
+
+ float_t p_Font::GetFontGlyphWidth() {
+ return ptr->GetFontGlyphWidth();
+ }
+
+ prj::string p_Font::GetName() {
+ return ptr->GetName();
+ }
+
+ void p_Font::SetGlyphSize(float_t glyph_width, float_t glyph_height) {
+ ptr->SetGlyphSize(glyph_width, glyph_height);
+ }
+
+ SelectionListener::SelectionListener() {
+
+ }
+
+ SelectionListener::~SelectionListener() {
+
+ }
+
+ SelectionAdapter::SelectionAdapter() {
+
+ }
+
+ SelectionAdapter::~SelectionAdapter() {
+
+ }
+
+ void SelectionAdapter::Callback(SelectionListener::CallbackData* data) {
+
+ }
+
+ void SelectionAdapter::Field_10(SelectionListener::CallbackData* data) {
+
+ }
+
+ SelectionListenerOnHook::SelectionListenerOnHook() : callback() {
+
+ }
+
+ SelectionListenerOnHook::SelectionListenerOnHook(SelectionListenerOnHook::CallbackFunc callback) {
+ this->callback = callback;
+ }
+
+ SelectionListenerOnHook::~SelectionListenerOnHook() {
+
+ }
+
+ void SelectionListenerOnHook::Callback(SelectionListener::CallbackData* data) {
+ callback(data->widget);
+ }
+
+ Widget::KeyCallbackData::KeyCallbackData() : widget(),
+ modifier(), field_C(), field_D(), input() {
+ }
+
+ Widget::MouseCallbackData::MouseCallbackData() : widget(), input(), modifier() {
+
+ }
+
+ Widget::Widget(Widget* parent, Flags flags) : freed(),
+ callback_data(), free_callback(), parent() {
+ text.assign(L"NO_NAME");
+ this->flags = flags;
+ font = current_font;
+ }
+
+ Widget::~Widget() {
+ Free();
+ }
+
+ void Widget::Draw() {
+
+ }
+
+ void Widget::Reset() {
+ text.clear();
+ }
+
+ prj::wstring Widget::GetText() {
+ return text;
+ }
+
+ void Widget::SetText(prj::wstring& str) {
+ text.assign(str);
+ }
+
+ int32_t Widget::KeyCallback(const Widget::KeyCallbackData& data) {
+ return 0;
+ }
+
+ int32_t Widget::MouseCallback(const Widget::MouseCallbackData& data) {
+ return 0;
+ }
+
+ void Widget::SetSize(const vec2& value) {
+ rect.size = value;
+ }
+
+ vec2 Widget::GetPos() {
+ return rect.pos;
+ }
+
+ bool Widget::CheckHitPos(const vec2& hit_pos) {
+ rectangle rect = GetRectangle();
+ return rect.pos.x <= hit_pos.x && hit_pos.x < rect.pos.x + rect.size.x
+ && rect.pos.y <= hit_pos.y && hit_pos.y < rect.size.y + rect.pos.y;
+ }
+
+ void Widget::Free() {
+ if (freed)
+ return;
+
+ Reset();
+
+ if (free_callback)
+ free_callback(this);
+
+ freed = true;
+
+ if (dw_gui_detail_display)
+ dw_gui_detail_display->free_widgets.push_back(this);
+ }
+
+ float_t Widget::GetFontGlyphHeight() {
+ return font.GetFontGlyphHeight();
+ }
+
+ rectangle Widget::GetRectangle() {
+ return { GetPos(), rect.size };
+ }
+
+ void Widget::SetText(prj::string& str) {
+ std::string temp_utf8(str.data(), str.size());
+ std::wstring temp_utf16(utf8_to_utf16(temp_utf8));
+ SetText(prj::wstring(temp_utf16.data(), temp_utf16.size()));
+ }
+
+ void Widget::UpdateDraw() {
+ print->sub_140302800();
+ Draw();
+ }
+
+ void Widget::sub_1402F3770(Widget* widget) {
+ if (!widget)
+ return;
+
+ rectangle v10 = widget->GetRectangle();
+ rectangle v11 = dw_gui_detail_display->init_data.field_0;
+ if (v11.pos.x > v10.pos.x || v10.pos.x + v10.size.x > v11.pos.x + v11.size.x
+ || v11.pos.y > v10.pos.y || v10.pos.y + v10.size.y > v11.pos.y + v11.size.y) {
+ vec2 v7 = v10.pos;
+ if (v10.pos.x + v10.size.x >= v11.pos.x + v11.size.x)
+ v7.x = v11.pos.x + v11.size.x - widget->rect.size.x;
+ if (v10.pos.x < v11.pos.x || v7.x < 0.0f)
+ v7.x = 0.0f;
+
+ if (v10.pos.y + v10.size.y >= v11.pos.y + v11.size.y)
+ v7.y = v11.pos.y + v11.size.y - widget->rect.size.y;
+ if (v10.pos.y < v11.pos.y || v7.y < 0.0f)
+ v7.y = 0.0f;
+ widget->rect.pos = v7;
+ }
+ }
+
+ Control::Control(Composite* parent, Flags flags) : Widget(parent, flags),
+ field_68(), parent_comp(), parent_shell(), parent_menu() {
+ parent_comp = parent;
+ foreground_color = colors_current.foreground;
+ background_color = colors_current.background;
+
+ if (parent) {
+ parent->controls.push_back(this);
+ parent_shell = parent->parent_shell;
+ }
+ }
+
+ Control::~Control() {
+
+ }
+
+ void Control::Draw() {
+
+ }
+
+ void Control::Reset() {
+ parent_comp = 0;
+ Widget::Reset();
+ }
+
+ int32_t Control::KeyCallback(const Widget::KeyCallbackData& data) {
+ if (!Field_A0())
+ return 0;
+
+ /*if ((data.field_8 & 0x20000) && data.field_10 == 0x1000013)
+ if (parent_menu)
+ parent_menu->sub_1402F35E0();*/
+
+ if (data.input[0] || (data.input[1] & 0x40000000)) {
+ Widget::KeyCallbackData v8 = data;
+ v8.widget = parent;
+ for (KeyListener*& i : key_listener)
+ i->Field_8(v8);
+ }
+ return 0;
+ }
+
+ int32_t Control::MouseCallback(const Widget::MouseCallbackData& data) {
+ if (!Field_A0())
+ return 0;
+
+ /*if (dw_gui_detail_display->field_C0.field_18 == 9 && (data.field_10 & 0x40) && !data.field_14)
+ if (parent_menu)
+ parent_menu->sub_1402F35E0();*/
+
+ if (!data.input)
+ return 0;
+
+ if (data.input & 0xF0) {
+ Widget::MouseCallbackData v19 = data;
+ v19.widget = parent;
+ v19.input = data.input & 0xF0;
+
+ for (MouseListener* i : mouse_listener)
+ i->Field_10(v19);
+ }
+
+ if (data.input & 0xF000000) {
+ Widget::MouseCallbackData v19 = data;
+ v19.widget = parent;
+ v19.input = data.input & 0xF000000;
+
+ for (MouseListener* i : mouse_listener)
+ i->Field_18(v19);
+ }
+
+ if (data.input & 0xF000) {
+ Widget::MouseCallbackData v19 = data;
+ v19.widget = parent;
+ v19.input = data.input & 0xF000;
+
+ for (MouseListener* i : mouse_listener)
+ i->Field_8(v19);
+ }
+
+ if (data.input & 0xF00) {
+ Widget::MouseCallbackData v19 = data;
+ v19.widget = parent;
+ v19.input = data.input & 0xF00;
+
+ for (MouseListener* i : mouse_listener)
+ i->Field_20(v19);
+ }
+
+ if (data.input & 0x40000000) {
+ Widget::MouseCallbackData v19 = data;
+ v19.widget = parent;
+
+ for (MouseMoveListener* i : mouse_move_listener)
+ i->Field_8(v19);
+ }
+ return 0;
+ }
+
+ vec2 Control::GetPos() {
+ vec2 pos = rect.pos;
+ if (parent_comp) {
+ rectangle parent_comp_bb = parent_comp->GetBoundingBox();
+ pos += parent_comp->GetPos() + parent_comp_bb.pos;
+ if (parent_comp->v_bar)
+ pos.y -= parent_comp->v_bar->value;
+ }
+ return pos;
+ }
+
+ void Control::UpdateLayout() {
+ SetSize(GetSize());
+ }
+
+ vec2 Control::GetSize() {
+ return rect.size;
+ }
+
+ bool Control::Field_58() {
+ return parent_comp->SetCurrentControl(this);
+ }
+
+ bool Control::Field_60() {
+ return parent_comp->sub_1402F1E60(this);
+ }
+
+ void Control::SetFont(p_Font& value) {
+ font = value;
+ }
+
+ p_Font& Control::GetFont() {
+ return font;
+ }
+
+ void Control::SetForegroundColor(color4u8 value) {
+ foreground_color = value;
+ }
+
+ void Control::SetBackgroundColor(color4u8 value) {
+ background_color = value;
+ }
+
+ color4u8 Control::GetForegroundColor() {
+ return foreground_color;
+ }
+
+ color4u8 Control::GetBackgroundColor() {
+ return background_color;
+ }
+
+ bool Control::Field_98() {
+ return !field_68;
+ }
+
+ bool Control::Field_A0() {
+ if (parent_comp)
+ return parent_comp->Field_A0() && Field_98();
+ return Field_98();
+ }
+
+ void Control::Field_A8(bool value) {
+ field_68 = !value;
+ }
+
+ Widget* Control::GetHitWidget(const vec2& hit_pos) {
+ if (CheckHitPos(hit_pos))
+ return this;
+ return 0;
+ }
+
+ void Control::SetParentMenu(Menu* menu) {
+ if (menu) {
+ //menu->Field_60();
+ parent_menu = menu;
+ }
+ else
+ parent_menu = 0;
+ }
+
+ Scrollable::Scrollable(Composite* parent, Flags flags) : Control(parent, flags), h_bar(), v_bar() {
+ if (flags & HORIZONTAL) {
+ h_bar = new ScrollBar(this, HORIZONTAL);
+ h_bar->SetText(L"h_bar");
+ }
+
+ if (flags & VERTICAL) {
+ v_bar = new ScrollBar(this, VERTICAL);
+ v_bar->SetText(L"v_bar");
+ }
+ }
+
+ Scrollable::~Scrollable() {
+
+ }
+
+ void Scrollable::Draw() {
+ if (v_bar)
+ v_bar->UpdateDraw();
+ }
+
+ void Scrollable::Reset() {
+ if (h_bar) {
+ h_bar->Free();
+ h_bar = 0;
+ }
+
+ if (v_bar) {
+ v_bar->Free();
+ v_bar = 0;
+ }
+
+ Control::Reset();
+ }
+
+ int32_t Scrollable::MouseCallback(const Widget::MouseCallbackData& data) {
+ if (!v_bar)
+ return Control::MouseCallback(data);
+
+ bool v4 = v_bar->field_A6;
+ int32_t ret = v_bar->MouseCallback(data);
+ if (v4 != v_bar->field_A6)
+ dw_gui_detail_display_set_selected_widget(v_bar, v_bar->field_A6);
+ return ret;
+ }
+
+ void Scrollable::SetSize(const vec2& value) {
+ Widget::SetSize(value);
+
+ vec2 size = value;
+ if (flags & FLAG_800)
+ size -= 2.0f * 2.0f;
+
+ if (v_bar) {
+ v_bar->rect.pos.x = size.x - v_bar->rect.size.x;
+ v_bar->rect.pos.y = 0.0f;
+ v_bar->SetWidth(size.y);
+ }
+ }
+
+ void Scrollable::SetFont(p_Font& value) {
+ font = value;
+ if (h_bar)
+ h_bar->SetFont(value);
+ if (v_bar)
+ v_bar->SetFont(value);
+ }
+
+ Widget* Scrollable::GetHitWidget(const vec2& hit_pos) {
+ if (!CheckHitPos(hit_pos))
+ return 0;
+
+ if (v_bar && v_bar->CheckHitPos(hit_pos))
+ return v_bar;
+ return this;
+ }
+
+ rectangle Scrollable::GetBoundingBox() {
+ rectangle rect;
+ rect.size = this->rect.size;
+
+ if (flags & FLAG_800) {
+ rect.pos = 2.0f;
+ rect.size -= 2.0f * 2.0f;
+ }
+
+ if (v_bar)
+ rect.size.x -= v_bar->rect.size.x;
+ return rect;
+ }
+
+ rectangle Scrollable::GetScrollableRectangle() {
+ vec2 pos = GetPos();
+ rectangle rect = GetBoundingBox();
+ rect.pos += pos;
+ return rect;
+ }
+
+ Composite::Composite(Composite* parent, Flags flags) : Scrollable(parent, flags) {
+ layout = row_layout_vertical;
+ current_control = -1;
+ }
+
+ Composite::~Composite() {
+
+ }
+
+ void Composite::Draw() {
+ rectangle rect = GetBoundingBox();
+ rect.pos = 0.0f;
+
+ if (v_bar)
+ rect.pos.y = v_bar->value;
+
+ for (Control*& i : controls)
+ if ((i->rect.pos.x + i->rect.size.x) > rect.pos.x && (rect.pos.x + rect.size.x) > i->rect.pos.x
+ && (i->rect.pos.y + i->rect.size.y) > rect.pos.y && (rect.pos.y + rect.size.y) > i->rect.pos.y)
+ i->UpdateDraw();
+
+ Scrollable::Draw();
+ }
+
+ void Composite::Reset() {
+ for (Control*& i : controls)
+ i->Free();
+
+ controls.clear();
+
+ Scrollable::Reset();
+ }
+
+ int32_t Composite::KeyCallback(const Widget::KeyCallbackData& data) {
+ if (current_control != -1 && current_control < controls.size())
+ return controls[current_control]->KeyCallback(data);
+ else
+ return 0;
+ }
+
+ int32_t Composite::MouseCallback(const Widget::MouseCallbackData& data) {
+ for (Control*& i : controls)
+ if (i->CheckHitPos(data.pos))
+ return i->MouseCallback(data);
+
+ return Scrollable::MouseCallback(data);
+ }
+
+ void Composite::SetSize(const vec2& size) {
+ Scrollable::SetSize(size);
+ layout->SetSize(this);
+ }
+
+ void Composite::UpdateLayout() {
+ SetSize(GetSize());
+ }
+
+ vec2 Composite::GetSize() {
+ return layout->GetSize(this);
+ }
+
+ bool Composite::Field_58() {
+ current_control = -1;
+ return Control::Field_58();
+ }
+
+ bool Composite::Field_60() {
+ return current_control == -1 && Field_C0();
+ }
+
+ Widget* Composite::GetHitWidget(const vec2& hit_pos) {
+ if (!CheckHitPos(hit_pos))
+ return Scrollable::GetHitWidget(hit_pos);
+
+ for (Control*& i : controls) {
+ Widget* widget = i->GetHitWidget(hit_pos);
+ if (widget)
+ return widget;
+ }
+
+ return this;
+ }
+
+ bool Composite::Field_C0() {
+ return parent_comp->sub_1402F1E60(this);
+ }
+
+ bool Composite::SetCurrentControl(Control* control) {
+ current_control = GetControlIndex(control);
+ return parent_comp->SetCurrentControl(this);
+ }
+
+ size_t Composite::GetControlIndex(Control* control) {
+ for (Control*& i : controls)
+ if (i == control)
+ return &i - controls.data();
+ return -1;
+ }
+
+ void Composite::SetLayout(Layout* value) {
+ layout = value;
+ }
+
+ bool Composite::sub_1402F1E60(Control* control) {
+ return GetControlIndex(control) == current_control && Field_C0();
+ }
+
+ Shell::Shell(Shell* parent, Flags flags) : Composite(parent, flags), disp(), disp_callback(),
+ hide_callback(), field_128(), destroy(), close_button(), field_170(), field_178() {
+ parent_shell = this;
+
+ if (flags & CLOSE_BUTTON) {
+ close_button = new ShellCloseButton(this);
+ if (controls.size())
+ controls.pop_back();
+ }
+
+ if (parent) {
+ parent_comp = parent;
+ parent->children.push_back(this);
+ }
+
+ dw_gui_detail_display->shells.push_back(this);
+ }
+
+ Shell::~Shell() {
+
+ }
+
+ void Shell::Draw() {
+ if (!GetDisp())
+ return;
+
+ rectangle v12 = GetRectangle();
+ bool active = dw_gui_detail_display->selected_shell == this;
+
+ print->SetColor(active
+ ? colors_current.active_border_color
+ : colors_current.inactive_border_color);
+ print->sub_140301390(v12, 2.0f);
+
+ if (flags & CHECKBOX) {
+ rectangle v11 = v12;
+ v11.size.y = current_font.GetFontGlyphHeight() + 2.0f + 2.0f;
+ print->sub_140301390(v11, 2.0f);
+
+ rectangle v10;
+ v10.pos = v11.pos + 2.0f;
+ v10.size = v11.size - 2.0f * 2.0f;
+
+ print->SetFillColor(active
+ ? colors_current.title_background
+ : colors_current.title_inactive_background);
+ print->FillRectangle(v10);
+
+ print->SetColor(active
+ ? colors_current.title_foreground
+ : colors_current.title_inactive_foreground);
+ print->SetFont(¤t_font);
+ print->SetClipData(v10);
+
+ print->PrintText(GetText(), v10.pos.x, v10.pos.y);
+
+ print->sub_140302800();
+ if (close_button)
+ close_button->UpdateDraw();
+ }
+
+ print->SetFillColor(colors_current.background);
+ print->FillRectangle(GetScrollableRectangle());
+ print->SetColor(colors_current.foreground);
+ Composite::Draw();
+
+ if (field_178) {
+ field_170 = true;
+ field_178->UpdateDraw();
+ field_170 = false;
+ }
+ }
+
+ void Shell::Reset() {
+ prj::vector vec;
+ vec.assign(children.begin(), children.end());
+ children.clear();
+
+ for (Widget* i : vec)
+ i->Free();
+
+ for (Menu* i : menus)
+ ;//i->Free();
+ menus.clear();
+
+ if (close_button) {
+ close_button->Free();
+ close_button = 0;
+ }
+
+ if (parent_comp) {
+ Shell* parent_shell = dynamic_cast(parent_comp);
+ if (parent_shell) {
+ auto i = parent_shell->children.begin();
+ auto i_end = parent_shell->children.end();
+ while (i != i_end)
+ if (*i == this) {
+ parent_shell->children.erase(i);
+ break;
+ }
+ }
+ }
+
+ dw_gui_detail_display->RemoveShell(this);
+
+ Composite::Reset();
+ }
+
+ int32_t Shell::KeyCallback(const Widget::KeyCallbackData& data) {
+ if (!GetDisp())
+ return 0;
+
+ if ((data.modifier & 0x10000) && data.input[0] == 0x100000D || (data.input[0] & 0x2000)) {
+ Hide();
+ return 0;
+ }
+
+ return Composite::KeyCallback(data);
+ }
+
+ int32_t Shell::MouseCallback(const Widget::MouseCallbackData& data) {
+ if (!GetDisp())
+ return 0;
+
+ bool (FASTCALL * sub_140192D00)() = (bool (FASTCALL*)())0x0000000140192D00;
+
+ if (data.input & 0xF0) {
+ if (!sub_140192D00())
+ return 0;
+
+ dw_gui_detail_display->MakeShellFirst(this);
+ }
+
+ if ((uint16_t)dw_gui_detail_display->field_C0.field_18 >= 1 && (uint16_t)dw_gui_detail_display->field_C0.field_18 <= 8) {
+ if (data.input & 0x10) {
+ if (sub_140192D00()) {
+ dw_gui_detail_display->field_C0.field_18 |= 0x20000000;
+ dw_gui_detail_display->move_resize_shell = dw_gui_detail_display->selected_shell;
+ }
+ return 0;
+ }
+ }
+ else if ((uint16_t)dw_gui_detail_display->field_C0.field_18 == 10) {
+ if (close_button && close_button->CheckHitPos(data.pos))
+ return close_button->MouseCallback(data);
+
+ if (data.input & 0x10) {
+ if (sub_140192D00()) {
+ dw_gui_detail_display->field_C0.field_18 |= 0x40000000;
+ dw_gui_detail_display->move_resize_shell = dw_gui_detail_display->selected_shell;
+ }
+ return 0;
+ }
+ }
+
+ return Composite::MouseCallback(data);
+ }
+
+ void Shell::SetSize(const vec2& size) {
+ Widget::SetSize(size);
+ if (flags & CHECKBOX) {
+ if (close_button) {
+ vec2 size = close_button->GetSize();
+ close_button->rect.pos.x = rect.size.x - (size.x + 2.0f);
+ close_button->rect.pos.y = 2.0f;
+ }
+ }
+
+ rectangle bounding_box = GetBoundingBox();
+ if (v_bar) {
+ v_bar->rect.pos.x = bounding_box.pos.x + bounding_box.size.x - v_bar->rect.size.x;
+ v_bar->rect.pos.y = bounding_box.pos.y;
+ v_bar->SetWidth(bounding_box.size.y);
+ }
+
+ layout->SetSize(this);
+ }
+
+ vec2 Shell::GetPos() {
+ return rect.pos;
+ }
+
+ vec2 Shell::GetSize() {
+ vec2 size = Composite::GetSize() + 2.0f * 2.0f;
+ if (flags & CHECKBOX)
+ size.y += current_font.GetFontGlyphHeight() + 2.0f;
+ return size;
+ }
+
+ bool Shell::Field_58() {
+ return this == dw_gui_detail_display->selected_shell && GetDisp();
+ }
+
+ Widget* Shell::GetHitWidget(const vec2& hit_pos) {
+ rectangle rect = GetRectangle();
+ if (rect.pos.x > hit_pos.x || hit_pos.x >= rect.pos.x + rect.size.x
+ || rect.pos.y > hit_pos.y || hit_pos.y >= rect.size.y + rect.pos.y)
+ return 0;
+
+ if (close_button && close_button->CheckHitPos(hit_pos))
+ return close_button;
+
+ Widget* widget = Composite::GetHitWidget(hit_pos);
+ if (widget)
+ return widget;
+
+ return this;
+ }
+
+ rectangle Shell::GetBoundingBox() {
+ rectangle rect;
+ rect.pos = 2.0f;
+ rect.size = this->rect.size - 2.0f * 2.0f;
+
+ if (flags & CHECKBOX) {
+ rect.size.y -= current_font.GetFontGlyphHeight() + 2.0f;
+ rect.pos.y += current_font.GetFontGlyphHeight() + 2.0f;
+ }
+
+ if (v_bar)
+ rect.size.x -= v_bar->rect.size.x;
+ return rect;
+ }
+
+ bool Shell::Field_C0() {
+ return Field_58();
+ }
+
+ bool Shell::SetCurrentControl(Control* control) {
+ current_control = GetControlIndex(control);
+ return Field_58();
+ }
+
+ void Shell::Hide() {
+ destroy = true;
+ }
+
+ void Shell::Disp() {
+ SetDisp(true);
+ dw_gui_detail_display->MakeShellFirst(this);
+ dw_gui_detail_display->focused_shell = this;
+ dw_gui_detail_display->set_focus = true;
+ }
+
+ bool Shell::GetDisp() {
+ return disp;
+ }
+
+ void Shell::SetDisp(bool value) {
+ if (disp == value)
+ return;
+
+ disp = value;
+ if (disp) {
+ dw_gui_detail_display->MakeShellFirst(this);
+ dw_gui_detail_display->focused_shell = this;
+ dw_gui_detail_display->set_focus = true;
+ if (disp_callback)
+ disp_callback(this);
+ }
+ else {
+ dw_gui_detail_display->find_focus = true;
+ if (hide_callback)
+ hide_callback(this);
+ }
+ }
+
+ void Shell::sub_1402E43C0(Widget* widget) {
+ if (!field_178)
+ field_178 = widget;
+ }
+
+ void Shell::sub_1402E61F0(Widget* widget) {
+ if (field_178 && field_178 == widget)
+ field_178 = 0;
+ }
+
+ void Shell::sub_1402F38B0() {
+ sub_1402F3770(this);
+ Disp();
+ }
+
+ KeyListener::KeyListener() {
+
+ }
+
+ KeyListener::~KeyListener() {
+
+ }
+
+ KeyAdapter::KeyAdapter() {
+
+ }
+
+ KeyAdapter::~KeyAdapter() {
+
+ }
+
+ void KeyAdapter::Field_8(const Widget::KeyCallbackData& data) {
+
+ }
+
+ void KeyAdapter::Field_10(const Widget::KeyCallbackData& data) {
+
+ }
+
+ void KeyAdapter::Field_18(const Widget::KeyCallbackData& data) {
+
+ }
+
+ MouseListener::MouseListener() {
+
+ }
+
+ MouseListener::~MouseListener() {
+
+ }
+
+ MouseAdapter::MouseAdapter() {
+
+ }
+
+ MouseAdapter::~MouseAdapter() {
+
+ }
+
+ void MouseAdapter::Field_8(const Widget::MouseCallbackData& data) {
+
+ }
+
+ void MouseAdapter::Field_10(const Widget::MouseCallbackData& data) {
+
+ }
+
+ void MouseAdapter::Field_18(const Widget::MouseCallbackData& data) {
+
+ }
+
+ void MouseAdapter::Field_20(const Widget::MouseCallbackData& data) {
+
+ }
+
+ MouseMoveListener::MouseMoveListener() {
+
+ }
+
+ MouseMoveListener::~MouseMoveListener() {
+
+ }
+
+ Layout::Layout() {
+
+ }
+
+ Layout::~Layout() {
+
+ }
+
+ FillLayout::FillLayout(Flags flags) {
+ this->flags = flags;
+ }
+
+ FillLayout::~FillLayout() {
+
+ }
+
+ vec2 FillLayout::GetSize(Composite* comp) {
+ if (!comp->controls.size()) {
+ vec2 size = comp->rect.size;
+ if (comp->v_bar)
+ size.x += comp->v_bar->rect.size.x;
+ return size;
+ }
+
+ vec2 size = 0.0f;
+ if (flags == VERTICAL)
+ for (Control* i : comp->controls) {
+ vec2 _size = i->GetSize();
+ size.x = max_def(_size.x, size.x);
+ }
+ else
+ for (Control* i : comp->controls) {
+ vec2 _size = i->GetSize();
+ size.y = max_def(_size.y, size.y);
+ }
+
+ if (comp->v_bar)
+ size.x += comp->v_bar->rect.size.x;
+ return size;
+ }
+
+ void FillLayout::SetSize(Composite* comp) {
+ rectangle comp_bb = comp->GetBoundingBox();
+ if (!comp->controls.size())
+ return;
+
+ float_t size = (float_t)(int64_t)comp->controls.size();
+ if (size < 0.0f)
+ size += (float_t)UINT64_MAX;
+
+ if (flags == VERTICAL) {
+ float_t pos = 0.0f;
+ size = comp_bb.size.y / size;
+ for (Control* i : comp->controls) {
+ i->rect.pos = { 0.0f, pos };
+ i->SetSize({ comp_bb.size.x, size });
+ pos += size;
+ }
+ }
+ else {
+ float_t pos = 0.0f;
+ size = comp_bb.size.x / size;
+ for (Control* i : comp->controls) {
+ i->rect.pos = { pos, 0.0f };
+ i->SetSize({ size, comp_bb.size.y });
+ pos += size;
+ }
+ }
+ }
+
+ GraphLayout::GraphLayout(Flags flags) {
+ this->flags = flags;
+ }
+
+ GraphLayout::~GraphLayout() {
+
+ }
+
+ vec2 GraphLayout::GetSize(Composite* comp) {
+ return comp->rect.size;
+ }
+
+ void GraphLayout::SetSize(Composite* comp) {
+ const rectangle rect = comp->rect;
+ for (Control* i : comp->controls) {
+ i->rect.pos = rect.pos;
+ i->SetSize(rect.size);
+ }
+ }
+
+ GridLayout::GridLayout(size_t columns) : rows() {
+ this->columns = columns;
+ spacing = 2.0f;
+ }
+
+ GridLayout::~GridLayout() {
+
+ }
+
+ vec2 GridLayout::GetSize(Composite* comp) {
+ prj::vector& controls = comp->controls;
+ size_t controls_count = controls.size();
+ if (!controls_count) {
+ vec2 size = comp->rect.size;
+ if (comp->v_bar)
+ size.x += comp->v_bar->rect.size.x;
+ return size;
+ }
+
+ rows = (controls_count + columns - 1) / columns;
+ rows = rows ? rows : 1;
+
+ column_size.resize(columns);
+ row_size.resize(rows);
+
+ size_t control = 0;
+ for (size_t row = 0; row < rows && control < controls_count; row++)
+ for (size_t column = 0; column < columns && control < controls_count; column++, control++) {
+ vec2 size = controls.data()[control]->GetSize();
+ column_size.data()[column] = max_def(size.x, column_size.data()[column]);
+ row_size.data()[row] = max_def(size.y, row_size.data()[row]);
+ }
+
+ vec2 size;
+ size.x = (float_t)(int64_t)(columns - 1);
+ if (size.x < 0.0f)
+ size.x += (float_t)UINT64_MAX;
+
+ size.y = (float_t)(int64_t)(rows - 1);
+ if (size.y < 0.0f)
+ size.y += (float_t)UINT64_MAX;
+
+ size *= spacing;
+
+ float_t size_x = size.x;
+ for (float_t i : column_size)
+ size_x += i;
+ size.x = size_x;
+
+ float_t size_y = size.y;
+ for (float_t i : row_size)
+ size_y += i;
+ size.y = size_y;
+
+ if (comp->v_bar)
+ size.x += comp->v_bar->rect.size.x;
+ return size;
+ }
+
+ void GridLayout::SetSize(Composite* comp) {
+ prj::vector& controls = comp->controls;
+ size_t controls_count = controls.size();
+
+ rectangle comp_bb = comp->GetBoundingBox();
+ if (!controls_count)
+ return;
+
+ if (controls_count == 1) {
+ Scrollable* scrollable = dynamic_cast(comp->controls.front());
+ if (scrollable) {
+ scrollable->rect.pos = 0.0f;
+ scrollable->SetSize(comp_bb.size);
+ return;
+ }
+ }
+
+ size_t control = 0;
+ vec2 pos = 0.0f;
+ for (size_t row = 0; row < rows && control < controls_count; row++) {
+ vec2 _pos = pos;
+ for (size_t column = 0; column < columns && control < controls_count; column++, control++) {
+ comp->controls.data()[control]->rect.pos = _pos;
+ comp->controls.data()[control]->SetSize({ column_size.data()[column], row_size.data()[row] });
+ _pos.x += column_size.data()[column] + spacing.x;
+ }
+ pos.y += row_size.data()[row] + spacing.y;
+ }
+ }
+
+ RowLayout::RowLayout(Flags flags) {
+ this->flags = flags;
+ spacing = 2.0f;
+ }
+
+ RowLayout::~RowLayout() {
+
+ }
+
+ vec2 RowLayout::GetSize(Composite* comp) {
+ if (!comp->controls.size()) {
+ vec2 size = comp->rect.size;
+ if (comp->v_bar)
+ size.x += comp->v_bar->rect.size.x;
+ return size;
+ }
+
+ vec2 size = 0.0f;
+ if (flags == VERTICAL) {
+ for (Control* i : comp->controls) {
+ vec2 _size = i->GetSize();
+ size.x = max_def(_size.x, size.x);
+ size.y += _size.y + spacing;
+ }
+ size.y -= spacing;
+ }
+ else {
+ for (Control* i : comp->controls) {
+ vec2 _size = i->GetSize();
+ size.x += _size.x + spacing;
+ size.y = max_def(_size.y, size.y);
+ }
+ size.x -= spacing;
+ }
+
+ if (comp->v_bar)
+ size.x += comp->v_bar->rect.size.x;
+ return size;
+ }
+
+ void RowLayout::SetSize(Composite* comp) {
+ rectangle comp_bb = comp->GetBoundingBox();
+ if (!comp->controls.size())
+ return;
+
+ if (comp->controls.size() == 1) {
+ Scrollable* scrollable = dynamic_cast(comp->controls.front());
+ if (scrollable) {
+ scrollable->rect.pos = 0.0f;
+ scrollable->SetSize(comp_bb.size);
+ return;
+ }
+ }
+
+ float_t pos = 0.0f;
+ if (flags == VERTICAL)
+ for (Control*& i : comp->controls) {
+ i->rect.pos = { 0.0f, pos };
+ float_t size_y = i->GetSize().y;
+ i->SetSize({ comp_bb.size.x, size_y });
+ pos += size_y + spacing;
+ }
+ else
+ for (Control*& i : comp->controls) {
+ i->rect.pos = { pos, 0.0f };
+ float_t size_x = i->GetSize().x;
+ i->SetSize({ size_x, comp_bb.size.y });
+ pos += size_x + spacing;
+ }
+ }
+
+ Group::Group(Composite* parent, Flags flag) : Composite(parent, (Flags)(flags & ~(VERTICAL | HORIZONTAL))) {
+
+ }
+
+ Group::~Group() {
+
+ }
+
+ void Group::Draw() {
+ print->SetFont(&font);
+
+ rectangle rect = GetRectangle();
+
+ float_t half_glyph_height = prj::floorf(font.GetFontGlyphHeight() * 0.5f);
+ rect.pos.y += half_glyph_height;
+ rect.size.y -= half_glyph_height;
+
+ print->SetColor(colors_current.border_color);
+ print->sub_140301390(rect, 2.0f);
+
+ rect.size += -1.0f;
+ print->SetColor(color_black);
+ print->sub_140301390(rect, 1.0f);
+
+ if (GetText().size()) {
+ rectangle rect = GetRectangle();
+
+ rect.pos.x += 2.0f;
+ rect.pos.y = rect.pos.y;
+ rect.size.x += 2.0f * -2.0f;
+ rect.size.y = font.GetFontGlyphHeight();
+
+ vec2 text_size = print->GetTextSize(GetText());
+ rect.size.x = min_def(text_size.x, rect.size.x);
+
+ print->SetFillColor(colors_current.background);
+ print->FillRectangle(rect);
+
+ print->SetColor(colors_current.foreground);
+ print->SetClipData(rect);
+ print->PrintText(GetText(), rect.pos.x, rect.pos.y);
+ }
+
+ Composite::Draw();
+ }
+
+ vec2 Group::GetSize() {
+ vec2 size = Composite::GetSize();
+ size.x += 2.0f * 2.0f;
+ size.y += font.GetFontGlyphHeight() + 2.0f;
+ return size;
+ }
+
+ rectangle Group::GetBoundingBox() {
+ float_t glyph_height = font.GetFontGlyphHeight();
+
+ rectangle rect = Scrollable::GetBoundingBox();
+ rect.pos.x += 2.0f;
+ rect.pos.y += glyph_height;
+ rect.size.x -= 2.0f * 2.0f;
+ rect.size.y -= glyph_height + 2.0f;
+ return rect;
+ }
+
+ Label::Label(Composite* parent, Flags flags) : Control(parent, flags) {
+
+ }
+
+ Label::~Label() {
+
+ }
+
+ void Label::Draw() {
+ rectangle rect = GetRectangle();
+ print->SetFont(&font);
+ vec2 text_size = print->GetTextSize(GetText());
+
+ float_t pos_x;
+ if (flags & FLAG_4000)
+ pos_x = rect.pos.x;
+ else if (flags & FLAG_20000)
+ pos_x = rect.pos.x + rect.size.x - text_size.x;
+ else
+ pos_x = rect.pos.x + (rect.size.x - text_size.x) * 0.5f;
+ float_t pos_y = rect.pos.y + (rect.size.y - text_size.y) * 0.5f;
+
+ print->SetColor(Field_A0()
+ ? colors_current.foreground
+ : colors_current.disable_foreground);
+ print->SetClipData(rect);
+ print->SetFont(&font);
+ print->PrintText(GetText(), pos_x, pos_y);
+ }
+
+ vec2 Label::GetSize() {
+ print->SetFont(&font);
+ return print->GetTextSize(text) + 2.0f * 2.0f;
+ }
+
+ Button::Button(Composite* parent, Flags flags) : Control(parent, flags), value(), callback(), field_100() {
+ field_104 = 1;
+ SetSize(GetSize());
+ }
+
+ Button::~Button() {
+
+ }
+
+ void Button::Draw() {
+ print->SetFont(&this->font);
+ vec2 checkbox_size = print->GetTextSize(L"[X]");
+
+ rectangle v6 = GetRectangle();
+ rectangle v8 = v6;
+
+ if (flags & (FLAG_8 | MULTISELECT)) {
+ int32_t v3;
+ if ((field_100 & 0x01) && (field_100 & 0x02)) {
+ v3 = 4;
+ v8.pos.x += 2.0f;
+ v8.size.x += -2.0f;
+ }
+ else
+ v3 = 2;
+
+ sub_1402EE3C0(v6, 2.0f, v3, &colors_current.button_background);
+
+ v8.pos += 2.0f;
+ v8.size -= 2.0f * 2.0f;
+ }
+ else if (flags & CHECKBOX) {
+ print->SetColor(colors_current.button_foreground);
+ print->SetClipData(v8);
+ print->PrintText(value ? L"[X]" : L"[ ]", v8.pos.x, v8.pos.y);
+
+ v8.size.x -= checkbox_size.x;
+ v8.pos.x += checkbox_size.x;
+ }
+ else if (flags & RADIOBUTTON) {
+ print->SetColor(colors_current.button_foreground);
+ print->SetClipData(v8);
+ print->PrintText(value ? L"(*)" : L"( )", v8.pos.x, v8.pos.y);
+
+ v8.size.x -= checkbox_size.x;
+ v8.pos.x += checkbox_size.x;
+ }
+
+ prj::wstring text = GetText();
+
+ print->SetFont(&font);
+ vec2 text_size = print->GetTextSize(text);
+
+ if (!(flags & (CHECKBOX | RADIOBUTTON))) {
+ float_t v5 = (v8.size.x - text_size.x) * 0.5f;
+ v8.pos.x = v8.pos.x + v5;
+ v8.size.x = v8.size.x + (v5 * -2.0f);
+ }
+
+ if (Field_A0()) {
+ print->SetColor(colors_current.button_foreground);
+ print->SetClipData(v8);
+ print->PrintText(text, v8.pos.x, v8.pos.y);
+ if (Field_60()) {
+ print->SetColor(colors_current.focus_border_color);
+ print->sub_140301390(v8, 1.0);
+ }
+ }
+ else {
+ print->SetColor(colors_current.button_disable_foreground);
+ print->SetClipData(v8);
+ print->PrintText(text, v8.pos.x, v8.pos.y);
+ }
+ }
+
+ int32_t Button::KeyCallback(const Widget::KeyCallbackData& data) {
+ if (!Field_A0())
+ return 0;
+
+ if (data.input[0] != 0x0D && data.input[0] != 0x20)
+ return Control::KeyCallback(data);
+
+ if (flags & CHECKBOX)
+ SetValue(!value);
+ else if (flags & RADIOBUTTON)
+ SetValue(true);
+
+ if (callback)
+ callback(this);
+
+ SelectionListener::CallbackData callback_data = this;
+ for (SelectionListener*& i : selection_listeners)
+ i->Callback(&callback_data);
+
+ field_100 &= ~0x102;
+ return Control::KeyCallback(data);
+ }
+
+ int32_t Button::MouseCallback(const Widget::MouseCallbackData& data) {
+ if (!Field_A0())
+ return 0;
+
+ field_100 &= ~0x01;
+ if (CheckHitPos(data.pos))
+ field_100 |= 0x01;
+
+ if (field_100 & 0x01) {
+ if ((data.input & 0xF0) && !Field_60())
+ Field_58();
+
+ if (data.input & 0x100) {
+ if (field_100 & 0x02)
+ field_100 = (field_100 & ~0x02) | 0x100;
+ }
+ else if (data.input & 0x10)
+ field_100 |= 0x2;
+ }
+
+ if (field_100 & 0x100) {
+ field_104--;
+
+ if (flags & CHECKBOX)
+ SetValue(!value);
+ else if (flags & RADIOBUTTON)
+ SetValue(true);
+
+ if (callback)
+ callback(this);
+
+ SelectionListener::CallbackData callback_data = this;
+ for (SelectionListener*& i : selection_listeners)
+ i->Callback(&callback_data);
+
+ field_100 &= ~0x102;
+ field_104 = 1;
+ }
+
+ return Control::MouseCallback(data);
+ }
+
+ vec2 Button::GetSize() {
+ print->SetFont(&font);
+ vec2 size = print->GetTextSize(text);
+
+ if (flags & FLAG_8) {
+ size.x += 2.0f;
+ size.x += 2.0f * 2.0f;
+ size.y += 2.0f * 2.0f;
+ }
+ else if (flags & RADIOBUTTON) {
+ print->SetFont(&font);
+ size.x += print->GetTextSize("(X)").x;
+ }
+ else if (flags & CHECKBOX) {
+ print->SetFont(&font);
+ size.x += print->GetTextSize("[X]").x;
+ }
+ return size;
+ }
+
+ void Button::AddSelectionListener(SelectionListener* value) {
+ selection_listeners.push_back(value);
+ }
+
+ void Button::SetValue(bool value) {
+ this->value = value;
+ if (!(flags & RADIOBUTTON))
+ return;
+
+ for (Control* i : parent_comp->controls) {
+ Button* button = (Button*)dynamic_cast