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(i); + if (button && button != this && button->flags & RADIOBUTTON) + button->value = false; + } + } + + List::List(Composite* parent, Flags flags) : Scrollable(parent, flags), field_148() { + hovered_item = -1; + selected_item = -1; + + max_items = -1; + if (flags & VERTICAL) + max_items = 10; + } + + List::~List() { + + } + + void List::Draw() { + if (flags & FLAG_800) { + rectangle rect; + color4u8* v3; + if (Field_A0()) { + rect = GetRectangle(); + v3 = 0; + } + else { + rect = GetRectangle(); + v3 = &colors_current.disable_background; + } + sub_1402EE3C0(rect, 2.0f, 2, v3); + } + + Scrollable::Draw(); + + float_t glyph_height = GetFontGlyphHeight(); + + float_t pos_y = 0.0f; + if (v_bar) + pos_y = prj::floorf(v_bar->value); + print->SetFont(&font); + + rectangle v21 = GetScrollableRectangle(); + + pos_y = -pos_y; + print->SetClipData(v21); + + size_t items_count = items.size(); + for (size_t i = 0; i < items_count; i++, pos_y += glyph_height) { + rectangle v22; + v22.pos.x = v21.pos.x; + v22.pos.y = v21.pos.y + pos_y; + v22.size.x = v21.size.x; + v22.size.y = glyph_height; + if (v21.pos.x + v21.size.x <= v21.pos.x + || v21.pos.y + pos_y + glyph_height <= v21.pos.y + || v21.size.y + v21.pos.y <= v21.pos.y + pos_y) + continue; + + bool selected = false; + bool hovered = false; + + color4u8 color; + if (!field_148) { + if ((flags & MULTISELECT) && selected_item == i || (flags & FLAG_2) && selections[i]) + selected = true; + + if (Field_60()) + hovered = hovered_item == i; + + if (selected) { + print->SetFillColor(colors_current.selection_background); + print->FillRectangle(v22); + color = colors_current.selection_foreground; + } + else if (Field_A0()) + color = colors_current.foreground; + else + color = colors_current.disable_foreground; + } + else { + if (hovered_item == i) { + print->SetFillColor(colors_current.popup_selection_background); + print->FillRectangle(v22); + color = colors_current.popup_selection_foreground; + } + else if (field_148) + color = colors_current.popup_foreground; + else if (Field_A0()) + color = colors_current.foreground; + else + color = colors_current.disable_foreground; + } + + print->SetColor(color); + print->SetFont(&font); + print->PrintText(items[i], v21.pos.x, pos_y + v21.pos.y); + + if (hovered) { + print->SetColor(colors_current.focus_border_color); + print->sub_140301390(v22, 1.0f); + } + } + } + + void List::Reset() { + items.clear(); + items.shrink_to_fit(); + selections.clear(); + Scrollable::Reset(); + } + + int32_t List::KeyCallback(const Widget::KeyCallbackData& data) { + size_t items_count = items.size(); + if (!data.input[0] || !items_count) + return Control::KeyCallback(data); + + size_t hovered_item = this->hovered_item; + + SelectionListener::CallbackData v12 = v_bar; + + size_t max_items_visible = GetMaxItemsVisible(); + switch (data.input[0]) { + case 0x1000001: + if (hovered_item == -1) + hovered_item = 0; + else if (hovered_item) + hovered_item--; + + if (sub_1402F1F20(hovered_item) && !sub_1402F1F20(hovered_item)) + v12.field_8 = data.input[0]; + break; + case 0x1000002: + if (hovered_item == -1) + hovered_item = 0; + else if (hovered_item < items_count - 1) + hovered_item++; + + if (sub_1402F1F20(hovered_item) && !sub_1402F1F20(hovered_item)) + v12.field_8 = data.input[0]; + break; + case 0x1000005: + if (hovered_item == -1 || hovered_item < max_items_visible) + hovered_item = 0; + else + hovered_item -= max_items_visible; + v12.field_8 = data.input[0]; + break; + case 0x1000006: + if (hovered_item == -1) + hovered_item = 0; + else if (max_items_visible >= items_count + || hovered_item > items_count - max_items_visible - 1) + hovered_item = items_count - 1; + else + hovered_item += max_items_visible; + v12.field_8 = data.input[0]; + break; + case 0x1000007: + hovered_item = 0; + v12.field_8 = data.input[0]; + break; + case 0x1000008: + hovered_item = items_count - 1; + v12.field_8 = data.input[0]; + break; + } + + if (hovered_item < items_count && hovered_item != -1 && this->hovered_item != hovered_item) { + SetItemIndex(hovered_item); + + SelectionListener::CallbackData callback_data = parent; + for (SelectionListener*& i : selection_listeners) + i->Callback(&callback_data); + + if (v12.field_8 && v_bar) + ScrollBar::sub_1402E6CC0(v12); + + sub_1402F9C90(hovered_item); + } + + return Control::KeyCallback(data); + } + + int32_t List::MouseCallback(const Widget::MouseCallbackData& data) { + if (!Field_A0() || !CheckHitPos(data.pos)) + return 0; + + if (!field_148 && (data.input & 0xF0) && !Field_60()) + Field_58(); + + rectangle v27 = GetScrollableRectangle(); + if (v27.pos.x > data.pos.x || data.pos.x >= v27.size.x + v27.pos.x + || v27.pos.y > data.pos.y || data.pos.y >= v27.size.y + v27.pos.y) + return Scrollable::MouseCallback(data); + + size_t hovered_item = this->hovered_item; + if (field_148 && (data.input & 0x40000000) || (data.input & 0x10)) { + float_t glyph_height = GetFontGlyphHeight(); + float_t v10 = (float_t)sub_1402EF570(); + if (v10 < 0.0f) + v10 += (float_t)UINT64_MAX; + + size_t v11 = 0; + float_t v12 = (data.pos.y - (v27.pos.y - v10 * glyph_height)) / glyph_height; + + if (v12 >= (float_t)INT64_MAX) { + v12 -= (float_t)INT64_MAX; + if (v12 < (float_t)INT64_MAX) + v11 = 0x8000000000000000u; + } + + size_t hovered_item = v11 + (int64_t)v12; + if (hovered_item < items.size()) + this->hovered_item = hovered_item; + } + + if (hovered_item < this->items.size()) { + if (data.input & 0x10) { + if (data.modifier & 0x20000) { + ResetSelectedItem(); + size_t end = this->hovered_item; + size_t begin = hovered_item; + if (end < begin) { + begin = this->hovered_item; + end = hovered_item; + } + + SetSelectedItems(begin, end); + } + else if (data.modifier & 0x40000) { + if (CheckItemSelected(hovered_item)) + UnsetSelectedItem(hovered_item); + else + SetSelectedItem(hovered_item); + } + else { + ResetSelectedItem(); + SetSelectedItem(this->hovered_item); + } + + SelectionListener::CallbackData v26 = parent; + for (SelectionListener*& i : selection_listeners) + i->Callback(&v26); + } + + if (data.input & 0x1000) { + SelectionListener::CallbackData v26 = parent; + for (SelectionListener*& i : selection_listeners) + i->Field_10(&v26); + } + } + + if ((data.input & 0x100000) || (data.input & 0x200000)) + return Scrollable::MouseCallback(data); + return 0; + } + + void List::SetSize(const vec2& size) { + Scrollable::SetSize(size); + SetScrollBarParams(); + } + + vec2 List::GetSize() { + print->SetFont(&font); + + float_t max_text_size = 0.0f; + for (prj::wstring& i : items) { + vec2 text_size = print->GetTextSize(i); + max_text_size = max_def(text_size.x, max_text_size); + } + + size_t max_items_visible = GetMaxItemsVisible(); + size_t items_count = items.size(); + float_t glyph_height = font.GetFontGlyphHeight(); + + float_t v14 = (float_t)(int64_t)min_def(max_items_visible, items_count); + if (v14 < 0.0f) + v14 += (float_t)UINT64_MAX; + + vec2 size = { max_text_size, glyph_height * v14 }; + if (v_bar) + size.x += v_bar->rect.size.x; + + if (flags & FLAG_800) + size += 2.0f * 2.0f; + return size; + } + + void List::AddItem(const prj::string& str) { + std::string temp_utf8(str.data(), str.size()); + std::wstring temp_utf16(utf8_to_utf16(temp_utf8)); + items.push_back(prj::wstring(temp_utf16.data(), temp_utf16.size())); + } + + void List::AddItem(const prj::wstring& str) { + items.push_back(str); + } + + void List::AddSelectionListener(SelectionListener* value) { + selection_listeners.push_back(value); + } + + void List::Callback(SelectionListener::CallbackData* data) { + if (data->widget) + for (SelectionListener*& i : selection_listeners) + i->Callback(data); + } + + bool List::CheckItemSelected(size_t index) { + if (index >= items.size()) + return false; + else if (flags & MULTISELECT) + return index == selected_item; + return selections[index] != 0; + } + + void List::ClearItems() { + items.clear(); + selections.clear(); + hovered_item = -1; + selected_item = -1; + } + + prj::string List::GetItemStr(size_t index) const { + std::wstring temp_utf16(items[index].data(), items[index].size()); + std::string temp_utf8(utf16_to_utf8(temp_utf16)); + return prj::string(temp_utf8.data(), temp_utf8.size()); + } + + prj::wstring List::GetItem(size_t index) const { + return items[index]; + } + + size_t List::GetItemCount() { + return items.size(); + } + + size_t List::GetMaxItemsVisible() { + if (!v_bar) + return items.size(); + else if (max_items >= items.size()) + return items.size(); + return max_items; + } + + void List::ResetSelectedItem() { + if (flags & MULTISELECT) + selected_item = -1; + else + for (int32_t& i : selections) + i = 0; + } + + void List::SetMaxItems(size_t value) { + max_items = value; + } + + void List::SetScrollBarParams() { + rectangle bb = GetBoundingBox(); + if (v_bar) + v_bar->SetParams(bb.size.y, font.GetFontGlyphHeight(), items.size()); + } + + void List::SetSelectedItem(size_t index) { + if (index < items.size()) + if (flags & MULTISELECT) + selected_item = index; + else + selections[index] = 1; + } + + void List::SetSelectedItems(size_t begin, size_t end) { + if (end < begin || end >= items.size()) + return; + + if (flags & MULTISELECT) { + if (begin == end) + selected_item = begin; + } + else + for (size_t i = begin; i <= end; i++) + selections[i] = 1; + } + + void List::UnsetSelectedItem(size_t index) { + if (index < items.size()) + if (flags & MULTISELECT) + selected_item = -1; + else + selections[index] = 0; + } + + int64_t List::sub_1402EF570() { + float_t glyph_height = GetFontGlyphHeight(); + + float_t v4 = 0.0f; + if (v_bar) + v4 = prj::floorf(v_bar->value / glyph_height); + + int64_t v6 = 0; + if (v4 >= (float_t)INT64_MAX) { + v4 -= (float_t)INT64_MAX; + if (v4 < (float_t)INT64_MAX) + v6 = 0x8000000000000000u; + } + return v6 + (int64_t)v4; + } + + bool List::sub_1402F1F20(size_t index) { + size_t max_items_visible = GetMaxItemsVisible(); + size_t v5 = sub_1402EF570(); + return max_items_visible >= items.size() + || v5 <= index && index < max_items_visible + v5; + } + + void List::sub_1402F9680(int64_t index) { + if (!v_bar) + return; + + float_t glyph_height = GetFontGlyphHeight(); + + size_t max_items_visible = GetMaxItemsVisible(); + size_t items_count = items.size(); + if (items_count <= max_items_visible) + return; + + float_t value = 0.0f; + if (index != -1) { + if (items_count - index >= max_items_visible) + value = (float_t)index; + else + value = (float_t)(items_count - max_items_visible); + + if (value < 0.0f) + value += (float_t)UINT64_MAX; + + value *= glyph_height; + } + + v_bar->SetValue(value); + } + + void List::sub_1402F9C90(size_t index) { + if (!sub_1402F1F20(index)) + sub_1402F9680(index); + } + + ListBox::ListBox(Composite* parent, Flags flags) : Composite(parent, flags), list(), field_118() { + list = new List(this, flags); + list->field_148 = true; + list->SetText(L"ddl"); + list->parent = this; + + if (list->v_bar) { + list->v_bar->parent = this; + list->v_bar->AddSelectionListener(&drop_down_list_scroll_bar_selection_listener); + } + } + + ListBox::~ListBox() { + + } + + void ListBox::Draw() { + if (!parent_shell->field_170) { + rectangle v13 = GetRectangle(); + sub_1402EE3C0(v13, 2.0, 4, Field_A0() + ? &colors_current.background + : &colors_current.disable_background); + v13.pos = v13.pos + 2.0f; + v13.size = v13.size - 2.0f * 2.0f; + + rectangle v14 = v13; + + vec2 glyph_size = font.GetFontGlyphSize(); + + rectangle v15; + v15.pos = v13.pos + v13.size - glyph_size; + v15.size = glyph_size; + + print->SetFont(&font); + print->SetColor(colors_current.foreground); + print->sub_140301390(v15, 1.0f); + print->SetClipData(v15); + print->PrintText(L"v", v15.pos.x, v15.pos.y); + + v14.size.x -= glyph_size.x; + + if (Field_60()) { + print->SetColor(colors_current.focus_border_color); + print->sub_140301390(v14, 1.0f); + } + + if (list->selected_item < list->items.size()) { + print->SetFont(&font); + print->SetColor(Field_A0() + ? colors_current.foreground + : colors_current.disable_foreground); + print->SetClipData(v14); + print->PrintText(GetItem(list->selected_item), v14.pos.x, v14.pos.y); + } + } + + if (parent_shell->field_170 && field_118) { + rectangle rect = GetListRectangle(); + print->SetFillColor(colors_current.popup_background); + print->FillRectangle(rect); + list->UpdateDraw(); + print->SetColor(color_black); + print->sub_140301390(rect, 1.0f); + } + } + + void ListBox::Reset() { + Composite::Reset(); + } + + int32_t ListBox::KeyCallback(const Widget::KeyCallbackData& data) { + if (!Field_A0()) + return 0; + + list->KeyCallback(data); + if (field_118 && data.input[0] == 0x0D) + sub_1402E4F40(); + return 0; + } + + int32_t ListBox::MouseCallback(const Widget::MouseCallbackData& data) { + if (!Field_A0()) + return 0; + + if ((data.input & 0xF0) && !Field_60()) + Field_58(); + + if (field_118) { + list->MouseCallback(data); + + if ((data.input & 0x10) && (!list->CheckHitPos(data.pos) + || ListBox::sub_1402EC8C0(list->GetScrollableRectangle(), data.pos))) { + sub_1402E4F40(); + return 0; + } + } + else if (CheckHitPos(data.pos) && (data.input & 0x10)) + sub_1402E4F90(); + return 0; + } + + vec2 ListBox::GetSize() { + vec2 size = list->GetSize(); + size.x += font.GetFontGlyphWidth(); + size.y = font.GetFontGlyphHeight(); + return size + 2.0f * 2.0f; + } + + void ListBox::SetFont(p_Font& value) { + Scrollable::SetFont(value); + + if (list) + list->SetFont(value); + } + + rectangle ListBox::GetListRectangle() { + return list->GetRectangle(); + } + + void ListBox::sub_1402E4440() { + rectangle rect = GetRectangle(); + vec2 size = list->GetSize(); + + vec2 pos; + if (dw_gui_detail_display->init_data.field_0.pos.y + + dw_gui_detail_display->init_data.field_0.size.y > rect.pos.y + rect.size.y + size.y) + pos.y = rect.size.y; + else + pos.y = -size.y; + + list->rect.pos = pos; + list->SetSize({ max_def(rect.size.x, size.x), size.y }); + } + + void ListBox::sub_1402E4F40() { + parent_shell->sub_1402E61F0(this); + dw_gui_detail_display_set_selected_widget(this, false); + + list->hovered_item = list->selected_item; + field_118 = false; + } + + void ListBox::sub_1402E4F90() { + field_118 = true; + sub_1402E4440(); + + list->hovered_item = list->selected_item; + list->sub_1402F9C90(list->selected_item); + + dw_gui_detail_display_set_selected_widget(this, true); + parent_shell->sub_1402E43C0(this); + } + + bool ListBox::sub_1402EC8C0(rectangle rect, vec2 pos) { + return (rect.pos.x <= pos.x && pos.x < rect.pos.x + rect.size.x) + && (rect.pos.y <= pos.y && pos.y < rect.pos.y + rect.size.y); + } + + ScrollBar::ScrollBar(Control* parent, Flags flags) : Widget(parent, flags), + value(), min(), field_A0(), field_A5(), field_A6() { + parent_control = parent; + max = 100.0f; + field_94 = 10.0f; + step = 1.0f; + step_fast = 10.0f; + round = true; + font = p_font_type_scroll_bar; + SetSize({ 8.0f, 8.0f }); + } + + ScrollBar::~ScrollBar() { + + } + + void ScrollBar::Draw() { + rectangle v14 = GetRectangle(); + print->SetColor(colors_current.border_color); + print->sub_140301390(v14, 1.0f); + print->SetClipData(v14); + print->SetColor(Field_60() + ? colors_current.foreground + : colors_current.disable_foreground); + print->SetFont(&font); + + vec2 glyph_size = font.GetFontGlyphSize(); + rectangle v16; + v16.pos = v14.pos; + v16.size = glyph_size; + + if (flags & HORIZONTAL) { + print->sub_140301390(v16, 1.0f); + print->PrintText(L"<", v14.pos.x, v14.pos.y); + + v16.pos.x = v14.size.x + v14.pos.x - glyph_size.x; + print->sub_140301390(v16, 1.0f); + print->PrintText(L">", v14.size.x + v14.pos.x - v16.size.x, v14.pos.y); + + rectangle v18 = v14; + v18.pos.x = v14.pos.x + glyph_size.x; + v18.size.x = v14.size.x - v16.size.x * 2.0f; + print->SetFillColor(color_grey); + print->FillRectangle(v18); + + vec2 v11 = sub_1402E4790(); + rectangle v17 = v18; + v17.pos.x = v11.x + v18.pos.x; + v17.size.x = v11.y; + print->SetFillColor(colors_current.background); + print->FillRectangle(v17); + print->sub_140301390(v17, 1.0f); + print->PrintText(L"#", v17.size.x * 0.5f + v17.pos.x - glyph_size.x * 0.5f, v17.pos.y); + } + else { + print->sub_140301390(v16, 1.0f); + print->PrintText(L"A", v14.pos.x, v14.pos.y); + + v16.pos.y = v14.size.y + v14.pos.y - glyph_size.y; + print->sub_140301390(v16, 1.0f); + print->PrintText(L"V", v14.pos.x, v14.size.y + v14.pos.y - v16.size.y); + + rectangle v18 = v14; + v18.pos.y = v14.pos.y + glyph_size.y; + v18.size.y = v14.size.y - v16.size.y * 2.0f; + print->SetFillColor(color_grey); + print->FillRectangle(v18); + + vec2 v11 = sub_1402E4790(); + rectangle v17 = v18; + v17.pos.y = v11.x + v18.pos.y; + v17.size.y = v11.y; + print->SetFillColor(colors_current.background); + print->FillRectangle(v17); + print->sub_140301390(v17, 1.0f); + print->PrintText(L"#", v17.pos.x, v17.size.y * 0.5f + v17.pos.y - glyph_size.y * 0.5f); + } + + } + + int32_t ScrollBar::KeyCallback(const Widget::KeyCallbackData& data) { + if (!Field_60()) + return 0; + + SelectionListener::CallbackData v6 = sub_1402E5140(data); + if (v6.widget) + for (SelectionListener*& i : selection_listeners) + i->Callback(&v6); + return 0; + } + + int32_t ScrollBar::MouseCallback(const Widget::MouseCallbackData& data) { + if (!Field_60()) + return 0; + + bool v4 = field_A6; + SelectionListener::CallbackData v8 = sub_1402E5380(data); + if (v4 != field_A6) + dw_gui_detail_display_set_selected_widget(this, field_A6); + + if (v8.widget) + for (SelectionListener*& i : selection_listeners) + i->Callback(&v8); + + return 0; + } + + void ScrollBar::SetSize(const vec2& size) { + if (flags & HORIZONTAL) { + rect.size.x = size.x; + rect.size.y = font.GetFontGlyphHeight(); + } + else { + rect.size.x = font.GetFontGlyphWidth(); + rect.size.y = size.y; + } + } + + vec2 ScrollBar::GetPos() { + vec2 pos = rect.pos; + Control* control = GetParentControl(); + if (control) { + pos += control->GetPos(); + Scrollable* scrollable = dynamic_cast(control); + if (scrollable && scrollable->flags & FLAG_800) + pos += 2.0f; + } + return pos; + } + + Control* ScrollBar::GetParentControl() { + return parent_control; + } + + void ScrollBar::SetFont(p_Font& value) { + font = value; + } + + bool ScrollBar::Field_58() { + return !field_A5; + } + + bool ScrollBar::Field_60() { + return GetParentControl()->Field_A0() && Field_58(); + } + + void ScrollBar::Field_68(bool value) { + field_A5 = !value; + } + + void ScrollBar::SetMax(float_t value) { + max = value; + } + + void ScrollBar::SetMin(float_t value) { + min = value; + } + + void ScrollBar::SetParams(float_t value, float_t min, + float_t max, float_t a5, float_t step, float_t step_fast) { + this->value = value; + this->field_94 = a5; + this->min = min; + this->step_fast = step_fast; + this->max = max; + this->step = step; + } + + void ScrollBar::SetParams(float_t size, float_t step, size_t items_count) { + if (!items_count) + return; + + float_t v5 = (float_t)(int64_t)items_count; + if (v5 < 0.0f) + v5 += (float_t)UINT64_MAX; + + float_t v6 = v5 * step; + if (v6 > size) { + min = 0.0f; + max = v6 - size; + field_94 = (size / v6) * (v6 - size); + ScrollBar::SetValue(value); + this->step = step; + + size_t v8 = 0; + float_t v9 = size / step; + if (v9 >= (float_t)INT64_MAX) { + v9 -= (float_t)INT64_MAX; + if (v9 < (float_t)INT64_MAX) + v8 = INT64_MIN; + } + + float_t v11 = (float_t)(int64_t)(v8 + (int64_t)v9); + if (v11 < 0.0f) + v11 += (float_t)UINT64_MAX; + step_fast = v11 * step; + } + else { + min = 0.0f; + max = 0.0f; + field_94 = v6; + SetValue(value); + this->step = step; + step_fast = v6; + } + } + + void ScrollBar::SetRound(bool value) { + round = value; + } + + void ScrollBar::SetValue(float_t value) { + value = clamp_def(value, min, max); + if (round) + this->value = prj::roundf(value / step) * step; + else + this->value = value; + } + + void ScrollBar::SetWidth(float_t value) { + vec2 glyph_size = font.GetFontGlyphSize(); + if (flags & HORIZONTAL) { + rect.size.x = value; + rect.size.y = glyph_size.y; + } + else { + rect.size.x = glyph_size.x; + rect.size.y = value; + } + } + + void ScrollBar::AddSelectionListener(SelectionListener* value) { + selection_listeners.push_back(value); + } + + vec2 ScrollBar::sub_1402E4790() { + vec2 glyph_size = font.GetFontGlyphSize(); + + float_t _glyph_size; + float_t size; + if (flags & HORIZONTAL) { + _glyph_size = glyph_size.x; + size = rect.size.x; + } + else { + _glyph_size = glyph_size.y; + size = rect.size.y; + } + + size -= _glyph_size * 2.0f; + float_t range = max - min; + if (range > 0.0) { + float_t v10 = max_def((field_94 * (1.0f / range)) * size, 20.0f); + float_t v11 = ((value - min) * (1.0f / range)) * (size - v10); + return { v11, v10 }; + } + + return { 0.0f, size }; + } + + SelectionListener::CallbackData ScrollBar::sub_1402E5140(const Widget::KeyCallbackData& key_callback_data) { + SelectionListener::CallbackData callback_data; + switch (key_callback_data.input[0]) { + case 0x1000001: + case 0x1000002: + case 0x1000005: + case 0x1000006: + case 0x1000007: + case 0x1000008: + callback_data.field_8 = key_callback_data.input[0]; + break; + case 0x1000003: + callback_data.field_8 = 0x1000001; + break; + case 0x1000004: + callback_data.field_8 = 0x1000002; + break; + default: + break; + } + + if (callback_data.field_8 != -1) { + callback_data.widget = this; + ScrollBar::sub_1402E6CC0(callback_data); + callback_data.widget = parent; + } + + return callback_data; + } + + SelectionListener::CallbackData ScrollBar::sub_1402E5380(const Widget::MouseCallbackData& mouse_callback_data) { + if (field_A6) { + SelectionListener::CallbackData callback_data; + if ((mouse_callback_data.input & 1) != 0) { + callback_data.field_8 = 1; + callback_data.mouse_pos = mouse_callback_data.pos; + } + else { + callback_data.field_8 = 0; + field_A6 = false; + } + + if (callback_data.field_8 != -1) { + callback_data.widget = this; + ScrollBar::sub_1402E6CC0(callback_data); + callback_data.widget = this->parent; + } + return callback_data; + } + + SelectionListener::CallbackData callback_data; + if (mouse_callback_data.input & 0x100000) + callback_data.field_8 = 0x1000071; + else if (mouse_callback_data.input & 0x200000) + callback_data.field_8 = 0x1000072; + + if (callback_data.field_8 == -1 && !CheckHitPos(mouse_callback_data.pos)) + return callback_data; + + vec2 glyph_size = font.GetFontGlyphSize(); + rectangle rect = GetRectangle(); + + float_t v8; + float_t v9; + float_t v10; + float_t v11; + if (flags & HORIZONTAL) { + v8 = glyph_size.x; + v9 = mouse_callback_data.pos.x; + v10 = glyph_size.x + rect.pos.x; + v11 = rect.size.x + rect.pos.x; + } + else { + v8 = glyph_size.y; + v9 = mouse_callback_data.pos.y; + v10 = glyph_size.y + rect.pos.y; + v11 = rect.size.y + rect.pos.y; + } + + if (mouse_callback_data.input & 0x1000000) { + if (v9 < v10) + callback_data.field_8 = 0x1000001; + else if (v11 - v8 < v9) + callback_data.field_8 = 0x1000002; + else { + vec2 v23 = sub_1402E4790(); + if (v23.x + v10 > v9) + callback_data.field_8 = 0x1000005; + else if (v9 > v23.x + v10 + v23.y) + callback_data.field_8 = 0x1000006; + } + } + + if (callback_data.field_8 == -1 && (mouse_callback_data.input & 0x01) && (mouse_callback_data.input & 0x40000000)) { + vec2 v23 = sub_1402E4790(); + rectangle rect = GetRectangle(); + + float_t v14; + float_t v15; + float_t v17; + float_t v18; + if (flags & HORIZONTAL) { + v14 = rect.pos.x + glyph_size.x + v23.x; + v15 = rect.pos.y; + v17 = v23.y; + v18 = rect.size.y; + } + else { + v14 = rect.pos.x; + v15 = rect.pos.y + glyph_size.y + v23.x; + v17 = rect.size.x; + v18 = v23.y; + } + + if (v14 <= mouse_callback_data.pos.x && mouse_callback_data.pos.x < v17 + v14 + && v15 <= mouse_callback_data.pos.y && mouse_callback_data.pos.y < v18 + v15) { + field_A6 = true; + if (flags & HORIZONTAL) + field_A0 = mouse_callback_data.pos.x - (v17 * 0.5f + v14); + else + field_A0 = mouse_callback_data.pos.y - (v18 * 0.5f + v15); + callback_data.field_8 = 1; + callback_data.mouse_pos = mouse_callback_data.pos; + } + } + + if (callback_data.field_8 != -1) { + callback_data.widget = this; + ScrollBar::sub_1402E6CC0(callback_data); + callback_data.widget = parent; + } + return callback_data; + } + + void ScrollBar::sub_1402F9670(float_t value) { + field_94 = value; + } + + void ScrollBar::sub_1402E6CC0(SelectionListener::CallbackData data) { + if (!data.field_8) + return; + + ScrollBar* scroll_bar = dynamic_cast(data.widget); + if (!scroll_bar) + return; + + float_t value = scroll_bar->value; + switch (data.field_8) { + case 1: { + vec2 glyph_size = scroll_bar->font.GetFontGlyphSize(); + rectangle v14 = scroll_bar->GetRectangle(); + float_t v6; + float_t v7; + float_t v8; + float_t v9; + if (scroll_bar->flags & HORIZONTAL) { + v6 = glyph_size.x; + v7 = data.mouse_pos.x; + v8 = v14.pos.x + glyph_size.x; + v9 = v14.pos.x + v14.size.x; + } + else { + v6 = glyph_size.y; + v7 = data.mouse_pos.y; + v8 = v14.pos.y + glyph_size.y; + v9 = v14.pos.y + v14.size.y; + } + + float_t v10 = v7 - scroll_bar->field_A0; + vec2 size = scroll_bar->sub_1402E4790(); + float_t v11 = v9 - v6 - v8 - size.y; + float_t v12 = v8 + size.y * 0.5f; + if (v12 >= v10) + value = scroll_bar->min; + else if (v10 >= v12 + v11) + value = scroll_bar->max; + else + value = scroll_bar->min + (v10 - v8 - size.y * 0.5f) / v11 * (scroll_bar->max - scroll_bar->min); + } break; + case 0x1000001: + value -= scroll_bar->step; + break; + case 0x1000002: + value += scroll_bar->step; + break; + case 0x1000005: + value -= scroll_bar->step_fast; + break; + case 0x1000006: + value += scroll_bar->step_fast; + break; + case 0x1000007: + value = scroll_bar->min; + break; + case 0x1000008: + value = scroll_bar->max; + break; + case 0x1000071: + if (scroll_bar->flags & VERTICAL) + value += scroll_bar->step * -3.0f; + break; + case 0x1000072: + if (scroll_bar->flags & VERTICAL) + value += scroll_bar->step * 3.0f; + break; + } + scroll_bar->SetValue(value); + } + + ShellCloseButton::ShellCloseButton(Shell* parent) : Button(parent) { + SetSize({ 14.0f, 14.0f }); + SetText(L"Close Box"); + callback = Callback; + field_100 = 0; + field_104 = 4; + } + + ShellCloseButton::~ShellCloseButton() { + + } + + void ShellCloseButton::Draw() { + print->SetFont(¤t_font); + + vec2 pos = GetPos(); + print->PrintText(!(field_100 & 2) || !(field_100 & 1) ? "x" : "*", pos.x, pos.y); + } + + vec2 ShellCloseButton::GetPos() { + return parent_comp->GetPos() + rect.pos; + } + + vec2 ShellCloseButton::GetSize() { + return current_font.GetFontGlyphSize(); + } + + void ShellCloseButton::Callback(Widget* data) { + ShellCloseButton* close_button = dynamic_cast(data); + if (close_button) + close_button->parent_shell->Hide(); + } + + Slider::Slider(Composite* parent, Flags flags) : Control(parent, flags) { + format = "%f"; + scroll_bar = new ScrollBar(this, (Flags)(flags & (HORIZONTAL | VERTICAL))); + scroll_bar->parent = this; + } + + Slider::~Slider() { + + } + + void Slider::Draw() { + rectangle rect = GetRectangle(); + print->SetClipData(rect); + + float_t pos_x = 0.0f; + if (GetText().size()) { + print->SetFont(&font); + print->SetColor(Field_A0() + ? colors_current.foreground + : colors_current.disable_foreground); + print->PrintText(GetText(), rect.pos.x, rect.pos.y); + pos_x = font.GetFontGlyphWidth() + print->GetTextSize(GetText()).x; + } + + print->SetFont(&font); + print->SetColor(Field_A0() + ? colors_current.foreground + : colors_current.disable_foreground); + + char buf[256]; + sprintf_s(buf, sizeof(buf), format, scroll_bar->value); + print->PrintText(buf, rect.pos.x + pos_x, rect.pos.y); + + scroll_bar->UpdateDraw(); + if (Field_A0() && Field_60()) { + print->SetColor(colors_current.focus_border_color); + print->sub_140301390(GetRectangle(), 1.0f); + } + } + + void Slider::Reset() { + if (scroll_bar) { + scroll_bar->Free(); + scroll_bar = 0; + } + + Control::Reset(); + } + + int32_t Slider::KeyCallback(const Widget::KeyCallbackData& data) { + if (!Field_A0()) + return 0; + + SelectionListener::CallbackData v6 = scroll_bar->sub_1402E5140(data); + if (v6.widget) + for (SelectionListener*& i : selection_listeners) + i->Callback(&v6); + return 0; + } + + int32_t Slider::MouseCallback(const Widget::MouseCallbackData& data) { + if (!Field_A0()) + return 0; + + if ((data.input & 0xF0) && !Field_60()) + Field_58(); + + bool v5 = scroll_bar->field_A6; + SelectionListener::CallbackData v9 = scroll_bar->sub_1402E5380(data); + if (v5 != scroll_bar->field_A6) + dw_gui_detail_display_set_selected_widget(this, scroll_bar->field_A6); + + if (v9.widget) + for (SelectionListener*& i : selection_listeners) + i->Callback(&v9); + return 0; + } + + void Slider::SetSize(const vec2& value) { + Widget::SetSize(value); + scroll_bar->rect.pos.x = value.x - scroll_bar->rect.size.x; + scroll_bar->rect.pos.y = 0.0f; + } + + void Slider::UpdateLayout() { + scroll_bar->rect.pos = { GetTextSize().x, 0.0f }; + SetSize(GetSize()); + } + + vec2 Slider::GetSize() { + vec2 v10 = Slider::GetTextSize(); + vec2 v11 = scroll_bar->rect.size; + + vec2 size; + size.x = v11.x + v10.x; + size.y = max_def(v11.y, v10.y); + return size; + } + + void Slider::AddSelectionListener(SelectionListener* value) { + selection_listeners.push_back(value); + } + + vec2 Slider::GetTextSize() { + vec2 size; + if (GetText().size()) { + print->SetFont(&font); + size.x += font.GetFontGlyphWidth() + print->GetTextSize(GetText()).x; + } + + char buf[0x100]; + sprintf_s(buf, sizeof(buf), format, scroll_bar->value); + size.x += font.GetFontGlyphWidth() + print->GetTextSize(buf).x; + return size; + } + + Slider* Slider::Create(Composite* parent, Flags flags, const char* name, const char* format, float_t width) { + Slider* slider = new Slider(parent, flags); + slider->scroll_bar->SetText(L"slider's bar"); + slider->SetText(name); + slider->format = format; + slider->scroll_bar->SetWidth(width); + return slider; + } + + Slider* Slider::Create(Composite* parent, Flags flags, + float_t pos_x, float_t pos_y, float_t width, float_t height, const char* text) { + Slider* slider = new Slider(parent, flags); + ScrollBar* scroll_bar = slider->scroll_bar; + slider->SetText(text); + scroll_bar->SetText(L"slider's bar"); + scroll_bar->SetSize({ width, height }); + print->SetFont(&slider->font); + vec2 size; + if (flags & HORIZONTAL) { + vec2 v21 = print->GetTextSize(slider->text); + vec2 v22 = print->GetTextSize(L"0000"); + scroll_bar->rect.pos.x = v21.x + v22.x; + scroll_bar->rect.pos.y = 0.0f; + size.x = v21.x + v22.x + scroll_bar->rect.size.x; + size.y = slider->font.GetFontGlyphHeight(); + } + else { + vec2 v21 = print->GetTextSize(slider->text); + vec2 v22 = print->GetTextSize(L"0000"); + size.x = slider->font.GetFontGlyphWidth(); + size.y = v21.x + v22.x + scroll_bar->rect.size.y; + } + slider->rect.pos = { pos_x, pos_y }; + slider->SetSize(size); + return slider; + } + + init_data::init_data() { + + } + + int32_t font_get_index(prj::string& name) { + for (auto& i : font_collection) + if (!i.second->GetName().compare(name)) { + current_font = *i.second; + return i.first; + } + + return -1; + } +} + +PrintWorkDebug::PrintWorkDebug() { + prio = spr::SPR_PRIO_29; + SetResolutionMode(RESOLUTION_MODE_MAX); +} + +namespace dw { + Print::Print(float_t width, float_t height) { + font = ¤t_font; + print_work = new PrintWorkDebug; + field_10 = color_black; + field_14 = color_white; + field_18 = { 0.0f, 0.0f, width, height }; + clip_data = field_18; + field_38 = 1.0f; + } + + Print::~Print() { + delete print_work; + } + + void Print::FillRectangle(rectangle rect) { + if (rect.size.x > 0.0f && rect.size.y > 0.0f) + print_work->FillRectangle(rect); + } + + vec2 Print::GetTextSize(prj::string& str) { + std::string temp_utf8(str.data(), str.size()); + std::wstring temp_utf16(utf8_to_utf16(temp_utf8)); + return GetTextSize(prj::wstring(temp_utf16.data(), temp_utf16.size())); + } + + vec2 Print::GetTextSize(prj::wstring& str) { + return print_work->GetTextSize(str.c_str(), str.c_str() + str.size()); + } + + vec2 Print::GetTextSize(const wchar_t* str, size_t length) { + return print_work->GetTextSize(str, str + length); + } + + void Print::PrintText(prj::string& str, float_t pos_x, float_t pos_y) { + std::string temp_utf8(str.data(), str.size()); + std::wstring temp_utf16(utf8_to_utf16(temp_utf8)); + PrintText(prj::wstring(temp_utf16.data(), temp_utf16.size()), pos_x, pos_y); + } + + void Print::PrintText(prj::wstring& str, float_t pos_x, float_t pos_y) { + PrintWorkDebug* print_work = this->print_work; + print_work->line_origin_loc = { pos_x, pos_y }; + print_work->text_current_loc = print_work->line_origin_loc; + print_work->PrintText(app::TEXT_FLAG_ALIGN_FLAG_LEFT, str.c_str(), str.c_str() + str.size()); + } + + void Print::SetColor(color4u8 value) { + print_work->color = value; + } + + void Print::SetFillColor(color4u8 value) { + print_work->fill_color = value; + } + + void Print::SetClipData(rectangle rect) { + clip_data = rect; + print_work->clip = true; + print_work->clip_data = clip_data; + } + + void Print::SetFont(p_Font* value) { + this->font = value; + print_work->SetFont(&value->ptr->font); + } + + void Print::sub_140301390(rectangle rect, float_t a3) { + color4u8 v3 = field_14; + + print_work->fill_color = print_work->color; + + rectangle v10; + v10.pos.x = rect.pos.x; + v10.pos.y = rect.pos.y; + v10.size.x = a3; + v10.size.y = rect.size.y; + FillRectangle(v10); + + v10.pos.x = rect.size.x + rect.pos.x - a3; + FillRectangle(v10); + + v10.pos.x = a3 + rect.pos.x; + v10.pos.y = rect.pos.y; + v10.size.x = rect.size.x - a3 - a3; + v10.size.y = a3; + FillRectangle(v10); + + v10.pos.y = rect.size.y + rect.pos.y - a3; + FillRectangle(v10); + + print_work->fill_color = v3; + } + + void Print::sub_140302800() { + SetClipData(field_18); + } +} + +dw::Shell* dw_gui_detail::Display::GetHoveredShell() { + auto i_begin = shells.end(); + auto i_end = shells.begin(); + for (auto i = i_begin; i != i_end;) { + i--; + + if (!(*i)->freed && (*i)->GetDisp()) { + rectangle rect = (*i)->GetRectangle(); + if (rect.pos.x <= mouse_callback_data.pos.x && mouse_callback_data.pos.x < rect.pos.x + rect.size.x + && rect.pos.y <= mouse_callback_data.pos.y && mouse_callback_data.pos.y < rect.pos.y + rect.size.y) + return *i; + } + } + + return 0; +} + +void dw_gui_detail::Display::MakeShellFirst(dw::Shell* value) { + if (!value) + return; + + auto i = shells.begin(); + auto i_end = shells.end(); + while (i != i_end) + if (*i == value) { + shells.erase(i); + shells.push_back(value); + break; + } + else + i++; +} + +void dw_gui_detail::Display::MakeShellLast(dw::Shell* value) { + if (!value) + return; + + auto i = shells.begin(); + auto i_end = shells.end(); + while (i != i_end) + if (*i == value) { + shells.erase(i); + shells.insert(shells.begin(), value); + break; + } + else + i++; +} + +void dw_gui_detail::Display::RemoveShell(dw::Shell* value) { + auto i = shells.begin(); + auto i_end = shells.end(); + while (i != i_end) + if (*i == value) { + shells.erase(i); + break; + } + else + i++; + + if (selected_shell == value) { + selected_shell = 0; + find_focus = true; + } + + if (howered_shell == value) + howered_shell = 0; + + if (move_resize_shell == value) + move_resize_shell = 0; +} + +static void dw_gui_detail_display_set_selected_widget(dw::Widget* widget, bool set) { + dw_gui_detail_display->selected_widget = set ? widget : 0; +} + +static void sub_1402EE3C0(rectangle rect, float_t border, int32_t type, color4u8* fill_color) { + if (type != 2 && type != 4) + return; + + color4u8 v26 = type == 2 ? dw::colors_current.border_light_color : dw::colors_current.border_dark_color; + color4u8 v25 = type == 2 ? dw::colors_current.border_dark_color : dw::colors_current.border_light_color; + + rectangle v24a; + v24a.pos.x = rect.pos.x; + v24a.pos.y = rect.pos.y; + v24a.size.x = rect.size.x; + v24a.size.y = border; + dw::print->SetFillColor(v26); + dw::print->FillRectangle(v24a); + + rectangle v24b; + v24b.pos.x = rect.pos.x; + v24b.pos.y = rect.pos.y + border; + v24b.size.x = border; + v24b.size.y = rect.size.y - border; + dw::print->SetFillColor(v26); + dw::print->FillRectangle(v24b); + + rectangle v24c; + v24c.pos.x = rect.pos.x + rect.size.x - border; + v24c.pos.y = rect.pos.y + border; + v24c.size.x = border; + v24c.size.y = rect.size.y - border; + dw::print->SetFillColor(v25); + dw::print->FillRectangle(v24c); + + rectangle v24d; + v24d.pos.x = rect.pos.x + border; + v24d.pos.y = rect.pos.y + rect.size.y - border; + v24d.size.x = rect.size.x - border; + v24d.size.y = border; + dw::print->SetFillColor(v25); + dw::print->FillRectangle(v24d); + + if (fill_color) { + rectangle v24; + v24.pos.x = border + rect.pos.x; + v24.pos.y = border + rect.pos.y; + v24.size.x = rect.size.x - border - border; + v24.size.y = rect.size.y - border - border; + dw::print->SetFillColor(*fill_color); + dw::print->FillRectangle(v24); + } +} diff --git a/src/DivaGL/dw.hpp b/src/DivaGL/dw.hpp new file mode 100644 index 0000000..8723b54 --- /dev/null +++ b/src/DivaGL/dw.hpp @@ -0,0 +1,922 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.hpp" +#include "../KKdLib/rectangle.hpp" +#include "../KKdLib/vec.hpp" +#include "color.hpp" +#include "print_work.hpp" +#include + +namespace dw { + enum Flags { + FLAG_1 = 0x0000001, + FLAG_2 = 0x0000002, + MULTISELECT = 0x0000004, + FLAG_8 = 0x0000008, + RADIOBUTTON = 0x0000010, + CHECKBOX = 0x0000020, + CLOSE_BUTTON = 0x0000040, + FLAG_80 = 0x0000080, + HORIZONTAL = 0x0000100, + VERTICAL = 0x0000200, + FLAG_400 = 0x0000400, + FLAG_800 = 0x0000800, + FLAG_1000 = 0x0001000, + FLAG_2000 = 0x0002000, + FLAG_4000 = 0x0004000, + FLAG_8000 = 0x0008000, + FLAG_10000 = 0x0010000, + FLAG_20000 = 0x0020000, + FLAG_40000 = 0x0040000, + FLAG_80000 = 0x0080000, + FLAG_100000 = 0x0100000, + FLAG_200000 = 0x0200000, + FLAG_400000 = 0x0400000, + FLAG_800000 = 0x0800000, + FLAG_1000000 = 0x1000000, + }; + + struct Font { + font_info font; + prj::string name; + bool half_width; + + Font(int32_t font_handler_index, prj::string& name); + Font(int32_t font_handler_index, prj::string& name, bool half_width); + + inline Font(int32_t font_handler_index, prj::string&& name) + : Font(font_handler_index, name) { + + } + + inline Font(int32_t font_handler_index, prj::string&& name, bool half_width) + : Font(font_handler_index, name, half_width) { + + } + + ~Font(); + + float_t GetFontGlyphHeight(); + vec2 GetFontGlyphSize(); + float_t GetFontGlyphWidth(); + prj::string GetName(); + void SetGlyphSize(float_t glyph_width, float_t glyph_height); + }; + + static_assert(sizeof(dw::Font) == 0x68, "\"dw::Font\" struct should have a size of 0x68"); + + struct p_Font { + Font* ptr; + + p_Font(); + + inline p_Font(Font* ptr) { + this->ptr = ptr; + } + + ~p_Font(); + + float_t GetFontGlyphHeight(); + vec2 GetFontGlyphSize(); + float_t GetFontGlyphWidth(); + prj::string GetName(); + void SetGlyphSize(float_t glyph_width, float_t glyph_height); + }; + + static_assert(sizeof(dw::p_Font) == 0x08, "\"dw::p_Font\" struct should have a size of 0x08"); + + class Widget; + + class SelectionListener { + public: + struct CallbackData { + int64_t field_0; + int32_t field_8; + int8_t field_C; + vec2 mouse_pos; + int32_t field_18; + Widget* widget; + + inline CallbackData() : field_0(), field_8(), field_C(), field_18(), widget() { + field_8 = -1; + } + + inline CallbackData(Widget* widget) : field_0(), field_8(), field_C(), field_18() { + this->widget = widget; + } + }; + + static_assert(sizeof(dw::SelectionListener::CallbackData) == 0x28, "\"dw::SelectionListener::CallbackData\" struct should have a size of 0x28"); + + typedef void(*CallbackFunc)(SelectionListener::CallbackData* data); + + SelectionListener(); + virtual ~SelectionListener(); + + virtual void Callback(CallbackData* data) = 0; + virtual void Field_10(CallbackData* data) = 0; + }; + + static_assert(sizeof(dw::SelectionListener) == 0x08, "\"dw::SelectionListener\" struct should have a size of 0x08"); + + class SelectionAdapter : public SelectionListener { + public: + SelectionAdapter(); + virtual ~SelectionAdapter() override; + + virtual void Callback(SelectionListener::CallbackData* data) override; + virtual void Field_10(SelectionListener::CallbackData* data) override; + }; + + static_assert(sizeof(dw::SelectionAdapter) == 0x08, "\"dw::SelectionAdapter\" struct should have a size of 0x08"); + + class SelectionListenerOnHook : public SelectionAdapter { + public: + typedef void(*CallbackFunc)(Widget* widget); + + CallbackFunc callback; + + SelectionListenerOnHook(); + SelectionListenerOnHook(SelectionListenerOnHook::CallbackFunc callback); + virtual ~SelectionListenerOnHook() override; + + virtual void Callback(SelectionListener::CallbackData* data) override; + }; + + static_assert(sizeof(dw::SelectionListenerOnHook) == 0x10, "\"dw::SelectionListenerOnHook\" struct should have a size of 0x10"); + + class Widget { + public: + typedef void(*Callback)(Widget* data); + + struct KeyCallbackData { + Widget* widget; + int32_t modifier; + int8_t field_C; + int8_t field_D; + int32_t input[2]; + + KeyCallbackData(); + }; + + static_assert(sizeof(dw::Widget::KeyCallbackData) == 0x18, "\"dw::Widget::KeyCallbackData\" struct should have a size of 0x18"); + + struct MouseCallbackData { + Widget* widget; + vec2 pos; + int32_t input; + int32_t modifier; + + MouseCallbackData(); + }; + + static_assert(sizeof(dw::Widget::MouseCallbackData) == 0x18, "\"dw::Widget::MouseCallbackData\" struct should have a size of 0x18"); + + bool freed; + + union { + int8_t i8; + uint8_t u8; + int16_t i16; + uint16_t u16; + int32_t i32; + uint32_t u32; + int64_t i64; + uint64_t u64; + void* v64; + } callback_data; + + Callback free_callback; + prj::wstring text; + rectangle rect; + Widget* parent; + Flags flags; + p_Font font; + + Widget(Widget* parent = 0, Flags flags = (Flags)0); + virtual ~Widget(); + + virtual void Draw(); + virtual void Reset(); + virtual prj::wstring GetText(); + virtual void SetText(prj::wstring& str); + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data); + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data); + virtual void SetSize(const vec2& value); + virtual vec2 GetPos(); + + bool CheckHitPos(const vec2& hit_pos); + void Free(); + float_t GetFontGlyphHeight(); + rectangle GetRectangle(); + void SetText(prj::string& str); + void UpdateDraw(); + + inline void SetText(prj::wstring&& str) { + SetText(str); + } + + inline void SetText(prj::string&& str) { + SetText(str); + } + + static void sub_1402F3770(Widget* widget); + }; + + static_assert(sizeof(dw::Widget) == 0x68, "\"dw::Widget\" struct should have a size of 0x68"); + + class KeyListener; + class MouseListener; + class MouseMoveListener; + class Composite; + class Shell; + class Menu; + + class Control : public Widget { + public: + bool field_68; + color4u8 foreground_color; + color4u8 background_color; + prj::vector key_listener; + prj::vector mouse_listener; + prj::vector mouse_move_listener; + Composite* parent_comp; + Shell* parent_shell; + Menu* parent_menu; + + Control(Composite* parent = 0, Flags flags = (Flags)0); + virtual ~Control() override; + + virtual void Draw() override; + virtual void Reset() override; + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data) override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + virtual vec2 GetPos() override; + + virtual void UpdateLayout(); + virtual vec2 GetSize(); + virtual bool Field_58(); + virtual bool Field_60(); + virtual void SetFont(p_Font& font); + virtual p_Font& GetFont(); + virtual void SetForegroundColor(color4u8 value); + virtual void SetBackgroundColor(color4u8 value); + virtual color4u8 GetForegroundColor(); + virtual color4u8 GetBackgroundColor(); + virtual bool Field_98(); + virtual bool Field_A0(); + virtual void Field_A8(bool value); + virtual Widget* GetHitWidget(const vec2& hit_pos); + + void SetParentMenu(Menu* menu); + }; + + static_assert(sizeof(dw::Control) == 0xD8, "\"dw::Control\" struct should have a size of 0xD8"); + + class ScrollBar; + + class Scrollable : public Control { + public: + ScrollBar* h_bar; + ScrollBar* v_bar; + + Scrollable(Composite* parent = 0, Flags flags = (Flags)0); + virtual ~Scrollable() override; + + virtual void Draw() override; + virtual void Reset() override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + virtual void SetSize(const vec2& value) override; + virtual void SetFont(p_Font& font) override; + virtual Widget* GetHitWidget(const vec2& hit_pos) override; + + virtual rectangle GetBoundingBox(); + + rectangle GetScrollableRectangle(); + }; + + static_assert(sizeof(dw::Scrollable) == 0xE8, "\"dw::Scrollable\" struct should have a size of 0xE8"); + + class Layout; + + class Composite : public Scrollable { + public: + size_t current_control; + Layout* layout; + prj::vector controls; + + Composite(Composite* parent = 0, Flags flags = (Flags)0); + virtual ~Composite() override; + + virtual void Draw() override; + virtual void Reset() override; + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data) override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + virtual void SetSize(const vec2& size) override; + + virtual void UpdateLayout() override; + virtual vec2 GetSize() override; + virtual bool Field_58() override; + virtual bool Field_60() override; + virtual Widget* GetHitWidget(const vec2& hit_pos) override; + + virtual bool Field_C0(); + virtual bool SetCurrentControl(Control* control); + + size_t GetControlIndex(Control* control); + void SetLayout(Layout* value); + + bool sub_1402F1E60(Control* control); + }; + + static_assert(sizeof(dw::Composite) == 0x110, "\"dw::Composite\" struct should have a size of 0x110"); + + class ShellCloseButton; + + class Shell : public Composite { + public: + typedef void(*Callback)(Shell* data); + + bool disp; + Callback disp_callback; + Callback hide_callback; + int64_t field_128; + bool destroy; + ShellCloseButton* close_button; + prj::vector children; + prj::vector menus; + bool field_170; + Widget* field_178; + + Shell(Shell* parent = 0, Flags flags + = (Flags)(FLAG_400 | FLAG_80 | CLOSE_BUTTON | CHECKBOX | RADIOBUTTON)); + virtual ~Shell() override; + + virtual void Draw() override; + virtual void Reset() override; + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data) override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + virtual void SetSize(const vec2& size) override; + virtual vec2 GetPos() override; + + virtual vec2 GetSize() override; + virtual bool Field_58() override; + virtual Widget* GetHitWidget(const vec2& hit_pos) override; + + virtual rectangle GetBoundingBox() override; + + virtual bool Field_C0() override; + virtual bool SetCurrentControl(Control* control) override; + + virtual void Hide(); + + void Disp(); + bool GetDisp(); + void SetDisp(bool value = false); + + void sub_1402E43C0(Widget* widget); + void sub_1402E61F0(Widget* widget); + void sub_1402F38B0(); + }; + + static_assert(sizeof(dw::Shell) == 0x180, "\"dw::Shell\" struct should have a size of 0x180"); + + class KeyListener { + public: + KeyListener(); + virtual ~KeyListener(); + + virtual void Field_8(const Widget::KeyCallbackData& data) = 0; + virtual void Field_10(const Widget::KeyCallbackData& data) = 0; + virtual void Field_18(const Widget::KeyCallbackData& data) = 0; + }; + + static_assert(sizeof(dw::KeyListener) == 0x08, "\"dw::KeyListener\" struct should have a size of 0x08"); + + class KeyAdapter : public KeyListener { + public: + KeyAdapter(); + virtual ~KeyAdapter() override; + + virtual void Field_8(const Widget::KeyCallbackData& data) override; + virtual void Field_10(const Widget::KeyCallbackData& data) override; + virtual void Field_18(const Widget::KeyCallbackData& data) override; + }; + + static_assert(sizeof(dw::KeyAdapter) == 0x08, "\"dw::KeyAdapter\" struct should have a size of 0x08"); + + class MouseListener { + public: + MouseListener(); + virtual ~MouseListener(); + + virtual void Field_8(const Widget::MouseCallbackData& data) = 0; + virtual void Field_10(const Widget::MouseCallbackData& data) = 0; + virtual void Field_18(const Widget::MouseCallbackData& data) = 0; + virtual void Field_20(const Widget::MouseCallbackData& data) = 0; + }; + + static_assert(sizeof(dw::MouseListener) == 0x08, "\"dw::MouseListener\" struct should have a size of 0x08"); + + class MouseAdapter : public MouseListener { + public: + MouseAdapter(); + virtual ~MouseAdapter() override; + + virtual void Field_8(const Widget::MouseCallbackData& data) override; + virtual void Field_10(const Widget::MouseCallbackData& data) override; + virtual void Field_18(const Widget::MouseCallbackData& data) override; + virtual void Field_20(const Widget::MouseCallbackData& data) override; + }; + + static_assert(sizeof(dw::MouseAdapter) == 0x08, "\"dw::MouseAdapter\" struct should have a size of 0x08"); + + class MouseMoveListener { + public: + MouseMoveListener(); + virtual ~MouseMoveListener(); + + virtual void Field_8(const Widget::MouseCallbackData& data) = 0; + }; + + static_assert(sizeof(dw::MouseMoveListener) == 0x08, "\"dw::MouseMoveListener\" struct should have a size of 0x08"); + + class Layout { + public: + Layout(); + virtual ~Layout(); + + virtual vec2 GetSize(Composite* comp) = 0; + virtual void SetSize(Composite* comp) = 0; + }; + + static_assert(sizeof(dw::Layout) == 0x08, "\"dw::Layout\" struct should have a size of 0x08"); + + __declspec(align(8)) class FillLayout : public Layout { + public: + Flags flags; + + FillLayout(Flags flags = VERTICAL); + virtual ~FillLayout() override; + + virtual vec2 GetSize(Composite* comp) override; + virtual void SetSize(Composite* comp) override; + }; + + static_assert(sizeof(dw::FillLayout) == 0x10, "\"dw::FillLayout\" struct should have a size of 0x10"); + + __declspec(align(8)) class GraphLayout : public Layout { + public: + Flags flags; + + GraphLayout(Flags flags = VERTICAL); + virtual ~GraphLayout() override; + + virtual vec2 GetSize(Composite* comp) override; + virtual void SetSize(Composite* comp) override; + }; + + static_assert(sizeof(dw::GraphLayout) == 0x10, "\"dw::GraphLayout\" struct should have a size of 0x10"); + + class GridLayout : public Layout { + public: + size_t rows; + prj::vector column_size; + prj::vector row_size; + size_t columns; + vec2 spacing; + + GridLayout(size_t columns = 2); + virtual ~GridLayout() override; + + virtual vec2 GetSize(Composite* comp) override; + virtual void SetSize(Composite* comp) override; + }; + + static_assert(sizeof(dw::GridLayout) == 0x50, "\"dw::GridLayout\" struct should have a size of 0x50"); + + class RowLayout : public Layout { + public: + Flags flags; + float_t spacing; + + RowLayout(Flags flags = VERTICAL); + virtual ~RowLayout() override; + + virtual vec2 GetSize(Composite* comp) override; + virtual void SetSize(Composite* comp) override; + }; + + static_assert(sizeof(dw::RowLayout) == 0x10, "\"dw::RowLayout\" struct should have a size of 0x10"); + + class Group : public Composite { + public: + Group(Composite* parent = 0, Flags flags = (Flags)0); + virtual ~Group() override; + + virtual void Draw() override; + + virtual vec2 GetSize() override; + + virtual rectangle GetBoundingBox() override; + }; + + static_assert(sizeof(dw::Group) == 0x110, "\"dw::Group\" struct should have a size of 0x110"); + + class Label : public Control { + public: + Label(Composite* parent = 0, Flags flags = (Flags)0); + virtual ~Label() override; + + virtual void Draw() override; + virtual vec2 GetSize() override; + }; + + static_assert(sizeof(dw::Label) == 0xD8, "\"dw::Label\" struct should have a size of 0xD8"); + + class Button : public Control { + public: + bool value; + prj::vector selection_listeners; + Widget::Callback callback; + int32_t field_100; + int32_t field_104; + + Button(Composite* parent = 0, Flags flags = (Flags)0); + virtual ~Button() override; + + virtual void Draw() override; + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data) override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + + virtual vec2 GetSize() override; + + void AddSelectionListener(SelectionListener* value); + void SetValue(bool value); + }; + + static_assert(sizeof(dw::Button) == 0x108, "\"dw::Button\" struct should have a size of 0x108"); + + class List : public Scrollable { + public: + prj::vector items; + prj::vector selections; + size_t hovered_item; + size_t selected_item; + prj::vector selection_listeners; + size_t max_items; + bool field_148; + + List(Composite* parent = 0, Flags flags = (Flags)0); + virtual ~List() override; + + virtual void Draw() override; + virtual void Reset() override; + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data) override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + virtual void SetSize(const vec2& size) override; + + virtual vec2 GetSize() override; + + void AddItem(const prj::string& str); + void AddItem(const prj::wstring& str); + void AddSelectionListener(SelectionListener* value); + void Callback(SelectionListener::CallbackData* data); + bool CheckItemSelected(size_t index); + void ClearItems(); + prj::string GetItemStr(size_t index) const; + prj::wstring GetItem(size_t index) const; + size_t GetItemCount(); + size_t GetMaxItemsVisible(); + void ResetSelectedItem(); + void SetMaxItems(size_t value); + void SetScrollBarParams(); + void SetSelectedItem(size_t index); + void SetSelectedItems(size_t begin, size_t end); + void UnsetSelectedItem(size_t index); + + inline void AddItem(const prj::string&& str) { + AddItem(str); + } + + inline void AddItem(const prj::wstring&& str) { + AddItem(str); + } + + inline prj::string GetHoveredItemStr() { + return GetItemStr(hovered_item); + } + + inline prj::wstring GetHoveredItem() { + return GetItem(hovered_item); + } + + inline prj::string GetSelectedItemStr() { + return GetItemStr(selected_item); + } + + inline prj::wstring GetSelectedItem() { + return GetItem(selected_item); + } + + inline void ResetSetSelectedItem(size_t index) { + ResetSelectedItem(); + SetSelectedItem(index); + } + + inline void SetItemIndex(size_t index) { + hovered_item = index; + ResetSetSelectedItem(index); + } + + int64_t sub_1402EF570(); + bool sub_1402F1F20(size_t index); + void sub_1402F9680(int64_t index); + void sub_1402F9C90(size_t index); + }; + + static_assert(sizeof(dw::List) == 0x150, "\"dw::List\" struct should have a size of 0x150"); + + class ListBox : public Composite { + public: + List* list; + bool field_118; + + ListBox(Composite* parent = 0, Flags flags = (Flags)(VERTICAL | MULTISELECT)); + virtual ~ListBox() override; + + virtual void Draw() override; + virtual void Reset() override; + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data) override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + + virtual vec2 GetSize() override; + virtual void SetFont(p_Font& value) override; + + rectangle GetListRectangle(); + + inline void AddItem(const prj::string& str) { + if (list) + list->AddItem(str); + } + + inline void AddItem(const prj::string&& str) { + if (list) + list->AddItem(str); + } + + inline void AddSelectionListener(SelectionListener* value) { + if (list) + list->AddSelectionListener(value); + } + + inline void ClearItems() { + if (list) + list->ClearItems(); + } + + inline prj::string GetItemStr(size_t index) { + if (list) + return list->GetItemStr(index); + return {}; + } + + inline prj::wstring GetItem(size_t index) { + if (list) + return list->GetItem(index); + return {}; + } + + inline size_t GetItemCount() { + if (list) + return list->GetItemCount(); + return 0; + } + + inline prj::string GetHoveredItemStr() { + if (list) + return list->GetHoveredItemStr(); + return {}; + } + + inline prj::wstring GetHoveredItem() { + if (list) + return list->GetHoveredItem(); + return {}; + } + + inline prj::string GetSelectedItemStr() { + if (list) + return list->GetSelectedItemStr(); + return {}; + } + + inline prj::wstring GetSelectedItem() { + if (list) + return list->GetSelectedItem(); + return {}; + } + + inline void SetItemIndex(size_t index) { + if (list) + list->SetItemIndex(index); + } + + inline void SetMaxItems(size_t value) { + if (list) + list->SetMaxItems(value); + } + + void sub_1402E4440(); + void sub_1402E4F40(); + void sub_1402E4F90(); + + static bool sub_1402EC8C0(rectangle rect, vec2 pos); + }; + + static_assert(sizeof(dw::ListBox) == 0x120, "\"dw::ListBox\" struct should have a size of 0x120"); + + class ScrollBar : public Widget { + public: + Control* parent_control; + prj::vector selection_listeners; + float_t value; + float_t min; + float_t max; + float_t field_94; + float_t step; + float_t step_fast; + float_t field_A0; + bool round; + bool field_A5; + bool field_A6; + __int64 field_A8; + __int64 field_B0; + __int64 field_B8; + __int64 field_C0; + __int64 field_C8; + __int64 field_D0; + __int64 field_D8; + __int64 field_E0; + __int64 field_E8; + __int64 field_F0; + __int64 field_F8; + __int64 field_100; + __int64 field_108; + __int64 field_110; + __int64 field_118; + __int64 field_120; + __int64 field_128; + __int64 field_130; + __int64 field_138; + __int64 field_140; + __int64 field_148; + __int64 field_150; + __int64 field_158; + __int64 field_160; + + ScrollBar(Control* parent, Flags flags); + virtual ~ScrollBar() override; + + virtual void Draw() override; + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data) override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + virtual void SetSize(const vec2& value) override; + virtual vec2 GetPos() override; + + virtual Control* GetParentControl(); + virtual void SetFont(p_Font& value); + virtual bool Field_58(); + virtual bool Field_60(); + virtual void Field_68(bool value); + + void SetMax(float_t value); + void SetMin(float_t value); + void SetParams(float_t value, float_t min, float_t max, + float_t a5, float_t step, float_t step_fast); + void SetParams(float_t size, float_t step, size_t items_count); + void SetRound(bool value); + void SetValue(float_t value); + void SetWidth(float_t value); + + void AddSelectionListener(SelectionListener* value); + + vec2 sub_1402E4790(); + SelectionListener::CallbackData sub_1402E5140(const Widget::KeyCallbackData& key_callback_data); + SelectionListener::CallbackData sub_1402E5380(const Widget::MouseCallbackData& mouse_callback_data); + void sub_1402F9670(float_t value); + + static void sub_1402E6CC0(SelectionListener::CallbackData callback_data); + }; + + static_assert(sizeof(dw::ScrollBar) == 0x168, "\"dw::ScrollBar\" struct should have a size of 0x168"); + + class ShellCloseButton : public Button { + public: + ShellCloseButton(Shell* parent); + virtual ~ShellCloseButton() override; + + virtual void Draw() override; + virtual vec2 GetPos() override; + + virtual vec2 GetSize() override; + + static void Callback(Widget* data); + }; + + static_assert(sizeof(dw::ShellCloseButton) == 0x108, "\"dw::ShellCloseButton\" struct should have a size of 0x108"); + + class Slider : public Control { + public: + const char* format; + prj::vector selection_listeners; + ScrollBar* scroll_bar; + + Slider(Composite* parent, Flags flags); + virtual ~Slider(); + + virtual void Draw() override; + virtual void Reset() override; + virtual int32_t KeyCallback(const Widget::KeyCallbackData& data) override; + virtual int32_t MouseCallback(const Widget::MouseCallbackData& data) override; + virtual void SetSize(const vec2& value) override; + + virtual void UpdateLayout() override; + virtual vec2 GetSize() override; + + void AddSelectionListener(SelectionListener* value); + vec2 GetTextSize(); + + static Slider* Create(Composite* parent, Flags flags, const char* text, + const char* format, float_t width = 128.f); + static Slider* Create(Composite* parent = 0, + Flags flags = (Flags)(FLAG_800 | HORIZONTAL), + float_t pos_x = 0.0f, float_t pos_y = 0.0f, + float_t width = 128.0f, float_t height = 20.0f, const char* text = "slider"); + + inline void SetMax(float_t value) { + scroll_bar->SetMax(value); + } + + inline void SetMin(float_t value) { + scroll_bar->SetMin(value); + } + + inline void SetParams(float_t value, float_t min, float_t max, + float_t a5, float_t step, float_t step_fast) { + scroll_bar->SetParams(value, min, max, a5, step, step_fast); + } + + inline void SetRound(bool value) { + scroll_bar->SetRound(value); + } + + inline void SetValue(float_t value) { + scroll_bar->SetValue(value); + } + + inline void sub_1402F9670(float_t value) { + scroll_bar->sub_1402F9670(value); + } + }; + + static_assert(sizeof(dw::Slider) == 0x100, "\"dw::Slider\" struct should have a size of 0x100"); + + struct init_data { + rectangle field_0; + rectangle field_10; + + init_data(); + }; + + static_assert(sizeof(dw::init_data) == 0x20, "\"dw::init_data\" struct should have a size of 0x20"); + + class DropDownListScrollBarSelectionListener : public SelectionAdapter { + public: + }; + + static_assert(sizeof(dw::DropDownListScrollBarSelectionListener) == 0x08, "\"dw::DropDownListScrollBarSelectionListener\" struct should have a size of 0x08"); + + class ScrollBarTestSelectionListener : public SelectionAdapter { + public: + }; + + static_assert(sizeof(dw::ScrollBarTestSelectionListener) == 0x08, "\"dw::ScrollBarTestSelectionListener\" struct should have a size of 0x08"); + + extern p_Font& current_font; + + extern p_Font& p_font_type_6x12; + extern p_Font& p_font_type_8x12; + extern p_Font& p_font_type_8x16; + extern p_Font& p_font_type_10x16; + extern p_Font& p_font_type_10x20; + extern p_Font& p_font_type_12x24; + extern p_Font& p_font_type_scroll_bar; + + extern int32_t font_get_index(prj::string& name); +} diff --git a/src/DivaGL/hook.cpp b/src/DivaGL/hook.cpp index 41c6bf7..04881e6 100644 --- a/src/DivaGL/hook.cpp +++ b/src/DivaGL/hook.cpp @@ -5,6 +5,7 @@ #include "hook.hpp" #include "Glitter/glitter.hpp" +#include "data_test/rob_osage_test.hpp" #include "mdl/disp_manager.hpp" #include "pv_game/pv_game.hpp" #include "rob/rob.hpp" @@ -76,6 +77,7 @@ HOOK(int32_t, FASTCALL, data_init, 0x0000000140192FF0) { rctx->init(); sprite_manager_init(); + rob_osage_test_init(); return ret; } diff --git a/src/DivaGL/object.cpp b/src/DivaGL/object.cpp index 6ab6547..fec0737 100644 --- a/src/DivaGL/object.cpp +++ b/src/DivaGL/object.cpp @@ -55,6 +55,8 @@ obj_mesh* (FASTCALL* object_info_get_mesh_by_index)(object_info object, int32_t = (obj_mesh * (FASTCALL*)(object_info object, int32_t mesh_index))0x0000000140459D40; int32_t(FASTCALL* object_info_get_mesh_index)(object_info object, const char* mesh_name) = (int32_t(FASTCALL*)(object_info object, const char* mesh_name))0x0000000140459DE0; +const char* (FASTCALL* object_database_get_object_name)(object_info obj_info) + = (const char* (FASTCALL*)(object_info obj_info))0x0000000140459F20; uint32_t(FASTCALL* object_database_get_object_info)(const char* name) = (uint32_t(FASTCALL*)(const char* name))0x0000000140459F80; obj* (FASTCALL* object_info_get_object)(object_info obj_info) diff --git a/src/DivaGL/object.hpp b/src/DivaGL/object.hpp index e600ffd..dc4aff9 100644 --- a/src/DivaGL/object.hpp +++ b/src/DivaGL/object.hpp @@ -585,6 +585,7 @@ static_assert(sizeof(obj_vertex_buffer) == 0x10, "\"obj_vertex_buffer\" struct s extern void (FASTCALL* object_database_unload_set)(int32_t set); extern obj_mesh* (FASTCALL* object_info_get_mesh_by_index)(object_info object, int32_t mesh_index); extern int32_t(FASTCALL* object_info_get_mesh_index)(object_info object, const char* mesh_name); +extern const char* (FASTCALL* object_database_get_object_name)(object_info obj_info); extern uint32_t(FASTCALL* object_database_get_object_info)(const char* name); extern obj* (FASTCALL* object_info_get_object)(object_info obj_info); extern obj_mesh_index_buffer* (FASTCALL* object_info_get_mesh_index_buffer)(object_info obj_info, int32_t a2);