mirror of
https://github.com/MadeOfJelly/MushMachine.git
synced 2025-06-19 19:26:36 +02:00
initial import, >900commits predate this
This commit is contained in:
130
framework/imgui/src/mm/imgui/file_shader_editor.cpp
Normal file
130
framework/imgui/src/mm/imgui/file_shader_editor.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
#include "./file_shader_editor.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#ifdef MM_OPENGL_3_GLES
|
||||
//#include <SDL_opengles2_gl2.h>
|
||||
#include <GLES3/gl3.h>
|
||||
#else
|
||||
#include <glad/glad.h>
|
||||
#endif
|
||||
|
||||
#include <IconsIonicons.h>
|
||||
|
||||
#include <cstdlib>
|
||||
//#include <charconv>
|
||||
|
||||
namespace MM {
|
||||
|
||||
FileShaderEditor::FileShaderEditor(Engine& engine) : FileTextEditor(engine) {
|
||||
setLanguageDefinition(TextEditor::LanguageDefinition::GLSL());
|
||||
shaderType = GL_FRAGMENT_SHADER;
|
||||
|
||||
_windowID = ICON_II_CODE " " ICON_II_IMAGE " File Shader Text Editor##";
|
||||
_windowID += std::to_string(rand()); // lets hope they dont collide
|
||||
}
|
||||
|
||||
void FileShaderEditor::postSave(void) {
|
||||
checkErrors();
|
||||
}
|
||||
|
||||
void FileShaderEditor::checkErrors(void) {
|
||||
_markers.clear();
|
||||
_te.SetErrorMarkers(_markers);
|
||||
|
||||
auto source = _te.GetText();
|
||||
const char* src = source.c_str();
|
||||
|
||||
uint32_t id = glCreateShader(shaderType);
|
||||
glShaderSource(id, 1, &src, nullptr);
|
||||
glCompileShader(id);
|
||||
|
||||
int32_t res;
|
||||
glGetShaderiv(id, GL_COMPILE_STATUS, &res);
|
||||
int length;
|
||||
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
|
||||
if (length) {
|
||||
char* msg = (char*) alloca(length * sizeof(char));
|
||||
glGetShaderInfoLog(id, length, &length, msg);
|
||||
handleErrorString(msg);
|
||||
}
|
||||
|
||||
glDeleteShader(id);
|
||||
}
|
||||
|
||||
void FileShaderEditor::handleErrorString(const char* msg) {
|
||||
// TODO: detect compiler info format
|
||||
handleErrorStringFormat1(msg);
|
||||
}
|
||||
|
||||
// accepts error messages in this format
|
||||
// msgs separated by newline
|
||||
// [number?]:[line number](char in line): [type eg. "error"]: [error text]
|
||||
// TODO: has alot of bugs, rework
|
||||
void FileShaderEditor::handleErrorStringFormat1(const char* msg) {
|
||||
std::istringstream stream;
|
||||
stream.str(msg);
|
||||
|
||||
for (std::string line; std::getline(stream, line);) {
|
||||
std::string_view view(line);
|
||||
|
||||
|
||||
view.remove_prefix(view.find(':')+1);
|
||||
auto next_pos = view.find('(');
|
||||
char* ptr = nullptr;
|
||||
unsigned int line_number = ::strtoul(&view[0], &ptr, 10);
|
||||
if (ptr != &view[next_pos]) {
|
||||
//std::cout << "error" << std::endl;
|
||||
continue;
|
||||
}
|
||||
// no support yet :(
|
||||
//unsigned int line_number = std::from_chars(&view[0], &view[next_pos-1], 10);
|
||||
view.remove_prefix(next_pos);
|
||||
|
||||
_markers.insert(std::make_pair(line_number, view));
|
||||
}
|
||||
|
||||
_te.SetErrorMarkers(_markers);
|
||||
}
|
||||
|
||||
void FileShaderEditor::renderImGui(void) {
|
||||
FileTextEditor::renderImGui();
|
||||
|
||||
// append to window
|
||||
if (ImGui::Begin(_windowID.c_str())) {
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
if (ImGui::BeginMenu("Shader")) {
|
||||
if (ImGui::BeginMenu("Error Checks")) {
|
||||
if (ImGui::MenuItem("Toggle Live Error Checks", nullptr, checkErrorsOnChange)) {
|
||||
checkErrorsOnChange = !checkErrorsOnChange;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Shader Type")) {
|
||||
if (ImGui::MenuItem("Vertex Shader", nullptr, shaderType == GL_VERTEX_SHADER)) {
|
||||
shaderType = GL_VERTEX_SHADER;
|
||||
}
|
||||
if (ImGui::MenuItem("Fragment Shader", nullptr, shaderType == GL_FRAGMENT_SHADER)) {
|
||||
shaderType = GL_FRAGMENT_SHADER;
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
|
||||
if(checkErrorsOnChange && _te.IsTextChanged()) {
|
||||
checkErrors();
|
||||
}
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
30
framework/imgui/src/mm/imgui/file_shader_editor.hpp
Normal file
30
framework/imgui/src/mm/imgui/file_shader_editor.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "./file_text_editor.hpp"
|
||||
|
||||
namespace MM {
|
||||
|
||||
class FileShaderEditor : public FileTextEditor {
|
||||
protected:
|
||||
TextEditor::ErrorMarkers _markers;
|
||||
|
||||
protected:
|
||||
void postSave(void) override;
|
||||
|
||||
void checkErrors(void);
|
||||
void handleErrorString(const char* msg);
|
||||
|
||||
void handleErrorStringFormat1(const char* msg);
|
||||
|
||||
public:
|
||||
FileShaderEditor(Engine& engine);
|
||||
|
||||
void renderImGui(void);
|
||||
|
||||
public:
|
||||
bool checkErrorsOnChange = true;
|
||||
|
||||
uint32_t shaderType;
|
||||
};
|
||||
} // MM
|
||||
|
236
framework/imgui/src/mm/imgui/file_text_editor.cpp
Normal file
236
framework/imgui/src/mm/imgui/file_text_editor.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
#include "./file_text_editor.hpp"
|
||||
|
||||
#include <mm/services/filesystem.hpp>
|
||||
#include <physfs.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <mm/imgui/widgets/filesystem.hpp>
|
||||
|
||||
#include <IconsIonicons.h>
|
||||
|
||||
#include <mm/logger.hpp>
|
||||
#define LOGFTE(x) LOG("FileTextEditor", x)
|
||||
|
||||
namespace MM {
|
||||
|
||||
FileTextEditor::FileTextEditor(Engine& engine) {
|
||||
_windowID = ICON_II_CODE " File Text Editor##";
|
||||
_windowID += std::to_string(rand()); // lets hope they dont collide
|
||||
|
||||
_fs_ptr = engine.tryService<MM::Services::FilesystemService>();
|
||||
}
|
||||
|
||||
void FileTextEditor::setLanguageDefinition(const TextEditor::LanguageDefinition& lang) {
|
||||
_te_lang = lang;
|
||||
_te.SetLanguageDefinition(_te_lang);
|
||||
}
|
||||
|
||||
void FileTextEditor::renderPopups(void) {
|
||||
if (ImGui::BeginPopupModal("Open File", nullptr,
|
||||
ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_NoSavedSettings)) {
|
||||
MM::ImGuiWidgets::FilePicker("open", *_fs_ptr, _tmp_file_path);
|
||||
|
||||
if (ImGui::Button("Load File")) {
|
||||
bool succ = open(_tmp_file_path);
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
if (!succ) {
|
||||
// TODO: handle error
|
||||
LOGFTE("error: opening file");
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal("Save File As", nullptr,
|
||||
ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_NoSavedSettings)) {
|
||||
MM::ImGuiWidgets::FilePicker("save", *_fs_ptr, _tmp_file_path, true);
|
||||
|
||||
if (ImGui::Button("Save")) {
|
||||
auto old = _file_path;
|
||||
_file_path = _tmp_file_path;
|
||||
|
||||
if (!save()) {
|
||||
LOGFTE(std::string("error: saving file as '") + _file_path + "'");
|
||||
_file_path = old; // retore in case of error
|
||||
}
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void FileTextEditor::renderImGui(bool* is_open) {
|
||||
if (ImGui::Begin(_windowID.c_str(), is_open, /*ImGuiWindowFlags_HorizontalScrollbar | */ImGuiWindowFlags_MenuBar)) {
|
||||
ImGui::SetWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
|
||||
|
||||
bool open_file_open = false;
|
||||
bool open_file_save = false;
|
||||
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Open")) {
|
||||
open_file_open = true;
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("New File")) {
|
||||
_file_path.clear();
|
||||
_tmp_file_path.clear();
|
||||
_te.SetText("");
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Save")) {
|
||||
save();
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Save as")) {
|
||||
open_file_save = true;
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Edit")) {
|
||||
if (_te.IsReadOnly() && ImGui::MenuItem("Enable Editing")) {
|
||||
_te.SetReadOnly(false);
|
||||
}
|
||||
|
||||
if (!_te.IsReadOnly() && ImGui::MenuItem("Disable Editing")) {
|
||||
_te.SetReadOnly(true);
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
|
||||
// popups
|
||||
{
|
||||
if (open_file_open)
|
||||
ImGui::OpenPopup("Open File");
|
||||
|
||||
if (open_file_save)
|
||||
ImGui::OpenPopup("Save File As");
|
||||
|
||||
renderPopups();
|
||||
}
|
||||
|
||||
auto cpos = _te.GetCursorPosition();
|
||||
|
||||
ImGui::Text("%6d/%-6d %6d lines | %s | %s | %s | %s",
|
||||
cpos.mLine + 1,
|
||||
cpos.mColumn + 1,
|
||||
_te.GetTotalLines(),
|
||||
_te.IsOverwrite() ? "Ovr" : "Ins",
|
||||
_te.CanUndo() ? "*" : " ",
|
||||
_te.GetLanguageDefinition().mName.c_str(), _file_path.c_str());
|
||||
|
||||
_te.Render("TextEditor");
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool FileTextEditor::open(Services::FilesystemService::fs_file_t file, bool write) {
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
//auto& fs = MM::locator::filesystem_service::ref();
|
||||
|
||||
_fs_ptr->seek(file, 0);
|
||||
|
||||
std::string text;
|
||||
//char buffer [265];
|
||||
//while (auto r = _fs_ptr->read(file, buffer, 265)) {
|
||||
//text.append(buffer, r);
|
||||
//}
|
||||
_fs_ptr->readString(file, text);
|
||||
|
||||
_te.SetText(text);
|
||||
|
||||
_te.SetReadOnly(!write);
|
||||
|
||||
postOpen();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileTextEditor::open(const std::string& path, bool write) {
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
//auto& fs = MM::locator::filesystem_service::ref();
|
||||
|
||||
auto h = _fs_ptr->open(path.c_str());
|
||||
if (!h)
|
||||
return false;
|
||||
|
||||
_file_path = path;
|
||||
|
||||
// lang detection
|
||||
{
|
||||
// TODO: make better
|
||||
std::string tmp = path.substr(path.size()-4);
|
||||
std::transform(tmp.begin(), tmp.end(), tmp.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
if (tmp == "glsl") {
|
||||
setLanguageDefinition(TextEditor::LanguageDefinition::GLSL());
|
||||
}
|
||||
}
|
||||
|
||||
return open(h, write) && _fs_ptr->close(h); // lul
|
||||
}
|
||||
|
||||
bool FileTextEditor::save(void) {
|
||||
if (_file_path.empty()/* || !_fs_ptr->exists(_file_path.c_str())*/)
|
||||
return false;
|
||||
|
||||
// create dir in write, if not exists (bug in physfs?)
|
||||
{
|
||||
std::string tmp = _file_path.substr(0, _file_path.find_last_of('/'));
|
||||
if (!tmp.empty()) {
|
||||
if (!PHYSFS_mkdir(tmp.c_str())) {
|
||||
LOGFTE("error making dir");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto h = _fs_ptr->open(_file_path.c_str(), Services::FilesystemService::WRITE);
|
||||
if (!h) {
|
||||
LOGFTE("error opening file for saving");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto text = _te.GetText();
|
||||
|
||||
auto written = _fs_ptr->write(h, text.c_str(), text.size());
|
||||
_fs_ptr->close(h);
|
||||
if (written != text.size()) {
|
||||
LOGFTE("written size not equal to text size");
|
||||
return false;
|
||||
}
|
||||
|
||||
postSave();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
42
framework/imgui/src/mm/imgui/file_text_editor.hpp
Normal file
42
framework/imgui/src/mm/imgui/file_text_editor.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <TextEditor.h>
|
||||
|
||||
#include <mm/services/filesystem.hpp>
|
||||
|
||||
namespace MM {
|
||||
|
||||
class FileTextEditor {
|
||||
protected:
|
||||
TextEditor _te;
|
||||
TextEditor::LanguageDefinition _te_lang;
|
||||
|
||||
std::string _file_path;
|
||||
std::string _tmp_file_path;
|
||||
|
||||
std::string _windowID;
|
||||
|
||||
Services::FilesystemService* _fs_ptr = nullptr;
|
||||
|
||||
protected:
|
||||
bool open(Services::FilesystemService::fs_file_t file, bool write = true);
|
||||
|
||||
void renderPopups(void);
|
||||
|
||||
virtual void postSave(void) {}
|
||||
virtual void postOpen(void) {}
|
||||
|
||||
public:
|
||||
FileTextEditor(Engine& engine);
|
||||
virtual ~FileTextEditor(void) {}
|
||||
|
||||
void renderImGui(bool* is_open = nullptr);
|
||||
|
||||
void setLanguageDefinition(const TextEditor::LanguageDefinition& lang);
|
||||
|
||||
bool open(const std::string& path, bool write = true);
|
||||
|
||||
bool save(void);
|
||||
};
|
||||
} // MM
|
||||
|
49
framework/imgui/src/mm/imgui/fps_overlay.cpp
Normal file
49
framework/imgui/src/mm/imgui/fps_overlay.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "./fps_overlay.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui_plot_var.hpp>
|
||||
|
||||
namespace MM {
|
||||
|
||||
void ImGuiSimpleFPSOverlay::renderImGui(void) {
|
||||
const float DISTANCE = 10.0f;
|
||||
|
||||
ImVec2 window_pos = ImVec2(DISTANCE, DISTANCE + 15.f);
|
||||
|
||||
ImVec2 window_pos_pivot = ImVec2(0.f, 0.f);
|
||||
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
|
||||
|
||||
ImGui::SetNextWindowBgAlpha(0.2f);
|
||||
ImGui::Begin("SimpleFPSOverlay", NULL,
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_NoSavedSettings |
|
||||
ImGuiWindowFlags_NoFocusOnAppearing |
|
||||
ImGuiWindowFlags_NoNav
|
||||
);
|
||||
|
||||
ImGui::Text("%.1f FPS", ImGui::GetIO().Framerate);
|
||||
|
||||
if (_show_plot) {
|
||||
ImGui::Separator();
|
||||
ImGui::PlotVar("frame time", ImGui::GetIO().DeltaTime, 0.f, 0.05f, 120);
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextWindow()) {
|
||||
if (ImGui::MenuItem("Show Plot", NULL, _show_plot)) {
|
||||
_show_plot = !_show_plot;
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PlotVarFlushOldEntries();
|
||||
}
|
||||
|
||||
} // namespace MM
|
||||
|
12
framework/imgui/src/mm/imgui/fps_overlay.hpp
Normal file
12
framework/imgui/src/mm/imgui/fps_overlay.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace MM {
|
||||
class ImGuiSimpleFPSOverlay {
|
||||
private:
|
||||
bool _show_plot = false;
|
||||
|
||||
public:
|
||||
void renderImGui(void);
|
||||
};
|
||||
} // namespace MM
|
||||
|
309
framework/imgui/src/mm/imgui/imgui_entt_entity_editor.hpp
Normal file
309
framework/imgui/src/mm/imgui/imgui_entt_entity_editor.hpp
Normal file
@ -0,0 +1,309 @@
|
||||
// for the license, see the end of the file
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
#ifndef MM_IEEE_ASSERT
|
||||
#define MM_IEEE_ASSERT(x) assert(x)
|
||||
#endif
|
||||
|
||||
#define MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY "MM_IEEE_ENTITY"
|
||||
|
||||
#ifndef MM_IEEE_ENTITY_WIDGET
|
||||
#define MM_IEEE_ENTITY_WIDGET ::MM::EntityWidget
|
||||
#endif
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <class EntityType>
|
||||
inline void EntityWidget(EntityType& e, entt::basic_registry<EntityType>& reg, bool dropTarget = false)
|
||||
{
|
||||
ImGui::PushID(static_cast<int>(entt::to_integral(e)));
|
||||
|
||||
if (reg.valid(e)) {
|
||||
ImGui::Text("ID: %d", entt::to_integral(e));
|
||||
} else {
|
||||
ImGui::Text("Invalid Entity");
|
||||
}
|
||||
|
||||
if (reg.valid(e)) {
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) {
|
||||
ImGui::SetDragDropPayload(MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY, &e, sizeof(e));
|
||||
ImGui::Text("ID: %d", entt::to_integral(e));
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
}
|
||||
|
||||
if (dropTarget && ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY)) {
|
||||
e = *(EntityType*)payload->Data;
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
template <class Component, class EntityType>
|
||||
void ComponentEditorWidget([[maybe_unused]] entt::basic_registry<EntityType>& registry, [[maybe_unused]] EntityType entity) {}
|
||||
|
||||
template <class Component, class EntityType>
|
||||
void ComponentAddAction(entt::basic_registry<EntityType>& registry, EntityType entity)
|
||||
{
|
||||
registry.template emplace<Component>(entity);
|
||||
}
|
||||
|
||||
template <class Component, class EntityType>
|
||||
void ComponentRemoveAction(entt::basic_registry<EntityType>& registry, EntityType entity)
|
||||
{
|
||||
registry.template remove<Component>(entity);
|
||||
}
|
||||
|
||||
template <class EntityType>
|
||||
class EntityEditor {
|
||||
public:
|
||||
using Registry = entt::basic_registry<EntityType>;
|
||||
using ComponentTypeID = ENTT_ID_TYPE;
|
||||
|
||||
struct ComponentInfo {
|
||||
using Callback = std::function<void(Registry&, EntityType)>;
|
||||
std::string name;
|
||||
Callback widget, create, destroy;
|
||||
};
|
||||
|
||||
bool show_window = true;
|
||||
|
||||
private:
|
||||
std::map<ComponentTypeID, ComponentInfo> component_infos;
|
||||
|
||||
bool entityHasComponent(Registry& registry, EntityType& entity, ComponentTypeID type_id)
|
||||
{
|
||||
ComponentTypeID type[] = { type_id };
|
||||
return registry.runtime_view(std::cbegin(type), std::cend(type)).contains(entity);
|
||||
}
|
||||
|
||||
public:
|
||||
template <class Component>
|
||||
ComponentInfo& registerComponent(const ComponentInfo& component_info)
|
||||
{
|
||||
auto index = entt::type_info<Component>::id();
|
||||
[[maybe_unused]] auto [it, insert_result] = component_infos.insert_or_assign(index, component_info);
|
||||
MM_IEEE_ASSERT(insert_result);
|
||||
return std::get<ComponentInfo>(*it);
|
||||
}
|
||||
|
||||
template <class Component>
|
||||
ComponentInfo& registerComponent(const std::string& name, typename ComponentInfo::Callback widget)
|
||||
{
|
||||
return registerComponent<Component>(ComponentInfo{
|
||||
name,
|
||||
widget,
|
||||
ComponentAddAction<Component, EntityType>,
|
||||
ComponentRemoveAction<Component, EntityType>,
|
||||
});
|
||||
}
|
||||
|
||||
template <class Component>
|
||||
ComponentInfo& registerComponent(const std::string& name)
|
||||
{
|
||||
return registerComponent<Component>(name, ComponentEditorWidget<Component, EntityType>);
|
||||
}
|
||||
|
||||
void renderEditor(Registry& registry, EntityType& e)
|
||||
{
|
||||
ImGui::TextUnformatted("Editing:");
|
||||
ImGui::SameLine();
|
||||
|
||||
MM_IEEE_ENTITY_WIDGET(e, registry, true);
|
||||
|
||||
if (ImGui::Button("New")) {
|
||||
e = registry.create();
|
||||
}
|
||||
if (registry.valid(e)) {
|
||||
ImGui::SameLine();
|
||||
|
||||
// clone would go here
|
||||
//if (ImGui::Button("Clone")) {
|
||||
//auto old_e = e;
|
||||
//e = registry.create();
|
||||
//}
|
||||
|
||||
ImGui::Dummy({10, 0}); // space destroy a bit, to not accidentally click it
|
||||
ImGui::SameLine();
|
||||
|
||||
// red button
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.65f, 0.15f, 0.15f, 1.f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.8f, 0.3f, 0.3f, 1.f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.f, 0.2f, 0.2f, 1.f));
|
||||
if (ImGui::Button("Destroy")) {
|
||||
registry.destroy(e);
|
||||
e = entt::null;
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (registry.valid(e)) {
|
||||
ImGui::PushID(static_cast<int>(entt::to_integral(e)));
|
||||
std::map<ComponentTypeID, ComponentInfo> has_not;
|
||||
for (auto& [component_type_id, ci] : component_infos) {
|
||||
if (entityHasComponent(registry, e, component_type_id)) {
|
||||
ImGui::PushID(component_type_id);
|
||||
if (ImGui::Button("-")) {
|
||||
ci.destroy(registry, e);
|
||||
ImGui::PopID();
|
||||
continue; // early out to prevent access to deleted data
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader(ci.name.c_str())) {
|
||||
ImGui::Indent(30.f);
|
||||
ImGui::PushID("Widget");
|
||||
ci.widget(registry, e);
|
||||
ImGui::PopID();
|
||||
ImGui::Unindent(30.f);
|
||||
}
|
||||
ImGui::PopID();
|
||||
} else {
|
||||
has_not[component_type_id] = ci;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_not.empty()) {
|
||||
if (ImGui::Button("+ Add Component")) {
|
||||
ImGui::OpenPopup("Add Component");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("Add Component")) {
|
||||
ImGui::TextUnformatted("Available:");
|
||||
ImGui::Separator();
|
||||
|
||||
for (auto& [component_type_id, ci] : has_not) {
|
||||
ImGui::PushID(component_type_id);
|
||||
if (ImGui::Selectable(ci.name.c_str())) {
|
||||
ci.create(registry, e);
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
void renderEntityList(Registry& registry, std::set<ComponentTypeID>& comp_list)
|
||||
{
|
||||
ImGui::Text("Components Filter:");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton("clear")) {
|
||||
comp_list.clear();
|
||||
}
|
||||
|
||||
ImGui::Indent();
|
||||
|
||||
for (const auto& [component_type_id, ci] : component_infos) {
|
||||
bool is_in_list = comp_list.count(component_type_id);
|
||||
bool active = is_in_list;
|
||||
|
||||
ImGui::Checkbox(ci.name.c_str(), &active);
|
||||
|
||||
if (is_in_list && !active) { // remove
|
||||
comp_list.erase(component_type_id);
|
||||
} else if (!is_in_list && active) { // add
|
||||
comp_list.emplace(component_type_id);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Unindent();
|
||||
ImGui::Separator();
|
||||
|
||||
if (comp_list.empty()) {
|
||||
ImGui::Text("Orphans:");
|
||||
registry.orphans([®istry](auto e){
|
||||
MM_IEEE_ENTITY_WIDGET(e, registry, false);
|
||||
});
|
||||
} else {
|
||||
auto view = registry.runtime_view(comp_list.begin(), comp_list.end());
|
||||
ImGui::Text("%lu Entities Matching:", view.size());
|
||||
|
||||
if (ImGui::BeginChild("entity list")) {
|
||||
for (auto e : view) {
|
||||
MM_IEEE_ENTITY_WIDGET(e, registry, false);
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
[[deprecated("Use renderEditor() instead. And manage the window yourself.")]]
|
||||
void render(Registry& registry, EntityType& e)
|
||||
{
|
||||
if (show_window) {
|
||||
if (ImGui::Begin("Entity Editor", &show_window)) {
|
||||
renderEditor(registry, e);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
// displays both, editor and list
|
||||
// uses static internally, use only as a quick way to get going!
|
||||
void renderSimpleCombo(Registry& registry, EntityType& e)
|
||||
{
|
||||
if (show_window) {
|
||||
ImGui::SetNextWindowSize(ImVec2(550, 400), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("Entity Editor", &show_window)) {
|
||||
if (ImGui::BeginChild("list", {200, 0}, true)) {
|
||||
static std::set<ComponentTypeID> comp_list;
|
||||
renderEntityList(registry, comp_list);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("editor")) {
|
||||
renderEditor(registry, e);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // MM
|
||||
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2020 Erik Scholz, Gnik Droy
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
33
framework/imgui/src/mm/imgui/sound_info.cpp
Normal file
33
framework/imgui/src/mm/imgui/sound_info.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "./sound_info.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <mm/services/sound_service.hpp>
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
|
||||
namespace MM {
|
||||
|
||||
void ImGuiSoundInfo(Engine& engine) {
|
||||
if (ImGui::Begin("Sound Info")) {
|
||||
auto& sound = engine.getService<MM::Services::SoundService>();
|
||||
|
||||
ImGui::Text("SoLoud v%d", sound.engine.getVersion());
|
||||
ImGui::Text("Backend: %s, ch: %d, rate: %d, buffersize: %d",
|
||||
sound.engine.getBackendString(),
|
||||
sound.engine.getBackendChannels(),
|
||||
sound.engine.getBackendSamplerate(),
|
||||
sound.engine.getBackendBufferSize());
|
||||
ImGui::Text("Max Active Voice Count: %d", sound.engine.getMaxActiveVoiceCount());
|
||||
|
||||
ImGui::Text("Active Voice Count: %d", sound.engine.getActiveVoiceCount());
|
||||
|
||||
sound.engine.getWave();
|
||||
ImGui::PlotLines("##Wave", sound.engine.getWave(), 256, 0, "Wave", -1.f, 1.f, ImVec2(0, 80));
|
||||
ImGui::PlotHistogram("##Spectrum", sound.engine.calcFFT(), 256 / 2, 0, "FFT", 0.f, 20.f, ImVec2(0, 80));
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
8
framework/imgui/src/mm/imgui/sound_info.hpp
Normal file
8
framework/imgui/src/mm/imgui/sound_info.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace MM {
|
||||
class Engine; // fwd
|
||||
|
||||
void ImGuiSoundInfo(Engine& engine);
|
||||
} // MM
|
||||
|
21
framework/imgui/src/mm/imgui/sound_pref.cpp
Normal file
21
framework/imgui/src/mm/imgui/sound_pref.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "sound_pref.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <mm/services/sound_service.hpp>
|
||||
|
||||
namespace MM {
|
||||
|
||||
void ImGuiSoundPref(Engine& engine) {
|
||||
if (ImGui::Begin("Sound Preferences")) {
|
||||
auto& e = engine.getService<MM::Services::SoundService>().engine;
|
||||
|
||||
auto gvolume = e.getGlobalVolume();
|
||||
ImGui::SliderFloat("Global Volume", &gvolume, 0.f, 1.f);
|
||||
e.setGlobalVolume(gvolume);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
8
framework/imgui/src/mm/imgui/sound_pref.hpp
Normal file
8
framework/imgui/src/mm/imgui/sound_pref.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace MM {
|
||||
class Engine; // fwd
|
||||
|
||||
void ImGuiSoundPref(Engine& engine);
|
||||
} // MM
|
||||
|
34
framework/imgui/src/mm/imgui/widgets/auto_wrap.hpp
Normal file
34
framework/imgui/src/mm/imgui/widgets/auto_wrap.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
template<typename Iterator>
|
||||
void ListWrap(Iterator begin, Iterator end, std::function<void(Iterator)> fn, float item_with) {
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
|
||||
|
||||
for (auto it = begin; it != end; it++) {
|
||||
//ImGui::PushID(n);
|
||||
//ImGui::Button("Box", button_sz);
|
||||
|
||||
fn(it);
|
||||
|
||||
float last_item_x2 = ImGui::GetItemRectMax().x;
|
||||
|
||||
float next_item_x2 = last_item_x2 + style.ItemSpacing.x + item_with; // Expected position if next item was on same line
|
||||
|
||||
if (it + 1 != end && next_item_x2 < window_visible_x2) {
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
//ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
77
framework/imgui/src/mm/imgui/widgets/camera.cpp
Normal file
77
framework/imgui/src/mm/imgui/widgets/camera.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include "./camera.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include "./entity.hpp"
|
||||
|
||||
#include <mm/components/transform2d.hpp>
|
||||
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void Camera3D(MM::Scene& scene) {
|
||||
ImGui::TextUnformatted("Camera:");
|
||||
|
||||
ImGui::Indent();
|
||||
|
||||
auto* camera = scene.try_ctx<MM::OpenGL::Camera3D>();
|
||||
if (!camera) {
|
||||
ImGui::TextUnformatted("NO CAMERA!");
|
||||
return;
|
||||
}
|
||||
|
||||
static bool follow_entity = false;
|
||||
static MM::Entity tracking = entt::null;
|
||||
|
||||
ImGui::InputFloat("screenRatio", &camera->screenRatio);
|
||||
ImGui::InputFloat("nearPlane", &camera->nearPlane);
|
||||
ImGui::InputFloat("farPlane", &camera->farPlane);
|
||||
|
||||
if (camera->ortho) {
|
||||
ImGui::TextUnformatted("orthographic mode");
|
||||
ImGui::Checkbox("follow entity", &follow_entity);
|
||||
|
||||
if (follow_entity) {
|
||||
ImGui::SameLine();
|
||||
|
||||
MM::ImGuiWidgets::Entity(tracking, scene);
|
||||
if (scene.valid(tracking)) {
|
||||
if (scene.has<MM::Components::Transform2D>(tracking)) {
|
||||
camera->translation = {scene.get<MM::Components::Transform2D>(tracking).position, 0.f};
|
||||
} else {
|
||||
ImGui::TextUnformatted("error: Entity has no Transform");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ImGui::DragFloat2("translation", &camera->translation.x, 0.1f);
|
||||
}
|
||||
|
||||
|
||||
ImGui::DragFloat("h_vp_size", &camera->horizontalViewPortSize, 0.1f);
|
||||
|
||||
// TODO: aspect ratio
|
||||
|
||||
// TODO: check for change
|
||||
camera->setOrthographic();
|
||||
} else { // perspective
|
||||
ImGui::TextUnformatted("perspective mode");
|
||||
|
||||
ImGui::DragFloat3("translation", &camera->translation.x, 0.1f);
|
||||
ImGui::SliderFloat("fov", &camera->fov, 0.1f, glm::pi<float>());
|
||||
|
||||
ImGui::SliderFloat("yaw", &camera->yaw, 0.0f, 2*glm::pi<float>());
|
||||
ImGui::SliderFloat("pitch", &camera->pitch, -glm::pi<float>()/2, glm::pi<float>()/2);
|
||||
|
||||
ImGui::InputFloat3("up", &camera->up.x);
|
||||
|
||||
camera->setPerspective();
|
||||
}
|
||||
|
||||
camera->updateView();
|
||||
|
||||
ImGui::Unindent();
|
||||
}
|
||||
|
||||
}
|
||||
|
12
framework/imgui/src/mm/imgui/widgets/camera.hpp
Normal file
12
framework/imgui/src/mm/imgui/widgets/camera.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/opengl/camera_3d.hpp>
|
||||
|
||||
#include <mm/services/scene_service_interface.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void Camera3D(MM::Scene& scene);
|
||||
|
||||
}
|
||||
|
21
framework/imgui/src/mm/imgui/widgets/components/color.cpp
Normal file
21
framework/imgui/src/mm/imgui/widgets/components/color.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "color.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void Color(MM::Components::Color& c) {
|
||||
ImGui::ColorEdit4("color##Color", &c.color[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Color>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::Color(reg.get<Components::Color>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
15
framework/imgui/src/mm/imgui/widgets/components/color.hpp
Normal file
15
framework/imgui/src/mm/imgui/widgets/components/color.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/components/color.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
#include <mm/engine_fwd.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
void Color(MM::Components::Color& c);
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Color>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
25
framework/imgui/src/mm/imgui/widgets/components/name.cpp
Normal file
25
framework/imgui/src/mm/imgui/widgets/components/name.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "name.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui/misc/cpp/imgui_stdlib.h>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
// TODO: make editable
|
||||
void Name(MM::Components::Name& n) {
|
||||
if (ImGui::InputText("str##Name", &n.str)) {
|
||||
n.str = n.str.substr(0, MM::Components::Name::max_str_len); // limit size
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Name>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::Name(reg.get<Components::Name>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
15
framework/imgui/src/mm/imgui/widgets/components/name.hpp
Normal file
15
framework/imgui/src/mm/imgui/widgets/components/name.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/components/name.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
#include <mm/services/scene_service_interface.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
void Name(MM::Components::Name& n);
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Name>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
22
framework/imgui/src/mm/imgui/widgets/components/texture.cpp
Normal file
22
framework/imgui/src/mm/imgui/widgets/components/texture.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "texture.hpp"
|
||||
#include "../texture.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void Texture(MM::Components::OpenGL::Texture& tex) {
|
||||
LabelTexture("tex##Texture", tex.tex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::OpenGL::Texture>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::Texture(reg.get<Components::OpenGL::Texture>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
17
framework/imgui/src/mm/imgui/widgets/components/texture.hpp
Normal file
17
framework/imgui/src/mm/imgui/widgets/components/texture.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/opengl/components/texture.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
#include <mm/engine_fwd.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void Texture(MM::Components::OpenGL::Texture& tex);
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::OpenGL::Texture>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
#include "./tilemap_renderable.hpp"
|
||||
|
||||
#include <mm/opengl/render_tasks/tilemap_renderable.hpp>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <mm/imgui/widgets/spritesheet.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void TilemapRenderable(MM::OpenGL::TilemapRenderable& tm_r) {
|
||||
ImGui::InputFloat("z", &tm_r.z);
|
||||
|
||||
for (size_t i = 0; i < tm_r.sprite_layer.size(); i++) {
|
||||
ImGui::Separator();
|
||||
std::string label = "sprite_sheet##";
|
||||
label += std::to_string(i);
|
||||
MM::ImGuiWidgets::LabelSpriteSheet(label.c_str(), tm_r.sprite_layer[i].sprite_sheet);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<OpenGL::TilemapRenderable>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::TilemapRenderable(reg.get<OpenGL::TilemapRenderable>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
#include <mm/engine_fwd.hpp>
|
||||
|
||||
// fwd
|
||||
namespace MM::OpenGL {
|
||||
struct TilemapRenderable;
|
||||
}
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void TilemapRenderable(MM::OpenGL::TilemapRenderable& tm_r);
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<OpenGL::TilemapRenderable>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
#include "./transform2d.hpp"
|
||||
#include "mm/components/transform2d.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void Transform(MM::Components::Transform2D& t) {
|
||||
ImGui::DragFloat2("position (x,y)##Transform", &t.position.x, 0.1f);
|
||||
ImGui::SliderFloat("rotation##Transform", &t.rotation, 0.f, glm::pi<float>() * 2.f);
|
||||
ImGui::DragFloat2("scale (x,y)##Transform", &t.scale.x, 1.f, 0.f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Transform2D>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::Transform(reg.get<Components::Transform2D>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/components/transform2d.hpp>
|
||||
#include <mm/services/scene_service_interface.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
void Transform(MM::Components::Transform2D& t);
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Transform2D>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
#include "./transform3d.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void Transform(MM::Components::Transform3D& t) {
|
||||
ImGui::DragFloat3("position (x,y,z)##Transform3D", &t.position.x, 0.1f);
|
||||
ImGui::SliderFloat("rotation##Transform3D", &t.rotation, 0.f, glm::pi<float>() * 2.f);
|
||||
ImGui::DragFloat3("scale (x,y,z)##Transform3D", &t.scale.x, 1.f, 0.f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Transform3D>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::Transform(reg.get<Components::Transform3D>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/components/transform3d.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
#include <mm/services/scene_service_interface.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
void Transform(MM::Components::Transform3D& t);
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Transform3D>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
#include "./velocity2d.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void Velocity(MM::Components::Velocity2D& v) {
|
||||
ImGui::DragFloat2("velocity (x,y)##Velocity", &v.velocity.x, 0.1f);
|
||||
ImGui::SliderFloat("rotation##Velocity", &v.rotation, -glm::two_pi<float>(), glm::two_pi<float>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Velocity2D>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::Velocity(reg.get<Components::Velocity2D>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/components/velocity2d.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
#include <mm/services/scene_service_interface.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
void Velocity(MM::Components::Velocity2D& v);
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::Velocity2D>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
#include "./view_dir2d.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void ViewDir(MM::Components::ViewDir2D& vd) {
|
||||
ImGui::SliderFloat("dir##ViewDir2D", &vd.dir, 0.0f, glm::two_pi<float>());
|
||||
}
|
||||
|
||||
} // MM::ImGuiWidgets::Components
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::ViewDir2D>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::ViewDir(reg.get<Components::ViewDir2D>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/components/view_dir2d.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
#include <mm/services/scene_service_interface.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
void ViewDir(MM::Components::ViewDir2D& t);
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::ViewDir2D>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
#include "./view_dir3d.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
|
||||
void ViewDir(MM::Components::ViewDir3D& vd) {
|
||||
ImGui::SliderFloat("yaw##ViewDir3D", &vd.yaw, 0.0f, glm::two_pi<float>());
|
||||
ImGui::SliderFloat("pitch##ViewDir3D", &vd.pitch, -glm::half_pi<float>(), glm::half_pi<float>());
|
||||
ImGui::SliderFloat("roll##ViewDir3D", &vd.roll, -glm::half_pi<float>(), glm::half_pi<float>());
|
||||
}
|
||||
|
||||
} // MM::ImGuiWidgets::Components
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::ViewDir3D>(MM::Scene& reg, MM::Entity e) {
|
||||
ImGuiWidgets::Components::ViewDir(reg.get<Components::ViewDir3D>(e));
|
||||
}
|
||||
|
||||
} // MM
|
||||
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/components/view_dir3d.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
#include <mm/services/scene_service_interface.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets::Components {
|
||||
void ViewDir(MM::Components::ViewDir3D& t);
|
||||
}
|
||||
|
||||
namespace MM {
|
||||
template <>
|
||||
void ComponentEditorWidget<Components::ViewDir3D>(MM::Scene& reg, MM::Entity e);
|
||||
}
|
||||
|
94
framework/imgui/src/mm/imgui/widgets/entity.cpp
Normal file
94
framework/imgui/src/mm/imgui/widgets/entity.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#include "entity.hpp"
|
||||
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
|
||||
#include <mm/components/name.hpp>
|
||||
|
||||
#include <IconsIonicons.h>
|
||||
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void Entity(MM::Entity& e, MM::Scene& ecs, bool dropTarget) {
|
||||
ImGui::PushID(static_cast<int>(entt::to_integral(e)));
|
||||
|
||||
if (ecs.valid(e)) {
|
||||
if (ecs.has<MM::Components::Name>(e)) {
|
||||
ImGui::Text(ICON_II_CUBE "E: %d v%d (%s)", entt::to_integral(ecs.entity(e)), ecs.version(e), ecs.get<MM::Components::Name>(e).str.c_str());
|
||||
} else {
|
||||
ImGui::Text(ICON_II_CUBE "E: %d v%d", entt::to_integral(ecs.entity(e)), ecs.version(e));
|
||||
}
|
||||
} else {
|
||||
ImGui::Text(ICON_II_CUBE "E: invalid");
|
||||
}
|
||||
|
||||
if (ecs.valid(e)) {
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) {
|
||||
ImGui::SetDragDropPayload(MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY, &e, sizeof(e));
|
||||
ImGui::Text(ICON_II_CUBE "E: %d v%d", entt::to_integral(ecs.entity(e)), ecs.version(e));
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
}
|
||||
|
||||
if (dropTarget && ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY)) {
|
||||
e = *(MM::Entity*)payload->Data;
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void EntityTrashCan(MM::Scene& ecs) {
|
||||
ImGui::TextColored({1.f, 0.2f, 0.2f, 1.f}, ICON_II_TRASH_A " Entity TrashCan");
|
||||
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY)) {
|
||||
auto e = *(MM::Entity*)payload->Data;
|
||||
ecs.destroy(e);
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
}
|
||||
|
||||
//void EntityList(MM::Scene& ecs, const std::vector<component_type>& comps) {
|
||||
//auto view = ecs.runtime_view(comps.begin(), comps.end());
|
||||
|
||||
//ImGui::Text("%lu Entities matching components:", view.size());
|
||||
|
||||
//if (ImGui::BeginChild("entity list")) {
|
||||
//ImGui::Indent();
|
||||
//for (auto e : view) {
|
||||
//MM::ImGuiWidgets::Entity(e, ecs, false);
|
||||
//}
|
||||
//ImGui::Unindent();
|
||||
//}
|
||||
//ImGui::EndChild();
|
||||
//}
|
||||
|
||||
//void EntityListByComponents(MM::Scene& ecs, std::map<component_type, std::pair<std::string, bool>>& named_comps) {
|
||||
//ImGui::Text("Components:");
|
||||
//ImGui::Indent();
|
||||
//std::vector<component_type> comps;
|
||||
|
||||
//for (auto& it : named_comps) {
|
||||
//ImGui::Checkbox(it.second.first.c_str(), &it.second.second);
|
||||
|
||||
//if (it.second.second) {
|
||||
//comps.push_back(it.first);
|
||||
//}
|
||||
|
||||
//}
|
||||
|
||||
//ImGui::Unindent();
|
||||
|
||||
//ImGui::Separator();
|
||||
//EntityList(ecs, comps);
|
||||
//}
|
||||
|
||||
}
|
||||
|
18
framework/imgui/src/mm/imgui/widgets/entity.hpp
Normal file
18
framework/imgui/src/mm/imgui/widgets/entity.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <mm/services/scene_service_interface.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void Entity(MM::Entity& e, MM::Scene& ecs, bool dropTarget = true);
|
||||
|
||||
// just a drop target
|
||||
void EntityTrashCan(MM::Scene& ecs);
|
||||
|
||||
//void EntityList(MM::Scene& ecs, const std::vector<component_type>& comps);
|
||||
|
||||
//void EntityListByComponents(MM::Scene& ecs, std::map<component_type, std::pair<std::string, bool>>& named_comps);
|
||||
|
||||
}
|
119
framework/imgui/src/mm/imgui/widgets/filesystem.cpp
Normal file
119
framework/imgui/src/mm/imgui/widgets/filesystem.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include "./filesystem.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <IconsIonicons.h>
|
||||
|
||||
#include <physfs.h>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
// also removes leafs
|
||||
static std::string internal_remove_last_folder(const std::string& path) {
|
||||
if (path.empty())
|
||||
return path;
|
||||
|
||||
if (path == "/")
|
||||
return path;
|
||||
|
||||
auto pos = path.find_last_of('/');
|
||||
if (pos+1 == path.length()) {
|
||||
pos = path.find_last_of('/', pos-1);
|
||||
}
|
||||
|
||||
//path = path.substr(0, pos+1);
|
||||
return path.substr(0, pos+1);
|
||||
}
|
||||
|
||||
void FilePicker(const char* label, MM::Services::FilesystemService& fs, std::string& path, bool save) {
|
||||
ImGui::PushID(label);
|
||||
if (ImGui::Button("pick file")) {
|
||||
ImGui::OpenPopup("file dialogue");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("\"%s\"", path.c_str());
|
||||
|
||||
if (ImGui::BeginPopup("file dialogue")) {
|
||||
if (path.empty()) {
|
||||
path = "/";
|
||||
}
|
||||
|
||||
ImGui::Text("path: %s", path.c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
std::string dirlist_path = path;
|
||||
|
||||
if (dirlist_path.back() != '/')
|
||||
dirlist_path = internal_remove_last_folder(dirlist_path);
|
||||
|
||||
//ImGui::TextUnformatted(dirlist_path.c_str());
|
||||
|
||||
if (dirlist_path != "/") {
|
||||
if (ImGui::Selectable(ICON_II_FOLDER " ..", false, ImGuiSelectableFlags_DontClosePopups)) {
|
||||
path = internal_remove_last_folder(dirlist_path);
|
||||
}
|
||||
}
|
||||
|
||||
// list folders and files
|
||||
fs.forEachIn(dirlist_path.c_str(), [&](const char* i) -> bool {
|
||||
std::string tmp_text;
|
||||
std::string tmp_path = dirlist_path + i;
|
||||
PHYSFS_Stat stat;
|
||||
PHYSFS_stat(tmp_path.c_str(), &stat);
|
||||
|
||||
if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY) {
|
||||
tmp_text += ICON_II_FOLDER " ";
|
||||
} else {
|
||||
tmp_text += ICON_II_DOCUMENT " ";
|
||||
}
|
||||
|
||||
tmp_text += i;
|
||||
|
||||
if (ImGui::Selectable(tmp_text.c_str(), false, ImGuiSelectableFlags_DontClosePopups)) {
|
||||
if (path.back() != '/') {
|
||||
path = internal_remove_last_folder(path);
|
||||
}
|
||||
|
||||
path += i;
|
||||
|
||||
if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY) {
|
||||
path += '/';
|
||||
} else if (!save) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (save) {
|
||||
ImGui::Separator();
|
||||
|
||||
// TODO: perf?
|
||||
char buffer[201] = {};
|
||||
|
||||
std::string path_leaf = path.substr(path.find_last_of('/')+1);
|
||||
strcpy(buffer, path_leaf.c_str());
|
||||
|
||||
if (ImGui::InputText("file name", buffer, 200)) {
|
||||
// got input ?
|
||||
|
||||
if (path.back() != '/')
|
||||
path = internal_remove_last_folder(path);
|
||||
|
||||
path += buffer;
|
||||
}
|
||||
|
||||
if (ImGui::Button("confirm")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
}
|
||||
|
15
framework/imgui/src/mm/imgui/widgets/filesystem.hpp
Normal file
15
framework/imgui/src/mm/imgui/widgets/filesystem.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <mm/services/filesystem.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
//#define IMGUI_PAYLOAD_TYPE_MM_FILE "MM_FILE"
|
||||
//#define IMGUI_PAYLOAD_TYPE_MM_FILE_PATH "MM_FILE_PATH"
|
||||
|
||||
void FilePicker(const char* label, MM::Services::FilesystemService& fs, std::string& path, bool save = false);
|
||||
|
||||
}
|
||||
|
79
framework/imgui/src/mm/imgui/widgets/knob.cpp
Normal file
79
framework/imgui/src/mm/imgui/widgets/knob.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "./knob.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
// this implementation is base on:
|
||||
// https://github.com/Flix01/imgui/blob/imgui_with_addons/addons/imguivariouscontrols/imguivariouscontrols.cpp#L4119
|
||||
// and has been modified.
|
||||
//
|
||||
// LICENSE of original code:
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
bool KnobFloat(const char* label, float* v, float v_min, float v_max, float step, bool show_tooltip) {
|
||||
//@ocornut https://github.com/ocornut/imgui/issues/942
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
float radius_outer = 20.0f;
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 center = ImVec2(pos.x + radius_outer, pos.y + radius_outer);
|
||||
float line_height = ImGui::GetTextLineHeight();
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
float ANGLE_MIN = 3.141592f * 0.75f;
|
||||
float ANGLE_MAX = 3.141592f * 2.25f;
|
||||
|
||||
ImGui::InvisibleButton(label, ImVec2(radius_outer*2, radius_outer*2 + line_height + style.ItemInnerSpacing.y));
|
||||
bool value_changed = false;
|
||||
bool is_active = ImGui::IsItemActive();
|
||||
bool is_hovered = ImGui::IsItemHovered();
|
||||
if (is_active && io.MouseDelta.x != 0.0f) {
|
||||
if (step<=0) step=50.f;
|
||||
float tmp_step = (v_max - v_min) / step;
|
||||
*v += io.MouseDelta.x * tmp_step;
|
||||
|
||||
if (*v < v_min) *v = v_min;
|
||||
if (*v > v_max) *v = v_max;
|
||||
value_changed = true;
|
||||
} else if (is_hovered && (io.MouseDoubleClicked[0] || io.MouseClicked[2])) {
|
||||
*v = (v_max + v_min) * 0.5f; // reset value
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
float t = (*v - v_min) / (v_max - v_min);
|
||||
float angle = ANGLE_MIN + (ANGLE_MAX - ANGLE_MIN) * t;
|
||||
float angle_cos = cosf(angle), angle_sin = sinf(angle);
|
||||
float radius_inner = radius_outer*0.60f;
|
||||
|
||||
draw_list->AddCircleFilled(center, radius_outer, ImGui::GetColorU32(ImGuiCol_FrameBg), 16);
|
||||
draw_list->AddLine(ImVec2(center.x + angle_cos*radius_inner, center.y + angle_sin*radius_inner), ImVec2(center.x + angle_cos*(radius_outer-2), center.y + angle_sin*(radius_outer-2)), ImGui::GetColorU32(ImGuiCol_SliderGrabActive), 2.0f);
|
||||
draw_list->AddCircleFilled(center, radius_inner, ImGui::GetColorU32(is_active ? ImGuiCol_FrameBgActive : is_hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
|
||||
draw_list->AddText(ImVec2(pos.x, pos.y + radius_outer * 2 + style.ItemInnerSpacing.y), ImGui::GetColorU32(ImGuiCol_Text), label);
|
||||
|
||||
if (show_tooltip && (is_active || is_hovered)) {
|
||||
ImGui::SetNextWindowPos(ImVec2(pos.x - style.WindowPadding.x, pos.y - line_height - style.ItemInnerSpacing.y - style.WindowPadding.y));
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%.3f", *v);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
} // MM::ImGuiWidgets
|
||||
|
8
framework/imgui/src/mm/imgui/widgets/knob.hpp
Normal file
8
framework/imgui/src/mm/imgui/widgets/knob.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
bool KnobFloat(const char* label, float* v, float v_min, float v_max, float step = 0.0f, bool show_tooltip = true);
|
||||
|
||||
}
|
||||
|
192
framework/imgui/src/mm/imgui/widgets/plot_radar.cpp
Normal file
192
framework/imgui/src/mm/imgui/widgets/plot_radar.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
#include "./plot_radar.hpp"
|
||||
|
||||
#include <glm/common.hpp> // min max
|
||||
#include <glm/trigonometric.hpp> // sin cos
|
||||
#include <glm/gtc/constants.hpp> // two_pi
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void PlotRadar(
|
||||
const char* label,
|
||||
const float* values, int values_count,
|
||||
const char** vlabels,
|
||||
float scale_min, float scale_max,
|
||||
ImVec2 graph_size,
|
||||
|
||||
bool draw_net_first,
|
||||
|
||||
// polygon
|
||||
const ImVec4& poly_line_color,
|
||||
const ImVec4& poly_fill_color,
|
||||
const float poly_line_thickness,
|
||||
|
||||
// net
|
||||
const ImVec4& net_line_color,
|
||||
const float net_line_thicknes
|
||||
) {
|
||||
if (values == nullptr || values_count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set up scale
|
||||
if (scale_min == FLT_MAX) {
|
||||
scale_min = values[0];
|
||||
for (int i = 1; i < values_count; i++) {
|
||||
scale_min = glm::min(scale_min, values[i]);
|
||||
}
|
||||
}
|
||||
if (scale_max == FLT_MAX) {
|
||||
scale_max = values[0];
|
||||
for (int i = 1; i < values_count; i++) {
|
||||
scale_max = glm::max(scale_max, values[i]);
|
||||
}
|
||||
}
|
||||
if (scale_min == scale_max) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
const ImVec2 p = ImGui::GetCursorScreenPos();
|
||||
|
||||
const ImVec2 center_p {
|
||||
p.x + graph_size.x/2,
|
||||
p.y + graph_size.y/2,
|
||||
};
|
||||
|
||||
const float inner_spacing_from_center = (graph_size.x/2) * 0.15f; // TODO: expose?
|
||||
const float outer_spacing_from_center = (graph_size.x/2) * 0.8f; // TODO: expose?
|
||||
|
||||
auto draw_ngon = [&](const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) {
|
||||
if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < num_segments; i++) {
|
||||
const float a0 = (float(i) / (num_segments-1)) * (glm::two_pi<float>()) * (num_segments-1 / float(num_segments)) - glm::half_pi<float>();
|
||||
const float a1 = (float(i+1) / (num_segments-1)) * (glm::two_pi<float>()) * (num_segments-1 / float(num_segments)) - glm::half_pi<float>();
|
||||
|
||||
draw_list->AddLine(
|
||||
{center.x + glm::cos(a0) * radius, center.y + glm::sin(a0) * radius},
|
||||
{center.x + glm::cos(a1) * radius, center.y + glm::sin(a1) * radius},
|
||||
col, thickness
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
auto draw_net = [&]() {
|
||||
// inner ring
|
||||
draw_ngon(center_p, inner_spacing_from_center, ImColor(net_line_color), values_count, net_line_thicknes);
|
||||
|
||||
// depends on min and max
|
||||
draw_ngon(center_p, glm::mix(inner_spacing_from_center, outer_spacing_from_center, 0.5), ImColor(net_line_color), values_count, net_line_thicknes);
|
||||
|
||||
// outer ring
|
||||
draw_ngon(center_p, outer_spacing_from_center, ImColor(net_line_color), values_count, net_line_thicknes);
|
||||
|
||||
// axies
|
||||
for (int i = 0; i < values_count; i++) {
|
||||
const float a = (float(i) / (values_count-1)) * (glm::two_pi<float>()) * (values_count-1 / float(values_count)) - glm::half_pi<float>();
|
||||
draw_list->AddLine(
|
||||
{center_p.x + glm::cos(a) * inner_spacing_from_center, center_p.y + glm::sin(a) * inner_spacing_from_center},
|
||||
{center_p.x + glm::cos(a) * outer_spacing_from_center, center_p.y + glm::sin(a) * outer_spacing_from_center},
|
||||
ImColor(net_line_color), net_line_thicknes
|
||||
);
|
||||
}
|
||||
|
||||
// lables
|
||||
// TODO
|
||||
};
|
||||
|
||||
auto value_to_radius = [&](float v) -> float {
|
||||
//v -= scale_min;
|
||||
//v /= scale_max;
|
||||
//return v;
|
||||
return (v - scale_min) / scale_max;
|
||||
};
|
||||
|
||||
auto draw_polygon_fills = [&]() {
|
||||
// fills
|
||||
for (int i = 0; i < values_count; i++) {
|
||||
const float a0 = (float(i) / (values_count-1)) * (glm::two_pi<float>()) * (values_count-1 / float(values_count)) - glm::half_pi<float>();
|
||||
const float a1 = (float(i+1) / (values_count-1)) * (glm::two_pi<float>()) * (values_count-1 / float(values_count)) - glm::half_pi<float>();
|
||||
|
||||
float v0 = values[i];
|
||||
float v1 = values[(i+1) % values_count];
|
||||
|
||||
v0 = value_to_radius(v0);
|
||||
v1 = value_to_radius(v1);
|
||||
|
||||
float r0 = glm::mix(inner_spacing_from_center, outer_spacing_from_center, v0);
|
||||
float r1 = glm::mix(inner_spacing_from_center, outer_spacing_from_center, v1);
|
||||
|
||||
draw_list->AddQuadFilled(
|
||||
{center_p.x + glm::cos(a0) * r0, center_p.y + glm::sin(a0) * r0},
|
||||
{center_p.x + glm::cos(a1) * r1, center_p.y + glm::sin(a1) * r1},
|
||||
|
||||
{center_p.x + glm::cos(a1) * inner_spacing_from_center, center_p.y + glm::sin(a1) * inner_spacing_from_center},
|
||||
{center_p.x + glm::cos(a0) * inner_spacing_from_center, center_p.y + glm::sin(a0) * inner_spacing_from_center},
|
||||
ImColor(poly_fill_color)
|
||||
);
|
||||
}
|
||||
};
|
||||
auto draw_polygon_lines = [&]() {
|
||||
// lines
|
||||
for (int i = 0; i < values_count; i++) {
|
||||
const float a0 = (float(i) / (values_count-1)) * (glm::two_pi<float>()) * (values_count-1 / float(values_count)) - glm::half_pi<float>();
|
||||
const float a1 = (float(i+1) / (values_count-1)) * (glm::two_pi<float>()) * (values_count-1 / float(values_count)) - glm::half_pi<float>();
|
||||
|
||||
float v0 = values[i];
|
||||
float v1 = values[(i+1) % values_count];
|
||||
|
||||
v0 = value_to_radius(v0);
|
||||
v1 = value_to_radius(v1);
|
||||
|
||||
float r0 = glm::mix(inner_spacing_from_center, outer_spacing_from_center, v0);
|
||||
float r1 = glm::mix(inner_spacing_from_center, outer_spacing_from_center, v1);
|
||||
|
||||
draw_list->AddLine(
|
||||
{center_p.x + glm::cos(a0) * r0, center_p.y + glm::sin(a0) * r0},
|
||||
{center_p.x + glm::cos(a1) * r1, center_p.y + glm::sin(a1) * r1},
|
||||
ImColor(poly_line_color), poly_line_thickness
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
auto draw_text = [&]() {
|
||||
if (vlabels == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < values_count; i++) {
|
||||
const float a0 = (float(i) / (values_count-1)) * (glm::two_pi<float>()) * (values_count-1 / float(values_count)) - glm::half_pi<float>();
|
||||
|
||||
const float text_spacing_from_center = (graph_size.x/2) * 0.9f;
|
||||
draw_list->AddText(
|
||||
{
|
||||
center_p.x + glm::cos(a0) * text_spacing_from_center,
|
||||
center_p.y + glm::sin(a0) * text_spacing_from_center - ImGui::GetTextLineHeight()/2
|
||||
},
|
||||
ImColor(1.f,1.f,1.f,1.f), vlabels[i]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (draw_net_first) {
|
||||
draw_net();
|
||||
draw_polygon_fills();
|
||||
draw_polygon_lines();
|
||||
draw_text();
|
||||
} else {
|
||||
draw_polygon_fills();
|
||||
draw_net();
|
||||
draw_polygon_lines();
|
||||
draw_text();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
} // MM::ImGuiWidgets
|
||||
|
31
framework/imgui/src/mm/imgui/widgets/plot_radar.hpp
Normal file
31
framework/imgui/src/mm/imgui/widgets/plot_radar.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
//#include <cfloat>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void PlotRadar(
|
||||
const char* label,
|
||||
const float* values, int values_count, // values offset?
|
||||
const char** vlabels = nullptr, // list of null-terminated c-strings, same size as values
|
||||
float scale_min = FLT_MAX, float scale_max = FLT_MAX,
|
||||
ImVec2 graph_size = {100, 100},
|
||||
|
||||
bool draw_net_first = false,
|
||||
|
||||
// polygon
|
||||
const ImVec4& poly_line_color = {0.8f, 0.8f, 0.0f, 1.0f},
|
||||
const ImVec4& poly_fill_color = {0.8f, 0.8f, 0.0f, 0.4f},
|
||||
const float poly_line_thickness = 2.f,
|
||||
|
||||
// net
|
||||
const ImVec4& net_line_color = {0.9f, 0.9f, 0.9f, 0.8f},
|
||||
const float net_line_thickness = 1.f
|
||||
|
||||
//bool show_tooltip = true
|
||||
);
|
||||
|
||||
} // MM::ImGuiWidgets
|
||||
|
26
framework/imgui/src/mm/imgui/widgets/soloud.hpp
Normal file
26
framework/imgui/src/mm/imgui/widgets/soloud.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
// fwd
|
||||
namespace SoLoud {
|
||||
class Soloud;
|
||||
class Sfxr;
|
||||
struct SfxrParams;
|
||||
class Filter;
|
||||
class FilterInstance;
|
||||
|
||||
typedef unsigned int handle;
|
||||
}
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
bool SoLoudSfxrPlain(const char* label, SoLoud::SfxrParams* sfxr_params);
|
||||
// uses knobs and childs
|
||||
bool SoLoudSfxrFancy(const char* label, SoLoud::SfxrParams* sfxr_params);
|
||||
|
||||
// calls getParam*() methods
|
||||
//bool SoLoudFilterLiveParams(const char* label, SoLoud::Filter* filter, SoLoud::FilterInstance* filter_instance); // no access to instance
|
||||
bool SoLoudFilterLiveParams(const char* label, SoLoud::Soloud* soloud, SoLoud::Filter* filter, unsigned int filter_id, SoLoud::handle voice_handle = 0);
|
||||
bool SoLoudFilterLiveParamsFancy(const char* label, SoLoud::Soloud* soloud, SoLoud::Filter* filter, unsigned int filter_id, SoLoud::handle voice_handle = 0, bool same_line = false);
|
||||
|
||||
} // MM::ImGuiWidgets
|
||||
|
134
framework/imgui/src/mm/imgui/widgets/soloud_filter.cpp
Normal file
134
framework/imgui/src/mm/imgui/widgets/soloud_filter.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "./soloud.hpp"
|
||||
|
||||
#include <mm/imgui/widgets/knob.hpp>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <soloud.h>
|
||||
#include <soloud_filter.h>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
//bool SoLoudFilterLiveParams(const char* label, SoLoud::Filter* filter, SoLoud::FilterInstance* filter_instance) {
|
||||
//if (!filter || !filter_instance) return false;
|
||||
//ImGui::PushID(label);
|
||||
|
||||
//bool value_changed = false;
|
||||
|
||||
//size_t param_count = filter->getParamCount();
|
||||
//for (size_t i = 0; i < param_count; i++) {
|
||||
//if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::FLOAT_PARAM) {
|
||||
//float tmp = filter_instance->getFilterParameter(i);
|
||||
|
||||
//if (ImGui::SliderFloat(
|
||||
//filter->getParamName(i),
|
||||
//&tmp,
|
||||
//filter->getParamMin(i),
|
||||
//filter->getParamMax(i)
|
||||
//)) {
|
||||
//filter_instance->setFilterParameter(i, tmp);
|
||||
//value_changed = true;
|
||||
//}
|
||||
|
||||
|
||||
//} else if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::INT_PARAM) {
|
||||
//ImGui::Text("int %s min:%f max%f", filter->getParamName(i), filter->getParamMin(i), filter->getParamMax(i));
|
||||
//} else if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::BOOL_PARAM) {
|
||||
//bool tmp = filter_instance->getFilterParameter(i) != filter->getParamMin(i);
|
||||
//if (ImGui::Checkbox(filter->getParamName(i), &tmp)) {
|
||||
//filter_instance->setFilterParameter(i, tmp ? filter->getParamMax(i) : filter->getParamMin(i));
|
||||
//value_changed = true;
|
||||
//}
|
||||
|
||||
//}
|
||||
|
||||
//}
|
||||
|
||||
//ImGui::PopID();
|
||||
//return value_changed;
|
||||
//}
|
||||
|
||||
bool SoLoudFilterLiveParams(const char* label, SoLoud::Soloud* soloud, SoLoud::Filter* filter, unsigned int filter_id, SoLoud::handle voice_handle) {
|
||||
if (!filter) return false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
bool value_changed = false;
|
||||
|
||||
unsigned int param_count = static_cast<unsigned int>(filter->getParamCount());
|
||||
for (unsigned int i = 0; i < param_count; i++) {
|
||||
if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::FLOAT_PARAM) {
|
||||
float tmp = soloud->getFilterParameter(voice_handle, filter_id, i);
|
||||
|
||||
if (ImGui::SliderFloat(
|
||||
filter->getParamName(i),
|
||||
&tmp,
|
||||
filter->getParamMin(i),
|
||||
filter->getParamMax(i)
|
||||
)) {
|
||||
soloud->setFilterParameter(voice_handle, filter_id, i, tmp);
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
|
||||
} else if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::INT_PARAM) {
|
||||
ImGui::Text("int %s min:%f max%f", filter->getParamName(i), filter->getParamMin(i), filter->getParamMax(i));
|
||||
} else if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::BOOL_PARAM) {
|
||||
bool tmp = soloud->getFilterParameter(voice_handle, filter_id, i) != filter->getParamMin(i);
|
||||
if (ImGui::Checkbox(filter->getParamName(i), &tmp)) {
|
||||
soloud->setFilterParameter(voice_handle, filter_id, i, tmp ? filter->getParamMax(i) : filter->getParamMin(i));
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
bool SoLoudFilterLiveParamsFancy(const char* label, SoLoud::Soloud* soloud, SoLoud::Filter* filter, unsigned int filter_id, SoLoud::handle voice_handle, bool same_line) {
|
||||
if (!filter) return false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
bool value_changed = false;
|
||||
|
||||
unsigned int param_count = static_cast<unsigned int>(filter->getParamCount());
|
||||
for (unsigned int i = 0; i < param_count; i++) {
|
||||
if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::FLOAT_PARAM) {
|
||||
float tmp = soloud->getFilterParameter(voice_handle, filter_id, i);
|
||||
|
||||
if (MM::ImGuiWidgets::KnobFloat(
|
||||
filter->getParamName(i),
|
||||
&tmp,
|
||||
filter->getParamMin(i),
|
||||
filter->getParamMax(i),
|
||||
400.f
|
||||
)) {
|
||||
soloud->setFilterParameter(voice_handle, filter_id, i, tmp);
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
|
||||
} else if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::INT_PARAM) {
|
||||
ImGui::Text("int %s min:%f max%f", filter->getParamName(i), filter->getParamMin(i), filter->getParamMax(i));
|
||||
} else if (filter->getParamType(i) == SoLoud::Filter::PARAMTYPE::BOOL_PARAM) {
|
||||
bool tmp = soloud->getFilterParameter(voice_handle, filter_id, i) != filter->getParamMin(i);
|
||||
if (ImGui::Checkbox(filter->getParamName(i), &tmp)) {
|
||||
soloud->setFilterParameter(voice_handle, filter_id, i, tmp ? filter->getParamMax(i) : filter->getParamMin(i));
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (same_line && (i+1 != param_count)) {
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
} // MM::ImGuiWidgets
|
||||
|
235
framework/imgui/src/mm/imgui/widgets/soloud_sfxr.cpp
Normal file
235
framework/imgui/src/mm/imgui/widgets/soloud_sfxr.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
#include "./soloud.hpp"
|
||||
|
||||
#include <mm/imgui/widgets/knob.hpp>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <soloud_sfxr.h>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
bool SoLoudSfxrPlain(const char* label, SoLoud::SfxrParams* sfxr_params) {
|
||||
ImGui::PushID(label);
|
||||
|
||||
bool value_changed = false;
|
||||
|
||||
{
|
||||
const char* wlist[] {"SquareWave", "SawTooth", "SineWave", "Noise"};
|
||||
if (ImGui::BeginCombo("Wave Type", wlist[sfxr_params->wave_type])) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ImGui::Selectable(wlist[i])) {
|
||||
sfxr_params->wave_type = i;
|
||||
value_changed = true;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
//internal_sec1();
|
||||
{
|
||||
value_changed |= ImGui::SliderFloat("Attack Time", &sfxr_params->p_env_attack, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Sustain Time", &sfxr_params->p_env_sustain, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Sustain Punch", &sfxr_params->p_env_punch, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Decay Time", &sfxr_params->p_env_decay, 0.f, 1.f);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
//internal_sec2();
|
||||
{
|
||||
value_changed |= ImGui::SliderFloat("Start Freq", &sfxr_params->p_base_freq, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Min Freq", &sfxr_params->p_freq_limit, 0.f, 1.f);
|
||||
|
||||
value_changed |= ImGui::SliderFloat("Slide", &sfxr_params->p_freq_ramp, -1.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Slide Delta", &sfxr_params->p_freq_dramp, -1.f, 1.f);
|
||||
|
||||
value_changed |= ImGui::SliderFloat("Vibrato Depth", &sfxr_params->p_vib_strength, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Vibrato Speed", &sfxr_params->p_vib_speed, 0.f, 1.f);
|
||||
//ImGui::SliderFloat("Vibrato Delay", &sfxr_params->p_vib_delay, 0.f, 1.f); // useless?
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
//internal_sec3();
|
||||
{
|
||||
value_changed |= ImGui::SliderFloat("Change Amount", &sfxr_params->p_arp_mod, -1.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Change Speed", &sfxr_params->p_arp_speed, 0.f, 1.f);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
//internal_sec4();
|
||||
{
|
||||
value_changed |= ImGui::SliderFloat("Square Duty", &sfxr_params->p_duty, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Duty Sweep", &sfxr_params->p_duty_ramp, -1.f, 1.f);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
//internal_sec5();
|
||||
{
|
||||
value_changed |= ImGui::SliderFloat("Repeat Speed", &sfxr_params->p_repeat_speed, 0.f, 1.f);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
//internal_sec6();
|
||||
{
|
||||
value_changed |= ImGui::SliderFloat("Phaser Offset", &sfxr_params->p_pha_offset, -1.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("Phaser Sweep", &sfxr_params->p_pha_ramp, -1.f, 1.f);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
//internal_sec7();
|
||||
{
|
||||
value_changed |= ImGui::SliderFloat("LP Filter Cutoff", &sfxr_params->p_lpf_freq, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("LP Filter Cutoff Sweep", &sfxr_params->p_lpf_ramp, -1.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("LP Filter Resonace", &sfxr_params->p_lpf_resonance, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("HP Filter Cutoff", &sfxr_params->p_hpf_freq, 0.f, 1.f);
|
||||
value_changed |= ImGui::SliderFloat("HP Filter Cutoff Sweep", &sfxr_params->p_hpf_ramp, -1.f, 1.f);
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
bool SoLoudSfxrFancy(const char* label, SoLoud::SfxrParams* sfxr_params) {
|
||||
ImGui::PushID(label);
|
||||
|
||||
bool value_changed = false;
|
||||
|
||||
{
|
||||
const char* wlist[] {"SquareWave", "SawTooth", "SineWave", "Noise"};
|
||||
if (ImGui::BeginCombo("Wave Type", wlist[sfxr_params->wave_type])) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ImGui::Selectable(wlist[i])) {
|
||||
sfxr_params->wave_type = i;
|
||||
value_changed = true;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
// square wave mods
|
||||
if (sfxr_params->wave_type == 0) {
|
||||
if (ImGui::BeginChild("SquareWaveMod", ImVec2(105, 90), true)) {
|
||||
ImGui::TextDisabled("SQW Mod");
|
||||
|
||||
value_changed |= KnobFloat("Duty", &sfxr_params->p_duty, 0.f, 1.f, 400.f);
|
||||
ImGui::SameLine();
|
||||
value_changed |= KnobFloat("Sweep", &sfxr_params->p_duty_ramp, -1.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild(); // SquareWaveMod
|
||||
}
|
||||
|
||||
// +-------------+----+
|
||||
// |EG |VOL |
|
||||
// | O O O O | O |
|
||||
// +----------+--+-+--+
|
||||
// |FQ |ARP |
|
||||
// | O O O | O |
|
||||
// | O O O | O |
|
||||
// +----------+----+
|
||||
|
||||
if (ImGui::BeginChild("EG", ImVec2(200, 90), true)) {
|
||||
ImGui::TextDisabled("EG");
|
||||
|
||||
value_changed |= KnobFloat("Attack", &sfxr_params->p_env_attack, 0.f, 1.f, 400.f);
|
||||
ImGui::SameLine();
|
||||
value_changed |= KnobFloat("Sustain", &sfxr_params->p_env_sustain, 0.f, 1.f, 400.f);
|
||||
ImGui::SameLine();
|
||||
value_changed |= KnobFloat("Punch", &sfxr_params->p_env_punch, 0.f, 1.f, 400.f);
|
||||
ImGui::SameLine();
|
||||
value_changed |= KnobFloat("Decay", &sfxr_params->p_env_decay, 0.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild(); // EG
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("Vol", ImVec2(58, 90), true)) {
|
||||
ImGui::TextDisabled("Vol");
|
||||
|
||||
value_changed |= KnobFloat("Volume", &sfxr_params->sound_vol, 0.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild(); // Vol
|
||||
|
||||
// next line
|
||||
|
||||
if (ImGui::BeginChild("Frequency", ImVec2(58, 152), true)) {
|
||||
ImGui::TextDisabled("Freq");
|
||||
value_changed |= KnobFloat("Base", &sfxr_params->p_base_freq, 0.f, 1.f, 400.f);
|
||||
value_changed |= KnobFloat("Limit", &sfxr_params->p_freq_limit, 0.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("Slide", ImVec2(58, 152), true)) {
|
||||
ImGui::TextDisabled("Slide");
|
||||
value_changed |= KnobFloat("Slide", &sfxr_params->p_freq_ramp, -1.f, 1.f, 400.f);
|
||||
value_changed |= KnobFloat("Delta", &sfxr_params->p_freq_dramp, -1.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("Vibrato", ImVec2(58, 152), true)) {
|
||||
ImGui::TextDisabled("Vib");
|
||||
value_changed |= KnobFloat("Depth", &sfxr_params->p_vib_strength, 0.f, 1.f, 400.f);
|
||||
value_changed |= KnobFloat("Speed", &sfxr_params->p_vib_speed, 0.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("Arp", ImVec2(58, 152), true)) {
|
||||
ImGui::TextDisabled("Arp");
|
||||
value_changed |= KnobFloat("Amount", &sfxr_params->p_arp_mod, -1.f, 1.f, 400.f);
|
||||
value_changed |= KnobFloat("Speed", &sfxr_params->p_arp_speed, 0.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild(); // Arp
|
||||
|
||||
// next line
|
||||
|
||||
if (ImGui::BeginChild("Repeat", ImVec2(58, 90), true)) {
|
||||
ImGui::TextDisabled("Repeat");
|
||||
value_changed |= KnobFloat("Speed", &sfxr_params->p_repeat_speed, 0.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild(); // Repeat
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("Phaser", ImVec2(105, 90), true)) {
|
||||
ImGui::TextDisabled("Phaser");
|
||||
value_changed |= KnobFloat("Offset", &sfxr_params->p_pha_offset, -1.f, 1.f, 400.f);
|
||||
ImGui::SameLine();
|
||||
value_changed |= KnobFloat("Sweep", &sfxr_params->p_pha_ramp, -1.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild(); // Phaser
|
||||
|
||||
// next line
|
||||
|
||||
if (ImGui::BeginChild("LP Filter", ImVec2(152, 90), true)) {
|
||||
ImGui::TextDisabled("LP Filter");
|
||||
value_changed |= KnobFloat("Cutoff", &sfxr_params->p_lpf_freq, 0.f, 1.f, 400.f);
|
||||
ImGui::SameLine();
|
||||
value_changed |= KnobFloat("Sweep", &sfxr_params->p_lpf_ramp, -1.f, 1.f, 400.f);
|
||||
ImGui::SameLine();
|
||||
value_changed |= KnobFloat("Peak", &sfxr_params->p_lpf_resonance, 0.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild(); // LP Filter
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("HP Filter", ImVec2(105, 90), true)) {
|
||||
ImGui::TextDisabled("HP Filter");
|
||||
value_changed |= KnobFloat("Cutoff", &sfxr_params->p_hpf_freq, 0.f, 1.f, 400.f);
|
||||
ImGui::SameLine();
|
||||
value_changed |= KnobFloat("Sweep", &sfxr_params->p_hpf_ramp, -1.f, 1.f, 400.f);
|
||||
}
|
||||
ImGui::EndChild(); // HP Filter
|
||||
|
||||
ImGui::PopID();
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
} // MM::ImGuiWidgets
|
||||
|
117
framework/imgui/src/mm/imgui/widgets/spritesheet.cpp
Normal file
117
framework/imgui/src/mm/imgui/widgets/spritesheet.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include "./spritesheet.hpp"
|
||||
|
||||
#include <mm/opengl/spritesheet.hpp>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
#include "./texture.hpp"
|
||||
|
||||
#include <mm/logger.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void SpriteSheetPreview(MM::OpenGL::SpriteSheet& sheet, ImVec2 size) {
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
const ImVec2 p = ImGui::GetCursorScreenPos();
|
||||
|
||||
const ImVec2 uv_a {0.f, 1.f};
|
||||
const ImVec2 uv_b {1.f, 0.f};
|
||||
|
||||
draw_list->AddImage(sheet.tex->getHandle(), p, {p.x + size.x, p.y + size.y}, uv_a, uv_b);
|
||||
|
||||
const ImU32 line_col = ImColor(ImVec4(1.f, 0.f, 0.f, 1.f));
|
||||
|
||||
// TODO: tile size?
|
||||
|
||||
// v lines
|
||||
for (uint32_t i = 0; i <= sheet.tile_count.x; i++) {
|
||||
const float scale = size.x/sheet.tile_count.x;
|
||||
const float x = p.x + scale*(float)i;
|
||||
draw_list->AddLine({x, p.y}, {x, p.y + size.y}, line_col);
|
||||
}
|
||||
|
||||
// h lines
|
||||
for (uint32_t i = 0; i <= sheet.tile_count.y; i++) {
|
||||
const float scale = size.y/sheet.tile_count.y;
|
||||
const float y = p.y + scale*(float)i;;
|
||||
draw_list->AddLine({p.x, y}, {p.x + size.x, y}, line_col);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteSheet(MM::OpenGL::SpriteSheet& sheet) {
|
||||
const float w_all = ImGui::CalcItemWidth();
|
||||
const ImVec2 dims {w_all, w_all * ((float)sheet.tex->height/sheet.tex->width)};
|
||||
SpriteSheetPreview(sheet, dims);
|
||||
|
||||
// TODO: also activate by drag n drop targeting
|
||||
if (ImGui::InvisibleButton("clickability", dims)) {
|
||||
ImGui::OpenPopup("sprite_sheet_editor_popup");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("sprite_sheet_editor_popup")) {
|
||||
SpriteSheetEditor(sheet);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void LabelSpriteSheet(const char* label, MM::OpenGL::SpriteSheet& sheet) {
|
||||
const char* lable_display_end = ImGui::FindRenderedTextEnd(label);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushID(label);
|
||||
|
||||
SpriteSheet(sheet);
|
||||
|
||||
// drop
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_MM_REND_TEXTURE)) {
|
||||
if (payload->DataSize != sizeof(MM::ResourceManager<MM::OpenGL::Texture>::res_id_type)) {
|
||||
SPDLOG_ERROR("drag'n'drop data size missmatch ({} {})", payload->DataSize, sizeof(MM::ResourceManager<MM::OpenGL::Texture>::res_id_type));
|
||||
} else {
|
||||
auto& id = *(MM::ResourceManager<MM::OpenGL::Texture>::res_id_type*)payload->Data;
|
||||
sheet.tex = MM::ResourceManager<MM::OpenGL::Texture>::ref().get(id);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
//const ImVec2 label_size = ImGui::CalcTextSize(label, lable_display_end, true);
|
||||
|
||||
//ImGui::Dummy({(w_all - (size.x + label_size.x) + 42.f), s_sz});
|
||||
|
||||
if (label != lable_display_end) {
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(label, lable_display_end);
|
||||
}
|
||||
|
||||
|
||||
ImGui::PopID(); // pop label
|
||||
ImGui::EndGroup();
|
||||
|
||||
}
|
||||
|
||||
void SpriteSheetEditor(MM::OpenGL::SpriteSheet& sheet) {
|
||||
assert(sheet.tex);
|
||||
const float w_all = ImGui::CalcItemWidth();
|
||||
const ImVec2 dims {w_all, w_all * ((float)sheet.tex->height/sheet.tex->width)};
|
||||
SpriteSheetPreview(sheet, dims);
|
||||
ImGui::Dummy(dims);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
MM::ImGuiWidgets::LabelTexture("tex##SpriteSheet", sheet.tex);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
uint32_t step = 1;
|
||||
ImGui::InputScalar("tile_count x##SpriteSheet", ImGuiDataType_U32, &sheet.tile_count.x, &step, NULL, NULL, 0);
|
||||
ImGui::InputScalar("tile_count y##SpriteSheet", ImGuiDataType_U32, &sheet.tile_count.y, &step, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
} // MM::ImGuiWidgets
|
||||
|
17
framework/imgui/src/mm/imgui/widgets/spritesheet.hpp
Normal file
17
framework/imgui/src/mm/imgui/widgets/spritesheet.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
// forward
|
||||
struct ImVec2;
|
||||
namespace MM::OpenGL {
|
||||
struct SpriteSheet;
|
||||
}
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void SpriteSheetPreview(MM::OpenGL::SpriteSheet& sheet, ImVec2 size);
|
||||
void SpriteSheet(MM::OpenGL::SpriteSheet& sheet);
|
||||
void LabelSpriteSheet(const char* label, MM::OpenGL::SpriteSheet& sheet);
|
||||
void SpriteSheetEditor(MM::OpenGL::SpriteSheet& sheet);
|
||||
|
||||
} // MM::ImGuiWidgets
|
||||
|
93
framework/imgui/src/mm/imgui/widgets/texture.cpp
Normal file
93
framework/imgui/src/mm/imgui/widgets/texture.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "./texture.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
#include <mm/logger.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
// TODO: fix formating
|
||||
void Texture(MM::OpenGL::Texture::handle& texture, bool dropTarget) {
|
||||
const float s_sz = ImGui::GetFrameHeight();
|
||||
//const float w_all = ImGui::CalcItemWidth();
|
||||
//const char* lable_display_end = ImGui::FindRenderedTextEnd(label);
|
||||
ImVec2 size{s_sz*2.f, s_sz*2.f};
|
||||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
if (texture) {
|
||||
ImGui::Image(texture->getHandle(), size, {0.f, 1.f}, {1.f, 0.f}, ImVec4(1,1,1,1), ImVec4(1,1,1,1));
|
||||
|
||||
// "tooltip"
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
const ImVec2 orig_size {(float)texture->width, (float)texture->height};
|
||||
ImGui::Image(texture->getHandle(), orig_size, {0.f, 1.f}, {1.f, 0.f});
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
// drag
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) {
|
||||
auto id = MM::ResourceManager<MM::OpenGL::Texture>::ref().id_from_handle(texture);
|
||||
if (id) {
|
||||
ImGui::SetDragDropPayload(IMGUI_PAYLOAD_TYPE_MM_REND_TEXTURE, &(id.value()), sizeof(id.value()));
|
||||
ImGui::Image(texture->getHandle(), size, {0.f, 1.f}, {1.f, 0.f}, ImVec4(1,1,1,1), ImVec4(1,1,1,1));
|
||||
}
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
} else {
|
||||
// TODO: default texture
|
||||
ImGui::TextUnformatted("NO TEXTURE");
|
||||
}
|
||||
|
||||
// drop
|
||||
if (dropTarget && ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_MM_REND_TEXTURE)) {
|
||||
if (payload->DataSize != sizeof(MM::ResourceManager<MM::OpenGL::Texture>::res_id_type)) {
|
||||
SPDLOG_ERROR("drag'n'drop data size missmatch ({} {})", payload->DataSize, sizeof(MM::ResourceManager<MM::OpenGL::Texture>::res_id_type));
|
||||
} else {
|
||||
auto& id = *(MM::ResourceManager<MM::OpenGL::Texture>::res_id_type*)payload->Data;
|
||||
texture = MM::ResourceManager<MM::OpenGL::Texture>::ref().get(id);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
void LabelTexture(const char* label, MM::OpenGL::Texture::handle& texture, bool dropTarget) {
|
||||
const float s_sz = ImGui::GetFrameHeight();
|
||||
const float w_all = ImGui::CalcItemWidth();
|
||||
const char* lable_display_end = ImGui::FindRenderedTextEnd(label);
|
||||
|
||||
ImVec2 size{s_sz*2.f, s_sz*2.f};
|
||||
if (!texture) {
|
||||
size = ImGui::CalcTextSize("NO TEXTURE");
|
||||
}
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushID(label);
|
||||
|
||||
Texture(texture, dropTarget);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
const ImVec2 label_size = ImGui::CalcTextSize(label, lable_display_end, true);
|
||||
|
||||
ImGui::Dummy({(w_all - (size.x + label_size.x) + 42.f), s_sz});
|
||||
|
||||
if (label != lable_display_end) {
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(label, lable_display_end);
|
||||
}
|
||||
|
||||
|
||||
ImGui::PopID(); // pop label
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
}
|
||||
|
13
framework/imgui/src/mm/imgui/widgets/texture.hpp
Normal file
13
framework/imgui/src/mm/imgui/widgets/texture.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/opengl/texture.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
#define IMGUI_PAYLOAD_TYPE_MM_REND_TEXTURE "MM_REND_TEXTURE"
|
||||
|
||||
void Texture(MM::OpenGL::Texture::handle& texture, bool dropTarget = true);
|
||||
void LabelTexture(const char* label, MM::OpenGL::Texture::handle& texture, bool dropTarget = true);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,85 @@
|
||||
#include "texture_resource_manager.hpp"
|
||||
|
||||
#include <mm/imgui/widgets/filesystem.hpp>
|
||||
|
||||
#include <mm/services/filesystem.hpp>
|
||||
|
||||
#include <mm/opengl/texture_loader.hpp>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <mm/logger.hpp>
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void TextureResourceManagerList(void) {
|
||||
auto& rm = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||
|
||||
ImGui::Text("textures is cache: %lu", rm.size());
|
||||
|
||||
std::function<void(MM::ResourceManager<MM::OpenGL::Texture>::res_id_type, std::shared_ptr<MM::OpenGL::Texture>)> fn =
|
||||
[](auto /*id*/, std::shared_ptr<MM::OpenGL::Texture> h) {
|
||||
Texture(h, false);
|
||||
return;
|
||||
};
|
||||
|
||||
if (ImGui::BeginChild("texture list")) {
|
||||
rm.each(fn);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void TextureResourceManagerLoader(MM::Engine& engine) {
|
||||
auto& rm = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||
static MM::OpenGL::Texture::handle texture = rm.get("default"_hs);
|
||||
|
||||
static std::string path = "";
|
||||
|
||||
auto& fs = engine.getService<MM::Services::FilesystemService>();
|
||||
MM::ImGuiWidgets::FilePicker("texture_loader", fs, path, false);
|
||||
|
||||
static char ident[30] = {};
|
||||
|
||||
ImGui::InputText("texture id", ident, 29);
|
||||
|
||||
bool load = false;
|
||||
bool force = false;
|
||||
ImGui::BeginGroup();
|
||||
if (ImGui::Button("load file!")) {
|
||||
load = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("force load file!")) {
|
||||
load = true;
|
||||
force = true;
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
if (load) {
|
||||
auto id = entt::hashed_string{ident}.value();
|
||||
if (!force && rm.contains(id)) {
|
||||
SPDLOG_ERROR("TextureResourceManagerLoader: id allready used! ({})", id);
|
||||
} else if (!force && strlen(ident) == 0) {
|
||||
SPDLOG_ERROR("TextureResourceManagerLoader: id empty!");
|
||||
} else if (!fs.isFile(path.c_str())) {
|
||||
SPDLOG_ERROR("TextureResourceManagerLoader: '{}' is not a file!", path);
|
||||
} else {
|
||||
if (!force && rm.load<MM::OpenGL::TextureLoaderFile>(ident, engine, path)) {
|
||||
texture = rm.get(id);
|
||||
} else if (force && rm.reload<MM::OpenGL::TextureLoaderFile>(ident, engine, path)) {
|
||||
texture = rm.get(id);
|
||||
} else {
|
||||
SPDLOG_ERROR("TextureResourceManagerLoader: loading texture from file! {}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("last loaded texture:");
|
||||
ImGui::SameLine();
|
||||
MM::ImGuiWidgets::Texture(texture, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/resource_manager.hpp>
|
||||
|
||||
#include <mm/opengl/texture.hpp>
|
||||
#include "./texture.hpp"
|
||||
|
||||
// fwd
|
||||
namespace MM {
|
||||
class Engine;
|
||||
}
|
||||
|
||||
namespace MM::ImGuiWidgets {
|
||||
|
||||
void TextureResourceManagerList(void);
|
||||
|
||||
void TextureResourceManagerLoader(Engine& engine);
|
||||
|
||||
}
|
||||
|
||||
|
141
framework/imgui/src/mm/services/imgui_s.cpp
Normal file
141
framework/imgui/src/mm/services/imgui_s.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include "./imgui_s.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui_impl_sdl.h>
|
||||
|
||||
#ifdef MM_OPENGL_3
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#endif
|
||||
|
||||
#include <IconsIonicons.h>
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define USE_BASE85
|
||||
#endif
|
||||
|
||||
#ifdef USE_BASE85
|
||||
#include "../../../res/ionicons/ionicons.ttf.base85.h"
|
||||
#else
|
||||
#include "../../../res/ionicons/ionicons.ttf.h"
|
||||
#endif
|
||||
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
bool ImGuiService::enable(Engine& engine) {
|
||||
IMGUI_CHECKVERSION();
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavNoCaptureKeyboard;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // TODO: dont, if ingame ?
|
||||
|
||||
auto& sdl_ss = engine.getService<MM::Services::SDLService>();
|
||||
#ifdef MM_OPENGL_3
|
||||
ImGui_ImplSDL2_InitForOpenGL(sdl_ss.win, sdl_ss.gl_context);
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
#endif
|
||||
|
||||
// style
|
||||
{
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
auto& style = ImGui::GetStyle();
|
||||
style.WindowRounding = 2.f;
|
||||
}
|
||||
|
||||
// font
|
||||
{
|
||||
io.Fonts->AddFontDefault();
|
||||
static const ImWchar icons_ranges[] = {ICON_MIN_II, ICON_MAX_II, 0};
|
||||
ImFontConfig icons_config;
|
||||
icons_config.MergeMode = true;
|
||||
icons_config.PixelSnapH = true;
|
||||
icons_config.FontDataOwnedByAtlas = false;
|
||||
icons_config.GlyphOffset = {0.f, 4.f};
|
||||
//io.Fonts->AddFontFromMemoryTTF(ionicons_ttf, ionicons_ttf_len, 16.f, &icons_config, icons_ranges);
|
||||
#ifdef USE_BASE85
|
||||
io.Fonts->AddFontFromMemoryCompressedBase85TTF(ionicons_ttf_compressed_data_base85, 16.f*1.3f, &icons_config, icons_ranges);
|
||||
#else
|
||||
io.Fonts->AddFontFromMemoryTTF(ionicons_ttf, ionicons_ttf_len, 16.f, &icons_config, icons_ranges);
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: register event handle
|
||||
_event_handle = sdl_ss.addEventHandler([](const SDL_Event& e) {
|
||||
if (!ImGui_ImplSDL2_ProcessEvent(&e)) {
|
||||
return false; // if the event was not relevant to imgui anyway
|
||||
}
|
||||
|
||||
auto& io = ImGui::GetIO();
|
||||
// keyboard
|
||||
if ((
|
||||
e.type == SDL_KEYDOWN ||
|
||||
e.type == SDL_KEYUP ||
|
||||
e.type == SDL_TEXTEDITING ||
|
||||
e.type == SDL_TEXTINPUT
|
||||
)
|
||||
&& io.WantCaptureKeyboard) {
|
||||
return true;
|
||||
}
|
||||
// mouse
|
||||
if ((
|
||||
e.type == SDL_MOUSEMOTION ||
|
||||
e.type == SDL_MOUSEBUTTONUP ||
|
||||
e.type == SDL_MOUSEBUTTONDOWN ||
|
||||
e.type == SDL_MOUSEWHEEL // ????
|
||||
)
|
||||
&& io.WantCaptureMouse) {
|
||||
return true;
|
||||
}
|
||||
//// controller ???
|
||||
//if ((
|
||||
//e.type == SDL_CONTROLLERBUTTONUP ||
|
||||
//e.type == SDL_CONTROLLERBUTTONDOWN
|
||||
//)[>
|
||||
//&& io.WantCaptureKeyboard*/) {
|
||||
//return false;
|
||||
//}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
_new_frame_handle = engine.addUpdate([this](Engine& e) { this->imgui_new_frame(e); });
|
||||
assert(!_new_frame_handle.expired());
|
||||
auto tmp_lock = _new_frame_handle.lock();
|
||||
tmp_lock->priority = 90; // after sdl events (100)
|
||||
tmp_lock->name = "imgui new frame";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGuiService::disable(Engine& engine) {
|
||||
auto& sdl_ss = engine.getService<MM::Services::SDLService>();
|
||||
sdl_ss.removeEventHandler(_event_handle);
|
||||
|
||||
engine.removeUpdate(_new_frame_handle);
|
||||
|
||||
ImGui::EndFrame(); // making sure, does not work????
|
||||
|
||||
#ifdef MM_OPENGL_3
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
#endif
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
void ImGuiService::imgui_new_frame(Engine& engine) {
|
||||
ZoneScopedN("MM::Services::ImGuiService::imgui_new_frame");
|
||||
|
||||
#ifdef MM_OPENGL_3
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
#endif
|
||||
|
||||
ImGui_ImplSDL2_NewFrame(engine.getService<MM::Services::SDLService>().win);
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
} // namespace MM::Services
|
||||
|
28
framework/imgui/src/mm/services/imgui_s.hpp
Normal file
28
framework/imgui/src/mm/services/imgui_s.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
#include <mm/services/sdl_service.hpp>
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
// responsable for event handling and setup
|
||||
// enable requires an open sdl window (and context)
|
||||
class ImGuiService : public Service {
|
||||
private:
|
||||
MM::Services::SDLService::EventHandlerHandle _event_handle = nullptr;
|
||||
|
||||
// new frame needs to start AFTER the events have been processed (and obv bf rendt)
|
||||
MM::Engine::FunctionDataHandle _new_frame_handle;
|
||||
|
||||
public:
|
||||
bool enable(Engine& engine) override;
|
||||
void disable(Engine& engine) override;
|
||||
|
||||
const char* name(void) override { return "ImGuiService"; }
|
||||
|
||||
private:
|
||||
void imgui_new_frame(Engine& engine);
|
||||
};
|
||||
|
||||
} // namespace MM::Services
|
||||
|
213
framework/imgui/src/mm/services/scene_tools.cpp
Normal file
213
framework/imgui/src/mm/services/scene_tools.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
#include "./scene_tools.hpp"
|
||||
|
||||
#include <entt/config/version.h>
|
||||
|
||||
#include <mm/services/opengl_renderer.hpp>
|
||||
|
||||
#include <mm/resource_manager.hpp>
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <mm/components/name.hpp>
|
||||
#include <mm/components/transform2d.hpp>
|
||||
#include <mm/components/velocity2d.hpp>
|
||||
|
||||
#include <mm/imgui/widgets/texture_resource_manager.hpp>
|
||||
#include <mm/imgui/widgets/entity.hpp>
|
||||
|
||||
#include <mm/imgui/widgets/components/name.hpp>
|
||||
#include <mm/imgui/widgets/components/transform2d.hpp>
|
||||
#include <mm/imgui/widgets/components/transform3d.hpp>
|
||||
#include <mm/imgui/widgets/components/velocity2d.hpp>
|
||||
#include <mm/imgui/widgets/components/view_dir2d.hpp>
|
||||
#include <mm/imgui/widgets/components/view_dir3d.hpp>
|
||||
#include <mm/imgui/widgets/components/color.hpp>
|
||||
#include <mm/imgui/widgets/components/texture.hpp>
|
||||
|
||||
#include <mm/imgui/widgets/camera.hpp>
|
||||
|
||||
#include <mm/imgui/widgets/filesystem.hpp>
|
||||
#include <mm/services/filesystem.hpp>
|
||||
|
||||
#include <mm/logger.hpp>
|
||||
#define LOGIGS(x) LOG("ImGuiSceneToolsService", x)
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
void ImGuiSceneToolsService::renderImGui(Engine& engine) {
|
||||
if (show_menu && ImGui::BeginMainMenuBar()) {
|
||||
if (ImGui::BeginMenu("Engine")) {
|
||||
if (ImGui::MenuItem("Stop Engine")) {
|
||||
engine.stop();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("TextEditor")) {
|
||||
if (ImGui::MenuItem("New Editor")) {
|
||||
_text_editor_list.emplace_back(engine);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Windows")) {
|
||||
ImGui::MenuItem("MM Metrics", NULL, &_show_mm_metrics);
|
||||
ImGui::MenuItem("ImGui Metrics", NULL, &_show_imgui_metrics);
|
||||
ImGui::MenuItem("Texture Loader", NULL, &_show_texture_loader);
|
||||
ImGui::MenuItem("Texture List", NULL, &_show_texture_list);
|
||||
ImGui::MenuItem("Entity Editor", NULL, &_show_entity_editor);
|
||||
ImGui::MenuItem("Camera Tool", NULL, &_show_camera_tool);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::Text("%.1fFPS", ImGui::GetIO().Framerate);
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
||||
|
||||
if (_show_mm_metrics) {
|
||||
if (ImGui::Begin("Metrics##MM", &_show_mm_metrics)) {
|
||||
if (ImGui::CollapsingHeader("ECS")) {
|
||||
ImGui::Text("EnTT v%d.%d.%d", ENTT_VERSION_MAJOR, ENTT_VERSION_MINOR, ENTT_VERSION_PATCH);
|
||||
ImGui::Text("capacity: %lu", scene.capacity());
|
||||
ImGui::Text("size: %lu", scene.size());
|
||||
ImGui::Text("alive: %lu", scene.alive());
|
||||
size_t orphans = 0;
|
||||
scene.orphans([&](auto) { orphans++; });
|
||||
ImGui::Text("orphans: %lu", orphans);
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (_show_imgui_metrics) {
|
||||
ImGui::ShowMetricsWindow(&_show_imgui_metrics);
|
||||
}
|
||||
|
||||
if (_show_texture_loader) {
|
||||
if (ImGui::Begin("Texture Loader", &_show_texture_loader)) {
|
||||
ImGuiWidgets::TextureResourceManagerLoader(engine);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (_show_texture_list) {
|
||||
if (ImGui::Begin("Texture List", &_show_texture_list)) {
|
||||
ImGuiWidgets::TextureResourceManagerList();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (_show_entity_editor) {
|
||||
ImGui::SetNextWindowSize(ImVec2(750, 500), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("Entity Editor", &_show_entity_editor, ImGuiWindowFlags_MenuBar)) {
|
||||
ImGui::BeginMenuBar();
|
||||
ImGui::Checkbox("Show List", &_show_entity_list);
|
||||
ImGui::EndMenuBar();
|
||||
|
||||
if (_show_entity_list) {
|
||||
if (ImGui::BeginChild("list", {300, 0}, true)) {
|
||||
ImGuiWidgets::EntityTrashCan(scene); // TODO: remove?
|
||||
_entity_editor.renderEntityList(scene, _entity_comp_list);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
if (ImGui::BeginChild("editor")) {
|
||||
_entity_editor.renderEditor(scene, _e);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (_show_camera_tool) {
|
||||
if (ImGui::Begin("Camera3D Tool", &_show_camera_tool)) {
|
||||
ImGuiWidgets::Camera3D(scene);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
for (auto it = _text_editor_list.begin(); it != _text_editor_list.end();) {
|
||||
bool keep_open = true;
|
||||
it->renderImGui(&keep_open);
|
||||
|
||||
if (!keep_open) {
|
||||
it = _text_editor_list.erase(it);
|
||||
continue;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
EntityEditor<Entity>& ImGuiSceneToolsService::getEntityEditor(void) {
|
||||
return _entity_editor;
|
||||
}
|
||||
|
||||
bool ImGuiSceneToolsService::enable(Engine& engine) {
|
||||
if (!engine.tryService<MM::Services::OpenGLRenderer>()) {
|
||||
LOGIGS("error: rendering is not in engine");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!engine.tryService<MM::Services::FilesystemService>()) {
|
||||
LOGIGS("error: filesystem not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!engine.tryService<MM::Services::SceneServiceInterface>()) {
|
||||
LOGIGS("error: no SceneServiceInterface");
|
||||
return false;
|
||||
}
|
||||
|
||||
// setup entity editor defaults
|
||||
{
|
||||
_entity_editor.show_window = false;
|
||||
|
||||
_entity_editor.registerComponent<MM::Components::Name>("Name");
|
||||
_entity_editor.registerComponent<MM::Components::Transform2D>("Transform2D");
|
||||
_entity_editor.registerComponent<MM::Components::Transform3D>("Transform3D");
|
||||
_entity_editor.registerComponent<MM::Components::Velocity2D>("Velocity2D");
|
||||
_entity_editor.registerComponent<MM::Components::ViewDir2D>("ViewDir2D");
|
||||
_entity_editor.registerComponent<MM::Components::ViewDir3D>("ViewDir3D");
|
||||
_entity_editor.registerComponent<MM::Components::Color>("Color");
|
||||
|
||||
_entity_editor.registerComponent<MM::Components::OpenGL::Texture>("Texture");
|
||||
}
|
||||
|
||||
_render_handle = engine.addUpdate([this](Engine& e){ this->renderImGui(e); });
|
||||
|
||||
auto* sdl_ss = engine.tryService<MM::Services::SDLService>();
|
||||
if (sdl_ss) {
|
||||
_event_handle = sdl_ss->addEventHandler([this](const SDL_Event& e) -> bool {
|
||||
if (e.type == SDL_KEYDOWN && !e.key.repeat && e.key.keysym.sym == this->toggle_key) {
|
||||
this->show_menu = !this->show_menu;
|
||||
}
|
||||
return false; // invis
|
||||
});
|
||||
} else {
|
||||
LOGIGS("Warn: no SDLService, skipping toggle hotkey");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGuiSceneToolsService::disable(Engine& engine) {
|
||||
if (!_render_handle.expired()) {
|
||||
engine.removeUpdate(_render_handle);
|
||||
_render_handle.reset();
|
||||
}
|
||||
|
||||
if (_event_handle) {
|
||||
auto* sdl_ss = engine.tryService<MM::Services::SDLService>();
|
||||
sdl_ss->removeEventHandler(_event_handle);
|
||||
_event_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace MM::Services
|
||||
|
53
framework/imgui/src/mm/services/scene_tools.hpp
Normal file
53
framework/imgui/src/mm/services/scene_tools.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include <mm/services/sdl_service.hpp>
|
||||
|
||||
#define MM_IEEE_ENTITY_WIDGET ::MM::ImGuiWidgets::Entity // evil
|
||||
#define MM_IEEE_ASSERT(x)
|
||||
#include <mm/imgui/widgets/entity.hpp>
|
||||
#include <mm/imgui/imgui_entt_entity_editor.hpp>
|
||||
|
||||
#include <mm/imgui/file_text_editor.hpp>
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
class ImGuiSceneToolsService : public Service {
|
||||
public:
|
||||
bool show_menu = true;
|
||||
|
||||
SDL_Keycode toggle_key = SDLK_F2;
|
||||
|
||||
private:
|
||||
bool _show_mm_metrics = false;
|
||||
bool _show_imgui_metrics = false;
|
||||
bool _show_texture_loader = false;
|
||||
bool _show_texture_list = false;
|
||||
bool _show_entity_editor = false;
|
||||
bool _show_entity_list = true;
|
||||
bool _show_camera_tool = false;
|
||||
|
||||
EntityEditor<Entity> _entity_editor;
|
||||
// for list
|
||||
std::set<EntityEditor<Entity>::ComponentTypeID> _entity_comp_list;
|
||||
|
||||
std::vector<MM::FileTextEditor> _text_editor_list;
|
||||
|
||||
Engine::FunctionDataHandle _render_handle;
|
||||
MM::Services::SDLService::EventHandlerHandle _event_handle = nullptr;
|
||||
|
||||
private:
|
||||
void renderImGui(Engine& engine);
|
||||
|
||||
public:
|
||||
EntityEditor<Entity>& getEntityEditor(void);
|
||||
Entity _e = entt::null; // entity currently in editor
|
||||
|
||||
public:
|
||||
bool enable(Engine& engine) override;
|
||||
void disable(Engine& engine) override;
|
||||
|
||||
const char* name(void) override { return "ImGuiSceneToolsService"; }
|
||||
};
|
||||
|
||||
} // namespace MM::Services
|
||||
|
Reference in New Issue
Block a user