initial import, >900commits predate this

This commit is contained in:
2020-09-29 13:47:50 +02:00
commit e74154ccee
352 changed files with 108120 additions and 0 deletions

View File

@ -0,0 +1,134 @@
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
project(imgui_lib CXX)
################## imgui_service
add_library(imgui_service
./src/mm/services/imgui_s.hpp
./src/mm/services/imgui_s.cpp
)
target_include_directories(imgui_service PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(imgui_service
engine
imgui_render_task
)
################## imgui_widgets
add_library(imgui_widgets
./src/mm/imgui/widgets/knob.hpp
./src/mm/imgui/widgets/plot_radar.hpp
./src/mm/imgui/widgets/camera.hpp
./src/mm/imgui/widgets/entity.hpp
./src/mm/imgui/widgets/filesystem.hpp
./src/mm/imgui/widgets/spritesheet.hpp
./src/mm/imgui/widgets/texture.hpp
./src/mm/imgui/widgets/texture_resource_manager.hpp
./src/mm/imgui/widgets/auto_wrap.hpp
./src/mm/imgui/widgets/components/name.hpp
./src/mm/imgui/widgets/components/transform2d.hpp
./src/mm/imgui/widgets/components/transform3d.hpp
./src/mm/imgui/widgets/components/velocity2d.hpp
./src/mm/imgui/widgets/components/view_dir2d.hpp
./src/mm/imgui/widgets/components/view_dir3d.hpp
./src/mm/imgui/widgets/components/color.hpp
./src/mm/imgui/widgets/components/texture.hpp
############
./src/mm/imgui/widgets/knob.cpp
./src/mm/imgui/widgets/plot_radar.cpp
./src/mm/imgui/widgets/camera.cpp
./src/mm/imgui/widgets/entity.cpp
./src/mm/imgui/widgets/filesystem.cpp
./src/mm/imgui/widgets/spritesheet.cpp
./src/mm/imgui/widgets/texture.cpp
./src/mm/imgui/widgets/texture_resource_manager.cpp
./src/mm/imgui/widgets/components/name.cpp
./src/mm/imgui/widgets/components/transform2d.cpp
./src/mm/imgui/widgets/components/transform3d.cpp
./src/mm/imgui/widgets/components/velocity2d.cpp
./src/mm/imgui/widgets/components/view_dir2d.cpp
./src/mm/imgui/widgets/components/view_dir3d.cpp
./src/mm/imgui/widgets/components/color.cpp
./src/mm/imgui/widgets/components/texture.cpp
)
target_include_directories(imgui_widgets PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(imgui_widgets
opengl_renderer_s
imgui_render_task
engine
common_components
)
################## imgui_tools
add_library(imgui_tools
./src/mm/imgui/imgui_entt_entity_editor.hpp
./src/mm/imgui/fps_overlay.hpp
./src/mm/imgui/file_text_editor.hpp
./src/mm/imgui/file_shader_editor.hpp
./src/mm/imgui/fps_overlay.cpp
./src/mm/imgui/file_text_editor.cpp
./src/mm/imgui/file_shader_editor.cpp
./src/mm/services/scene_tools.hpp
./src/mm/services/scene_tools.cpp
)
target_include_directories(imgui_tools PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(imgui_tools
imgui_render_task
imgui_widgets
imgui_color_text_edit
)
################## imgui_sound
add_library(imgui_sound
./src/mm/imgui/sound_info.hpp
./src/mm/imgui/sound_pref.hpp
./src/mm/imgui/widgets/soloud.hpp
./src/mm/imgui/sound_info.cpp
./src/mm/imgui/sound_pref.cpp
# soloud.hpp imps:
./src/mm/imgui/widgets/soloud_sfxr.cpp
./src/mm/imgui/widgets/soloud_filter.cpp
)
target_include_directories(imgui_sound PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(imgui_sound
imgui_render_task
imgui_widgets
sound_service
)
################## imgui_tilemap
add_library(imgui_tilemap
./src/mm/imgui/widgets/components/tilemap_renderable.hpp
./src/mm/imgui/widgets/components/tilemap_renderable.cpp
)
target_include_directories(imgui_tilemap PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(imgui_tilemap
imgui_render_task
imgui_widgets
tilemap
)
if (BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-present Ionic (http://ionic.io/)
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.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View File

@ -0,0 +1,12 @@
#pragma once
namespace MM {
class ImGuiSimpleFPSOverlay {
private:
bool _show_plot = false;
public:
void renderImGui(void);
};
} // namespace MM

View 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([&registry](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.

View 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

View File

@ -0,0 +1,8 @@
#pragma once
namespace MM {
class Engine; // fwd
void ImGuiSoundInfo(Engine& engine);
} // MM

View 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

View File

@ -0,0 +1,8 @@
#pragma once
namespace MM {
class Engine; // fwd
void ImGuiSoundPref(Engine& engine);
} // MM

View 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();
}
}
}

View 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();
}
}

View 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);
}

View 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

View 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);
}

View 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

View 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);
}

View 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

View 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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View 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);
//}
}

View 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);
}

View 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();
}
}

View 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);
}

View 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

View 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);
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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();
}
}

View 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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View 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

View 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

View 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

View 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

View File

@ -0,0 +1,75 @@
add_executable(imgui_widget_test
./widget_test.cpp
)
target_include_directories(imgui_widget_test PRIVATE ".")
target_link_libraries(imgui_widget_test
engine
sdl_service
opengl_renderer_s
imgui_service
imgui_render_task
imgui_widgets
gtest_main
)
add_test(NAME imgui_widget_test COMMAND imgui_widget_test)
####################
add_executable(imgui_scene_tools_test
scene_tools_test.cpp
#res/res_errig.zip.h
#res/res_default.zip.h
)
target_include_directories(imgui_scene_tools_test PRIVATE ".")
target_link_libraries(imgui_scene_tools_test
engine
simple_scene
opengl_renderer_s
imgui_service
imgui_render_task
imgui_tools
gtest_main
)
add_test(NAME imgui_scene_tools_test COMMAND imgui_scene_tools_test)
####################
add_executable(imgui_sound_test
sound_test.cpp
)
target_include_directories(imgui_sound_test PRIVATE ".")
target_link_libraries(imgui_sound_test
engine
sdl_service
opengl_renderer_s
imgui_service
imgui_render_task
imgui_sound
#imgui_tools
gtest_main
)
add_test(NAME imgui_sound_test COMMAND imgui_sound_test)
####################
add_executable(imgui_text_edit_test
./text_edit_test.cpp
)
target_include_directories(imgui_text_edit_test PRIVATE ".")
target_link_libraries(imgui_text_edit_test
engine
simple_scene
opengl_renderer_s
imgui_service
imgui_render_task
imgui_tools
gtest_main
)
add_test(NAME imgui_text_edit_test COMMAND imgui_text_edit_test)

View File

@ -0,0 +1,78 @@
#include <gtest/gtest.h>
#include <mm/resource_manager.hpp>
#include <mm/engine.hpp>
#include <mm/services/sdl_service.hpp>
#include <mm/services/filesystem.hpp>
#include <mm/services/simple_scene.hpp>
#include <mm/services/imgui_s.hpp>
#include <mm/services/opengl_renderer.hpp>
#include <mm/opengl/render_tasks/imgui.hpp>
#include <mm/imgui/fps_overlay.hpp>
#include <mm/services/scene_tools.hpp>
static char* argv0;
TEST(imgui_scene_tools, it) {
MM::Engine engine;
auto& sdl_ss = engine.addService<MM::Services::SDLService>(SDL_INIT_VIDEO);
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
sdl_ss.createGLWindow("imgui_scene_tools_test", 1280, 720);
engine.addService<MM::Services::FilesystemService>(argv0, "imgui_scene_tools_test");
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
engine.addService<MM::Services::SimpleSceneService>();
ASSERT_TRUE(engine.enableService<MM::Services::SimpleSceneService>());
bool provide_ret = engine.provide<MM::Services::SceneServiceInterface, MM::Services::SimpleSceneService>();
ASSERT_TRUE(provide_ret);
engine.addService<MM::Services::ImGuiService>();
ASSERT_TRUE(engine.enableService<MM::Services::ImGuiService>());
engine.addService<MM::Services::ImGuiSceneToolsService>();
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
ASSERT_TRUE(engine.enableService<MM::Services::ImGuiSceneToolsService>());
rs.addRenderTask<MM::OpenGL::RenderTasks::ImGuiRT>(engine);
//InitializeYojimbo();
{
MM::ImGuiSimpleFPSOverlay fps_overlay;
engine.addUpdate([&](MM::Engine&) {
fps_overlay.renderImGui();
}
);
engine.run();
}
// TODO: clear asset manager
sdl_ss.destroyWindow();
//ShutdownYojimbo();
}
int main(int argc, char** argv) {
argv0 = argv[0];
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,156 @@
#include <gtest/gtest.h>
#include <mm/engine.hpp>
// services
#include <mm/services/sdl_service.hpp>
#include <mm/services/filesystem.hpp>
#include <mm/services/sound_service.hpp>
#include <mm/services/opengl_renderer.hpp>
#include <mm/services/imgui_s.hpp>
#include <mm/opengl/render_tasks/imgui.hpp>
#include <mm/imgui/sound_info.hpp>
#include <mm/imgui/sound_pref.hpp>
#include <mm/imgui/widgets/soloud.hpp>
#include <imgui/imgui.h>
#include <soloud_speech.h>
#include <soloud_sfxr.h>
#include <soloud_freeverbfilter.h>
#include <soloud_echofilter.h>
#include <soloud_lofifilter.h>
const char* argv0;
class ImGuiSpeechy {
private:
SoLoud::Speech speech;
SoLoud::Sfxr sfxr;
SoLoud::FreeverbFilter freeverb;
SoLoud::EchoFilter echo;
SoLoud::LofiFilter lofi;
public:
explicit ImGuiSpeechy(SoLoud::Soloud& sound) {
speech.setText("Test text. 1. 2. 3.");
sfxr.loadPreset(SoLoud::Sfxr::COIN, 0);
sound.setGlobalFilter(0, &lofi);
sound.setGlobalFilter(1, &echo);
sound.setGlobalFilter(2, &freeverb);
}
void renderImGui(MM::Engine& engine) {
auto& sound = *engine.tryService<MM::Services::SoundService>();
if (ImGui::Begin("Inputs")) {
if (ImGui::Button("play sfx")) {
sound.engine.play(sfxr);
}
//ImGui::Text("Active Voice Count: %d", sound.engine.getActiveVoiceCount());
if (ImGui::Button("Read")) {
sound.engine.play(speech);
}
}
ImGui::End();
if (ImGui::Begin("Sfxr plain")) {
MM::ImGuiWidgets::SoLoudSfxrPlain("plain_sfxr", &sfxr.mParams);
}
ImGui::End();
if (ImGui::Begin("Sfxr fancy")) {
MM::ImGuiWidgets::SoLoudSfxrFancy("fancy_sfxr", &sfxr.mParams);
}
ImGui::End();
if (ImGui::Begin("filter lofi")) {
MM::ImGuiWidgets::SoLoudFilterLiveParams("filter lofi", &sound.engine, &lofi, 0);
}
ImGui::End();
if (ImGui::Begin("filter echo")) {
MM::ImGuiWidgets::SoLoudFilterLiveParams("filter echo", &sound.engine, &echo, 1);
}
ImGui::End();
if (ImGui::Begin("filter freeverb")) {
MM::ImGuiWidgets::SoLoudFilterLiveParams("filter freeverb", &sound.engine, &freeverb, 2);
}
ImGui::End();
if (ImGui::Begin("filter fancy lofi")) {
ImGui::TextDisabled("LoFi");
MM::ImGuiWidgets::SoLoudFilterLiveParamsFancy("filter fancy lofi", &sound.engine, &lofi, 0);
}
ImGui::End();
if (ImGui::Begin("filter fancy echo")) {
ImGui::TextDisabled("Echo");
MM::ImGuiWidgets::SoLoudFilterLiveParamsFancy("filter fancy echo", &sound.engine, &echo, 1);
}
ImGui::End();
if (ImGui::Begin("filter fancy freeverb")) {
ImGui::TextDisabled("Rev");
MM::ImGuiWidgets::SoLoudFilterLiveParamsFancy("filter fancy freeverb", &sound.engine, &freeverb, 2);
}
ImGui::End();
}
};
TEST(imgui_sound, basic) {
MM::Engine engine;
auto& sdl_ss = engine.addService<MM::Services::SDLService>();
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
sdl_ss.createGLWindow("imgui_sound_test", 800, 600);
engine.addService<MM::Services::FilesystemService>(argv0, "imgui_sound_test");
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
auto& sound = engine.addService<MM::Services::SoundService>();
ASSERT_TRUE(engine.enableService<MM::Services::SoundService>());
sound.engine.setVisualizationEnable(true);
engine.addService<MM::Services::ImGuiService>();
ASSERT_TRUE(engine.enableService<MM::Services::ImGuiService>());
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
rs.addRenderTask<MM::OpenGL::RenderTasks::ImGuiRT>(engine);
{
ImGuiSpeechy speechy(sound.engine);
engine.addUpdate([&](MM::Engine& engine) {
MM::ImGuiSoundInfo(engine);
MM::ImGuiSoundPref(engine);
speechy.renderImGui(engine);
}
);
engine.run();
}
sdl_ss.destroyWindow();
}
int main(int argc, char** argv) {
argv0 = argv[0];
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,159 @@
#include <gtest/gtest.h>
#include <mm/resource_manager.hpp>
#include <mm/engine.hpp>
#include <mm/services/sdl_service.hpp>
#include <mm/services/filesystem.hpp>
#include <mm/services/simple_scene.hpp>
#include <mm/services/opengl_renderer.hpp>
#include <mm/services/imgui_s.hpp>
#include <mm/opengl/render_tasks/imgui.hpp>
#include <mm/imgui/fps_overlay.hpp>
#include <mm/imgui/file_text_editor.hpp>
#include <mm/imgui/file_shader_editor.hpp>
#include <mm/services/scene_tools.hpp>
static char* argv0;
TEST(imgui_text_edit, it) {
MM::Engine engine;
auto& sdl_ss = engine.addService<MM::Services::SDLService>(SDL_INIT_VIDEO);
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
sdl_ss.createGLWindow("imgui_text_edit_test", 1280, 720);
engine.addService<MM::Services::FilesystemService>(argv0, "imgui_text_edit_test");
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
engine.addService<MM::Services::SimpleSceneService>();
ASSERT_TRUE(engine.enableService<MM::Services::SimpleSceneService>());
bool provide_ret = engine.provide<MM::Services::SceneServiceInterface, MM::Services::SimpleSceneService>();
ASSERT_TRUE(provide_ret);
engine.addService<MM::Services::ImGuiService>();
ASSERT_TRUE(engine.enableService<MM::Services::ImGuiService>());
engine.addService<MM::Services::ImGuiSceneToolsService>();
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
rs.addRenderTask<MM::OpenGL::RenderTasks::ImGuiRT>(engine);
ASSERT_TRUE(engine.enableService<MM::Services::ImGuiSceneToolsService>());
MM::ImGuiSimpleFPSOverlay fps_overlay;
engine.addUpdate([&](MM::Engine&) {
fps_overlay.renderImGui();
}
);
MM::FileTextEditor fte{engine};
engine.addUpdate([&](MM::Engine&) {
fte.renderImGui();
}
);
engine.run();
// TODO: clear asset manager
sdl_ss.destroyWindow();
}
TEST(imgui_text_edit, shader) {
MM::Engine engine;
auto& sdl_ss = engine.addService<MM::Services::SDLService>(SDL_INIT_VIDEO);
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
sdl_ss.createGLWindow("imgui_text_edit_test", 1280, 720);
engine.addService<MM::Services::FilesystemService>(argv0, "imgui_text_edit_test");
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
engine.addService<MM::Services::SimpleSceneService>();
ASSERT_TRUE(engine.enableService<MM::Services::SimpleSceneService>());
bool provide_ret = engine.provide<MM::Services::SceneServiceInterface, MM::Services::SimpleSceneService>();
ASSERT_TRUE(provide_ret);
engine.addService<MM::Services::ImGuiService>();
ASSERT_TRUE(engine.enableService<MM::Services::ImGuiService>());
engine.addService<MM::Services::ImGuiSceneToolsService>();
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
rs.addRenderTask<MM::OpenGL::RenderTasks::ImGuiRT>(engine);
ASSERT_TRUE(engine.enableService<MM::Services::ImGuiSceneToolsService>());
MM::ImGuiSimpleFPSOverlay fps_overlay;
engine.addUpdate([&](MM::Engine&) {
fps_overlay.renderImGui();
}
);
//auto& rc = engine.getScene().ctx<MM::OpenGL::RenderController>();
//rc.registerRenderer<MM::OpenGL::Renderers::QuadRenderer>();
MM::FileTextEditor fte{engine};
engine.addUpdate([&](MM::Engine&) {
fte.renderImGui();
}
);
MM::FileShaderEditor fse{engine};
engine.addUpdate([&](MM::Engine&) {
fse.renderImGui();
}
);
fte.open("shader/quad_renderer/vert.glsl");
fse.open("shader/quad_renderer/frag.glsl");
// TODO: a shader to display plx
//{
//auto& ecs = engine.getScene();
//auto& ee = igsts->getEntityEditor();
//ee.registerTrivial<MM::OpenGL::Renderers::QuadRenderable>("QuadRenderable");
//ee.registerComponentCreateFn(ecs.type<MM::OpenGL::Renderers::QuadRenderable>(),
//[](MM::EngineConfig::ECS& ecs, MM::EngineConfig::Entity e) {
//auto& r = ecs.assign<MM::OpenGL::Renderers::QuadRenderable>(e);
//r._texture = MM::ResourceManager<MM::OpenGL::Texture>::ref().get("default"_hs);
//}
//);
//ee.registerComponentWidgetFn(ecs.type<MM::OpenGL::Renderers::QuadRenderable>(),
//[](MM::EngineConfig::ECS& ecs, MM::EngineConfig::Entity e) {
//auto& r = ecs.get<MM::OpenGL::Renderers::QuadRenderable>(e);
//MM::ImGuiWidgets::Components::QuadRenderable(r);
//}
//);
//}
engine.run();
// TODO: clear asset manager
sdl_ss.destroyWindow();
}
int main(int argc, char** argv) {
argv0 = argv[0];
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,95 @@
#include <gtest/gtest.h>
#include <mm/engine.hpp>
// services
#include <mm/services/sdl_service.hpp>
#include <mm/services/filesystem.hpp>
#include <mm/services/opengl_renderer.hpp>
#include <mm/services/imgui_s.hpp>
#include <mm/opengl/render_tasks/imgui.hpp>
#include <imgui/imgui.h>
#include <mm/imgui/widgets/knob.hpp>
const char* argv0;
//class ImGuiSpeechy {
//private:
//SoLoud::Speech speech;
//SoLoud::Sfxr sfxr;
//public:
//ImGuiSpeechy(void) {
//speech.setText("Test text. 1. 2. 3.");
//sfxr.loadPreset(SoLoud::Sfxr::COIN, 0);
//}
//void renderImGui(MM::Engine& engine) {
//if (ImGui::Begin("Inputs")) {
//auto& sound = *engine.tryGetService<MM::Services::SoundService>();
//if (ImGui::Button("play sfx")) {
//sound.engine.play(sfxr);
//}
////ImGui::Text("Active Voice Count: %d", sound.engine.getActiveVoiceCount());
//if (ImGui::Button("Read")) {
//sound.engine.play(speech);
//}
//}
//ImGui::End();
//}
//};
TEST(imgui_widgets, basic) {
MM::Engine engine;
auto& sdl_ss = engine.addService<MM::Services::SDLService>();
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
sdl_ss.createGLWindow("imgui_widget_test", 1280, 720);
engine.addService<MM::Services::FilesystemService>(argv0, "imgui_widget_test");
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
engine.addService<MM::Services::ImGuiService>();
ASSERT_TRUE(engine.enableService<MM::Services::ImGuiService>());
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
rs.addRenderTask<MM::OpenGL::RenderTasks::ImGuiRT>(engine);
{
//ImGuiSpeechy speechy;
engine.addUpdate([&](MM::Engine&) {
if (ImGui::Begin("test window")) {
static float knob_test = 0.f;
MM::ImGuiWidgets::KnobFloat("knob1", &knob_test, 0.f, 1.f);
ImGui::SameLine();
MM::ImGuiWidgets::KnobFloat("knob2", &knob_test, 0.f, 1.f, 0.f, false);
}
ImGui::End();
});
engine.run();
}
sdl_ss.destroyWindow();
}
int main(int argc, char** argv) {
argv0 = argv[0];
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}