Compare commits
53 Commits
AnimGraphE
...
main
Author | SHA1 | Date |
---|---|---|
Martin Felis | 99d5a5eb0f | |
Martin Felis | 698abbce4b | |
Martin Felis | b9789bd1e1 | |
Martin Felis | fd032c273b | |
Martin Felis | da431a3879 | |
Martin Felis | 84fc49af30 | |
Martin Felis | 7c7a765455 | |
Martin Felis | e3baa65c3b | |
Martin Felis | 44087d7a7c | |
Martin Felis | e8af30d10c | |
Martin Felis | 4d1990bea8 | |
Martin Felis | 5e34aaf3db | |
Martin Felis | 3fb2995b02 | |
Martin Felis | c267276be3 | |
Martin Felis | 53c0bff7a6 | |
Martin Felis | 91e226945c | |
Martin Felis | d95bc9fb9c | |
Martin Felis | 2d5337ed1d | |
Martin Felis | 9f9ac60f9c | |
Martin Felis | 1741238a61 | |
Martin Felis | 8694a11416 | |
Martin Felis | 3444f8a625 | |
Martin Felis | cd56efca3d | |
Martin Felis | 28eca48a61 | |
Martin Felis | 76ea38f118 | |
Martin Felis | 0aebe44bd5 | |
Martin Felis | 99f11e61d8 | |
Martin Felis | 116bf7699b | |
Martin Felis | 3a7f470acf | |
Martin Felis | e687c9b613 | |
Martin Felis | ccb9bc4e9b | |
Martin Felis | c7d2d195a3 | |
Martin Felis | 1ef53d6486 | |
Martin Felis | fdb2b6ffc5 | |
Martin Felis | a5af917f4b | |
Martin Felis | a79ffaa420 | |
Martin Felis | e61180c4a7 | |
Martin Felis | 8388fbfe3e | |
Martin Felis | dc958dcabd | |
Martin Felis | 8b7de58131 | |
Martin Felis | 4f0331f941 | |
Martin Felis | 8c68737f62 | |
Martin Felis | 8dfc8dd05c | |
Martin Felis | 2dbf8373a8 | |
Martin Felis | c809fe0c8c | |
Martin Felis | c659909020 | |
Martin Felis | 9a1a82f681 | |
Martin Felis | 3f609310e2 | |
Martin Felis | 26d070c4d3 | |
Martin Felis | 72bcf8a21b | |
Martin Felis | eb70c06c57 | |
Martin Felis | 2e631b4fc3 | |
Martin Felis | 509f9616ad |
|
@ -0,0 +1,61 @@
|
||||||
|
name: build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
workflow_run:
|
||||||
|
# Use a workflow as a trigger of scheduled builds. Forked repositories can disable scheduled builds by disabling
|
||||||
|
# "scheduled" workflow, while maintaining ability to perform local CI builds.
|
||||||
|
workflows:
|
||||||
|
- scheduled
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
types:
|
||||||
|
- requested
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Windows:
|
||||||
|
runs-on: windows-2019
|
||||||
|
env:
|
||||||
|
VS_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\
|
||||||
|
MSBUILD_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -S examples -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
macOS:
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: |
|
||||||
|
brew install glfw3
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -S examples -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
Linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libglfw3-dev
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -S examples -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
.vs
|
||||||
|
.vscode
|
||||||
|
.build*
|
||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
[Bb]uild
|
||||||
|
*.VC.db
|
||||||
|
*.VC.opendb
|
||||||
|
*.user
|
||||||
|
*.ini
|
||||||
|
*.json
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Michał Cichoń
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,890 @@
|
||||||
|
// Crude implementation of JSON value object and parser.
|
||||||
|
//
|
||||||
|
// VERSION 0.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
# include "crude_json.h"
|
||||||
|
# include <iomanip>
|
||||||
|
# include <limits>
|
||||||
|
# include <cstdlib>
|
||||||
|
# include <clocale>
|
||||||
|
# include <cmath>
|
||||||
|
# include <cstring>
|
||||||
|
# if CRUDE_JSON_IO
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <memory>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
namespace crude_json {
|
||||||
|
|
||||||
|
value::value(value&& other)
|
||||||
|
: m_Type(other.m_Type)
|
||||||
|
{
|
||||||
|
switch (m_Type)
|
||||||
|
{
|
||||||
|
case type_t::object: construct(m_Storage, std::move( *object_ptr(other.m_Storage))); break;
|
||||||
|
case type_t::array: construct(m_Storage, std::move( *array_ptr(other.m_Storage))); break;
|
||||||
|
case type_t::string: construct(m_Storage, std::move( *string_ptr(other.m_Storage))); break;
|
||||||
|
case type_t::boolean: construct(m_Storage, std::move(*boolean_ptr(other.m_Storage))); break;
|
||||||
|
case type_t::number: construct(m_Storage, std::move( *number_ptr(other.m_Storage))); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
destruct(other.m_Storage, other.m_Type);
|
||||||
|
other.m_Type = type_t::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
value::value(const value& other)
|
||||||
|
: m_Type(other.m_Type)
|
||||||
|
{
|
||||||
|
switch (m_Type)
|
||||||
|
{
|
||||||
|
case type_t::object: construct(m_Storage, *object_ptr(other.m_Storage)); break;
|
||||||
|
case type_t::array: construct(m_Storage, *array_ptr(other.m_Storage)); break;
|
||||||
|
case type_t::string: construct(m_Storage, *string_ptr(other.m_Storage)); break;
|
||||||
|
case type_t::boolean: construct(m_Storage, *boolean_ptr(other.m_Storage)); break;
|
||||||
|
case type_t::number: construct(m_Storage, *number_ptr(other.m_Storage)); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value& value::operator[](size_t index)
|
||||||
|
{
|
||||||
|
if (is_null())
|
||||||
|
m_Type = construct(m_Storage, type_t::array);
|
||||||
|
|
||||||
|
if (is_array())
|
||||||
|
{
|
||||||
|
auto& v = *array_ptr(m_Storage);
|
||||||
|
if (index >= v.size())
|
||||||
|
v.insert(v.end(), index - v.size() + 1, value());
|
||||||
|
|
||||||
|
return v[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
CRUDE_ASSERT(false && "operator[] on unsupported type");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
const value& value::operator[](size_t index) const
|
||||||
|
{
|
||||||
|
if (is_array())
|
||||||
|
return (*array_ptr(m_Storage))[index];
|
||||||
|
|
||||||
|
CRUDE_ASSERT(false && "operator[] on unsupported type");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
value& value::operator[](const string& key)
|
||||||
|
{
|
||||||
|
if (is_null())
|
||||||
|
m_Type = construct(m_Storage, type_t::object);
|
||||||
|
|
||||||
|
if (is_object())
|
||||||
|
return (*object_ptr(m_Storage))[key];
|
||||||
|
|
||||||
|
CRUDE_ASSERT(false && "operator[] on unsupported type");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
const value& value::operator[](const string& key) const
|
||||||
|
{
|
||||||
|
if (is_object())
|
||||||
|
{
|
||||||
|
auto& o = *object_ptr(m_Storage);
|
||||||
|
auto it = o.find(key);
|
||||||
|
CRUDE_ASSERT(it != o.end());
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRUDE_ASSERT(false && "operator[] on unsupported type");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::contains(const string& key) const
|
||||||
|
{
|
||||||
|
if (is_object())
|
||||||
|
{
|
||||||
|
auto& o = *object_ptr(m_Storage);
|
||||||
|
auto it = o.find(key);
|
||||||
|
return it != o.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void value::push_back(const value& value)
|
||||||
|
{
|
||||||
|
if (is_null())
|
||||||
|
m_Type = construct(m_Storage, type_t::array);
|
||||||
|
|
||||||
|
if (is_array())
|
||||||
|
{
|
||||||
|
auto& v = *array_ptr(m_Storage);
|
||||||
|
v.push_back(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CRUDE_ASSERT(false && "operator[] on unsupported type");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void value::push_back(value&& value)
|
||||||
|
{
|
||||||
|
if (is_null())
|
||||||
|
m_Type = construct(m_Storage, type_t::array);
|
||||||
|
|
||||||
|
if (is_array())
|
||||||
|
{
|
||||||
|
auto& v = *array_ptr(m_Storage);
|
||||||
|
v.push_back(std::move(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CRUDE_ASSERT(false && "operator[] on unsupported type");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t value::erase(const string& key)
|
||||||
|
{
|
||||||
|
if (!is_object())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto& o = *object_ptr(m_Storage);
|
||||||
|
auto it = o.find(key);
|
||||||
|
|
||||||
|
if (it == o.end())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
o.erase(it);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void value::swap(value& other)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
if (m_Type == other.m_Type)
|
||||||
|
{
|
||||||
|
switch (m_Type)
|
||||||
|
{
|
||||||
|
case type_t::object: swap(*object_ptr(m_Storage), *object_ptr(other.m_Storage)); break;
|
||||||
|
case type_t::array: swap(*array_ptr(m_Storage), *array_ptr(other.m_Storage)); break;
|
||||||
|
case type_t::string: swap(*string_ptr(m_Storage), *string_ptr(other.m_Storage)); break;
|
||||||
|
case type_t::boolean: swap(*boolean_ptr(m_Storage), *boolean_ptr(other.m_Storage)); break;
|
||||||
|
case type_t::number: swap(*number_ptr(m_Storage), *number_ptr(other.m_Storage)); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value tmp(std::move(other));
|
||||||
|
other.~value();
|
||||||
|
new (&other) value(std::move(*this));
|
||||||
|
this->~value();
|
||||||
|
new (this) value(std::move(tmp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string value::dump(const int indent, const char indent_char) const
|
||||||
|
{
|
||||||
|
dump_context_t context(indent, indent_char);
|
||||||
|
|
||||||
|
context.out.precision(std::numeric_limits<double>::max_digits10 + 1);
|
||||||
|
context.out << std::defaultfloat;
|
||||||
|
|
||||||
|
dump(context, 0);
|
||||||
|
return context.out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void value::dump_context_t::write_indent(int level)
|
||||||
|
{
|
||||||
|
if (indent <= 0 || level == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
out.fill(indent_char);
|
||||||
|
out.width(indent * level);
|
||||||
|
out << indent_char;
|
||||||
|
out.width(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void value::dump_context_t::write_separator()
|
||||||
|
{
|
||||||
|
if (indent < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
out.put(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
void value::dump_context_t::write_newline()
|
||||||
|
{
|
||||||
|
if (indent < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
out.put('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void value::dump(dump_context_t& context, int level) const
|
||||||
|
{
|
||||||
|
context.write_indent(level);
|
||||||
|
|
||||||
|
switch (m_Type)
|
||||||
|
{
|
||||||
|
case type_t::null:
|
||||||
|
context.out << "null";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case type_t::object:
|
||||||
|
context.out << '{';
|
||||||
|
{
|
||||||
|
context.write_newline();
|
||||||
|
bool first = true;
|
||||||
|
for (auto& entry : *object_ptr(m_Storage))
|
||||||
|
{
|
||||||
|
if (!first) { context.out << ','; context.write_newline(); } else first = false;
|
||||||
|
context.write_indent(level + 1);
|
||||||
|
context.out << '\"' << entry.first << "\":";
|
||||||
|
if (!entry.second.is_structured())
|
||||||
|
{
|
||||||
|
context.write_separator();
|
||||||
|
entry.second.dump(context, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.write_newline();
|
||||||
|
entry.second.dump(context, level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!first)
|
||||||
|
context.write_newline();
|
||||||
|
}
|
||||||
|
context.write_indent(level);
|
||||||
|
context.out << '}';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case type_t::array:
|
||||||
|
context.out << '[';
|
||||||
|
{
|
||||||
|
context.write_newline();
|
||||||
|
bool first = true;
|
||||||
|
for (auto& entry : *array_ptr(m_Storage))
|
||||||
|
{
|
||||||
|
if (!first) { context.out << ','; context.write_newline(); } else first = false;
|
||||||
|
if (!entry.is_structured())
|
||||||
|
{
|
||||||
|
context.write_indent(level + 1);
|
||||||
|
entry.dump(context, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry.dump(context, level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!first)
|
||||||
|
context.write_newline();
|
||||||
|
}
|
||||||
|
context.write_indent(level);
|
||||||
|
context.out << ']';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case type_t::string:
|
||||||
|
context.out << '\"';
|
||||||
|
|
||||||
|
if (string_ptr(m_Storage)->find_first_of("\"\\/\b\f\n\r") != string::npos || string_ptr(m_Storage)->find('\0') != string::npos)
|
||||||
|
{
|
||||||
|
for (auto c : *string_ptr(m_Storage))
|
||||||
|
{
|
||||||
|
if (c == '\"') context.out << "\\\"";
|
||||||
|
else if (c == '\\') context.out << "\\\\";
|
||||||
|
else if (c == '/') context.out << "\\/";
|
||||||
|
else if (c == '\b') context.out << "\\b";
|
||||||
|
else if (c == '\f') context.out << "\\f";
|
||||||
|
else if (c == '\n') context.out << "\\n";
|
||||||
|
else if (c == '\r') context.out << "\\r";
|
||||||
|
else if (c == '\t') context.out << "\\t";
|
||||||
|
else if (c == 0) context.out << "\\u0000";
|
||||||
|
else context.out << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
context.out << *string_ptr(m_Storage);
|
||||||
|
context.out << '\"';
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case type_t::boolean:
|
||||||
|
if (*boolean_ptr(m_Storage))
|
||||||
|
context.out << "true";
|
||||||
|
else
|
||||||
|
context.out << "false";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case type_t::number:
|
||||||
|
context.out << *number_ptr(m_Storage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct value::parser
|
||||||
|
{
|
||||||
|
parser(const char* begin, const char* end)
|
||||||
|
: m_Cursor(begin)
|
||||||
|
, m_End(end)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
value parse()
|
||||||
|
{
|
||||||
|
value v;
|
||||||
|
|
||||||
|
// Switch to C locale to make strtod and strtol work as expected
|
||||||
|
auto previous_locale = std::setlocale(LC_NUMERIC, "C");
|
||||||
|
|
||||||
|
// Accept single value only when end of the stream is reached.
|
||||||
|
if (!accept_element(v) || !eof())
|
||||||
|
v = value(type_t::discarded);
|
||||||
|
|
||||||
|
if (previous_locale && strcmp(previous_locale, "C") != 0)
|
||||||
|
std::setlocale(LC_NUMERIC, previous_locale);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct cursor_state
|
||||||
|
{
|
||||||
|
cursor_state(parser* p)
|
||||||
|
: m_Owner(p)
|
||||||
|
, m_LastCursor(p->m_Cursor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
m_Owner->m_Cursor = m_LastCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(bool accept)
|
||||||
|
{
|
||||||
|
if (!accept)
|
||||||
|
reset();
|
||||||
|
else
|
||||||
|
m_LastCursor = m_Owner->m_Cursor;
|
||||||
|
return accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
parser* m_Owner;
|
||||||
|
const char* m_LastCursor;
|
||||||
|
};
|
||||||
|
|
||||||
|
cursor_state state()
|
||||||
|
{
|
||||||
|
return cursor_state(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_value(value& result)
|
||||||
|
{
|
||||||
|
return accept_object(result)
|
||||||
|
|| accept_array(result)
|
||||||
|
|| accept_string(result)
|
||||||
|
|| accept_number(result)
|
||||||
|
|| accept_boolean(result)
|
||||||
|
|| accept_null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_object(value& result)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
object o;
|
||||||
|
if (s(accept('{') && accept_ws() && accept('}')))
|
||||||
|
{
|
||||||
|
result = o;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (s(accept('{') && accept_members(o) && accept('}')))
|
||||||
|
{
|
||||||
|
result = std::move(o);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_members(object& o)
|
||||||
|
{
|
||||||
|
if (!accept_member(o))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
if (!s(accept(',') && accept_member(o)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_member(object& o)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
value key;
|
||||||
|
value v;
|
||||||
|
if (s(accept_ws() && accept_string(key) && accept_ws() && accept(':') && accept_element(v)))
|
||||||
|
{
|
||||||
|
o.emplace(std::move(key.get<string>()), std::move(v));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_array(value& result)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
if (s(accept('[') && accept_ws() && accept(']')))
|
||||||
|
{
|
||||||
|
result = array();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
array a;
|
||||||
|
if (s(accept('[') && accept_elements(a) && accept(']')))
|
||||||
|
{
|
||||||
|
result = std::move(a);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_elements(array& a)
|
||||||
|
{
|
||||||
|
value v;
|
||||||
|
if (!accept_element(v))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
a.emplace_back(std::move(v));
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
v = nullptr;
|
||||||
|
if (!s(accept(',') && accept_element(v)))
|
||||||
|
break;
|
||||||
|
a.emplace_back(std::move(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_element(value& result)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
return s(accept_ws() && accept_value(result) && accept_ws());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_string(value& result)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
string v;
|
||||||
|
if (s(accept('\"') && accept_characters(v) && accept('\"')))
|
||||||
|
{
|
||||||
|
result = std::move(v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_characters(string& result)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
while (accept_character(c))
|
||||||
|
{
|
||||||
|
CRUDE_ASSERT(c < 128); // #todo: convert characters > 127 to UTF-8
|
||||||
|
result.push_back(static_cast<char>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_character(int& c)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
if (accept('\\'))
|
||||||
|
{
|
||||||
|
return accept_escape(c);
|
||||||
|
}
|
||||||
|
else if (expect('\"'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// #todo: Handle UTF-8 sequences.
|
||||||
|
return s((c = peek()) >= 0) && advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_escape(int& c)
|
||||||
|
{
|
||||||
|
if (accept('\"')) { c = '\"'; return true; }
|
||||||
|
if (accept('\\')) { c = '\\'; return true; }
|
||||||
|
if (accept('/')) { c = '/'; return true; }
|
||||||
|
if (accept('b')) { c = '\b'; return true; }
|
||||||
|
if (accept('f')) { c = '\f'; return true; }
|
||||||
|
if (accept('n')) { c = '\n'; return true; }
|
||||||
|
if (accept('r')) { c = '\r'; return true; }
|
||||||
|
if (accept('t')) { c = '\t'; return true; }
|
||||||
|
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
string hex;
|
||||||
|
hex.reserve(4);
|
||||||
|
if (s(accept('u') && accept_hex(hex) && accept_hex(hex) && accept_hex(hex) && accept_hex(hex)))
|
||||||
|
{
|
||||||
|
char* end = nullptr;
|
||||||
|
auto v = std::strtol(hex.c_str(), &end, 16);
|
||||||
|
if (end != hex.c_str() + hex.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
c = static_cast<int>(v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_hex(string& result)
|
||||||
|
{
|
||||||
|
if (accept_digit(result))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto c = peek();
|
||||||
|
if ((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
|
||||||
|
{
|
||||||
|
advance();
|
||||||
|
result.push_back(static_cast<char>(c));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_number(value& result)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
string n;
|
||||||
|
if (s(accept_int(n) && accept_frac(n) && accept_exp(n)))
|
||||||
|
{
|
||||||
|
char* end = nullptr;
|
||||||
|
auto v = std::strtod(n.c_str(), &end);
|
||||||
|
if (end != n.c_str() + n.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (v != 0 && !std::isnormal(v))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
result = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_int(string& result)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
string part;
|
||||||
|
if (s(accept_onenine(part) && accept_digits(part)))
|
||||||
|
{
|
||||||
|
result += std::move(part);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
part.resize(0);
|
||||||
|
if (accept_digit(part))
|
||||||
|
{
|
||||||
|
result += std::move(part);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
part.resize(0);
|
||||||
|
if (s(accept('-') && accept_onenine(part) && accept_digits(part)))
|
||||||
|
{
|
||||||
|
result += '-';
|
||||||
|
result += std::move(part);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
part.resize(0);
|
||||||
|
if (s(accept('-') && accept_digit(part)))
|
||||||
|
{
|
||||||
|
result += '-';
|
||||||
|
result += std::move(part);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_digits(string& result)
|
||||||
|
{
|
||||||
|
string part;
|
||||||
|
if (!accept_digit(part))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (accept_digit(part))
|
||||||
|
;
|
||||||
|
|
||||||
|
result += std::move(part);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_digit(string& result)
|
||||||
|
{
|
||||||
|
if (accept('0'))
|
||||||
|
{
|
||||||
|
result.push_back('0');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (accept_onenine(result))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_onenine(string& result)
|
||||||
|
{
|
||||||
|
auto c = peek();
|
||||||
|
if (c >= '1' && c <= '9')
|
||||||
|
{
|
||||||
|
result.push_back(static_cast<char>(c));
|
||||||
|
return advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_frac(string& result)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
string part;
|
||||||
|
if (s(accept('.') && accept_digits(part)))
|
||||||
|
{
|
||||||
|
result += '.';
|
||||||
|
result += std::move(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_exp(string& result)
|
||||||
|
{
|
||||||
|
auto s = state();
|
||||||
|
|
||||||
|
string part;
|
||||||
|
if (s(accept('e') && accept_sign(part) && accept_digits(part)))
|
||||||
|
{
|
||||||
|
result += 'e';
|
||||||
|
result += std::move(part);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
part.resize(0);
|
||||||
|
if (s(accept('E') && accept_sign(part) && accept_digits(part)))
|
||||||
|
{
|
||||||
|
result += 'E';
|
||||||
|
result += std::move(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_sign(string& result)
|
||||||
|
{
|
||||||
|
if (accept('+'))
|
||||||
|
result.push_back('+');
|
||||||
|
else if (accept('-'))
|
||||||
|
result.push_back('-');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_ws()
|
||||||
|
{
|
||||||
|
while (expect('\x09') || expect('\x0A') || expect('\x0D') || expect('\x20'))
|
||||||
|
advance();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_boolean(value& result)
|
||||||
|
{
|
||||||
|
if (accept("true"))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (accept("false"))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept_null(value& result)
|
||||||
|
{
|
||||||
|
if (accept("null"))
|
||||||
|
{
|
||||||
|
result = nullptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept(char c)
|
||||||
|
{
|
||||||
|
if (expect(c))
|
||||||
|
return advance();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accept(const char* str)
|
||||||
|
{
|
||||||
|
auto last = m_Cursor;
|
||||||
|
|
||||||
|
while (*str)
|
||||||
|
{
|
||||||
|
if (eof() || *str != *m_Cursor)
|
||||||
|
{
|
||||||
|
m_Cursor = last;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
advance();
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int peek() const
|
||||||
|
{
|
||||||
|
if (!eof())
|
||||||
|
return *m_Cursor;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool expect(char c)
|
||||||
|
{
|
||||||
|
return peek() == c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool advance(int count = 1)
|
||||||
|
{
|
||||||
|
if (m_Cursor + count > m_End)
|
||||||
|
{
|
||||||
|
m_Cursor = m_End;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Cursor += count;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eof() const
|
||||||
|
{
|
||||||
|
return m_Cursor == m_End;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* m_Cursor;
|
||||||
|
const char* m_End;
|
||||||
|
};
|
||||||
|
|
||||||
|
value value::parse(const string& data)
|
||||||
|
{
|
||||||
|
auto p = parser(data.c_str(), data.c_str() + data.size());
|
||||||
|
|
||||||
|
auto v = p.parse();
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
# if CRUDE_JSON_IO
|
||||||
|
std::pair<value, bool> value::load(const string& path)
|
||||||
|
{
|
||||||
|
// Modern C++, so beautiful...
|
||||||
|
std::unique_ptr<FILE, void(*)(FILE*)> file{nullptr, [](FILE* file) { if (file) fclose(file); }};
|
||||||
|
# if defined(_MSC_VER) || (defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__)
|
||||||
|
FILE* handle = nullptr;
|
||||||
|
if (fopen_s(&handle, path.c_str(), "rb") != 0)
|
||||||
|
return {value{}, false};
|
||||||
|
file.reset(handle);
|
||||||
|
# else
|
||||||
|
file.reset(fopen(path.c_str(), "rb"));
|
||||||
|
# endif
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
return {value{}, false};
|
||||||
|
|
||||||
|
fseek(file.get(), 0, SEEK_END);
|
||||||
|
auto size = static_cast<size_t>(ftell(file.get()));
|
||||||
|
fseek(file.get(), 0, SEEK_SET);
|
||||||
|
|
||||||
|
string data;
|
||||||
|
data.resize(size);
|
||||||
|
if (fread(const_cast<char*>(data.data()), size, 1, file.get()) != 1)
|
||||||
|
return {value{}, false};
|
||||||
|
|
||||||
|
return {parse(data), true};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::save(const string& path, const int indent, const char indent_char) const
|
||||||
|
{
|
||||||
|
// Modern C++, so beautiful...
|
||||||
|
std::unique_ptr<FILE, void(*)(FILE*)> file{nullptr, [](FILE* file) { if (file) fclose(file); }};
|
||||||
|
# if defined(_MSC_VER) || (defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__)
|
||||||
|
FILE* handle = nullptr;
|
||||||
|
if (fopen_s(&handle, path.c_str(), "wb") != 0)
|
||||||
|
return false;
|
||||||
|
file.reset(handle);
|
||||||
|
# else
|
||||||
|
file.reset(fopen(path.c_str(), "wb"));
|
||||||
|
# endif
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto data = dump(indent, indent_char);
|
||||||
|
|
||||||
|
if (fwrite(data.data(), data.size(), 1, file.get()) != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
} // namespace crude_json
|
|
@ -0,0 +1,250 @@
|
||||||
|
// Crude implementation of JSON value object and parser.
|
||||||
|
//
|
||||||
|
// VERSION 0.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
# ifndef __CRUDE_JSON_H__
|
||||||
|
# define __CRUDE_JSON_H__
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
# include <type_traits>
|
||||||
|
# include <string>
|
||||||
|
# include <vector>
|
||||||
|
# include <map>
|
||||||
|
# include <cstddef>
|
||||||
|
# include <algorithm>
|
||||||
|
# include <sstream>
|
||||||
|
|
||||||
|
# ifndef CRUDE_ASSERT
|
||||||
|
# include <cassert>
|
||||||
|
# define CRUDE_ASSERT(expr) assert(expr)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef CRUDE_JSON_IO
|
||||||
|
# define CRUDE_JSON_IO 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
namespace crude_json {
|
||||||
|
|
||||||
|
struct value;
|
||||||
|
|
||||||
|
using string = std::string;
|
||||||
|
using object = std::map<string, value>;
|
||||||
|
using array = std::vector<value>;
|
||||||
|
using number = double;
|
||||||
|
using boolean = bool;
|
||||||
|
using null = std::nullptr_t;
|
||||||
|
|
||||||
|
enum class type_t
|
||||||
|
{
|
||||||
|
null,
|
||||||
|
object,
|
||||||
|
array,
|
||||||
|
string,
|
||||||
|
boolean,
|
||||||
|
number,
|
||||||
|
discarded
|
||||||
|
};
|
||||||
|
|
||||||
|
struct value
|
||||||
|
{
|
||||||
|
value(type_t type = type_t::null): m_Type(construct(m_Storage, type)) {}
|
||||||
|
value(value&& other);
|
||||||
|
value(const value& other);
|
||||||
|
|
||||||
|
value( null) : m_Type(construct(m_Storage, null())) {}
|
||||||
|
value( object&& v): m_Type(construct(m_Storage, std::move(v))) {}
|
||||||
|
value(const object& v): m_Type(construct(m_Storage, v)) {}
|
||||||
|
value( array&& v): m_Type(construct(m_Storage, std::move(v))) {}
|
||||||
|
value(const array& v): m_Type(construct(m_Storage, v)) {}
|
||||||
|
value( string&& v): m_Type(construct(m_Storage, std::move(v))) {}
|
||||||
|
value(const string& v): m_Type(construct(m_Storage, v)) {}
|
||||||
|
value(const char* v): m_Type(construct(m_Storage, v)) {}
|
||||||
|
value( boolean v): m_Type(construct(m_Storage, v)) {}
|
||||||
|
value( number v): m_Type(construct(m_Storage, v)) {}
|
||||||
|
~value() { destruct(m_Storage, m_Type); }
|
||||||
|
|
||||||
|
value& operator=(value&& other) { if (this != &other) { value(std::move(other)).swap(*this); } return *this; }
|
||||||
|
value& operator=(const value& other) { if (this != &other) { value( other).swap(*this); } return *this; }
|
||||||
|
|
||||||
|
value& operator=( null) { auto other = value( ); swap(other); return *this; }
|
||||||
|
value& operator=( object&& v) { auto other = value(std::move(v)); swap(other); return *this; }
|
||||||
|
value& operator=(const object& v) { auto other = value( v); swap(other); return *this; }
|
||||||
|
value& operator=( array&& v) { auto other = value(std::move(v)); swap(other); return *this; }
|
||||||
|
value& operator=(const array& v) { auto other = value( v); swap(other); return *this; }
|
||||||
|
value& operator=( string&& v) { auto other = value(std::move(v)); swap(other); return *this; }
|
||||||
|
value& operator=(const string& v) { auto other = value( v); swap(other); return *this; }
|
||||||
|
value& operator=(const char* v) { auto other = value( v); swap(other); return *this; }
|
||||||
|
value& operator=( boolean v) { auto other = value( v); swap(other); return *this; }
|
||||||
|
value& operator=( number v) { auto other = value( v); swap(other); return *this; }
|
||||||
|
|
||||||
|
type_t type() const { return m_Type; }
|
||||||
|
|
||||||
|
operator type_t() const { return m_Type; }
|
||||||
|
|
||||||
|
value& operator[](size_t index);
|
||||||
|
const value& operator[](size_t index) const;
|
||||||
|
value& operator[](const string& key);
|
||||||
|
const value& operator[](const string& key) const;
|
||||||
|
|
||||||
|
bool contains(const string& key) const;
|
||||||
|
|
||||||
|
void push_back(const value& value);
|
||||||
|
void push_back(value&& value);
|
||||||
|
|
||||||
|
size_t erase(const string& key);
|
||||||
|
|
||||||
|
bool is_primitive() const { return is_string() || is_number() || is_boolean() || is_null(); }
|
||||||
|
bool is_structured() const { return is_object() || is_array(); }
|
||||||
|
bool is_null() const { return m_Type == type_t::null; }
|
||||||
|
bool is_object() const { return m_Type == type_t::object; }
|
||||||
|
bool is_array() const { return m_Type == type_t::array; }
|
||||||
|
bool is_string() const { return m_Type == type_t::string; }
|
||||||
|
bool is_boolean() const { return m_Type == type_t::boolean; }
|
||||||
|
bool is_number() const { return m_Type == type_t::number; }
|
||||||
|
bool is_discarded() const { return m_Type == type_t::discarded; }
|
||||||
|
|
||||||
|
template <typename T> const T& get() const;
|
||||||
|
template <typename T> T& get();
|
||||||
|
|
||||||
|
template <typename T> const T* get_ptr() const;
|
||||||
|
template <typename T> T* get_ptr();
|
||||||
|
|
||||||
|
string dump(const int indent = -1, const char indent_char = ' ') const;
|
||||||
|
|
||||||
|
void swap(value& other);
|
||||||
|
|
||||||
|
inline friend void swap(value& lhs, value& rhs) { lhs.swap(rhs); }
|
||||||
|
|
||||||
|
// Returns discarded value for invalid inputs.
|
||||||
|
static value parse(const string& data);
|
||||||
|
|
||||||
|
# if CRUDE_JSON_IO
|
||||||
|
static std::pair<value, bool> load(const string& path);
|
||||||
|
bool save(const string& path, const int indent = -1, const char indent_char = ' ') const;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct parser;
|
||||||
|
|
||||||
|
// VS2015: std::max() is not constexpr yet.
|
||||||
|
# define CRUDE_MAX2(a, b) ((a) < (b) ? (b) : (a))
|
||||||
|
# define CRUDE_MAX3(a, b, c) CRUDE_MAX2(CRUDE_MAX2(a, b), c)
|
||||||
|
# define CRUDE_MAX4(a, b, c, d) CRUDE_MAX2(CRUDE_MAX3(a, b, c), d)
|
||||||
|
# define CRUDE_MAX5(a, b, c, d, e) CRUDE_MAX2(CRUDE_MAX4(a, b, c, d), e)
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
max_size = CRUDE_MAX5( sizeof(string), sizeof(object), sizeof(array), sizeof(number), sizeof(boolean)),
|
||||||
|
max_align = CRUDE_MAX5(alignof(string), alignof(object), alignof(array), alignof(number), alignof(boolean))
|
||||||
|
};
|
||||||
|
# undef CRUDE_MAX5
|
||||||
|
# undef CRUDE_MAX4
|
||||||
|
# undef CRUDE_MAX3
|
||||||
|
# undef CRUDE_MAX2
|
||||||
|
using storage_t = std::aligned_storage<max_size, max_align>::type;
|
||||||
|
|
||||||
|
static object* object_ptr( storage_t& storage) { return reinterpret_cast< object*>(&storage); }
|
||||||
|
static const object* object_ptr(const storage_t& storage) { return reinterpret_cast<const object*>(&storage); }
|
||||||
|
static array* array_ptr( storage_t& storage) { return reinterpret_cast< array*>(&storage); }
|
||||||
|
static const array* array_ptr(const storage_t& storage) { return reinterpret_cast<const array*>(&storage); }
|
||||||
|
static string* string_ptr( storage_t& storage) { return reinterpret_cast< string*>(&storage); }
|
||||||
|
static const string* string_ptr(const storage_t& storage) { return reinterpret_cast<const string*>(&storage); }
|
||||||
|
static boolean* boolean_ptr( storage_t& storage) { return reinterpret_cast< boolean*>(&storage); }
|
||||||
|
static const boolean* boolean_ptr(const storage_t& storage) { return reinterpret_cast<const boolean*>(&storage); }
|
||||||
|
static number* number_ptr( storage_t& storage) { return reinterpret_cast< number*>(&storage); }
|
||||||
|
static const number* number_ptr(const storage_t& storage) { return reinterpret_cast<const number*>(&storage); }
|
||||||
|
|
||||||
|
static type_t construct(storage_t& storage, type_t type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case type_t::object: new (&storage) object(); break;
|
||||||
|
case type_t::array: new (&storage) array(); break;
|
||||||
|
case type_t::string: new (&storage) string(); break;
|
||||||
|
case type_t::boolean: new (&storage) boolean(); break;
|
||||||
|
case type_t::number: new (&storage) number(); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static type_t construct(storage_t& storage, null) { (void)storage; return type_t::null; }
|
||||||
|
static type_t construct(storage_t& storage, object&& value) { new (&storage) object(std::forward<object>(value)); return type_t::object; }
|
||||||
|
static type_t construct(storage_t& storage, const object& value) { new (&storage) object(value); return type_t::object; }
|
||||||
|
static type_t construct(storage_t& storage, array&& value) { new (&storage) array(std::forward<array>(value)); return type_t::array; }
|
||||||
|
static type_t construct(storage_t& storage, const array& value) { new (&storage) array(value); return type_t::array; }
|
||||||
|
static type_t construct(storage_t& storage, string&& value) { new (&storage) string(std::forward<string>(value)); return type_t::string; }
|
||||||
|
static type_t construct(storage_t& storage, const string& value) { new (&storage) string(value); return type_t::string; }
|
||||||
|
static type_t construct(storage_t& storage, const char* value) { new (&storage) string(value); return type_t::string; }
|
||||||
|
static type_t construct(storage_t& storage, boolean value) { new (&storage) boolean(value); return type_t::boolean; }
|
||||||
|
static type_t construct(storage_t& storage, number value) { new (&storage) number(value); return type_t::number; }
|
||||||
|
|
||||||
|
static void destruct(storage_t& storage, type_t type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case type_t::object: object_ptr(storage)->~object(); break;
|
||||||
|
case type_t::array: array_ptr(storage)->~array(); break;
|
||||||
|
case type_t::string: string_ptr(storage)->~string(); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dump_context_t
|
||||||
|
{
|
||||||
|
std::ostringstream out;
|
||||||
|
const int indent = -1;
|
||||||
|
const char indent_char = ' ';
|
||||||
|
|
||||||
|
// VS2015: Aggregate initialization isn't a thing yet.
|
||||||
|
dump_context_t(const int indent, const char indent_char)
|
||||||
|
: indent(indent)
|
||||||
|
, indent_char(indent_char)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_indent(int level);
|
||||||
|
void write_separator();
|
||||||
|
void write_newline();
|
||||||
|
};
|
||||||
|
|
||||||
|
void dump(dump_context_t& context, int level) const;
|
||||||
|
|
||||||
|
storage_t m_Storage;
|
||||||
|
type_t m_Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> inline const object& value::get<object>() const { CRUDE_ASSERT(m_Type == type_t::object); return *object_ptr(m_Storage); }
|
||||||
|
template <> inline const array& value::get<array>() const { CRUDE_ASSERT(m_Type == type_t::array); return *array_ptr(m_Storage); }
|
||||||
|
template <> inline const string& value::get<string>() const { CRUDE_ASSERT(m_Type == type_t::string); return *string_ptr(m_Storage); }
|
||||||
|
template <> inline const boolean& value::get<boolean>() const { CRUDE_ASSERT(m_Type == type_t::boolean); return *boolean_ptr(m_Storage); }
|
||||||
|
template <> inline const number& value::get<number>() const { CRUDE_ASSERT(m_Type == type_t::number); return *number_ptr(m_Storage); }
|
||||||
|
|
||||||
|
template <> inline object& value::get<object>() { CRUDE_ASSERT(m_Type == type_t::object); return *object_ptr(m_Storage); }
|
||||||
|
template <> inline array& value::get<array>() { CRUDE_ASSERT(m_Type == type_t::array); return *array_ptr(m_Storage); }
|
||||||
|
template <> inline string& value::get<string>() { CRUDE_ASSERT(m_Type == type_t::string); return *string_ptr(m_Storage); }
|
||||||
|
template <> inline boolean& value::get<boolean>() { CRUDE_ASSERT(m_Type == type_t::boolean); return *boolean_ptr(m_Storage); }
|
||||||
|
template <> inline number& value::get<number>() { CRUDE_ASSERT(m_Type == type_t::number); return *number_ptr(m_Storage); }
|
||||||
|
|
||||||
|
template <> inline const object* value::get_ptr<object>() const { if (m_Type == type_t::object) return object_ptr(m_Storage); else return nullptr; }
|
||||||
|
template <> inline const array* value::get_ptr<array>() const { if (m_Type == type_t::array) return array_ptr(m_Storage); else return nullptr; }
|
||||||
|
template <> inline const string* value::get_ptr<string>() const { if (m_Type == type_t::string) return string_ptr(m_Storage); else return nullptr; }
|
||||||
|
template <> inline const boolean* value::get_ptr<boolean>() const { if (m_Type == type_t::boolean) return boolean_ptr(m_Storage); else return nullptr; }
|
||||||
|
template <> inline const number* value::get_ptr<number>() const { if (m_Type == type_t::number) return number_ptr(m_Storage); else return nullptr; }
|
||||||
|
|
||||||
|
template <> inline object* value::get_ptr<object>() { if (m_Type == type_t::object) return object_ptr(m_Storage); else return nullptr; }
|
||||||
|
template <> inline array* value::get_ptr<array>() { if (m_Type == type_t::array) return array_ptr(m_Storage); else return nullptr; }
|
||||||
|
template <> inline string* value::get_ptr<string>() { if (m_Type == type_t::string) return string_ptr(m_Storage); else return nullptr; }
|
||||||
|
template <> inline boolean* value::get_ptr<boolean>() { if (m_Type == type_t::boolean) return boolean_ptr(m_Storage); else return nullptr; }
|
||||||
|
template <> inline number* value::get_ptr<number>() { if (m_Type == type_t::number) return number_ptr(m_Storage); else return nullptr; }
|
||||||
|
|
||||||
|
} // namespace crude_json
|
||||||
|
|
||||||
|
# endif // __CRUDE_JSON_H__
|
|
@ -0,0 +1,289 @@
|
||||||
|
v0.9.4 (WIP):
|
||||||
|
|
||||||
|
NEW: Editor: Add smooth zoom (#266)
|
||||||
|
|
||||||
|
BUGFIX: Canvas: Remember index of first command buffer to not miss updating any used (#260)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Don't duplicated ImVec2/ImVec3 == != operators defined since ImGui r19002 (#268)
|
||||||
|
|
||||||
|
BUGFIX: Examples: Use imgui_impl_opengl3_loader.h instead of gl3w (#264)
|
||||||
|
|
||||||
|
v0.9.3 (2023-10-14):
|
||||||
|
|
||||||
|
CHANGE: Canvas: Use ImDrawCallback_ImCanvas macro as draw callback sentinel (#256), thanks @nspitko
|
||||||
|
|
||||||
|
BUGFIX: Canvas: Ensure SentinelDrawCallback cleanup (#255)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Don't call Reasume/Suspend on invisible canvas (#255)
|
||||||
|
|
||||||
|
v0.9.2 (2023-09-01):
|
||||||
|
|
||||||
|
NEW: Editor: Add offset of hover/select to style (thanks @MultiPain)
|
||||||
|
|
||||||
|
NEW: Editor: Add IMGUI_NODE_EDITOR_API to support building editor as a shared library (#189)
|
||||||
|
|
||||||
|
NEW: Canvas: Add IMGUIEX_CANVAS_API to support building canvas as a shared library (#189)
|
||||||
|
|
||||||
|
CHANGE: Editor: Support ImGui r18836 after SetItemUsingMouseWheel removal (#218), thanks @ocornut
|
||||||
|
|
||||||
|
CHANGE: Editor: Define IMGUI_DEFINE_MATH_OPERATORS before <imgui.h> (#209), thanks @ocornut
|
||||||
|
|
||||||
|
CHANGE: Examples: Define IMGUI_DEFINE_MATH_OPERATORS before <imgui.h> (#209), thanks @ocornut
|
||||||
|
|
||||||
|
CHANGE: Canvas: Don't use deprecated SetItemAllowOverlap (#250)
|
||||||
|
|
||||||
|
CHANGE: Examples: Don't use deprecated SetItemAllowOverlap (#250)
|
||||||
|
|
||||||
|
CHANGE: Editor: Define IMGUI_DEFINE_MATH_OPERATORS before <imgui.h> (#209), thanks @ocornut
|
||||||
|
|
||||||
|
CHANGE: Editor: Unary operator- for ImVec2 is defined by ImGui since r18955 (#248)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Correctly initialize 'width' for view resize code (thx @gnif)
|
||||||
|
|
||||||
|
BUGFIX: Examples: Handle node deletion before links (#182)
|
||||||
|
Deleting node queue connected links for deletion.
|
||||||
|
|
||||||
|
BUGFIX: Examples: Simplify and fix drawing of node header line (#180)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Cleanup tabs.
|
||||||
|
|
||||||
|
BUGFIX: Editor: Use ImGuiKey directly with ImGui r18822 (#183)
|
||||||
|
|
||||||
|
BUGFIX: Examples: Use ImGuiKey directly with ImGui r18822 (#183)
|
||||||
|
|
||||||
|
BUGFIX: Examples: Use ImGuiKey_KeypadEnter with ImGui r18604 (#183)
|
||||||
|
|
||||||
|
BUGFIX: Examples: Add missing <cstdint> include for std::intptr_t (#199)
|
||||||
|
|
||||||
|
BUGFIX: Examples: Don't use empty string as identifier
|
||||||
|
|
||||||
|
BUGFIX: Editor: Clean long to int implicit cast warning in crude_json
|
||||||
|
|
||||||
|
BUGFIX: Canvas: Ensure canvas draw commands are separated from other ImGui draw commands (#205, #250)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Don't call Canvas.End() when Canvas.Begin() failed (#186), thanks @pthom, @TheZoc
|
||||||
|
|
||||||
|
|
||||||
|
v0.9.1 (2022-08-27):
|
||||||
|
|
||||||
|
CHANGE: Remove unwanted extra frame height from node bottom
|
||||||
|
|
||||||
|
CHANGE: Allow to specify if links of deleted node should also be automatically deleted
|
||||||
|
Now it is possible to delete only node without automatically serving links,
|
||||||
|
application can choose to do this operation by itself and for example
|
||||||
|
short circuit flow links ot do any other special operation.
|
||||||
|
|
||||||
|
CHANGE: Canvas: Allow to overlap canvas widget
|
||||||
|
|
||||||
|
CHANGE: Natvis: Move crude_json natvis to separate file
|
||||||
|
|
||||||
|
CHANGE: Natvis: Show readable NodeId/PinId/LinkId
|
||||||
|
|
||||||
|
CHANGE: Make Navigate action to honor duration
|
||||||
|
|
||||||
|
CHANGE: Travis: Use Ubuntu Bionic (18.04) for CI, to get newer version of GLFW3
|
||||||
|
|
||||||
|
CHANGE: Editor: Make action button internally configurable
|
||||||
|
|
||||||
|
CHANGE: Make Node Editor forward compatible with ImGui 1.80+ (#112)
|
||||||
|
We're keeping backward compatibility with pre 1.8x versions.
|
||||||
|
|
||||||
|
CHANGE: Update internal copy ImGui to 1.84 (WIP) (3512f2c2c283ec86) (#107)
|
||||||
|
Internal copy has two PR's merged:
|
||||||
|
https://github.com/thedmd/imgui/tree/feature/layout - used in blueprints example only
|
||||||
|
https://github.com/thedmd/imgui/tree/feature/extra-keys - optional: used by Node Editor if present
|
||||||
|
|
||||||
|
CHANGE: Use github actions instead of Travis and AppVeyor (#113)
|
||||||
|
|
||||||
|
CHANGE: Delete operation on node/link will remove internal object (#173)
|
||||||
|
|
||||||
|
CHANGE: Natvis: Add crude_json::value visualization
|
||||||
|
|
||||||
|
NEW: All source components are now versioned
|
||||||
|
|
||||||
|
NEW: Make view state independent of window resolution.
|
||||||
|
|
||||||
|
NEW: Editor can now break links connected specified node or pin
|
||||||
|
New API:
|
||||||
|
int BreakLinks(NodeId nodeId);
|
||||||
|
int BreakLinks(PinId pinId);
|
||||||
|
|
||||||
|
NEW: Editor can now tell if node or pin has any links attached
|
||||||
|
New API:
|
||||||
|
bool HasAnyLinks(NodeId nodeId);
|
||||||
|
bool HasAnyLinks(PinId pinId);
|
||||||
|
|
||||||
|
NEW: Editor can be queried if particular node or link is selected
|
||||||
|
New API:
|
||||||
|
bool IsNodeSelected(NodeId nodeId);
|
||||||
|
bool IsLinkSelected(LinkId linkId);
|
||||||
|
|
||||||
|
NEW: Editor now can return pins of the link
|
||||||
|
New API:
|
||||||
|
bool GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId);
|
||||||
|
|
||||||
|
`startPinId` and `endPinId` may be null if caller is not interested
|
||||||
|
in particular id.
|
||||||
|
|
||||||
|
NEW: Editor now return ids of hovered node/pin/link
|
||||||
|
New API:
|
||||||
|
NodeId GetHoveredNode();
|
||||||
|
PinId GetHoveredPin();
|
||||||
|
LinkId GetHoveredLink();
|
||||||
|
|
||||||
|
NEW: Add SetGroupSize() to explicitly set group size
|
||||||
|
New API:
|
||||||
|
void SetGroupSize(NodeId nodeId, const ImVec2& size);
|
||||||
|
|
||||||
|
NEW: crude_json: Add save() and load()
|
||||||
|
|
||||||
|
When CRUDE_JSON_IO == 1 value will have load() and save()
|
||||||
|
function implemented using stdio.h FILE.
|
||||||
|
|
||||||
|
NEW: crude_json: Add erase() and get_ptr()
|
||||||
|
|
||||||
|
NEW: Application overhaul
|
||||||
|
- Convert from function based to inheritable class
|
||||||
|
- Add ability to close app and change title from code
|
||||||
|
- Add ability to control main window flags (ex. show menubar)
|
||||||
|
- Save ImGui state to ini file
|
||||||
|
- Render using pre-multiplied alpha textures
|
||||||
|
- Add extra fonts to examples.
|
||||||
|
|
||||||
|
NEW: Reintegrate Widgets example from @crolando (#77)
|
||||||
|
|
||||||
|
NEW: User can now override button indices for various actions (#88)
|
||||||
|
New API in Config:
|
||||||
|
int DragButtonIndex; // Mouse button index drag action will react to (0-left, 1-right, 2-middle)
|
||||||
|
int SelectButtonIndex; // Mouse button index select action will react to (0-left, 1-right, 2-middle)
|
||||||
|
int NavigateButtonIndex; // Mouse button index navigate action will react to (0-left, 1-right, 2-middle)
|
||||||
|
int ContextMenuButtonIndex; // Mouse button index context menu action will react to (0-left, 1-right, 2-middle)
|
||||||
|
|
||||||
|
NEW: Flow direction can now be picked per flow (#104)
|
||||||
|
New API:
|
||||||
|
enum class FlowDirection
|
||||||
|
{
|
||||||
|
Forward,
|
||||||
|
Backward
|
||||||
|
};
|
||||||
|
|
||||||
|
void Flow(LinkId linkId, FlowDirection direction = FlowDirection::Forward);
|
||||||
|
|
||||||
|
NEW: Editor can now return number of submitted nodes (#81)
|
||||||
|
New API:
|
||||||
|
int GetNodeCount(); // Returns number of submitted nodes since Begin() call
|
||||||
|
|
||||||
|
NEW: Editor can now return nodes in order they are drawn (#81)
|
||||||
|
New API:
|
||||||
|
int GetOrderedNodeIds(NodeId* nodes, int size); // Fills an array with node id's in order they're drawn; up to 'size` elements are set. Returns actual size of filled id's.
|
||||||
|
|
||||||
|
NEW: Editor now allow to set Z position for nodes (#109)
|
||||||
|
|
||||||
|
Nodes with higher Z position are drawn on top of ones with lower.
|
||||||
|
|
||||||
|
New API:
|
||||||
|
void SetNodeZPosition(NodeId nodeId, float z); // Sets node z position, nodes with higher value are drawn over nodes with lower value
|
||||||
|
float GetNodeZPosition(NodeId nodeId); // Returns node z position, defaults is 0.0f
|
||||||
|
|
||||||
|
NEW: Editor: SaveReasonFlags now inform about node creation/deletion
|
||||||
|
|
||||||
|
NEW: Editor: Expose button index background was clicked with
|
||||||
|
New API:
|
||||||
|
ImGuiMouseButton GetBackgroundClickButtonIndex(); // -1 if none
|
||||||
|
ImGuiMouseButton GetBackgroundDoubleClickButtonIndex(); // -1 if none
|
||||||
|
|
||||||
|
NEW: Editor: Expose configuration editor was created with
|
||||||
|
New API:
|
||||||
|
const Config& GetConfig(EditorContext* ctx = nullptr);
|
||||||
|
|
||||||
|
NEW: Editor: Add highlighting of Links connected to selected Node (#175)
|
||||||
|
New API:
|
||||||
|
StyleColor_HighlightLinkBorder
|
||||||
|
StyleVar_HighlightConnectedLinks
|
||||||
|
|
||||||
|
NEW: Editor: Add ability to snap link origin to pin direction (#167)
|
||||||
|
New API:
|
||||||
|
StyleVar_SnapLinkToPinDir
|
||||||
|
|
||||||
|
NEW: Editor: Add way to override default zoom levels (#174)
|
||||||
|
New API:
|
||||||
|
ImVector<float> Config::CustomZoomLevels;
|
||||||
|
|
||||||
|
NEW: Editor: Add canvas size mode (#170)
|
||||||
|
|
||||||
|
Config can now decide how editor should resize view when changing size.
|
||||||
|
|
||||||
|
New API:
|
||||||
|
enum class CanvasSizeMode;
|
||||||
|
Config::CanvasSizeMode;
|
||||||
|
|
||||||
|
BUGFIX: Avoid crash while destroying editor.
|
||||||
|
|
||||||
|
BUGFIX: Save draw list used by editor between Begin() and End()
|
||||||
|
There is a chance ImGui::GetWindowDrawList() will return different draw list
|
||||||
|
while nodes are being composed. To avoid troubles of manipulating incorrect
|
||||||
|
draw list one obtained in Begin() is remembered and used.
|
||||||
|
|
||||||
|
BUGFIX: Avoid division by zero in ImCubicBezierBoundingRect
|
||||||
|
|
||||||
|
BUGFIX: Don't stuck in delete action if user does not handle it
|
||||||
|
|
||||||
|
BUGFIX: Enable use channel splitter inside Begin/End for node and pin. #28
|
||||||
|
|
||||||
|
BUGFIX: Don't manipulate channels when editor is suspended #28
|
||||||
|
|
||||||
|
BUGFIX: Fix ObjectId serialization
|
||||||
|
|
||||||
|
BUGFIX: GroupNode resize instead of move on low zoom #87
|
||||||
|
|
||||||
|
BUGFIX: Make Canvas work with Viewports (#91, #90)
|
||||||
|
|
||||||
|
BUGFIX: Explicitly choose embedded GL3W as OpenGL extension loader (#96)
|
||||||
|
|
||||||
|
BUGFIX: Application: Don't apply HiDPI logic for (-FLT_MAX,-FLT_MAX) mouse position
|
||||||
|
|
||||||
|
BUGFIX: Editor: Clamp over-the-edge drag distance to prevent scrolling to infinity on focus lost
|
||||||
|
|
||||||
|
BUGFIX: Editor: Consume scroll event (#73) (require ImGui 17909 or later)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Respect window focus while handling actions (#99)
|
||||||
|
|
||||||
|
BUGFIX: Examples: Correct case of `data` directory (#97)
|
||||||
|
|
||||||
|
BUGFIX: Canvas: Save/Restore CursorMaxPos only in Begin/End (#101)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Don't implicitly capture keyboard (#83)
|
||||||
|
|
||||||
|
BUGFIX: Application: Reset key down state after loosing keyboard focus
|
||||||
|
|
||||||
|
BUGFIX: Editor: Make off-screen dragging work again
|
||||||
|
|
||||||
|
BUGFIX: ImGui: Disable obsolete functions (#103)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Allow nodes with zero size (#134)
|
||||||
|
|
||||||
|
BUGFIX: Canvas: Update call ImGui::IsClippedEx() on ImGui > 18415 (#138)
|
||||||
|
|
||||||
|
BUGFIX: Canvas: Disable pink debug outline around widget (#150)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Remove node settings when it is explicitly deleted (#153)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Improve link dragging with fast movement (#156)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Make selection rect start at click point
|
||||||
|
|
||||||
|
BUGFIX: Editor: Make selection rect sharp
|
||||||
|
|
||||||
|
BUGFIX: Editor: Don't populate unused channels with empty draw command, fixes memory leak (#168, #165)
|
||||||
|
|
||||||
|
BUGFIX: Application: Correctly set DX11 View for NULL textures (#162)
|
||||||
|
|
||||||
|
BUGFIX: Application: Recreate DX11 resources lazily (related to #162)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Don't steal input from active user widget (#172)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Delete item from internal list only when action accepts (#178)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Cycle canvas to correctly restore view on first frame (#159)
|
||||||
|
|
||||||
|
BUGFIX: Editor: Don't relay on ImGui CursorMaxPos to apply padding (https://github.com/ocornut/imgui/issues/5548)
|
|
@ -0,0 +1,169 @@
|
||||||
|
# Node Editor in ImGui
|
||||||
|
|
||||||
|
[![build](https://github.com/thedmd/imgui-node-editor/actions/workflows/build.yml/badge.svg)](https://github.com/thedmd/imgui-node-editor/actions/workflows/build.yml)
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
An implementation of node editor with ImGui-like API.
|
||||||
|
|
||||||
|
Project purpose is to serve as a basis for more complex solutions like blueprint editors.
|
||||||
|
|
||||||
|
![node_editor_overview](https://user-images.githubusercontent.com/1197433/89328475-c01bc680-d68d-11ea-88bf-8c4155480927.gif)
|
||||||
|
|
||||||
|
Node Editor is build around an idea "draw your content, we do the rest", which mean interactions are handled by editor, content rendering is handled by user. Editor will take care of:
|
||||||
|
* placing your node in the word
|
||||||
|
* dragging nodes
|
||||||
|
* zoom and scrolling
|
||||||
|
* selection
|
||||||
|
* various interaction that can be queried by API (creation, deletion, selection changes, etc.)
|
||||||
|
|
||||||
|
Here are some highlights:
|
||||||
|
* Node movement and selection is handled internally
|
||||||
|
* Node and pin contents are fully customizable
|
||||||
|
* Fully styled, default theme is modeled after UE4 blueprints
|
||||||
|
- Flexible enough to produce such nodes:
|
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381408-c3895b00-9a54-11e9-8312-d9fc9af63347.png)
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381400-a3599c00-9a54-11e9-9c51-a88f25f7db07.png)
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381589-7d81c680-9a57-11e9-87b1-9f73ec33bea4.png)
|
||||||
|
- Customizable links based on Bézier curves:
|
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381475-ac973880-9a55-11e9-9ad9-5862975cd2b8.png)
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381467-9db08600-9a55-11e9-9868-2ae849f67de9.png)
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381488-cd5f8e00-9a55-11e9-8346-1f4c8d6bea22.png)
|
||||||
|
* Automatic highlights for nodes, pins and links:
|
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381536-9e95e780-9a56-11e9-80bb-dad0d3d9557a.png)
|
||||||
|
* Smooth navigation and selection
|
||||||
|
* Node state can be saved in user context, so layout will not break
|
||||||
|
* Selection rectangles and group dragging
|
||||||
|
* Context menu support
|
||||||
|
* Basic shortcuts support (cut/copy/paste/delete)
|
||||||
|
* ImGui style API
|
||||||
|
|
||||||
|
Editor is used to implement blueprint editor in Spark CE engine, it proved itself there by allowing to do everything we needed. Therefore it is now slowly moving into stable state from beeing a prototype.
|
||||||
|
|
||||||
|
Note: Project recently was restructured to mimic ImGui layout.
|
||||||
|
|
||||||
|
Please report issues or questions if something isn't clear.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
* Vanilla ImGui 1.72+
|
||||||
|
* C++14
|
||||||
|
|
||||||
|
### Dependencies for examples:
|
||||||
|
* https://github.com/thedmd/imgui/tree/feature/layout (used in blueprints sample only)
|
||||||
|
|
||||||
|
### Optional extension you can pull into your local copy of ImGui node editor can take advantage of:
|
||||||
|
* ~~https://github.com/thedmd/imgui/tree/feature/draw-list-fringe-scale (for sharp rendering, while zooming)~~ It is part of ImGui since 1.80 release
|
||||||
|
* https://github.com/thedmd/imgui/tree/feature/extra-keys (for extra shortcuts)
|
||||||
|
|
||||||
|
## Building / Installing
|
||||||
|
|
||||||
|
Node Editor sources are located in root project directory. To use it, simply copy&paste sources into your project. Exactly like you can do with ImGui.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
[Examples](../examples) can be build with CMake:
|
||||||
|
```
|
||||||
|
Windows:
|
||||||
|
cmake -S examples -B build -G "Visual Studio 15 2017 Win64"
|
||||||
|
or
|
||||||
|
cmake -S examples -B build -G "Visual Studio 16 2019" -A x64
|
||||||
|
|
||||||
|
macOS:
|
||||||
|
cmake -S examples -B build -G "Xcode"
|
||||||
|
|
||||||
|
Linux:
|
||||||
|
cmake -S examples -B build -G "Unix Makefiles"
|
||||||
|
|
||||||
|
Build:
|
||||||
|
cmake --build build --config Release
|
||||||
|
```
|
||||||
|
Executables will be located in `build\bin` directory.
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
Main node editor header is located in [imgui_node_editor.h](../imgui_node_editor.h).
|
||||||
|
|
||||||
|
Minimal example of one node can be found in [simple-example.cpp](../examples/simple-example/simple-example.cpp).
|
||||||
|
Press 'F' in editor to focus on editor content if you see only grid.
|
||||||
|
```cpp
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <imgui_node_editor.h>
|
||||||
|
# include <application.h>
|
||||||
|
|
||||||
|
namespace ed = ax::NodeEditor;
|
||||||
|
|
||||||
|
struct Example:
|
||||||
|
public Application
|
||||||
|
{
|
||||||
|
using Application::Application;
|
||||||
|
|
||||||
|
void OnStart() override
|
||||||
|
{
|
||||||
|
ed::Config config;
|
||||||
|
config.SettingsFile = "Simple.json";
|
||||||
|
m_Context = ed::CreateEditor(&config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnStop() override
|
||||||
|
{
|
||||||
|
ed::DestroyEditor(m_Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnFrame(float deltaTime) override
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ed::SetCurrentEditor(m_Context);
|
||||||
|
ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||||
|
int uniqueId = 1;
|
||||||
|
// Start drawing nodes.
|
||||||
|
ed::BeginNode(uniqueId++);
|
||||||
|
ImGui::Text("Node A");
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||||
|
ImGui::Text("Out ->");
|
||||||
|
ed::EndPin();
|
||||||
|
ed::EndNode();
|
||||||
|
ed::End();
|
||||||
|
ed::SetCurrentEditor(nullptr);
|
||||||
|
|
||||||
|
//ImGui::ShowMetricsWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
ed::EditorContext* m_Context = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
int Main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
Example exampe("Simple", argc, argv);
|
||||||
|
|
||||||
|
if (exampe.Create())
|
||||||
|
return exampe.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
|
![00-Simple](https://user-images.githubusercontent.com/1197433/89328516-cca01f00-d68d-11ea-9959-2da159851101.png)
|
||||||
|
|
||||||
|
For more details please visit [examples](../examples) folder.
|
||||||
|
|
||||||
|
### Blueprints Example
|
||||||
|
|
||||||
|
![Preview2](https://user-images.githubusercontent.com/1197433/60053458-2f2b9b00-96d8-11e9-92f9-08aff63b2023.png)
|
||||||
|
|
||||||
|
### Here is Node Editor at work in Spark CE
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381756-174a7300-9a5a-11e9-9a04-00f10565e05e.png)
|
||||||
|
![image](https://user-images.githubusercontent.com/1197433/60381760-2f21f700-9a5a-11e9-9053-c0547a9cc40a.png)
|
|
@ -0,0 +1,14 @@
|
||||||
|
In random order:
|
||||||
|
* Documentation: Make one
|
||||||
|
|
||||||
|
Done:
|
||||||
|
* ~~ImGui: Factor out changes to ImGui to use vanilla version.~~
|
||||||
|
* ~~Editor: Fix variable naming (mainly add `m_` prefix)~~
|
||||||
|
* ~~Editor: Split NodeEditorImpl.cpp to multiple files, file has grown too big.~~
|
||||||
|
* ~~Editor: Factor out use of `picojson.h`~~
|
||||||
|
* ~~Editor: Move use of `<optional>` to optional code extensions~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#57 - join `ax::NodeEditor::EditorContext` with `struct EditorContext` and remove `reinterpret_cast<>`
|
|
@ -0,0 +1,134 @@
|
||||||
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
|
project(imgui-node-editor)
|
||||||
|
|
||||||
|
# Define IMGUI_NODE_EDITOR_ROOT_DIR pointing to project root directory
|
||||||
|
get_filename_component(IMGUI_NODE_EDITOR_ROOT_DIR ${CMAKE_SOURCE_DIR}/.. ABSOLUTE CACHE)
|
||||||
|
|
||||||
|
# Enable solution folders in Visual Studio and Folders in Xcode
|
||||||
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
|
# Point CMake where to look for module files.
|
||||||
|
list(APPEND CMAKE_MODULE_PATH ${IMGUI_NODE_EDITOR_ROOT_DIR}/misc/cmake-modules)
|
||||||
|
|
||||||
|
# Node editor use C++14
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Macro that will configure an example application
|
||||||
|
macro(add_example_executable name)
|
||||||
|
project(${name})
|
||||||
|
|
||||||
|
set(_Example_Sources
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
#source_group("" FILES ${_Example_Sources})
|
||||||
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${_Example_Sources})
|
||||||
|
|
||||||
|
file(GLOB _Example_CommonResources CONFIGURE_DEPENDS "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data/*")
|
||||||
|
file(GLOB _Example_Resources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
|
||||||
|
#message(FATAL_ERROR "_Example_Resources = ${_Example_Resources}")
|
||||||
|
|
||||||
|
set(_Example_Type)
|
||||||
|
if (WIN32)
|
||||||
|
set(_Example_Type WIN32)
|
||||||
|
|
||||||
|
set(ApplicationIcon ${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/Application/Support/Icon.ico)
|
||||||
|
file(TO_NATIVE_PATH "${ApplicationIcon}" ApplicationIcon)
|
||||||
|
string(REPLACE "\\" "\\\\" ApplicationIcon "${ApplicationIcon}")
|
||||||
|
configure_file(
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/Application/Support/Resource.rc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/Resource.rc
|
||||||
|
)
|
||||||
|
source_group(TREE "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples" FILES ${_Example_CommonResources})
|
||||||
|
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_Example_Resources})
|
||||||
|
list(APPEND _Example_Resources
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/Resource.rc
|
||||||
|
${_Example_CommonResources}
|
||||||
|
)
|
||||||
|
source_group("resources" FILES ${CMAKE_CURRENT_BINARY_DIR}/Resource.rc)
|
||||||
|
elseif (APPLE)
|
||||||
|
set(_Example_Type MACOSX_BUNDLE)
|
||||||
|
|
||||||
|
set_source_files_properties(${_Example_Resources} ${_Example_CommonResources} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION "Resources/data"
|
||||||
|
)
|
||||||
|
set(_Example_Icon "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/application/support/Icon.icns")
|
||||||
|
list(APPEND _Example_Resources ${_Example_Icon})
|
||||||
|
set_source_files_properties(${_Example_Icon} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION "Resources"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(${name} ${_Example_Type} ${_Example_Sources} ${_Example_Resources} ${_Example_CommonResources})
|
||||||
|
|
||||||
|
find_package(imgui REQUIRED)
|
||||||
|
find_package(imgui_node_editor REQUIRED)
|
||||||
|
target_link_libraries(${name} PRIVATE imgui imgui_node_editor application)
|
||||||
|
|
||||||
|
set(_ExampleBinDir ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
|
set_target_properties(${name} PROPERTIES
|
||||||
|
FOLDER "examples"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${_ExampleBinDir}"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${_ExampleBinDir}"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${_ExampleBinDir}"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${_ExampleBinDir}"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${_ExampleBinDir}"
|
||||||
|
DEBUG_POSTFIX _d
|
||||||
|
RELWITHDEBINGO_POSTFIX _rd
|
||||||
|
MINSIZEREL_POSTFIX _r
|
||||||
|
VS_DEBUGGER_WORKING_DIRECTORY ${_ExampleBinDir}
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/application/support/Info.plist.in"
|
||||||
|
MACOSX_BUNDLE_BUNDLE_NAME "${PACKAGE_NAME}"
|
||||||
|
MACOSX_BUNDLE_GUI_IDENTIFIER "com.sandbox.collisions"
|
||||||
|
MACOSX_BUNDLE_LONG_VERSION_STRING "${PACKAGE_VERSION}"
|
||||||
|
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}"
|
||||||
|
MACOSX_BUNDLE_ICON_FILE Icon.icns
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${name}
|
||||||
|
PRE_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ARGS ${_ExampleBinDir}/data
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_ResourceRoot ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
foreach(_Resource ROOT "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data" ${_Example_CommonResources} ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data" ${_Example_Resources})
|
||||||
|
if (_Resource STREQUAL ROOT)
|
||||||
|
set(_ResourceRoot FALSE)
|
||||||
|
continue()
|
||||||
|
elseif(NOT _ResourceRoot)
|
||||||
|
set(_ResourceRoot ${_Resource})
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if ("${_Resource}" MATCHES "\.DS_Store$")
|
||||||
|
list(REMOVE_ITEM _Example_Resources ${_Resource})
|
||||||
|
list(REMOVE_ITEM _Example_CommonResources ${_Resource})
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(RELATIVE_PATH _RelResource ${_ResourceRoot} ${_Resource})
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${name}
|
||||||
|
PRE_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ARGS ${_Resource} ${_ExampleBinDir}/data/${_RelResource}
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
add_subdirectory(application)
|
||||||
|
|
||||||
|
add_subdirectory(canvas-example)
|
||||||
|
add_subdirectory(simple-example)
|
||||||
|
add_subdirectory(widgets-example)
|
||||||
|
add_subdirectory(basic-interaction-example)
|
||||||
|
add_subdirectory(blueprints-example)
|
|
@ -0,0 +1,109 @@
|
||||||
|
project(application)
|
||||||
|
|
||||||
|
set(_Application_Sources
|
||||||
|
include/application.h
|
||||||
|
source/application.cpp
|
||||||
|
source/entry_point.cpp
|
||||||
|
source/imgui_extra_keys.h
|
||||||
|
source/config.h.in
|
||||||
|
source/setup.h
|
||||||
|
source/platform.h
|
||||||
|
source/platform_win32.cpp
|
||||||
|
source/platform_glfw.cpp
|
||||||
|
source/renderer.h
|
||||||
|
source/renderer_dx11.cpp
|
||||||
|
source/renderer_ogl3.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(application STATIC)
|
||||||
|
|
||||||
|
target_include_directories(application PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
find_package(imgui REQUIRED)
|
||||||
|
find_package(stb_image REQUIRED)
|
||||||
|
find_package(ScopeGuard REQUIRED)
|
||||||
|
target_link_libraries(application PUBLIC imgui)
|
||||||
|
target_link_libraries(application PRIVATE stb_image ScopeGuard)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
list(APPEND _Application_Sources
|
||||||
|
source/imgui_impl_dx11.cpp
|
||||||
|
source/imgui_impl_dx11.h
|
||||||
|
source/imgui_impl_win32.cpp
|
||||||
|
source/imgui_impl_win32.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_DXSDK_Dir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/DXSDK)
|
||||||
|
set(_DXSDK_Arch x86)
|
||||||
|
if (${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||||
|
set(_DXSDK_Arch x64)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(dxerr STATIC ${_DXSDK_Dir}/src/dxerr.cpp)
|
||||||
|
target_include_directories(dxerr PUBLIC "${_DXSDK_Dir}/include")
|
||||||
|
set_property(TARGET dxerr PROPERTY FOLDER "external")
|
||||||
|
|
||||||
|
add_library(d3dx11 UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(d3dx11 PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${_DXSDK_Dir}/lib/${_DXSDK_Arch}/d3dx11.lib"
|
||||||
|
IMPORTED_LOCATION_DEBUG "${_DXSDK_Dir}/lib/${_DXSDK_Arch}/d3dx11d.lib"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${_DXSDK_Dir}/include"
|
||||||
|
INTERFACE_LINK_LIBRARIES "$<$<CONFIG:Debug>:dxerr>"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(application PRIVATE d3d11.lib d3dcompiler.lib d3dx11)
|
||||||
|
else()
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
find_package(glfw3 3 REQUIRED)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(application PRIVATE
|
||||||
|
"-framework CoreFoundation"
|
||||||
|
"-framework Cocoa"
|
||||||
|
"-framework IOKit"
|
||||||
|
"-framework CoreVideo"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (OpenGL_FOUND)
|
||||||
|
set(HAVE_OPENGL YES)
|
||||||
|
|
||||||
|
target_include_directories(application PRIVATE ${OPENGL_INCLUDE_DIR})
|
||||||
|
target_link_libraries(application PRIVATE ${OPENGL_gl_LIBRARY})
|
||||||
|
list(APPEND _Application_Sources
|
||||||
|
source/imgui_impl_opengl3.cpp
|
||||||
|
source/imgui_impl_opengl3.h
|
||||||
|
source/imgui_impl_opengl3_loader.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (glfw3_FOUND)
|
||||||
|
set(HAVE_GLFW3 YES)
|
||||||
|
|
||||||
|
list(APPEND _Application_Sources
|
||||||
|
source/imgui_impl_glfw.cpp
|
||||||
|
source/imgui_impl_glfw.h
|
||||||
|
)
|
||||||
|
target_link_libraries(application PRIVATE
|
||||||
|
glfw
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
source/config.h.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/source/config.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(application PRIVATE
|
||||||
|
#BACKEND_CONFIG=IMGUI_GLFW
|
||||||
|
#RENDERER_CONFIG=IMGUI_OGL3
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(application PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/source)
|
||||||
|
|
||||||
|
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_Application_Sources})
|
||||||
|
|
||||||
|
target_sources(application PRIVATE ${_Application_Sources})
|
||||||
|
|
||||||
|
set_property(TARGET application PROPERTY FOLDER "examples")
|
|
@ -0,0 +1,57 @@
|
||||||
|
# pragma once
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <string>
|
||||||
|
# include <memory>
|
||||||
|
|
||||||
|
struct Platform;
|
||||||
|
struct Renderer;
|
||||||
|
|
||||||
|
struct Application
|
||||||
|
{
|
||||||
|
Application(const char* name);
|
||||||
|
Application(const char* name, int argc, char** argv);
|
||||||
|
~Application();
|
||||||
|
|
||||||
|
bool Create(int width = -1, int height = -1);
|
||||||
|
|
||||||
|
int Run();
|
||||||
|
|
||||||
|
void SetTitle(const char* title);
|
||||||
|
|
||||||
|
bool Close();
|
||||||
|
void Quit();
|
||||||
|
|
||||||
|
const std::string& GetName() const;
|
||||||
|
|
||||||
|
ImFont* DefaultFont() const;
|
||||||
|
ImFont* HeaderFont() const;
|
||||||
|
|
||||||
|
ImTextureID LoadTexture(const char* path);
|
||||||
|
ImTextureID CreateTexture(const void* data, int width, int height);
|
||||||
|
void DestroyTexture(ImTextureID texture);
|
||||||
|
int GetTextureWidth(ImTextureID texture);
|
||||||
|
int GetTextureHeight(ImTextureID texture);
|
||||||
|
|
||||||
|
virtual void OnStart() {}
|
||||||
|
virtual void OnStop() {}
|
||||||
|
virtual void OnFrame(float deltaTime) {}
|
||||||
|
|
||||||
|
virtual ImGuiWindowFlags GetWindowFlags() const;
|
||||||
|
|
||||||
|
virtual bool CanClose() { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RecreateFontAtlas();
|
||||||
|
|
||||||
|
void Frame();
|
||||||
|
|
||||||
|
std::string m_Name;
|
||||||
|
std::string m_IniFilename;
|
||||||
|
std::unique_ptr<Platform> m_Platform;
|
||||||
|
std::unique_ptr<Renderer> m_Renderer;
|
||||||
|
ImGuiContext* m_Context = nullptr;
|
||||||
|
ImFont* m_DefaultFont = nullptr;
|
||||||
|
ImFont* m_HeaderFont = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
int Main(int argc, char** argv);
|
|
@ -0,0 +1,244 @@
|
||||||
|
# include "application.h"
|
||||||
|
# include "setup.h"
|
||||||
|
# include "platform.h"
|
||||||
|
# include "renderer.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_STATIC
|
||||||
|
#include "stb_image.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Application::Application(const char* name)
|
||||||
|
: Application(name, 0, nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::Application(const char* name, int argc, char** argv)
|
||||||
|
: m_Name(name)
|
||||||
|
, m_Platform(CreatePlatform(*this))
|
||||||
|
, m_Renderer(CreateRenderer())
|
||||||
|
{
|
||||||
|
m_Platform->ApplicationStart(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::~Application()
|
||||||
|
{
|
||||||
|
m_Renderer->Destroy();
|
||||||
|
|
||||||
|
m_Platform->ApplicationStop();
|
||||||
|
|
||||||
|
if (m_Context)
|
||||||
|
{
|
||||||
|
ImGui::DestroyContext(m_Context);
|
||||||
|
m_Context= nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::Create(int width /*= -1*/, int height /*= -1*/)
|
||||||
|
{
|
||||||
|
m_Context = ImGui::CreateContext();
|
||||||
|
ImGui::SetCurrentContext(m_Context);
|
||||||
|
|
||||||
|
if (!m_Platform->OpenMainWindow("Application", width, height))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_Renderer->Create(*m_Platform))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_IniFilename = m_Name + ".ini";
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||||
|
io.IniFilename = m_IniFilename.c_str();
|
||||||
|
io.LogFilename = nullptr;
|
||||||
|
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
|
RecreateFontAtlas();
|
||||||
|
|
||||||
|
m_Platform->AcknowledgeWindowScaleChanged();
|
||||||
|
m_Platform->AcknowledgeFramebufferScaleChanged();
|
||||||
|
|
||||||
|
OnStart();
|
||||||
|
|
||||||
|
Frame();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Application::Run()
|
||||||
|
{
|
||||||
|
m_Platform->ShowMainWindow();
|
||||||
|
|
||||||
|
while (m_Platform->ProcessMainWindowEvents())
|
||||||
|
{
|
||||||
|
if (!m_Platform->IsMainWindowVisible())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
OnStop();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::RecreateFontAtlas()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
IM_DELETE(io.Fonts);
|
||||||
|
|
||||||
|
io.Fonts = IM_NEW(ImFontAtlas);
|
||||||
|
|
||||||
|
ImFontConfig config;
|
||||||
|
config.OversampleH = 4;
|
||||||
|
config.OversampleV = 4;
|
||||||
|
config.PixelSnapH = false;
|
||||||
|
|
||||||
|
m_DefaultFont = io.Fonts->AddFontFromFileTTF("data/Play-Regular.ttf", 18.0f, &config);
|
||||||
|
m_HeaderFont = io.Fonts->AddFontFromFileTTF("data/Cuprum-Bold.ttf", 20.0f, &config);
|
||||||
|
|
||||||
|
io.Fonts->Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::Frame()
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
if (m_Platform->HasWindowScaleChanged())
|
||||||
|
m_Platform->AcknowledgeWindowScaleChanged();
|
||||||
|
|
||||||
|
if (m_Platform->HasFramebufferScaleChanged())
|
||||||
|
{
|
||||||
|
RecreateFontAtlas();
|
||||||
|
m_Platform->AcknowledgeFramebufferScaleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
const float windowScale = m_Platform->GetWindowScale();
|
||||||
|
const float framebufferScale = m_Platform->GetFramebufferScale();
|
||||||
|
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
{
|
||||||
|
io.MousePos.x *= windowScale;
|
||||||
|
io.MousePos.y *= windowScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Platform->NewFrame();
|
||||||
|
|
||||||
|
// Don't touch "uninitialized" mouse position
|
||||||
|
if (io.MousePos.x > -FLT_MAX && io.MousePos.y > -FLT_MAX)
|
||||||
|
{
|
||||||
|
io.MousePos.x /= windowScale;
|
||||||
|
io.MousePos.y /= windowScale;
|
||||||
|
}
|
||||||
|
io.DisplaySize.x /= windowScale;
|
||||||
|
io.DisplaySize.y /= windowScale;
|
||||||
|
|
||||||
|
io.DisplayFramebufferScale.x = framebufferScale;
|
||||||
|
io.DisplayFramebufferScale.y = framebufferScale;
|
||||||
|
|
||||||
|
m_Renderer->NewFrame();
|
||||||
|
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
||||||
|
ImGui::SetNextWindowSize(io.DisplaySize);
|
||||||
|
const auto windowBorderSize = ImGui::GetStyle().WindowBorderSize;
|
||||||
|
const auto windowRounding = ImGui::GetStyle().WindowRounding;
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||||
|
ImGui::Begin("Content", nullptr, GetWindowFlags());
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, windowBorderSize);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, windowRounding);
|
||||||
|
|
||||||
|
OnFrame(io.DeltaTime);
|
||||||
|
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
ImGui::End();
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
m_Renderer->Clear(ImColor(32, 32, 32, 255));
|
||||||
|
ImGui::Render();
|
||||||
|
m_Renderer->RenderDrawData(ImGui::GetDrawData());
|
||||||
|
|
||||||
|
m_Platform->FinishFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::SetTitle(const char* title)
|
||||||
|
{
|
||||||
|
m_Platform->SetMainWindowTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::Close()
|
||||||
|
{
|
||||||
|
return m_Platform->CloseMainWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::Quit()
|
||||||
|
{
|
||||||
|
m_Platform->Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Application::GetName() const
|
||||||
|
{
|
||||||
|
return m_Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImFont* Application::DefaultFont() const
|
||||||
|
{
|
||||||
|
return m_DefaultFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImFont* Application::HeaderFont() const
|
||||||
|
{
|
||||||
|
return m_HeaderFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImTextureID Application::LoadTexture(const char* path)
|
||||||
|
{
|
||||||
|
int width = 0, height = 0, component = 0;
|
||||||
|
if (auto data = stbi_load(path, &width, &height, &component, 4))
|
||||||
|
{
|
||||||
|
auto texture = CreateTexture(data, width, height);
|
||||||
|
stbi_image_free(data);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImTextureID Application::CreateTexture(const void* data, int width, int height)
|
||||||
|
{
|
||||||
|
return m_Renderer->CreateTexture(data, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::DestroyTexture(ImTextureID texture)
|
||||||
|
{
|
||||||
|
m_Renderer->DestroyTexture(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Application::GetTextureWidth(ImTextureID texture)
|
||||||
|
{
|
||||||
|
return m_Renderer->GetTextureWidth(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Application::GetTextureHeight(ImTextureID texture)
|
||||||
|
{
|
||||||
|
return m_Renderer->GetTextureHeight(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiWindowFlags Application::GetWindowFlags() const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
ImGuiWindowFlags_NoTitleBar |
|
||||||
|
ImGuiWindowFlags_NoResize |
|
||||||
|
ImGuiWindowFlags_NoMove |
|
||||||
|
ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse |
|
||||||
|
ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_NoBringToFrontOnFocus;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
# cmakedefine01 HAVE_GLFW3
|
||||||
|
# cmakedefine01 HAVE_OPENGL
|
|
@ -0,0 +1,21 @@
|
||||||
|
# include "application.h"
|
||||||
|
# include "platform.h"
|
||||||
|
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
# define NOMINMAX
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
# include <stdlib.h> // __argc, argv
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(_WIN32) && !defined(_CONSOLE)
|
||||||
|
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
|
||||||
|
{
|
||||||
|
return Main(__argc, __argv);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
return Main(argc, argv);
|
||||||
|
}
|
||||||
|
# endif
|
|
@ -0,0 +1,65 @@
|
||||||
|
# pragma once
|
||||||
|
# include <imgui.h>
|
||||||
|
|
||||||
|
# if !defined(IMGUI_VERSION_NUM) || (IMGUI_VERSION_NUM < 18822)
|
||||||
|
|
||||||
|
# include <type_traits>
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/8597498
|
||||||
|
# define DECLARE_HAS_NESTED(Name, Member) \
|
||||||
|
\
|
||||||
|
template<class T> \
|
||||||
|
struct has_nested_ ## Name \
|
||||||
|
{ \
|
||||||
|
typedef char yes; \
|
||||||
|
typedef yes(&no)[2]; \
|
||||||
|
\
|
||||||
|
template<class U> static yes test(decltype(U::Member)*); \
|
||||||
|
template<class U> static no test(...); \
|
||||||
|
\
|
||||||
|
static bool const value = sizeof(test<T>(0)) == sizeof(yes); \
|
||||||
|
};
|
||||||
|
|
||||||
|
# define DECLARE_KEY_TESTER(Key) \
|
||||||
|
DECLARE_HAS_NESTED(Key, Key) \
|
||||||
|
struct KeyTester_ ## Key \
|
||||||
|
{ \
|
||||||
|
template <typename T> \
|
||||||
|
static int Get(typename std::enable_if<has_nested_ ## Key<ImGuiKey_>::value, T>::type*) \
|
||||||
|
{ \
|
||||||
|
return T::Key; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
template <typename T> \
|
||||||
|
static int Get(typename std::enable_if<!has_nested_ ## Key<ImGuiKey_>::value, T>::type*) \
|
||||||
|
{ \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_KEY_TESTER(ImGuiKey_F);
|
||||||
|
DECLARE_KEY_TESTER(ImGuiKey_D);
|
||||||
|
|
||||||
|
static inline int GetEnumValueForF()
|
||||||
|
{
|
||||||
|
return KeyTester_ImGuiKey_F::Get<ImGuiKey_>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int GetEnumValueForD()
|
||||||
|
{
|
||||||
|
return KeyTester_ImGuiKey_D::Get<ImGuiKey_>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
# else
|
||||||
|
|
||||||
|
static inline ImGuiKey GetEnumValueForF()
|
||||||
|
{
|
||||||
|
return ImGuiKey_F;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ImGuiKey GetEnumValueForD()
|
||||||
|
{
|
||||||
|
return ImGuiKey_D;
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif
|
|
@ -0,0 +1,681 @@
|
||||||
|
// dear imgui: Renderer for DirectX11
|
||||||
|
// This needs to be used along with a Platform Binding (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
|
||||||
|
// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
|
||||||
|
// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2016-05-07: DirectX11: Disabling depth-write.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_dx11.h"
|
||||||
|
|
||||||
|
// DirectX
|
||||||
|
struct IUnknown;
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <d3d11.h>
|
||||||
|
#include <d3dcompiler.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct TEXTURE;
|
||||||
|
|
||||||
|
// DirectX data
|
||||||
|
static ID3D11Device* g_pd3dDevice = NULL;
|
||||||
|
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
|
||||||
|
static IDXGIFactory* g_pFactory = NULL;
|
||||||
|
static ID3D11Buffer* g_pVB = NULL;
|
||||||
|
static ID3D11Buffer* g_pIB = NULL;
|
||||||
|
static ID3D10Blob* g_pVertexShaderBlob = NULL;
|
||||||
|
static ID3D11VertexShader* g_pVertexShader = NULL;
|
||||||
|
static ID3D11InputLayout* g_pInputLayout = NULL;
|
||||||
|
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
|
||||||
|
static ID3D10Blob* g_pPixelShaderBlob = NULL;
|
||||||
|
static ID3D11PixelShader* g_pPixelShader = NULL;
|
||||||
|
static ID3D11SamplerState* g_pFontSampler = NULL;
|
||||||
|
static ImTextureID g_pFontTextureID = NULL;
|
||||||
|
static ID3D11RasterizerState* g_pRasterizerState = NULL;
|
||||||
|
static ID3D11BlendState* g_pBlendState = NULL;
|
||||||
|
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
|
||||||
|
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||||
|
static ImVector<TEXTURE*> g_Textures;
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER
|
||||||
|
{
|
||||||
|
float mvp[4][4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TEXTURE
|
||||||
|
{
|
||||||
|
TEXTURE()
|
||||||
|
{
|
||||||
|
View = NULL;
|
||||||
|
Width = 0;
|
||||||
|
Height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11ShaderResourceView* View;
|
||||||
|
int Width;
|
||||||
|
int Height;
|
||||||
|
ImVector<unsigned char> Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
static bool ImGui_UploadTexture(TEXTURE* texture);
|
||||||
|
static void ImGui_ReleaseTexture(TEXTURE* texture);
|
||||||
|
|
||||||
|
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
|
||||||
|
{
|
||||||
|
// Setup viewport
|
||||||
|
D3D11_VIEWPORT vp;
|
||||||
|
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
||||||
|
vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x;
|
||||||
|
vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y;
|
||||||
|
vp.MinDepth = 0.0f;
|
||||||
|
vp.MaxDepth = 1.0f;
|
||||||
|
vp.TopLeftX = vp.TopLeftY = 0;
|
||||||
|
ctx->RSSetViewports(1, &vp);
|
||||||
|
|
||||||
|
// Setup shader and vertex buffers
|
||||||
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
|
unsigned int offset = 0;
|
||||||
|
ctx->IASetInputLayout(g_pInputLayout);
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
||||||
|
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||||
|
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
ctx->VSSetShader(g_pVertexShader, NULL, 0);
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
||||||
|
ctx->PSSetShader(g_pPixelShader, NULL, 0);
|
||||||
|
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
|
||||||
|
|
||||||
|
// Setup blend state
|
||||||
|
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||||
|
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
|
||||||
|
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
|
||||||
|
ctx->RSSetState(g_pRasterizerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render function
|
||||||
|
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
||||||
|
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
|
||||||
|
|
||||||
|
// Create and grow vertex/index buffers if needed
|
||||||
|
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
{
|
||||||
|
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||||
|
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
D3D11_BUFFER_DESC desc;
|
||||||
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
|
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
||||||
|
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
desc.MiscFlags = 0;
|
||||||
|
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
{
|
||||||
|
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||||
|
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
D3D11_BUFFER_DESC desc;
|
||||||
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
|
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
|
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload vertex/index data into a single contiguous GPU buffer
|
||||||
|
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
|
||||||
|
if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
||||||
|
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||||
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
ctx->Unmap(g_pVB, 0);
|
||||||
|
ctx->Unmap(g_pIB, 0);
|
||||||
|
|
||||||
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
{
|
||||||
|
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
||||||
|
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
float mvp[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
|
};
|
||||||
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
|
ctx->Unmap(g_pVertexConstantBuffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||||
|
struct BACKUP_DX11_STATE
|
||||||
|
{
|
||||||
|
UINT ScissorRectsCount, ViewportsCount;
|
||||||
|
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
|
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
|
ID3D11RasterizerState* RS;
|
||||||
|
ID3D11BlendState* BlendState;
|
||||||
|
FLOAT BlendFactor[4];
|
||||||
|
UINT SampleMask;
|
||||||
|
UINT StencilRef;
|
||||||
|
ID3D11DepthStencilState* DepthStencilState;
|
||||||
|
ID3D11ShaderResourceView* PSShaderResource;
|
||||||
|
ID3D11SamplerState* PSSampler;
|
||||||
|
ID3D11PixelShader* PS;
|
||||||
|
ID3D11VertexShader* VS;
|
||||||
|
UINT PSInstancesCount, VSInstancesCount;
|
||||||
|
ID3D11ClassInstance* PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation
|
||||||
|
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
||||||
|
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
||||||
|
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
||||||
|
DXGI_FORMAT IndexBufferFormat;
|
||||||
|
ID3D11InputLayout* InputLayout;
|
||||||
|
};
|
||||||
|
BACKUP_DX11_STATE old;
|
||||||
|
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||||
|
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
||||||
|
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
||||||
|
ctx->RSGetState(&old.RS);
|
||||||
|
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
|
||||||
|
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
|
||||||
|
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
|
||||||
|
ctx->PSGetSamplers(0, 1, &old.PSSampler);
|
||||||
|
old.PSInstancesCount = old.VSInstancesCount = 256;
|
||||||
|
ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
|
||||||
|
ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
|
||||||
|
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
|
||||||
|
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
|
||||||
|
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
|
||||||
|
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
|
||||||
|
ctx->IAGetInputLayout(&old.InputLayout);
|
||||||
|
|
||||||
|
// Setup desired DX state
|
||||||
|
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
|
int global_idx_offset = 0;
|
||||||
|
int global_vtx_offset = 0;
|
||||||
|
|
||||||
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
|
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != NULL)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImVec4 clip_rect;
|
||||||
|
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
||||||
|
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
const D3D11_RECT r = { (LONG)clip_rect.x, (LONG)clip_rect.y, (LONG)clip_rect.z, (LONG)clip_rect.w };
|
||||||
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
TEXTURE* texture = (TEXTURE*)pcmd->TextureId;
|
||||||
|
ID3D11ShaderResourceView* textureView = texture ? texture->View : nullptr;
|
||||||
|
ctx->PSSetShaderResources(0, 1, &textureView);
|
||||||
|
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore modified DX state
|
||||||
|
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
||||||
|
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
||||||
|
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
|
||||||
|
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
|
||||||
|
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
|
||||||
|
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
|
||||||
|
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
|
||||||
|
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
|
||||||
|
for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
|
||||||
|
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
|
||||||
|
for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
|
||||||
|
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
||||||
|
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
|
||||||
|
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
|
g_pFontTextureID = ImGui_CreateTexture(pixels, width, height);
|
||||||
|
|
||||||
|
io.Fonts->TexID = g_pFontTextureID;
|
||||||
|
|
||||||
|
|
||||||
|
// Create texture sampler
|
||||||
|
{
|
||||||
|
D3D11_SAMPLER_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
|
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.MipLODBias = 0.f;
|
||||||
|
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
|
desc.MinLOD = 0.f;
|
||||||
|
desc.MaxLOD = 0.f;
|
||||||
|
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return false;
|
||||||
|
if (g_pFontSampler)
|
||||||
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
|
// If you would like to use this DX11 sample code but remove this dependency you can:
|
||||||
|
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
||||||
|
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||||
|
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||||
|
|
||||||
|
// Create the vertex shader
|
||||||
|
{
|
||||||
|
static const char* vertexShader =
|
||||||
|
"cbuffer vertexBuffer : register(b0) \
|
||||||
|
{\
|
||||||
|
float4x4 ProjectionMatrix; \
|
||||||
|
};\
|
||||||
|
struct VS_INPUT\
|
||||||
|
{\
|
||||||
|
float2 pos : POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
\
|
||||||
|
struct PS_INPUT\
|
||||||
|
{\
|
||||||
|
float4 pos : SV_POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
\
|
||||||
|
PS_INPUT main(VS_INPUT input)\
|
||||||
|
{\
|
||||||
|
PS_INPUT output;\
|
||||||
|
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
|
||||||
|
output.col = input.col;\
|
||||||
|
output.uv = input.uv;\
|
||||||
|
return output;\
|
||||||
|
}";
|
||||||
|
|
||||||
|
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, NULL);
|
||||||
|
if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
|
return false;
|
||||||
|
if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Create the input layout
|
||||||
|
D3D11_INPUT_ELEMENT_DESC local_layout[] =
|
||||||
|
{
|
||||||
|
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
};
|
||||||
|
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Create the constant buffer
|
||||||
|
{
|
||||||
|
D3D11_BUFFER_DESC desc;
|
||||||
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||||
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
|
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
desc.MiscFlags = 0;
|
||||||
|
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the pixel shader
|
||||||
|
{
|
||||||
|
static const char* pixelShader =
|
||||||
|
"struct PS_INPUT\
|
||||||
|
{\
|
||||||
|
float4 pos : SV_POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
sampler sampler0;\
|
||||||
|
Texture2D texture0;\
|
||||||
|
\
|
||||||
|
float4 main(PS_INPUT input) : SV_Target\
|
||||||
|
{\
|
||||||
|
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
|
||||||
|
out_col.rgb *= out_col.a; \
|
||||||
|
return out_col; \
|
||||||
|
}";
|
||||||
|
|
||||||
|
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, NULL);
|
||||||
|
if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
|
return false;
|
||||||
|
if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the blending setup
|
||||||
|
{
|
||||||
|
D3D11_BLEND_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.AlphaToCoverageEnable = false;
|
||||||
|
desc.RenderTarget[0].BlendEnable = true;
|
||||||
|
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
|
||||||
|
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
|
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||||
|
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||||
|
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||||
|
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||||
|
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||||
|
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the rasterizer state
|
||||||
|
{
|
||||||
|
D3D11_RASTERIZER_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.FillMode = D3D11_FILL_SOLID;
|
||||||
|
desc.CullMode = D3D11_CULL_NONE;
|
||||||
|
desc.ScissorEnable = true;
|
||||||
|
desc.DepthClipEnable = true;
|
||||||
|
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create depth-stencil State
|
||||||
|
{
|
||||||
|
D3D11_DEPTH_STENCIL_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.DepthEnable = false;
|
||||||
|
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
||||||
|
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
|
desc.StencilEnable = false;
|
||||||
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||||
|
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
|
desc.BackFace = desc.FrontFace;
|
||||||
|
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplDX11_CreateFontsTexture();
|
||||||
|
|
||||||
|
for (auto& texture : g_Textures)
|
||||||
|
ImGui_UploadTexture(texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto& texture : g_Textures)
|
||||||
|
ImGui_ReleaseTexture(texture);
|
||||||
|
|
||||||
|
if (g_pFontTextureID)
|
||||||
|
{
|
||||||
|
ImGui_DestroyTexture(g_pFontTextureID);
|
||||||
|
g_pFontTextureID = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
||||||
|
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||||
|
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||||
|
|
||||||
|
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
||||||
|
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
||||||
|
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
||||||
|
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
||||||
|
if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; }
|
||||||
|
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
||||||
|
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
||||||
|
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
||||||
|
if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
||||||
|
{
|
||||||
|
// Setup back-end capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_dx11";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
// Get factory from device
|
||||||
|
IDXGIDevice* pDXGIDevice = NULL;
|
||||||
|
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||||
|
IDXGIFactory* pFactory = NULL;
|
||||||
|
|
||||||
|
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||||
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
|
{
|
||||||
|
g_pd3dDevice = device;
|
||||||
|
g_pd3dDeviceContext = device_context;
|
||||||
|
g_pFactory = pFactory;
|
||||||
|
}
|
||||||
|
if (pDXGIDevice) pDXGIDevice->Release();
|
||||||
|
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||||
|
g_pd3dDevice->AddRef();
|
||||||
|
g_pd3dDeviceContext->AddRef();
|
||||||
|
|
||||||
|
g_Textures.reserve(16);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX11_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
||||||
|
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
||||||
|
if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX11_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_pFontSampler)
|
||||||
|
ImGui_ImplDX11_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_STATIC
|
||||||
|
#include "stb_image.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
ImTextureID ImGui_LoadTexture(const char* path)
|
||||||
|
{
|
||||||
|
int width = 0, height = 0, component = 0;
|
||||||
|
if (auto data = stbi_load(path, &width, &height, &component, 4))
|
||||||
|
{
|
||||||
|
auto texture = ImGui_CreateTexture(data, width, height);
|
||||||
|
stbi_image_free(data);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImTextureID ImGui_CreateTexture(const void* data, int width, int height)
|
||||||
|
{
|
||||||
|
auto texture = IM_NEW(TEXTURE);
|
||||||
|
texture->Width = width;
|
||||||
|
texture->Height = height;
|
||||||
|
texture->Data.resize(width * height * 4);
|
||||||
|
memcpy(texture->Data.Data, data, texture->Data.Size);
|
||||||
|
|
||||||
|
if (!ImGui_UploadTexture(texture))
|
||||||
|
{
|
||||||
|
IM_DELETE(texture);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_Textures.push_back(texture);
|
||||||
|
|
||||||
|
return (ImTextureID)texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_DestroyTexture(ImTextureID texture)
|
||||||
|
{
|
||||||
|
if (!texture)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TEXTURE* texture_object = (TEXTURE*)(texture);
|
||||||
|
|
||||||
|
ImGui_ReleaseTexture(texture_object);
|
||||||
|
|
||||||
|
for (TEXTURE** it = g_Textures.begin(), **itEnd = g_Textures.end(); it != itEnd; ++it)
|
||||||
|
{
|
||||||
|
if (*it == texture_object)
|
||||||
|
{
|
||||||
|
g_Textures.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IM_DELETE(texture_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_UploadTexture(TEXTURE* texture)
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice || !texture)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (texture->View)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
D3D11_TEXTURE2D_DESC desc = {};
|
||||||
|
desc.Width = texture->Width;
|
||||||
|
desc.Height = texture->Height;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.ArraySize = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||||
|
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
|
D3D11_SUBRESOURCE_DATA subResource = {};
|
||||||
|
subResource.pSysMem = texture->Data.Data;
|
||||||
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
|
subResource.SysMemSlicePitch = 0;
|
||||||
|
|
||||||
|
ID3D11Texture2D *pTexture = nullptr;
|
||||||
|
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
|
||||||
|
if (!pTexture)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Create texture view
|
||||||
|
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
|
|
||||||
|
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &texture->View);
|
||||||
|
pTexture->Release();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ReleaseTexture(TEXTURE* texture)
|
||||||
|
{
|
||||||
|
if (texture)
|
||||||
|
{
|
||||||
|
if (texture->View)
|
||||||
|
{
|
||||||
|
texture->View->Release();
|
||||||
|
texture->View = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImGui_GetTextureWidth(ImTextureID texture)
|
||||||
|
{
|
||||||
|
if (TEXTURE* tex = (TEXTURE*)(texture))
|
||||||
|
return tex->Width;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImGui_GetTextureHeight(ImTextureID texture)
|
||||||
|
{
|
||||||
|
if (TEXTURE* tex = (TEXTURE*)(texture))
|
||||||
|
return tex->Height;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// dear imgui: Renderer for DirectX11
|
||||||
|
// This needs to be used along with a Platform Binding (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct ID3D11Device;
|
||||||
|
struct ID3D11DeviceContext;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing ImGui state.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
|
||||||
|
|
||||||
|
IMGUI_IMPL_API ImTextureID ImGui_LoadTexture(const char* path);
|
||||||
|
IMGUI_IMPL_API ImTextureID ImGui_CreateTexture(const void* data, int width, int height);
|
||||||
|
IMGUI_IMPL_API void ImGui_DestroyTexture(ImTextureID texture);
|
||||||
|
IMGUI_IMPL_API int ImGui_GetTextureWidth(ImTextureID texture);
|
||||||
|
IMGUI_IMPL_API int ImGui_GetTextureHeight(ImTextureID texture);
|
|
@ -0,0 +1,382 @@
|
||||||
|
// dear imgui: Platform Binding for GLFW
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||||
|
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||||
|
// (Requires: GLFW 3.1+)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||||
|
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
|
||||||
|
// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
|
||||||
|
// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
|
||||||
|
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||||
|
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
|
||||||
|
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
|
||||||
|
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||||
|
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
|
||||||
|
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
|
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
|
||||||
|
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||||
|
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||||
|
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||||
|
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||||
|
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_glfw.h"
|
||||||
|
#include "imgui_extra_keys.h"
|
||||||
|
|
||||||
|
// GLFW
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef APIENTRY
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
|
||||||
|
#endif
|
||||||
|
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
|
||||||
|
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
|
||||||
|
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
|
||||||
|
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
|
||||||
|
#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
|
||||||
|
#ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
|
||||||
|
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
|
||||||
|
#else
|
||||||
|
#define GLFW_HAS_NEW_CURSORS (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Data
|
||||||
|
enum GlfwClientApi
|
||||||
|
{
|
||||||
|
GlfwClientApi_Unknown,
|
||||||
|
GlfwClientApi_OpenGL,
|
||||||
|
GlfwClientApi_Vulkan
|
||||||
|
};
|
||||||
|
static GLFWwindow* g_Window = NULL; // Main window
|
||||||
|
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
|
||||||
|
static double g_Time = 0.0;
|
||||||
|
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
|
||||||
|
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
|
||||||
|
static bool g_InstalledCallbacks = false;
|
||||||
|
|
||||||
|
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||||
|
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
|
||||||
|
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
|
||||||
|
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
|
||||||
|
static GLFWcharfun g_PrevUserCallbackChar = NULL;
|
||||||
|
|
||||||
|
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||||
|
{
|
||||||
|
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||||
|
{
|
||||||
|
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||||
|
{
|
||||||
|
if (g_PrevUserCallbackMousebutton != NULL)
|
||||||
|
g_PrevUserCallbackMousebutton(window, button, action, mods);
|
||||||
|
|
||||||
|
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
|
||||||
|
g_MouseJustPressed[button] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||||
|
{
|
||||||
|
if (g_PrevUserCallbackScroll != NULL)
|
||||||
|
g_PrevUserCallbackScroll(window, xoffset, yoffset);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.MouseWheelH += (float)xoffset;
|
||||||
|
io.MouseWheel += (float)yoffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
|
{
|
||||||
|
if (g_PrevUserCallbackKey != NULL)
|
||||||
|
g_PrevUserCallbackKey(window, key, scancode, action, mods);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (action == GLFW_PRESS)
|
||||||
|
io.KeysDown[key] = true;
|
||||||
|
if (action == GLFW_RELEASE)
|
||||||
|
io.KeysDown[key] = false;
|
||||||
|
|
||||||
|
// Modifiers are not reliable across systems
|
||||||
|
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
|
||||||
|
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
|
||||||
|
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
|
||||||
|
#ifdef _WIN32
|
||||||
|
io.KeySuper = false;
|
||||||
|
#else
|
||||||
|
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||||
|
{
|
||||||
|
if (g_PrevUserCallbackChar != NULL)
|
||||||
|
g_PrevUserCallbackChar(window, c);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddInputCharacter(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||||
|
{
|
||||||
|
g_Window = window;
|
||||||
|
g_Time = 0.0;
|
||||||
|
|
||||||
|
// Setup back-end capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
io.BackendPlatformName = "imgui_impl_glfw";
|
||||||
|
|
||||||
|
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||||
|
|
||||||
|
int f_index = GetEnumValueForF();
|
||||||
|
int d_index = GetEnumValueForD();
|
||||||
|
if (f_index >= 0)
|
||||||
|
io.KeyMap[f_index] = GLFW_KEY_F;
|
||||||
|
if (d_index >= 0)
|
||||||
|
io.KeyMap[d_index] = GLFW_KEY_D;
|
||||||
|
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||||
|
io.ClipboardUserData = g_Window;
|
||||||
|
#if defined(_WIN32)
|
||||||
|
//io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create mouse cursors
|
||||||
|
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
|
||||||
|
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
|
||||||
|
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
|
||||||
|
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||||
|
#if GLFW_HAS_NEW_CURSORS
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
|
||||||
|
#else
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
#endif
|
||||||
|
glfwSetErrorCallback(prev_error_callback);
|
||||||
|
|
||||||
|
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||||
|
g_PrevUserCallbackMousebutton = NULL;
|
||||||
|
g_PrevUserCallbackScroll = NULL;
|
||||||
|
g_PrevUserCallbackKey = NULL;
|
||||||
|
g_PrevUserCallbackChar = NULL;
|
||||||
|
if (install_callbacks)
|
||||||
|
{
|
||||||
|
g_InstalledCallbacks = true;
|
||||||
|
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||||
|
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
||||||
|
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
||||||
|
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ClientApi = client_api;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfw_InitForNone(GLFWwindow* window, bool install_callbacks)
|
||||||
|
{
|
||||||
|
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
|
||||||
|
{
|
||||||
|
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
|
||||||
|
{
|
||||||
|
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_Shutdown()
|
||||||
|
{
|
||||||
|
if (g_InstalledCallbacks)
|
||||||
|
{
|
||||||
|
glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);
|
||||||
|
glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);
|
||||||
|
glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);
|
||||||
|
glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);
|
||||||
|
g_InstalledCallbacks = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||||
|
{
|
||||||
|
glfwDestroyCursor(g_MouseCursors[cursor_n]);
|
||||||
|
g_MouseCursors[cursor_n] = NULL;
|
||||||
|
}
|
||||||
|
g_ClientApi = GlfwClientApi_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
|
||||||
|
{
|
||||||
|
// Update buttons
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||||
|
{
|
||||||
|
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||||
|
io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
|
||||||
|
g_MouseJustPressed[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update mouse position
|
||||||
|
const ImVec2 mouse_pos_backup = io.MousePos;
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
const bool focused = true; // Emscripten
|
||||||
|
#else
|
||||||
|
const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;
|
||||||
|
#endif
|
||||||
|
if (focused)
|
||||||
|
{
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
{
|
||||||
|
glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double mouse_x, mouse_y;
|
||||||
|
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
|
||||||
|
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show OS mouse cursor
|
||||||
|
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
||||||
|
glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||||
|
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateGamepads()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update gamepad inputs
|
||||||
|
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
|
||||||
|
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
|
||||||
|
int axes_count = 0, buttons_count = 0;
|
||||||
|
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
|
||||||
|
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
if (axes_count > 0 && buttons_count > 0)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
else
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
glfwGetWindowSize(g_Window, &w, &h);
|
||||||
|
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
if (w > 0 && h > 0)
|
||||||
|
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
double current_time = glfwGetTime();
|
||||||
|
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
ImGui_ImplGlfw_UpdateMousePosAndButtons();
|
||||||
|
ImGui_ImplGlfw_UpdateMouseCursor();
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplGlfw_UpdateGamepads();
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
// dear imgui: Platform Binding for GLFW
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||||
|
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
// About GLSL version:
|
||||||
|
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
|
||||||
|
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct GLFWwindow;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForNone(GLFWwindow* window, bool install_callbacks);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||||
|
|
||||||
|
// GLFW callbacks
|
||||||
|
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
|
||||||
|
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
947
3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.cpp
vendored
Normal file
947
3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.cpp
vendored
Normal file
|
@ -0,0 +1,947 @@
|
||||||
|
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||||
|
// - Desktop GL: 2.x 3.x 4.x
|
||||||
|
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||||
|
|
||||||
|
// About WebGL/ES:
|
||||||
|
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||||
|
// - This is done automatically on iOS, Android and Emscripten targets.
|
||||||
|
// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2023-11-08: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" instead of "libGL.so.1", accomodating for NetBSD systems having only "libGL.so.3" available. (#6983)
|
||||||
|
// 2023-10-05: OpenGL: Rename symbols in our internal loader so that LTO compilation with another copy of gl3w is possible. (#6875, #6668, #4445)
|
||||||
|
// 2023-06-20: OpenGL: Fixed erroneous use glGetIntegerv(GL_CONTEXT_PROFILE_MASK) on contexts lower than 3.2. (#6539, #6333)
|
||||||
|
// 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375)
|
||||||
|
// 2023-04-18: OpenGL: Restore front and back polygon mode separately when supported by context. (#6333)
|
||||||
|
// 2023-03-23: OpenGL: Properly restoring "no shader program bound" if it was the case prior to running the rendering function. (#6267, #6220, #6224)
|
||||||
|
// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns NULL. (#6154, #4445, #3530)
|
||||||
|
// 2023-03-06: OpenGL: Fixed restoration of a potentially deleted OpenGL program, by calling glIsProgram(). (#6220, #6224)
|
||||||
|
// 2022-11-09: OpenGL: Reverted use of glBufferSubData(), too many corruptions issues + old issues seemingly can't be reproed with Intel drivers nowadays (revert 2021-12-15 and 2022-05-23 changes).
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2022-09-27: OpenGL: Added ability to '#define IMGUI_IMPL_OPENGL_DEBUG'.
|
||||||
|
// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
|
||||||
|
// 2022-05-13: OpenGL: Fixed state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
|
||||||
|
// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
|
||||||
|
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
|
||||||
|
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
|
||||||
|
// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
|
||||||
|
// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
|
||||||
|
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
|
||||||
|
// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
|
||||||
|
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
|
||||||
|
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
|
||||||
|
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
|
||||||
|
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
|
||||||
|
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
|
||||||
|
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
|
||||||
|
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
|
||||||
|
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
|
||||||
|
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
|
||||||
|
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
|
||||||
|
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
|
||||||
|
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
|
||||||
|
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
|
||||||
|
// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
|
||||||
|
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
|
||||||
|
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
|
||||||
|
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||||
|
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
|
||||||
|
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||||
|
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||||
|
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||||
|
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||||
|
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||||
|
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a nullptr pointer.
|
||||||
|
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||||
|
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||||
|
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||||
|
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||||
|
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||||
|
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||||
|
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||||
|
|
||||||
|
//----------------------------------------
|
||||||
|
// OpenGL GLSL GLSL
|
||||||
|
// version version string
|
||||||
|
//----------------------------------------
|
||||||
|
// 2.0 110 "#version 110"
|
||||||
|
// 2.1 120 "#version 120"
|
||||||
|
// 3.0 130 "#version 130"
|
||||||
|
// 3.1 140 "#version 140"
|
||||||
|
// 3.2 150 "#version 150"
|
||||||
|
// 3.3 330 "#version 330 core"
|
||||||
|
// 4.0 400 "#version 400 core"
|
||||||
|
// 4.1 410 "#version 410 core"
|
||||||
|
// 4.2 420 "#version 410 core"
|
||||||
|
// 4.3 430 "#version 430 core"
|
||||||
|
// ES 2.0 100 "#version 100" = WebGL 1.0
|
||||||
|
// ES 3.0 300 "#version 300 es" = WebGL 2.0
|
||||||
|
//----------------------------------------
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui_impl_opengl3.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h> // intptr_t
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Clang/GCC warnings with -Weverything
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used
|
||||||
|
#pragma clang diagnostic ignored "-Wnonportable-system-include-path"
|
||||||
|
#pragma clang diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||||
|
#pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx'
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GL includes
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||||
|
#include <OpenGLES/ES2/gl.h> // Use GL ES 2
|
||||||
|
#else
|
||||||
|
#include <GLES2/gl2.h> // Use GL ES 2
|
||||||
|
#endif
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
#ifndef GL_GLEXT_PROTOTYPES
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
#endif
|
||||||
|
#include <GLES2/gl2ext.h>
|
||||||
|
#endif
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||||
|
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
||||||
|
#else
|
||||||
|
#include <GLES3/gl3.h> // Use GL ES 3
|
||||||
|
#endif
|
||||||
|
#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||||
|
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||||
|
// Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w.
|
||||||
|
// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
|
||||||
|
// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
|
||||||
|
// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
|
||||||
|
// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
|
||||||
|
// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
|
||||||
|
#define IMGL3W_IMPL
|
||||||
|
#include "imgui_impl_opengl3_loader.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
#define glBindVertexArray glBindVertexArrayOES
|
||||||
|
#define glGenVertexArrays glGenVertexArraysOES
|
||||||
|
#define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||||
|
#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
|
||||||
|
#ifdef GL_POLYGON_MODE
|
||||||
|
#define IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 3.3+ and GL ES 3.0+ have glBindSampler()
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && (defined(IMGUI_IMPL_OPENGL_ES3) || defined(GL_VERSION_3_3))
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL use extension detection
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// [Debugging]
|
||||||
|
//#define IMGUI_IMPL_OPENGL_DEBUG
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check
|
||||||
|
#else
|
||||||
|
#define GL_CALL(_CALL) _CALL // Call without error check
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// OpenGL Data
|
||||||
|
struct ImGui_ImplOpenGL3_Data
|
||||||
|
{
|
||||||
|
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||||
|
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
|
||||||
|
bool GlProfileIsES2;
|
||||||
|
bool GlProfileIsES3;
|
||||||
|
bool GlProfileIsCompat;
|
||||||
|
GLint GlProfileMask;
|
||||||
|
GLuint FontTexture;
|
||||||
|
GLuint ShaderHandle;
|
||||||
|
GLint AttribLocationTex; // Uniforms location
|
||||||
|
GLint AttribLocationProjMtx;
|
||||||
|
GLuint AttribLocationVtxPos; // Vertex attributes location
|
||||||
|
GLuint AttribLocationVtxUV;
|
||||||
|
GLuint AttribLocationVtxColor;
|
||||||
|
unsigned int VboHandle, ElementsHandle;
|
||||||
|
GLsizeiptr VertexBufferSize;
|
||||||
|
GLsizeiptr IndexBufferSize;
|
||||||
|
bool HasClipOrigin;
|
||||||
|
bool UseBufferSubData;
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
struct ImGui_ImplOpenGL3_VtxAttribState
|
||||||
|
{
|
||||||
|
GLint Enabled, Size, Type, Normalized, Stride;
|
||||||
|
GLvoid* Ptr;
|
||||||
|
|
||||||
|
void GetState(GLint index)
|
||||||
|
{
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &Enabled);
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &Size);
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &Type);
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &Normalized);
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &Stride);
|
||||||
|
glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &Ptr);
|
||||||
|
}
|
||||||
|
void SetState(GLint index)
|
||||||
|
{
|
||||||
|
glVertexAttribPointer(index, Size, Type, (GLboolean)Normalized, Stride, Ptr);
|
||||||
|
if (Enabled) glEnableVertexAttribArray(index); else glDisableVertexAttribArray(index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Initialize our loader
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||||
|
if (imgl3wInit() != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
|
io.BackendRendererName = "imgui_impl_opengl3";
|
||||||
|
|
||||||
|
// Query for GL version (e.g. 320 for GL 3.2)
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
// GLES 2
|
||||||
|
bd->GlVersion = 200;
|
||||||
|
bd->GlProfileIsES2 = true;
|
||||||
|
#else
|
||||||
|
// Desktop or GLES 3
|
||||||
|
GLint major = 0;
|
||||||
|
GLint minor = 0;
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||||
|
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||||
|
if (major == 0 && minor == 0)
|
||||||
|
{
|
||||||
|
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||||
|
const char* gl_version = (const char*)glGetString(GL_VERSION);
|
||||||
|
sscanf(gl_version, "%d.%d", &major, &minor);
|
||||||
|
}
|
||||||
|
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||||
|
#if defined(GL_CONTEXT_PROFILE_MASK)
|
||||||
|
if (bd->GlVersion >= 320)
|
||||||
|
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask);
|
||||||
|
bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
bd->GlProfileIsES3 = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bd->UseBufferSubData = false;
|
||||||
|
/*
|
||||||
|
// Query vendor to enable glBufferSubData kludge
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (const char* vendor = (const char*)glGetString(GL_VENDOR))
|
||||||
|
if (strncmp(vendor, "Intel", 5) == 0)
|
||||||
|
bd->UseBufferSubData = true;
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_DEBUG
|
||||||
|
printf("GlVersion = %d\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2 = %d, GlProfileIsES3 = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
|
if (bd->GlVersion >= 320)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Store GLSL version string so we can refer to it later in case we recreate shaders.
|
||||||
|
// Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure.
|
||||||
|
if (glsl_version == nullptr)
|
||||||
|
{
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
glsl_version = "#version 100";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
glsl_version = "#version 300 es";
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
glsl_version = "#version 150";
|
||||||
|
#else
|
||||||
|
glsl_version = "#version 130";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
|
||||||
|
strcpy(bd->GlslVersionString, glsl_version);
|
||||||
|
strcat(bd->GlslVersionString, "\n");
|
||||||
|
|
||||||
|
// Make an arbitrary GL call (we don't actually need the result)
|
||||||
|
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
|
||||||
|
GLint current_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||||
|
|
||||||
|
// Detect extensions we support
|
||||||
|
bd->HasClipOrigin = (bd->GlVersion >= 450);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||||
|
GLint num_extensions = 0;
|
||||||
|
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
||||||
|
for (GLint i = 0; i < num_extensions; i++)
|
||||||
|
{
|
||||||
|
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||||
|
if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0)
|
||||||
|
bd->HasClipOrigin = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||||
|
io.BackendRendererName = nullptr;
|
||||||
|
io.BackendRendererUserData = nullptr;
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplOpenGL3_Init()?");
|
||||||
|
|
||||||
|
if (!bd->ShaderHandle)
|
||||||
|
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
|
||||||
|
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
|
if (bd->GlVersion >= 310)
|
||||||
|
glDisable(GL_PRIMITIVE_RESTART);
|
||||||
|
#endif
|
||||||
|
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||||
|
#if defined(GL_CLIP_ORIGIN)
|
||||||
|
bool clip_origin_lower_left = true;
|
||||||
|
if (bd->HasClipOrigin)
|
||||||
|
{
|
||||||
|
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
|
||||||
|
if (current_clip_origin == GL_UPPER_LEFT)
|
||||||
|
clip_origin_lower_left = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup viewport, orthographic projection matrix
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height));
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
#if defined(GL_CLIP_ORIGIN)
|
||||||
|
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
|
||||||
|
#endif
|
||||||
|
const float ortho_projection[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||||
|
};
|
||||||
|
glUseProgram(bd->ShaderHandle);
|
||||||
|
glUniform1i(bd->AttribLocationTex, 0);
|
||||||
|
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
|
if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
|
||||||
|
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void)vertex_array_object;
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
glBindVertexArray(vertex_array_object);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||||
|
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle));
|
||||||
|
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle));
|
||||||
|
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxPos));
|
||||||
|
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxUV));
|
||||||
|
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxColor));
|
||||||
|
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, pos)));
|
||||||
|
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, uv)));
|
||||||
|
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenGL3 Render function.
|
||||||
|
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||||
|
// This is in order to be able to run within an OpenGL engine that doesn't do so.
|
||||||
|
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||||
|
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||||
|
if (fb_width <= 0 || fb_height <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
|
||||||
|
// Backup GL state
|
||||||
|
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||||
|
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
|
GLuint last_sampler; if (bd->GlVersion >= 330 || bd->GlProfileIsES3) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||||
|
#endif
|
||||||
|
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
// This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+.
|
||||||
|
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
|
||||||
|
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_pos; last_vtx_attrib_state_pos.GetState(bd->AttribLocationVtxPos);
|
||||||
|
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_uv; last_vtx_attrib_state_uv.GetState(bd->AttribLocationVtxUV);
|
||||||
|
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_color; last_vtx_attrib_state_color.GetState(bd->AttribLocationVtxColor);
|
||||||
|
#endif
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||||
|
#endif
|
||||||
|
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
|
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||||
|
#endif
|
||||||
|
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||||
|
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||||
|
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||||
|
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||||
|
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||||
|
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||||
|
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||||
|
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||||
|
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||||
|
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||||
|
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||||
|
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
||||||
|
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
|
GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup desired GL state
|
||||||
|
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||||
|
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||||
|
GLuint vertex_array_object = 0;
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
GL_CALL(glGenVertexArrays(1, &vertex_array_object));
|
||||||
|
#endif
|
||||||
|
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||||
|
|
||||||
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
|
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
||||||
|
// Upload vertex/index buffers
|
||||||
|
// - OpenGL drivers are in a very sorry state nowadays....
|
||||||
|
// During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports
|
||||||
|
// of leaks on Intel GPU when using multi-viewports on Windows.
|
||||||
|
// - After this we kept hearing of various display corruptions issues. We started disabling on non-Intel GPU, but issues still got reported on Intel.
|
||||||
|
// - We are now back to using exclusively glBufferData(). So bd->UseBufferSubData IS ALWAYS FALSE in this code.
|
||||||
|
// We are keeping the old code path for a while in case people finding new issues may want to test the bd->UseBufferSubData path.
|
||||||
|
// - See https://github.com/ocornut/imgui/issues/4468 and please report any corruption issues.
|
||||||
|
const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
|
||||||
|
const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
|
||||||
|
if (bd->UseBufferSubData)
|
||||||
|
{
|
||||||
|
if (bd->VertexBufferSize < vtx_buffer_size)
|
||||||
|
{
|
||||||
|
bd->VertexBufferSize = vtx_buffer_size;
|
||||||
|
GL_CALL(glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, nullptr, GL_STREAM_DRAW));
|
||||||
|
}
|
||||||
|
if (bd->IndexBufferSize < idx_buffer_size)
|
||||||
|
{
|
||||||
|
bd->IndexBufferSize = idx_buffer_size;
|
||||||
|
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, nullptr, GL_STREAM_DRAW));
|
||||||
|
}
|
||||||
|
GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data));
|
||||||
|
GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW));
|
||||||
|
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != nullptr)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||||
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
|
||||||
|
GL_CALL(glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)));
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
|
if (bd->GlVersion >= 320)
|
||||||
|
GL_CALL(glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset));
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
GL_CALL(glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the temporary VAO
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
GL_CALL(glDeleteVertexArrays(1, &vertex_array_object));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
// This "glIsProgram()" check is required because if the program is "pending deletion" at the time of binding backup, it will have been deleted by now and will cause an OpenGL error. See #6220.
|
||||||
|
if (last_program == 0 || glIsProgram(last_program)) glUseProgram(last_program);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
|
if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
|
||||||
|
glBindSampler(0, last_sampler);
|
||||||
|
#endif
|
||||||
|
glActiveTexture(last_active_texture);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
glBindVertexArray(last_vertex_array_object);
|
||||||
|
#endif
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
|
||||||
|
last_vtx_attrib_state_pos.SetState(bd->AttribLocationVtxPos);
|
||||||
|
last_vtx_attrib_state_uv.SetState(bd->AttribLocationVtxUV);
|
||||||
|
last_vtx_attrib_state_color.SetState(bd->AttribLocationVtxColor);
|
||||||
|
#endif
|
||||||
|
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||||
|
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||||
|
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||||
|
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||||
|
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||||
|
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
|
||||||
|
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
|
if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
|
// Desktop OpenGL 3.0 and OpenGL 3.1 had separate polygon draw modes for front-facing and back-facing faces of polygons
|
||||||
|
if (bd->GlVersion <= 310 || bd->GlProfileIsCompat)
|
||||||
|
{
|
||||||
|
glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]);
|
||||||
|
glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||||
|
}
|
||||||
|
#endif // IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
|
|
||||||
|
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||||
|
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||||
|
(void)bd; // Not all compilation paths use this
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
|
||||||
|
// Build texture atlas
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
|
GLint last_texture;
|
||||||
|
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
|
||||||
|
GL_CALL(glGenTextures(1, &bd->FontTexture));
|
||||||
|
GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture));
|
||||||
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||||
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||||
|
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
|
||||||
|
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||||
|
#endif
|
||||||
|
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||||
|
|
||||||
|
// Restore state
|
||||||
|
GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
if (bd->FontTexture)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &bd->FontTexture);
|
||||||
|
io.Fonts->SetTexID(0);
|
||||||
|
bd->FontTexture = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
|
||||||
|
static bool CheckShader(GLuint handle, const char* desc)
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
GLint status = 0, log_length = 0;
|
||||||
|
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||||
|
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if ((GLboolean)status == GL_FALSE)
|
||||||
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString);
|
||||||
|
if (log_length > 1)
|
||||||
|
{
|
||||||
|
ImVector<char> buf;
|
||||||
|
buf.resize((int)(log_length + 1));
|
||||||
|
glGetShaderInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
|
||||||
|
fprintf(stderr, "%s\n", buf.begin());
|
||||||
|
}
|
||||||
|
return (GLboolean)status == GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
||||||
|
static bool CheckProgram(GLuint handle, const char* desc)
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
GLint status = 0, log_length = 0;
|
||||||
|
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||||
|
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if ((GLboolean)status == GL_FALSE)
|
||||||
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString);
|
||||||
|
if (log_length > 1)
|
||||||
|
{
|
||||||
|
ImVector<char> buf;
|
||||||
|
buf.resize((int)(log_length + 1));
|
||||||
|
glGetProgramInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
|
||||||
|
fprintf(stderr, "%s\n", buf.begin());
|
||||||
|
}
|
||||||
|
return (GLboolean)status == GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
|
||||||
|
// Backup GL state
|
||||||
|
GLint last_texture, last_array_buffer;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
GLint last_vertex_array;
|
||||||
|
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Parse GLSL version string
|
||||||
|
int glsl_version = 130;
|
||||||
|
sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_120 =
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"attribute vec2 Position;\n"
|
||||||
|
"attribute vec2 UV;\n"
|
||||||
|
"attribute vec4 Color;\n"
|
||||||
|
"varying vec2 Frag_UV;\n"
|
||||||
|
"varying vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_130 =
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"in vec2 Position;\n"
|
||||||
|
"in vec2 UV;\n"
|
||||||
|
"in vec4 Color;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_300_es =
|
||||||
|
"precision highp float;\n"
|
||||||
|
"layout (location = 0) in vec2 Position;\n"
|
||||||
|
"layout (location = 1) in vec2 UV;\n"
|
||||||
|
"layout (location = 2) in vec4 Color;\n"
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_410_core =
|
||||||
|
"layout (location = 0) in vec2 Position;\n"
|
||||||
|
"layout (location = 1) in vec2 UV;\n"
|
||||||
|
"layout (location = 2) in vec4 Color;\n"
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_120 =
|
||||||
|
"#ifdef GL_ES\n"
|
||||||
|
" precision mediump float;\n"
|
||||||
|
"#endif\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"varying vec2 Frag_UV;\n"
|
||||||
|
"varying vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_130 =
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_300_es =
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"layout (location = 0) out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_410_core =
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"layout (location = 0) out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
// Select shaders matching our GLSL versions
|
||||||
|
const GLchar* vertex_shader = nullptr;
|
||||||
|
const GLchar* fragment_shader = nullptr;
|
||||||
|
if (glsl_version < 130)
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_120;
|
||||||
|
fragment_shader = fragment_shader_glsl_120;
|
||||||
|
}
|
||||||
|
else if (glsl_version >= 410)
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_410_core;
|
||||||
|
fragment_shader = fragment_shader_glsl_410_core;
|
||||||
|
}
|
||||||
|
else if (glsl_version == 300)
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_300_es;
|
||||||
|
fragment_shader = fragment_shader_glsl_300_es;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_130;
|
||||||
|
fragment_shader = fragment_shader_glsl_130;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create shaders
|
||||||
|
const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
|
||||||
|
GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr);
|
||||||
|
glCompileShader(vert_handle);
|
||||||
|
CheckShader(vert_handle, "vertex shader");
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
|
||||||
|
GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr);
|
||||||
|
glCompileShader(frag_handle);
|
||||||
|
CheckShader(frag_handle, "fragment shader");
|
||||||
|
|
||||||
|
// Link
|
||||||
|
bd->ShaderHandle = glCreateProgram();
|
||||||
|
glAttachShader(bd->ShaderHandle, vert_handle);
|
||||||
|
glAttachShader(bd->ShaderHandle, frag_handle);
|
||||||
|
glLinkProgram(bd->ShaderHandle);
|
||||||
|
CheckProgram(bd->ShaderHandle, "shader program");
|
||||||
|
|
||||||
|
glDetachShader(bd->ShaderHandle, vert_handle);
|
||||||
|
glDetachShader(bd->ShaderHandle, frag_handle);
|
||||||
|
glDeleteShader(vert_handle);
|
||||||
|
glDeleteShader(frag_handle);
|
||||||
|
|
||||||
|
bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
|
||||||
|
bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
|
||||||
|
bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
|
||||||
|
bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
|
||||||
|
bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
|
||||||
|
|
||||||
|
// Create buffers
|
||||||
|
glGenBuffers(1, &bd->VboHandle);
|
||||||
|
glGenBuffers(1, &bd->ElementsHandle);
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
glBindVertexArray(last_vertex_array);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
|
||||||
|
if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
|
||||||
|
if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
|
||||||
|
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
|
@ -0,0 +1,66 @@
|
||||||
|
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||||
|
// - Desktop GL: 2.x 3.x 4.x
|
||||||
|
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||||
|
|
||||||
|
// About WebGL/ES:
|
||||||
|
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||||
|
// - This is done automatically on iOS, Android and Emscripten targets.
|
||||||
|
// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
// About GLSL version:
|
||||||
|
// The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string.
|
||||||
|
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||||
|
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
|
||||||
|
// Backend API
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// (Optional) Called by Init/NewFrame/Shutdown
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||||
|
|
||||||
|
// Specific OpenGL ES versions
|
||||||
|
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
||||||
|
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
|
||||||
|
|
||||||
|
// You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
|
||||||
|
// Try to detect GLES on matching platforms
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
||||||
|
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
||||||
|
#elif defined(__EMSCRIPTEN__) || defined(__amigaos4__)
|
||||||
|
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||||
|
#else
|
||||||
|
// Otherwise imgui_impl_opengl3_loader.h will be used.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
462
3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.cpp
vendored
Normal file
462
3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.cpp
vendored
Normal file
|
@ -0,0 +1,462 @@
|
||||||
|
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications)
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_win32.h"
|
||||||
|
#include "imgui_extra_keys.h"
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
|
// Using XInput library for gamepad (with recent Windows SDK this may leads to executables which won't run on Windows 7)
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
#include <XInput.h>
|
||||||
|
#else
|
||||||
|
#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER) && !defined(IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT)
|
||||||
|
#pragma comment(lib, "xinput")
|
||||||
|
//#pragma comment(lib, "Xinput9_1_0")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
|
||||||
|
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
|
||||||
|
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
|
||||||
|
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||||
|
// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
|
||||||
|
// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
|
||||||
|
// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
|
||||||
|
// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||||
|
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
|
||||||
|
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
|
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||||
|
// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
|
||||||
|
// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
|
||||||
|
// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
|
||||||
|
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
|
||||||
|
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
|
||||||
|
|
||||||
|
// Win32 Data
|
||||||
|
static HWND g_hWnd = NULL;
|
||||||
|
static INT64 g_Time = 0;
|
||||||
|
static INT64 g_TicksPerSecond = 0;
|
||||||
|
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||||
|
static bool g_HasGamepad = false;
|
||||||
|
static bool g_WantUpdateHasGamepad = true;
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplWin32_Init(void* hwnd)
|
||||||
|
{
|
||||||
|
if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&g_TicksPerSecond))
|
||||||
|
return false;
|
||||||
|
if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Setup back-end capabilities flags
|
||||||
|
g_hWnd = (HWND)hwnd;
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
io.BackendPlatformName = "imgui_impl_win32";
|
||||||
|
//io.ImeWindowHandle = hwnd;
|
||||||
|
|
||||||
|
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = VK_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = VK_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = VK_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = VK_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
|
||||||
|
# if defined(IMGUI_VERSION_NUM) && (IMGUI_VERSION_NUM >= 18604)
|
||||||
|
io.KeyMap[ImGuiKey_KeypadEnter] = VK_RETURN;
|
||||||
|
# else
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN;
|
||||||
|
# endif
|
||||||
|
io.KeyMap[ImGuiKey_A] = 'A';
|
||||||
|
io.KeyMap[ImGuiKey_C] = 'C';
|
||||||
|
io.KeyMap[ImGuiKey_V] = 'V';
|
||||||
|
io.KeyMap[ImGuiKey_X] = 'X';
|
||||||
|
io.KeyMap[ImGuiKey_Y] = 'Y';
|
||||||
|
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||||
|
|
||||||
|
int f_index = GetEnumValueForF();
|
||||||
|
int d_index = GetEnumValueForD();
|
||||||
|
if (f_index >= 0)
|
||||||
|
io.KeyMap[f_index] = 'F';
|
||||||
|
if (d_index >= 0)
|
||||||
|
io.KeyMap[d_index] = 'D';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWin32_Shutdown()
|
||||||
|
{
|
||||||
|
g_hWnd = (HWND)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplWin32_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
::SetCursor(NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show OS mouse cursor
|
||||||
|
LPTSTR win32_cursor = IDC_ARROW;
|
||||||
|
switch (imgui_cursor)
|
||||||
|
{
|
||||||
|
case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
|
||||||
|
case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
|
||||||
|
case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
|
||||||
|
case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
|
||||||
|
case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
|
||||||
|
case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break;
|
||||||
|
}
|
||||||
|
::SetCursor(::LoadCursor(NULL, win32_cursor));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWin32_UpdateMousePos()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
{
|
||||||
|
POINT pos = { (int)(io.MousePos.x), (int)(io.MousePos.y) };
|
||||||
|
::ClientToScreen(g_hWnd, &pos);
|
||||||
|
::SetCursorPos(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set mouse position
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
POINT pos;
|
||||||
|
if (HWND active_window = ::GetForegroundWindow())
|
||||||
|
if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd))
|
||||||
|
if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos))
|
||||||
|
io.MousePos = ImVec2((float)pos.x, (float)pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gamepad navigation mapping
|
||||||
|
static void ImGui_ImplWin32_UpdateGamepads()
|
||||||
|
{
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
|
||||||
|
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
|
||||||
|
if (g_WantUpdateHasGamepad)
|
||||||
|
{
|
||||||
|
XINPUT_CAPABILITIES caps;
|
||||||
|
g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS);
|
||||||
|
g_WantUpdateHasGamepad = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
XINPUT_STATE xinput_state;
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
|
||||||
|
#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
|
||||||
|
#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
}
|
||||||
|
#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWin32_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
RECT rect;
|
||||||
|
::GetClientRect(g_hWnd, &rect);
|
||||||
|
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
INT64 current_time;
|
||||||
|
::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time);
|
||||||
|
io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
// Read keyboard modifiers inputs
|
||||||
|
io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
|
||||||
|
io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
|
||||||
|
io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
|
||||||
|
io.KeySuper = false;
|
||||||
|
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
|
||||||
|
|
||||||
|
// Update OS mouse position
|
||||||
|
ImGui_ImplWin32_UpdateMousePos();
|
||||||
|
|
||||||
|
// Update OS mouse cursor with the cursor requested by imgui
|
||||||
|
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
|
||||||
|
if (g_LastMouseCursor != mouse_cursor)
|
||||||
|
{
|
||||||
|
g_LastMouseCursor = mouse_cursor;
|
||||||
|
ImGui_ImplWin32_UpdateMouseCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplWin32_UpdateGamepads();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
|
||||||
|
#ifndef WM_MOUSEHWHEEL
|
||||||
|
#define WM_MOUSEHWHEEL 0x020E
|
||||||
|
#endif
|
||||||
|
#ifndef DBT_DEVNODES_CHANGED
|
||||||
|
#define DBT_DEVNODES_CHANGED 0x0007
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
|
||||||
|
// Call from your application's message handler.
|
||||||
|
// When implementing your own back-end, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
|
||||||
|
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||||
|
// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
|
||||||
|
// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds.
|
||||||
|
// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag.
|
||||||
|
#if 0
|
||||||
|
// Copy this line into your .cpp file to forward declare the function.
|
||||||
|
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
#endif
|
||||||
|
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (ImGui::GetCurrentContext() == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
|
||||||
|
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
|
||||||
|
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
|
||||||
|
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
|
||||||
|
{
|
||||||
|
int button = 0;
|
||||||
|
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
|
||||||
|
if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
|
||||||
|
if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
|
||||||
|
if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
|
||||||
|
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
|
||||||
|
::SetCapture(hwnd);
|
||||||
|
io.MouseDown[button] = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
case WM_RBUTTONUP:
|
||||||
|
case WM_MBUTTONUP:
|
||||||
|
case WM_XBUTTONUP:
|
||||||
|
{
|
||||||
|
int button = 0;
|
||||||
|
if (msg == WM_LBUTTONUP) { button = 0; }
|
||||||
|
if (msg == WM_RBUTTONUP) { button = 1; }
|
||||||
|
if (msg == WM_MBUTTONUP) { button = 2; }
|
||||||
|
if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
|
||||||
|
io.MouseDown[button] = false;
|
||||||
|
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
|
||||||
|
::ReleaseCapture();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case WM_MOUSEWHEEL:
|
||||||
|
io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
|
||||||
|
return 0;
|
||||||
|
case WM_MOUSEHWHEEL:
|
||||||
|
io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
|
||||||
|
return 0;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_SYSKEYDOWN:
|
||||||
|
if (wParam < 256)
|
||||||
|
io.KeysDown[wParam] = 1;
|
||||||
|
return 0;
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_SYSKEYUP:
|
||||||
|
if (wParam < 256)
|
||||||
|
io.KeysDown[wParam] = 0;
|
||||||
|
return 0;
|
||||||
|
case WM_CHAR:
|
||||||
|
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
|
||||||
|
if (wParam > 0 && wParam < 0x10000)
|
||||||
|
io.AddInputCharacterUTF16((unsigned short)wParam);
|
||||||
|
return 0;
|
||||||
|
case WM_SETCURSOR:
|
||||||
|
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
case WM_DEVICECHANGE:
|
||||||
|
if ((UINT)wParam == DBT_DEVNODES_CHANGED)
|
||||||
|
g_WantUpdateHasGamepad = true;
|
||||||
|
return 0;
|
||||||
|
case WM_KILLFOCUS:
|
||||||
|
for (int n = 0; n < IM_ARRAYSIZE(io.KeysDown); n++)
|
||||||
|
io.KeysDown[n] = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// DPI-related helpers (optional)
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// - Use to enable DPI awareness without having to create an application manifest.
|
||||||
|
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
|
||||||
|
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
|
||||||
|
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
|
||||||
|
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
|
||||||
|
// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
|
||||||
|
// If you are trying to implement your own back-end for your own engine, you may ignore that noise.
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Implement some of the functions and types normally declared in recent Windows SDK.
|
||||||
|
#if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS)
|
||||||
|
static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
|
||||||
|
{
|
||||||
|
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 };
|
||||||
|
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
|
||||||
|
ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||||
|
cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||||
|
cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
||||||
|
return ::VerifyVersionInfoW(&osvi, mask, cond);
|
||||||
|
}
|
||||||
|
#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WINBLUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DPI_ENUMS_DECLARED
|
||||||
|
typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;
|
||||||
|
typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE;
|
||||||
|
#endif
|
||||||
|
#ifndef _DPI_AWARENESS_CONTEXTS_
|
||||||
|
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||||
|
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
|
||||||
|
#endif
|
||||||
|
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
|
||||||
|
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
|
||||||
|
#endif
|
||||||
|
typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+
|
||||||
|
typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+
|
||||||
|
typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
|
||||||
|
|
||||||
|
// Helper function to enable DPI awareness without setting up a manifest
|
||||||
|
void ImGui_ImplWin32_EnableDpiAwareness()
|
||||||
|
{
|
||||||
|
// if (IsWindows10OrGreater()) // This needs a manifest to succeed. Instead we try to grab the function pointer!
|
||||||
|
{
|
||||||
|
static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
|
||||||
|
if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
|
||||||
|
{
|
||||||
|
SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (IsWindows8Point1OrGreater())
|
||||||
|
{
|
||||||
|
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
|
||||||
|
if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
|
||||||
|
{
|
||||||
|
SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if _WIN32_WINNT >= 0x0600
|
||||||
|
::SetProcessDPIAware();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(NOGDI)
|
||||||
|
#pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
|
||||||
|
{
|
||||||
|
UINT xdpi = 96, ydpi = 96;
|
||||||
|
static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater();
|
||||||
|
if (bIsWindows8Point1OrGreater)
|
||||||
|
{
|
||||||
|
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
|
||||||
|
if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"))
|
||||||
|
GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
|
||||||
|
}
|
||||||
|
#ifndef NOGDI
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const HDC dc = ::GetDC(NULL);
|
||||||
|
xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
|
||||||
|
ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
|
||||||
|
::ReleaseDC(NULL, dc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
|
||||||
|
return xdpi / 96.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
|
||||||
|
{
|
||||||
|
HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);
|
||||||
|
return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
|
@ -0,0 +1,37 @@
|
||||||
|
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications)
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
// - Disable gamepad support or linking with xinput.lib
|
||||||
|
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
//#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
|
||||||
|
|
||||||
|
// Win32 message handler your application need to call.
|
||||||
|
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
|
||||||
|
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
|
||||||
|
#if 0
|
||||||
|
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DPI-related helpers (optional)
|
||||||
|
// - Use to enable DPI awareness without having to create an application manifest.
|
||||||
|
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
|
||||||
|
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
|
||||||
|
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
|
||||||
|
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
|
||||||
|
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
|
||||||
|
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
|
|
@ -0,0 +1,60 @@
|
||||||
|
# pragma once
|
||||||
|
# include "setup.h"
|
||||||
|
# include <memory>
|
||||||
|
|
||||||
|
struct Application;
|
||||||
|
struct Renderer;
|
||||||
|
|
||||||
|
struct Platform
|
||||||
|
{
|
||||||
|
virtual ~Platform() {};
|
||||||
|
|
||||||
|
virtual bool ApplicationStart(int argc, char** argv) = 0;
|
||||||
|
virtual void ApplicationStop() = 0;
|
||||||
|
|
||||||
|
virtual bool OpenMainWindow(const char* title, int width, int height) = 0;
|
||||||
|
virtual bool CloseMainWindow() = 0;
|
||||||
|
virtual void* GetMainWindowHandle() const = 0;
|
||||||
|
virtual void SetMainWindowTitle(const char* title) = 0;
|
||||||
|
virtual void ShowMainWindow() = 0;
|
||||||
|
virtual bool ProcessMainWindowEvents() = 0;
|
||||||
|
virtual bool IsMainWindowVisible() const = 0;
|
||||||
|
|
||||||
|
virtual void SetRenderer(Renderer* renderer) = 0;
|
||||||
|
|
||||||
|
virtual void NewFrame() = 0;
|
||||||
|
virtual void FinishFrame() = 0;
|
||||||
|
|
||||||
|
virtual void Quit() = 0;
|
||||||
|
|
||||||
|
bool HasWindowScaleChanged() const { return m_WindowScaleChanged; }
|
||||||
|
void AcknowledgeWindowScaleChanged() { m_WindowScaleChanged = false; }
|
||||||
|
float GetWindowScale() const { return m_WindowScale; }
|
||||||
|
void SetWindowScale(float windowScale)
|
||||||
|
{
|
||||||
|
if (windowScale == m_WindowScale)
|
||||||
|
return;
|
||||||
|
m_WindowScale = windowScale;
|
||||||
|
m_WindowScaleChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasFramebufferScaleChanged() const { return m_FramebufferScaleChanged; }
|
||||||
|
void AcknowledgeFramebufferScaleChanged() { m_FramebufferScaleChanged = false; }
|
||||||
|
float GetFramebufferScale() const { return m_FramebufferScale; }
|
||||||
|
void SetFramebufferScale(float framebufferScale)
|
||||||
|
{
|
||||||
|
if (framebufferScale == m_FramebufferScale)
|
||||||
|
return;
|
||||||
|
m_FramebufferScale = framebufferScale;
|
||||||
|
m_FramebufferScaleChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_WindowScaleChanged = false;
|
||||||
|
float m_WindowScale = 1.0f;
|
||||||
|
bool m_FramebufferScaleChanged = false;
|
||||||
|
float m_FramebufferScale = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Platform> CreatePlatform(Application& application);
|
|
@ -0,0 +1,287 @@
|
||||||
|
# include "platform.h"
|
||||||
|
# include "setup.h"
|
||||||
|
|
||||||
|
# if BACKEND(IMGUI_GLFW)
|
||||||
|
|
||||||
|
# include "application.h"
|
||||||
|
# include "renderer.h"
|
||||||
|
|
||||||
|
# include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
# define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
# include <GLFW/glfw3native.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# include <imgui.h>
|
||||||
|
# include "imgui_impl_glfw.h"
|
||||||
|
|
||||||
|
struct PlatformGLFW final
|
||||||
|
: Platform
|
||||||
|
{
|
||||||
|
static PlatformGLFW* s_Instance;
|
||||||
|
|
||||||
|
PlatformGLFW(Application& application);
|
||||||
|
|
||||||
|
bool ApplicationStart(int argc, char** argv) override;
|
||||||
|
void ApplicationStop() override;
|
||||||
|
bool OpenMainWindow(const char* title, int width, int height) override;
|
||||||
|
bool CloseMainWindow() override;
|
||||||
|
void* GetMainWindowHandle() const override;
|
||||||
|
void SetMainWindowTitle(const char* title) override;
|
||||||
|
void ShowMainWindow() override;
|
||||||
|
bool ProcessMainWindowEvents() override;
|
||||||
|
bool IsMainWindowVisible() const override;
|
||||||
|
void SetRenderer(Renderer* renderer) override;
|
||||||
|
void NewFrame() override;
|
||||||
|
void FinishFrame() override;
|
||||||
|
void Quit() override;
|
||||||
|
|
||||||
|
void UpdatePixelDensity();
|
||||||
|
|
||||||
|
Application& m_Application;
|
||||||
|
GLFWwindow* m_Window = nullptr;
|
||||||
|
bool m_QuitRequested = false;
|
||||||
|
bool m_IsMinimized = false;
|
||||||
|
bool m_WasMinimized = false;
|
||||||
|
Renderer* m_Renderer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Platform> CreatePlatform(Application& application)
|
||||||
|
{
|
||||||
|
return std::make_unique<PlatformGLFW>(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformGLFW::PlatformGLFW(Application& application)
|
||||||
|
: m_Application(application)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformGLFW::ApplicationStart(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (!glfwInit())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformGLFW::ApplicationStop()
|
||||||
|
{
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformGLFW::OpenMainWindow(const char* title, int width, int height)
|
||||||
|
{
|
||||||
|
if (m_Window)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_VISIBLE, 0);
|
||||||
|
|
||||||
|
using InitializerType = bool (*)(GLFWwindow* window, bool install_callbacks);
|
||||||
|
|
||||||
|
InitializerType initializer = nullptr;
|
||||||
|
|
||||||
|
# if RENDERER(IMGUI_OGL3)
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
# if PLATFORM(MACOS)
|
||||||
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||||
|
# ifdef GLFW_COCOA_RETINA_FRAMEBUFFER
|
||||||
|
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GL_TRUE);
|
||||||
|
# endif
|
||||||
|
# ifdef GLFW_COCOA_GRAPHICS_SWITCHING
|
||||||
|
glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, GL_TRUE);
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
initializer = &ImGui_ImplGlfw_InitForOpenGL;
|
||||||
|
# else
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
initializer = &ImGui_ImplGlfw_InitForNone;
|
||||||
|
# endif
|
||||||
|
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GL_TRUE);
|
||||||
|
|
||||||
|
width = width < 0 ? 1440 : width;
|
||||||
|
height = height < 0 ? 800 : height;
|
||||||
|
|
||||||
|
m_Window = glfwCreateWindow(width, height, title, nullptr, nullptr);
|
||||||
|
if (!m_Window)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!initializer || !initializer(m_Window, true))
|
||||||
|
{
|
||||||
|
glfwDestroyWindow(m_Window);
|
||||||
|
m_Window = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwSetWindowUserPointer(m_Window, this);
|
||||||
|
|
||||||
|
glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<PlatformGLFW*>(glfwGetWindowUserPointer(window));
|
||||||
|
if (!self->m_QuitRequested)
|
||||||
|
self->CloseMainWindow();
|
||||||
|
});
|
||||||
|
|
||||||
|
glfwSetWindowIconifyCallback(m_Window, [](GLFWwindow* window, int iconified)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<PlatformGLFW*>(glfwGetWindowUserPointer(window));
|
||||||
|
if (iconified)
|
||||||
|
{
|
||||||
|
self->m_IsMinimized = true;
|
||||||
|
self->m_WasMinimized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->m_IsMinimized = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto onFramebuferSizeChanged = [](GLFWwindow* window, int width, int height)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<PlatformGLFW*>(glfwGetWindowUserPointer(window));
|
||||||
|
if (self->m_Renderer)
|
||||||
|
{
|
||||||
|
self->m_Renderer->Resize(width, height);
|
||||||
|
self->UpdatePixelDensity();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
glfwSetFramebufferSizeCallback(m_Window, onFramebuferSizeChanged);
|
||||||
|
|
||||||
|
auto onWindowContentScaleChanged = [](GLFWwindow* window, float xscale, float yscale)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<PlatformGLFW*>(glfwGetWindowUserPointer(window));
|
||||||
|
self->UpdatePixelDensity();
|
||||||
|
};
|
||||||
|
|
||||||
|
glfwSetWindowContentScaleCallback(m_Window, onWindowContentScaleChanged);
|
||||||
|
|
||||||
|
UpdatePixelDensity();
|
||||||
|
|
||||||
|
glfwMakeContextCurrent(m_Window);
|
||||||
|
|
||||||
|
glfwSwapInterval(1); // Enable vsync
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformGLFW::CloseMainWindow()
|
||||||
|
{
|
||||||
|
if (m_Window == nullptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto canClose = m_Application.CanClose();
|
||||||
|
|
||||||
|
glfwSetWindowShouldClose(m_Window, canClose ? 1 : 0);
|
||||||
|
|
||||||
|
return canClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* PlatformGLFW::GetMainWindowHandle() const
|
||||||
|
{
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
return m_Window ? glfwGetWin32Window(m_Window) : nullptr;
|
||||||
|
# else
|
||||||
|
return nullptr;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformGLFW::SetMainWindowTitle(const char* title)
|
||||||
|
{
|
||||||
|
glfwSetWindowTitle(m_Window, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformGLFW::ShowMainWindow()
|
||||||
|
{
|
||||||
|
if (m_Window == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
glfwShowWindow(m_Window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformGLFW::ProcessMainWindowEvents()
|
||||||
|
{
|
||||||
|
if (m_Window == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_IsMinimized)
|
||||||
|
glfwWaitEvents();
|
||||||
|
else
|
||||||
|
glfwPollEvents();
|
||||||
|
|
||||||
|
if (m_QuitRequested || glfwWindowShouldClose(m_Window))
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Shutdown();
|
||||||
|
|
||||||
|
glfwDestroyWindow(m_Window);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformGLFW::IsMainWindowVisible() const
|
||||||
|
{
|
||||||
|
if (m_Window == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_IsMinimized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformGLFW::SetRenderer(Renderer* renderer)
|
||||||
|
{
|
||||||
|
m_Renderer = renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformGLFW::NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_NewFrame();
|
||||||
|
|
||||||
|
if (m_WasMinimized)
|
||||||
|
{
|
||||||
|
ImGui::GetIO().DeltaTime = 0.1e-6f;
|
||||||
|
m_WasMinimized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformGLFW::FinishFrame()
|
||||||
|
{
|
||||||
|
if (m_Renderer)
|
||||||
|
m_Renderer->Present();
|
||||||
|
|
||||||
|
glfwSwapBuffers(m_Window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformGLFW::Quit()
|
||||||
|
{
|
||||||
|
m_QuitRequested = true;
|
||||||
|
|
||||||
|
glfwPostEmptyEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformGLFW::UpdatePixelDensity()
|
||||||
|
{
|
||||||
|
float xscale, yscale;
|
||||||
|
glfwGetWindowContentScale(m_Window, &xscale, &yscale);
|
||||||
|
float scale = xscale > yscale ? xscale : yscale;
|
||||||
|
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
float windowScale = scale;
|
||||||
|
float framebufferScale = scale;
|
||||||
|
# else
|
||||||
|
float windowScale = 1.0f;
|
||||||
|
float framebufferScale = scale;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
SetWindowScale(windowScale); // this is how windows is scaled, not window content
|
||||||
|
|
||||||
|
SetFramebufferScale(framebufferScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif // BACKEND(IMGUI_GLFW)
|
|
@ -0,0 +1,313 @@
|
||||||
|
# include "platform.h"
|
||||||
|
# include "setup.h"
|
||||||
|
|
||||||
|
# if BACKEND(IMGUI_WIN32)
|
||||||
|
|
||||||
|
# include "application.h"
|
||||||
|
# include "renderer.h"
|
||||||
|
|
||||||
|
# define NOMINMAX
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
# include <tchar.h>
|
||||||
|
# include <string>
|
||||||
|
|
||||||
|
# include <imgui.h>
|
||||||
|
# include "imgui_impl_win32.h"
|
||||||
|
|
||||||
|
# if defined(_UNICODE)
|
||||||
|
std::wstring Utf8ToNative(const std::string& str)
|
||||||
|
{
|
||||||
|
int size = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), nullptr, 0);
|
||||||
|
std::wstring result(size, 0);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), (wchar_t*)result.data(), size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
std::string Utf8ToNative(const std::string& str)
|
||||||
|
{
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
struct PlatformWin32 final
|
||||||
|
: Platform
|
||||||
|
{
|
||||||
|
static PlatformWin32* s_Instance;
|
||||||
|
|
||||||
|
PlatformWin32(Application& application);
|
||||||
|
|
||||||
|
bool ApplicationStart(int argc, char** argv) override;
|
||||||
|
void ApplicationStop() override;
|
||||||
|
bool OpenMainWindow(const char* title, int width, int height) override;
|
||||||
|
bool CloseMainWindow() override;
|
||||||
|
void* GetMainWindowHandle() const override;
|
||||||
|
void SetMainWindowTitle(const char* title) override;
|
||||||
|
void ShowMainWindow() override;
|
||||||
|
bool ProcessMainWindowEvents() override;
|
||||||
|
bool IsMainWindowVisible() const override;
|
||||||
|
void SetRenderer(Renderer* renderer) override;
|
||||||
|
void NewFrame() override;
|
||||||
|
void FinishFrame() override;
|
||||||
|
void Quit() override;
|
||||||
|
|
||||||
|
void SetDpiScale(float dpiScale);
|
||||||
|
|
||||||
|
LRESULT WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
Application& m_Application;
|
||||||
|
WNDCLASSEX m_WindowClass = {};
|
||||||
|
HWND m_MainWindowHandle = nullptr;
|
||||||
|
bool m_IsMinimized = false;
|
||||||
|
bool m_WasMinimized = false;
|
||||||
|
bool m_CanCloseResult = false;
|
||||||
|
Renderer* m_Renderer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Platform> CreatePlatform(Application& application)
|
||||||
|
{
|
||||||
|
return std::make_unique<PlatformWin32>(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformWin32* PlatformWin32::s_Instance = nullptr;
|
||||||
|
|
||||||
|
PlatformWin32::PlatformWin32(Application& application)
|
||||||
|
: m_Application(application)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformWin32::ApplicationStart(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (s_Instance)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
s_Instance = this;
|
||||||
|
|
||||||
|
auto winProc = [](HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -> LRESULT
|
||||||
|
{
|
||||||
|
return s_Instance->WinProc(hWnd, msg, wParam, lParam);
|
||||||
|
};
|
||||||
|
|
||||||
|
m_WindowClass =
|
||||||
|
{
|
||||||
|
sizeof(WNDCLASSEX),
|
||||||
|
CS_CLASSDC,
|
||||||
|
winProc,
|
||||||
|
0L,
|
||||||
|
0L,
|
||||||
|
GetModuleHandle(nullptr),
|
||||||
|
LoadIcon(GetModuleHandle(nullptr),
|
||||||
|
IDI_APPLICATION),
|
||||||
|
LoadCursor(nullptr, IDC_ARROW),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
_T("imgui-node-editor-application"),
|
||||||
|
LoadIcon(GetModuleHandle(nullptr),
|
||||||
|
IDI_APPLICATION)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!RegisterClassEx(&m_WindowClass))
|
||||||
|
{
|
||||||
|
s_Instance = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplWin32_EnableDpiAwareness();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformWin32::ApplicationStop()
|
||||||
|
{
|
||||||
|
if (!s_Instance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UnregisterClass(m_WindowClass.lpszClassName, m_WindowClass.hInstance);
|
||||||
|
|
||||||
|
s_Instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PlatformWin32::OpenMainWindow(const char* title, int width, int height)
|
||||||
|
{
|
||||||
|
if (m_MainWindowHandle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_MainWindowHandle = CreateWindow(
|
||||||
|
m_WindowClass.lpszClassName,
|
||||||
|
Utf8ToNative(title).c_str(),
|
||||||
|
WS_OVERLAPPEDWINDOW,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
width < 0 ? CW_USEDEFAULT : width,
|
||||||
|
height < 0 ? CW_USEDEFAULT : height,
|
||||||
|
nullptr, nullptr, m_WindowClass.hInstance, nullptr);
|
||||||
|
|
||||||
|
if (!m_MainWindowHandle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ImGui_ImplWin32_Init(m_MainWindowHandle))
|
||||||
|
{
|
||||||
|
DestroyWindow(m_MainWindowHandle);
|
||||||
|
m_MainWindowHandle = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDpiScale(ImGui_ImplWin32_GetDpiScaleForHwnd(m_MainWindowHandle));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformWin32::CloseMainWindow()
|
||||||
|
{
|
||||||
|
if (m_MainWindowHandle == nullptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
SendMessage(m_MainWindowHandle, WM_CLOSE, 0, 0);
|
||||||
|
|
||||||
|
return m_CanCloseResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* PlatformWin32::GetMainWindowHandle() const
|
||||||
|
{
|
||||||
|
return m_MainWindowHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformWin32::SetMainWindowTitle(const char* title)
|
||||||
|
{
|
||||||
|
SetWindowText(m_MainWindowHandle, Utf8ToNative(title).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformWin32::ShowMainWindow()
|
||||||
|
{
|
||||||
|
if (m_MainWindowHandle == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//ShowWindow(m_MainWindowHandle, SW_SHOWMAXIMIZED);
|
||||||
|
ShowWindow(m_MainWindowHandle, SW_SHOW);
|
||||||
|
UpdateWindow(m_MainWindowHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformWin32::ProcessMainWindowEvents()
|
||||||
|
{
|
||||||
|
if (m_MainWindowHandle == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto fetchMessage = [this](MSG* msg) -> bool
|
||||||
|
{
|
||||||
|
if (!m_IsMinimized)
|
||||||
|
return PeekMessage(msg, nullptr, 0U, 0U, PM_REMOVE) != 0;
|
||||||
|
else
|
||||||
|
return GetMessage(msg, nullptr, 0U, 0U) != 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
MSG msg = {};
|
||||||
|
while (fetchMessage(&msg))
|
||||||
|
{
|
||||||
|
if (msg.message == WM_KEYDOWN && (msg.wParam == VK_ESCAPE))
|
||||||
|
PostQuitMessage(0);
|
||||||
|
|
||||||
|
if (msg.message == WM_QUIT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformWin32::IsMainWindowVisible() const
|
||||||
|
{
|
||||||
|
if (m_MainWindowHandle == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_IsMinimized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformWin32::SetRenderer(Renderer* renderer)
|
||||||
|
{
|
||||||
|
m_Renderer = renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformWin32::NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplWin32_NewFrame();
|
||||||
|
|
||||||
|
if (m_WasMinimized)
|
||||||
|
{
|
||||||
|
ImGui::GetIO().DeltaTime = 0.1e-6f;
|
||||||
|
m_WasMinimized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformWin32::FinishFrame()
|
||||||
|
{
|
||||||
|
if (m_Renderer)
|
||||||
|
m_Renderer->Present();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformWin32::Quit()
|
||||||
|
{
|
||||||
|
PostQuitMessage(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformWin32::SetDpiScale(float dpiScale)
|
||||||
|
{
|
||||||
|
SetWindowScale(dpiScale);
|
||||||
|
SetFramebufferScale(dpiScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT PlatformWin32::WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_CLOSE:
|
||||||
|
m_CanCloseResult = m_Application.CanClose();
|
||||||
|
if (m_CanCloseResult)
|
||||||
|
{
|
||||||
|
ImGui_ImplWin32_Shutdown();
|
||||||
|
DestroyWindow(hWnd);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_SIZE:
|
||||||
|
if (wParam == SIZE_MINIMIZED)
|
||||||
|
{
|
||||||
|
m_IsMinimized = true;
|
||||||
|
m_WasMinimized = true;
|
||||||
|
}
|
||||||
|
else if (wParam == SIZE_RESTORED && m_IsMinimized)
|
||||||
|
{
|
||||||
|
m_IsMinimized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Renderer != nullptr && wParam != SIZE_MINIMIZED)
|
||||||
|
m_Renderer->Resize(static_cast<int>(LOWORD(lParam)), static_cast<int>(HIWORD(lParam)));
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_SYSCOMMAND:
|
||||||
|
if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_DPICHANGED:
|
||||||
|
SetDpiScale(ImGui_ImplWin32_GetDpiScaleForHwnd(hWnd));
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_DESTROY:
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif // BACKEND(IMGUI_WIN32)
|
|
@ -0,0 +1,32 @@
|
||||||
|
# pragma once
|
||||||
|
# include "setup.h"
|
||||||
|
# include <memory>
|
||||||
|
|
||||||
|
struct Platform;
|
||||||
|
struct ImDrawData;
|
||||||
|
struct ImVec4;
|
||||||
|
using ImTextureID= void*;
|
||||||
|
|
||||||
|
struct Renderer
|
||||||
|
{
|
||||||
|
virtual ~Renderer() {};
|
||||||
|
|
||||||
|
virtual bool Create(Platform& platform) = 0;
|
||||||
|
virtual void Destroy() = 0;
|
||||||
|
|
||||||
|
virtual void NewFrame() = 0;
|
||||||
|
|
||||||
|
virtual void RenderDrawData(ImDrawData* drawData) = 0;
|
||||||
|
|
||||||
|
virtual void Clear(const ImVec4& color) = 0;
|
||||||
|
virtual void Present() = 0;
|
||||||
|
|
||||||
|
virtual void Resize(int width, int height) = 0;
|
||||||
|
|
||||||
|
virtual ImTextureID CreateTexture(const void* data, int width, int height) = 0;
|
||||||
|
virtual void DestroyTexture(ImTextureID texture) = 0;
|
||||||
|
virtual int GetTextureWidth(ImTextureID texture) = 0;
|
||||||
|
virtual int GetTextureHeight(ImTextureID texture) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Renderer> CreateRenderer();
|
|
@ -0,0 +1,195 @@
|
||||||
|
# include "renderer.h"
|
||||||
|
# include "setup.h"
|
||||||
|
|
||||||
|
# if RENDERER(IMGUI_DX11)
|
||||||
|
|
||||||
|
# include "platform.h"
|
||||||
|
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
# define NOMINMAX
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# include <imgui.h>
|
||||||
|
# include "imgui_impl_dx11.h"
|
||||||
|
# include <d3d11.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct RendererDX11 final
|
||||||
|
: Renderer
|
||||||
|
{
|
||||||
|
bool Create(Platform& platform) override;
|
||||||
|
void Destroy() override;
|
||||||
|
void NewFrame() override;
|
||||||
|
void RenderDrawData(ImDrawData* drawData) override;
|
||||||
|
void Clear(const ImVec4& color) override;
|
||||||
|
void Present() override;
|
||||||
|
void Resize(int width, int height) override;
|
||||||
|
|
||||||
|
ImTextureID CreateTexture(const void* data, int width, int height) override;
|
||||||
|
void DestroyTexture(ImTextureID texture) override;
|
||||||
|
int GetTextureWidth(ImTextureID texture) override;
|
||||||
|
int GetTextureHeight(ImTextureID texture) override;
|
||||||
|
|
||||||
|
HRESULT CreateDeviceD3D(HWND hWnd);
|
||||||
|
void CleanupDeviceD3D();
|
||||||
|
|
||||||
|
void CreateRenderTarget();
|
||||||
|
void CleanupRenderTarget();
|
||||||
|
|
||||||
|
Platform* m_Platform = nullptr;
|
||||||
|
ID3D11Device* m_device = nullptr;
|
||||||
|
ID3D11DeviceContext* m_deviceContext = nullptr;
|
||||||
|
IDXGISwapChain* m_swapChain = nullptr;
|
||||||
|
ID3D11RenderTargetView* m_mainRenderTargetView = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Renderer> CreateRenderer()
|
||||||
|
{
|
||||||
|
return std::make_unique<RendererDX11>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RendererDX11::Create(Platform& platform)
|
||||||
|
{
|
||||||
|
m_Platform = &platform;
|
||||||
|
|
||||||
|
auto hr = CreateDeviceD3D(reinterpret_cast<HWND>(platform.GetMainWindowHandle()));
|
||||||
|
if (FAILED(hr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ImGui_ImplDX11_Init(m_device, m_deviceContext))
|
||||||
|
{
|
||||||
|
CleanupDeviceD3D();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Platform->SetRenderer(this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::Destroy()
|
||||||
|
{
|
||||||
|
if (!m_Platform)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_Platform->SetRenderer(nullptr);
|
||||||
|
|
||||||
|
ImGui_ImplDX11_Shutdown();
|
||||||
|
|
||||||
|
CleanupDeviceD3D();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX11_NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::RenderDrawData(ImDrawData* drawData)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX11_RenderDrawData(drawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::Clear(const ImVec4& color)
|
||||||
|
{
|
||||||
|
m_deviceContext->ClearRenderTargetView(m_mainRenderTargetView, (float*)&color.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::Present()
|
||||||
|
{
|
||||||
|
m_swapChain->Present(1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::Resize(int width, int height)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
CleanupRenderTarget();
|
||||||
|
m_swapChain->ResizeBuffers(0, (UINT)width, (UINT)height, DXGI_FORMAT_UNKNOWN, 0);
|
||||||
|
CreateRenderTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT RendererDX11::CreateDeviceD3D(HWND hWnd)
|
||||||
|
{
|
||||||
|
// Setup swap chain
|
||||||
|
DXGI_SWAP_CHAIN_DESC sd;
|
||||||
|
{
|
||||||
|
ZeroMemory(&sd, sizeof(sd));
|
||||||
|
sd.BufferCount = 2;
|
||||||
|
sd.BufferDesc.Width = 0;
|
||||||
|
sd.BufferDesc.Height = 0;
|
||||||
|
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||||
|
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||||||
|
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||||||
|
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||||
|
sd.OutputWindow = hWnd;
|
||||||
|
sd.SampleDesc.Count = 1;
|
||||||
|
sd.SampleDesc.Quality = 0;
|
||||||
|
sd.Windowed = TRUE;
|
||||||
|
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT createDeviceFlags = 0;
|
||||||
|
//createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||||
|
D3D_FEATURE_LEVEL featureLevel;
|
||||||
|
const D3D_FEATURE_LEVEL featureLevelArray[1] = { D3D_FEATURE_LEVEL_11_0, };
|
||||||
|
if (D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &m_swapChain, &m_device, &featureLevel, &m_deviceContext) != S_OK)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
CreateRenderTarget();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::CleanupDeviceD3D()
|
||||||
|
{
|
||||||
|
CleanupRenderTarget();
|
||||||
|
if (m_swapChain) { m_swapChain->Release(); m_swapChain = nullptr; }
|
||||||
|
if (m_deviceContext) { m_deviceContext->Release(); m_deviceContext = nullptr; }
|
||||||
|
if (m_device) { m_device->Release(); m_device = nullptr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::CreateRenderTarget()
|
||||||
|
{
|
||||||
|
DXGI_SWAP_CHAIN_DESC sd;
|
||||||
|
m_swapChain->GetDesc(&sd);
|
||||||
|
|
||||||
|
// Create the render target
|
||||||
|
ID3D11Texture2D* pBackBuffer;
|
||||||
|
D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
|
||||||
|
ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc));
|
||||||
|
render_target_view_desc.Format = sd.BufferDesc.Format;
|
||||||
|
render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||||
|
m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
|
||||||
|
m_device->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &m_mainRenderTargetView);
|
||||||
|
m_deviceContext->OMSetRenderTargets(1, &m_mainRenderTargetView, nullptr);
|
||||||
|
pBackBuffer->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::CleanupRenderTarget()
|
||||||
|
{
|
||||||
|
if (m_mainRenderTargetView) { m_mainRenderTargetView->Release(); m_mainRenderTargetView = nullptr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
ImTextureID RendererDX11::CreateTexture(const void* data, int width, int height)
|
||||||
|
{
|
||||||
|
return ImGui_CreateTexture(data, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererDX11::DestroyTexture(ImTextureID texture)
|
||||||
|
{
|
||||||
|
return ImGui_DestroyTexture(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RendererDX11::GetTextureWidth(ImTextureID texture)
|
||||||
|
{
|
||||||
|
return ImGui_GetTextureWidth(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RendererDX11::GetTextureHeight(ImTextureID texture)
|
||||||
|
{
|
||||||
|
return ImGui_GetTextureHeight(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif // RENDERER(IMGUI_DX11)
|
|
@ -0,0 +1,208 @@
|
||||||
|
# include "renderer.h"
|
||||||
|
|
||||||
|
# if RENDERER(IMGUI_OGL3)
|
||||||
|
|
||||||
|
# include "platform.h"
|
||||||
|
# include <algorithm>
|
||||||
|
# include <cstdint> // std::intptr_t
|
||||||
|
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
# define NOMINMAX
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# include "imgui_impl_opengl3.h"
|
||||||
|
|
||||||
|
# if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||||
|
# include <GL/gl3w.h> // Initialize with gl3wInit()
|
||||||
|
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||||
|
# include <GL/glew.h> // Initialize with glewInit()
|
||||||
|
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
# include <glad/glad.h> // Initialize with gladLoadGL()
|
||||||
|
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||||
|
# include <glad/gl.h> // Initialize with gladLoadGL(...) or gladLoaderLoadGL()
|
||||||
|
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||||
|
# define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||||
|
# include <glbinding/Binding.h> // Initialize with glbinding::Binding::initialize()
|
||||||
|
# include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||||
|
# define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||||
|
# include <glbinding/glbinding.h>// Initialize with glbinding::initialize()
|
||||||
|
# include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
# elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||||
|
# include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||||
|
# else
|
||||||
|
# include "imgui_impl_opengl3_loader.h"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
struct ImTexture
|
||||||
|
{
|
||||||
|
GLuint TextureID = 0;
|
||||||
|
int Width = 0;
|
||||||
|
int Height = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RendererOpenGL3 final
|
||||||
|
: Renderer
|
||||||
|
{
|
||||||
|
bool Create(Platform& platform) override;
|
||||||
|
void Destroy() override;
|
||||||
|
void NewFrame() override;
|
||||||
|
void RenderDrawData(ImDrawData* drawData) override;
|
||||||
|
void Clear(const ImVec4& color) override;
|
||||||
|
void Present() override;
|
||||||
|
void Resize(int width, int height) override;
|
||||||
|
|
||||||
|
ImVector<ImTexture>::iterator FindTexture(ImTextureID texture);
|
||||||
|
ImTextureID CreateTexture(const void* data, int width, int height) override;
|
||||||
|
void DestroyTexture(ImTextureID texture) override;
|
||||||
|
int GetTextureWidth(ImTextureID texture) override;
|
||||||
|
int GetTextureHeight(ImTextureID texture) override;
|
||||||
|
|
||||||
|
Platform* m_Platform = nullptr;
|
||||||
|
ImVector<ImTexture> m_Textures;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Renderer> CreateRenderer()
|
||||||
|
{
|
||||||
|
return std::make_unique<RendererOpenGL3>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RendererOpenGL3::Create(Platform& platform)
|
||||||
|
{
|
||||||
|
m_Platform = &platform;
|
||||||
|
|
||||||
|
// Technically we should initialize OpenGL context here,
|
||||||
|
// but for now we relay on one created by GLFW3
|
||||||
|
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||||
|
bool err = gl3wInit() != 0;
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||||
|
bool err = glewInit() != GLEW_OK;
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
bool err = gladLoadGL() == 0;
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||||
|
bool err = gladLoadGL(glfwGetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one.
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||||
|
bool err = false;
|
||||||
|
glbinding::Binding::initialize();
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||||
|
bool err = false;
|
||||||
|
glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)glfwGetProcAddress(name); });
|
||||||
|
#else
|
||||||
|
bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization.
|
||||||
|
#endif
|
||||||
|
if (err)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
# if PLATFORM(MACOS)
|
||||||
|
const char* glslVersion = "#version 150";
|
||||||
|
# else
|
||||||
|
const char* glslVersion = "#version 130";
|
||||||
|
# endif
|
||||||
|
|
||||||
|
if (!ImGui_ImplOpenGL3_Init(glslVersion))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_Platform->SetRenderer(this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererOpenGL3::Destroy()
|
||||||
|
{
|
||||||
|
if (!m_Platform)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_Platform->SetRenderer(nullptr);
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererOpenGL3::NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererOpenGL3::RenderDrawData(ImDrawData* drawData)
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(drawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererOpenGL3::Clear(const ImVec4& color)
|
||||||
|
{
|
||||||
|
glClearColor(color.x, color.y, color.z, color.w);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererOpenGL3::Present()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererOpenGL3::Resize(int width, int height)
|
||||||
|
{
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImTextureID RendererOpenGL3::CreateTexture(const void* data, int width, int height)
|
||||||
|
{
|
||||||
|
m_Textures.resize(m_Textures.size() + 1);
|
||||||
|
ImTexture& texture = m_Textures.back();
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
GLint last_texture = 0;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGenTextures(1, &texture.TextureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture.TextureID);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
|
||||||
|
texture.Width = width;
|
||||||
|
texture.Height = height;
|
||||||
|
|
||||||
|
return reinterpret_cast<ImTextureID>(static_cast<std::intptr_t>(texture.TextureID));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVector<ImTexture>::iterator RendererOpenGL3::FindTexture(ImTextureID texture)
|
||||||
|
{
|
||||||
|
auto textureID = static_cast<GLuint>(reinterpret_cast<std::intptr_t>(texture));
|
||||||
|
|
||||||
|
return std::find_if(m_Textures.begin(), m_Textures.end(), [textureID](ImTexture& texture)
|
||||||
|
{
|
||||||
|
return texture.TextureID == textureID;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererOpenGL3::DestroyTexture(ImTextureID texture)
|
||||||
|
{
|
||||||
|
auto textureIt = FindTexture(texture);
|
||||||
|
if (textureIt == m_Textures.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
glDeleteTextures(1, &textureIt->TextureID);
|
||||||
|
|
||||||
|
m_Textures.erase(textureIt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RendererOpenGL3::GetTextureWidth(ImTextureID texture)
|
||||||
|
{
|
||||||
|
auto textureIt = FindTexture(texture);
|
||||||
|
if (textureIt != m_Textures.end())
|
||||||
|
return textureIt->Width;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RendererOpenGL3::GetTextureHeight(ImTextureID texture)
|
||||||
|
{
|
||||||
|
auto textureIt = FindTexture(texture);
|
||||||
|
if (textureIt != m_Textures.end())
|
||||||
|
return textureIt->Height;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif // RENDERER(IMGUI_OGL3)
|
|
@ -0,0 +1,98 @@
|
||||||
|
# pragma once
|
||||||
|
# include "config.h"
|
||||||
|
|
||||||
|
# define DETAIL_PRIV_EXPAND(x) x
|
||||||
|
# define EXPAND(x) DETAIL_PRIV_EXPAND(x)
|
||||||
|
# define DETAIL_PRIV_CONCAT(x, y) x ## y
|
||||||
|
# define CONCAT(x, y) DETAIL_PRIV_CONCAT(x, y)
|
||||||
|
|
||||||
|
|
||||||
|
// Define PLATFORM(x) which evaluate to 0 or 1 when
|
||||||
|
// 'x' is: WINDOWS, MACOS or LINUX
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define PLATFORM_PRIV_WINDOWS() 1
|
||||||
|
# elif defined(__APPLE__)
|
||||||
|
# define PLATFORM_PRIV_MACOS() 1
|
||||||
|
# elif defined(__linux__)
|
||||||
|
# define PLATFORM_PRIV_LINUX() 1
|
||||||
|
# else
|
||||||
|
# error Unsupported platform
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef PLATFORM_PRIV_WINDOWS
|
||||||
|
# define PLATFORM_PRIV_WINDOWS() 0
|
||||||
|
# endif
|
||||||
|
# ifndef PLATFORM_PRIV_MACOS
|
||||||
|
# define PLATFORM_PRIV_MACOS() 0
|
||||||
|
# endif
|
||||||
|
# ifndef PLATFORM_PRIV_LINUX
|
||||||
|
# define PLATFORM_PRIV_LINUX() 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define PLATFORM(x) (PLATFORM_PRIV_##x())
|
||||||
|
|
||||||
|
|
||||||
|
// Define BACKEND(x) which evaluate to 0 or 1 when
|
||||||
|
// 'x' is: IMGUI_WIN32 or IMGUI_GLFW
|
||||||
|
//
|
||||||
|
// Use BACKEND_CONFIG to override desired backend
|
||||||
|
//
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
# define BACKEND_HAVE_IMGUI_WIN32() 1
|
||||||
|
# endif
|
||||||
|
# if HAVE_GLFW3
|
||||||
|
# define BACKEND_HAVE_IMGUI_GLFW() 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef BACKEND_HAVE_IMGUI_WIN32
|
||||||
|
# define BACKEND_HAVE_IMGUI_WIN32() 0
|
||||||
|
# endif
|
||||||
|
# ifndef BACKEND_HAVE_IMGUI_GLFW
|
||||||
|
# define BACKEND_HAVE_IMGUI_GLFW() 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define BACKEND_PRIV_IMGUI_WIN32() 1
|
||||||
|
# define BACKEND_PRIV_IMGUI_GLFW() 2
|
||||||
|
|
||||||
|
# if !defined(BACKEND_CONFIG)
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
# define BACKEND_CONFIG IMGUI_WIN32
|
||||||
|
# else
|
||||||
|
# define BACKEND_CONFIG IMGUI_GLFW
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define BACKEND(x) ((BACKEND_PRIV_##x()) == CONCAT(BACKEND_PRIV_, EXPAND(BACKEND_CONFIG))() && (BACKEND_HAVE_##x()))
|
||||||
|
|
||||||
|
|
||||||
|
// Define RENDERER(x) which evaluate to 0 or 1 when
|
||||||
|
// 'x' is: IMGUI_DX11 or IMGUI_OGL3
|
||||||
|
//
|
||||||
|
// Use RENDERER_CONFIG to override desired renderer
|
||||||
|
//
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
# define RENDERER_HAVE_IMGUI_DX11() 1
|
||||||
|
# endif
|
||||||
|
# if HAVE_OPENGL
|
||||||
|
# define RENDERER_HAVE_IMGUI_OGL3() 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef RENDERER_HAVE_IMGUI_DX11
|
||||||
|
# define RENDERER_HAVE_IMGUI_DX11() 0
|
||||||
|
# endif
|
||||||
|
# ifndef RENDERER_HAVE_IMGUI_OGL3
|
||||||
|
# define RENDERER_HAVE_IMGUI_OGL3() 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define RENDERER_PRIV_IMGUI_DX11() 1
|
||||||
|
# define RENDERER_PRIV_IMGUI_OGL3() 2
|
||||||
|
|
||||||
|
# if !defined(RENDERER_CONFIG)
|
||||||
|
# if PLATFORM(WINDOWS)
|
||||||
|
# define RENDERER_CONFIG IMGUI_DX11
|
||||||
|
# else
|
||||||
|
# define RENDERER_CONFIG IMGUI_OGL3
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define RENDERER(x) ((RENDERER_PRIV_##x()) == CONCAT(RENDERER_PRIV_, EXPAND(RENDERER_CONFIG))() && (RENDERER_HAVE_##x()))
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleGetInfoString</key>
|
||||||
|
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleLongVersionString</key>
|
||||||
|
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||||
|
<key>CSResourcesFileMapped</key>
|
||||||
|
<true/>
|
||||||
|
<key>LSRequiresCarbon</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||||
|
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#define IDI_APPLICATION 32512
|
||||||
|
|
||||||
|
IDI_APPLICATION ICON "${ApplicationIcon}"
|
|
@ -0,0 +1,3 @@
|
||||||
|
add_example_executable(basic-interaction-example
|
||||||
|
basic-interaction-example.cpp
|
||||||
|
)
|
216
3rdparty/imgui-node-editor/examples/basic-interaction-example/basic-interaction-example.cpp
vendored
Normal file
216
3rdparty/imgui-node-editor/examples/basic-interaction-example/basic-interaction-example.cpp
vendored
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <imgui_node_editor.h>
|
||||||
|
# include <application.h>
|
||||||
|
|
||||||
|
namespace ed = ax::NodeEditor;
|
||||||
|
|
||||||
|
struct Example:
|
||||||
|
public Application
|
||||||
|
{
|
||||||
|
// Struct to hold basic information about connection between
|
||||||
|
// pins. Note that connection (aka. link) has its own ID.
|
||||||
|
// This is useful later with dealing with selections, deletion
|
||||||
|
// or other operations.
|
||||||
|
struct LinkInfo
|
||||||
|
{
|
||||||
|
ed::LinkId Id;
|
||||||
|
ed::PinId InputId;
|
||||||
|
ed::PinId OutputId;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Application::Application;
|
||||||
|
|
||||||
|
void OnStart() override
|
||||||
|
{
|
||||||
|
ed::Config config;
|
||||||
|
config.SettingsFile = "BasicInteraction.json";
|
||||||
|
m_Context = ed::CreateEditor(&config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnStop() override
|
||||||
|
{
|
||||||
|
ed::DestroyEditor(m_Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx_BeginColumn()
|
||||||
|
{
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx_NextColumn()
|
||||||
|
{
|
||||||
|
ImGui::EndGroup();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx_EndColumn()
|
||||||
|
{
|
||||||
|
ImGui::EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnFrame(float deltaTime) override
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ed::SetCurrentEditor(m_Context);
|
||||||
|
|
||||||
|
// Start interaction with editor.
|
||||||
|
ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||||
|
|
||||||
|
int uniqueId = 1;
|
||||||
|
|
||||||
|
//
|
||||||
|
// 1) Commit known data to editor
|
||||||
|
//
|
||||||
|
|
||||||
|
// Submit Node A
|
||||||
|
ed::NodeId nodeA_Id = uniqueId++;
|
||||||
|
ed::PinId nodeA_InputPinId = uniqueId++;
|
||||||
|
ed::PinId nodeA_OutputPinId = uniqueId++;
|
||||||
|
|
||||||
|
if (m_FirstFrame)
|
||||||
|
ed::SetNodePosition(nodeA_Id, ImVec2(10, 10));
|
||||||
|
ed::BeginNode(nodeA_Id);
|
||||||
|
ImGui::Text("Node A");
|
||||||
|
ed::BeginPin(nodeA_InputPinId, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ed::BeginPin(nodeA_OutputPinId, ed::PinKind::Output);
|
||||||
|
ImGui::Text("Out ->");
|
||||||
|
ed::EndPin();
|
||||||
|
ed::EndNode();
|
||||||
|
|
||||||
|
// Submit Node B
|
||||||
|
ed::NodeId nodeB_Id = uniqueId++;
|
||||||
|
ed::PinId nodeB_InputPinId1 = uniqueId++;
|
||||||
|
ed::PinId nodeB_InputPinId2 = uniqueId++;
|
||||||
|
ed::PinId nodeB_OutputPinId = uniqueId++;
|
||||||
|
|
||||||
|
if (m_FirstFrame)
|
||||||
|
ed::SetNodePosition(nodeB_Id, ImVec2(210, 60));
|
||||||
|
ed::BeginNode(nodeB_Id);
|
||||||
|
ImGui::Text("Node B");
|
||||||
|
ImGuiEx_BeginColumn();
|
||||||
|
ed::BeginPin(nodeB_InputPinId1, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In1");
|
||||||
|
ed::EndPin();
|
||||||
|
ed::BeginPin(nodeB_InputPinId2, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In2");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGuiEx_NextColumn();
|
||||||
|
ed::BeginPin(nodeB_OutputPinId, ed::PinKind::Output);
|
||||||
|
ImGui::Text("Out ->");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGuiEx_EndColumn();
|
||||||
|
ed::EndNode();
|
||||||
|
|
||||||
|
// Submit Links
|
||||||
|
for (auto& linkInfo : m_Links)
|
||||||
|
ed::Link(linkInfo.Id, linkInfo.InputId, linkInfo.OutputId);
|
||||||
|
|
||||||
|
//
|
||||||
|
// 2) Handle interactions
|
||||||
|
//
|
||||||
|
|
||||||
|
// Handle creation action, returns true if editor want to create new object (node or link)
|
||||||
|
if (ed::BeginCreate())
|
||||||
|
{
|
||||||
|
ed::PinId inputPinId, outputPinId;
|
||||||
|
if (ed::QueryNewLink(&inputPinId, &outputPinId))
|
||||||
|
{
|
||||||
|
// QueryNewLink returns true if editor want to create new link between pins.
|
||||||
|
//
|
||||||
|
// Link can be created only for two valid pins, it is up to you to
|
||||||
|
// validate if connection make sense. Editor is happy to make any.
|
||||||
|
//
|
||||||
|
// Link always goes from input to output. User may choose to drag
|
||||||
|
// link from output pin or input pin. This determine which pin ids
|
||||||
|
// are valid and which are not:
|
||||||
|
// * input valid, output invalid - user started to drag new ling from input pin
|
||||||
|
// * input invalid, output valid - user started to drag new ling from output pin
|
||||||
|
// * input valid, output valid - user dragged link over other pin, can be validated
|
||||||
|
|
||||||
|
if (inputPinId && outputPinId) // both are valid, let's accept link
|
||||||
|
{
|
||||||
|
// ed::AcceptNewItem() return true when user release mouse button.
|
||||||
|
if (ed::AcceptNewItem())
|
||||||
|
{
|
||||||
|
// Since we accepted new link, lets add one to our list of links.
|
||||||
|
m_Links.push_back({ ed::LinkId(m_NextLinkId++), inputPinId, outputPinId });
|
||||||
|
|
||||||
|
// Draw new link.
|
||||||
|
ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// You may choose to reject connection between these nodes
|
||||||
|
// by calling ed::RejectNewItem(). This will allow editor to give
|
||||||
|
// visual feedback by changing link thickness and color.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ed::EndCreate(); // Wraps up object creation action handling.
|
||||||
|
|
||||||
|
|
||||||
|
// Handle deletion action
|
||||||
|
if (ed::BeginDelete())
|
||||||
|
{
|
||||||
|
// There may be many links marked for deletion, let's loop over them.
|
||||||
|
ed::LinkId deletedLinkId;
|
||||||
|
while (ed::QueryDeletedLink(&deletedLinkId))
|
||||||
|
{
|
||||||
|
// If you agree that link can be deleted, accept deletion.
|
||||||
|
if (ed::AcceptDeletedItem())
|
||||||
|
{
|
||||||
|
// Then remove link from your data.
|
||||||
|
for (auto& link : m_Links)
|
||||||
|
{
|
||||||
|
if (link.Id == deletedLinkId)
|
||||||
|
{
|
||||||
|
m_Links.erase(&link);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// You may reject link deletion by calling:
|
||||||
|
// ed::RejectDeletedItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ed::EndDelete(); // Wrap up deletion action
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// End of interaction with editor.
|
||||||
|
ed::End();
|
||||||
|
|
||||||
|
if (m_FirstFrame)
|
||||||
|
ed::NavigateToContent(0.0f);
|
||||||
|
|
||||||
|
ed::SetCurrentEditor(nullptr);
|
||||||
|
|
||||||
|
m_FirstFrame = false;
|
||||||
|
|
||||||
|
// ImGui::ShowMetricsWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
ed::EditorContext* m_Context = nullptr; // Editor context, required to trace a editor state.
|
||||||
|
bool m_FirstFrame = true; // Flag set for first frame only, some action need to be executed once.
|
||||||
|
ImVector<LinkInfo> m_Links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
|
||||||
|
int m_NextLinkId = 100; // Counter to help generate link ids. In real application this will probably based on pointer to user data structure.
|
||||||
|
};
|
||||||
|
|
||||||
|
int Main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
Example exampe("Basic Interaction", argc, argv);
|
||||||
|
|
||||||
|
if (exampe.Create())
|
||||||
|
return exampe.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
add_example_executable(blueprints-example
|
||||||
|
blueprints-example.cpp
|
||||||
|
utilities/builders.h
|
||||||
|
utilities/drawing.h
|
||||||
|
utilities/widgets.h
|
||||||
|
utilities/builders.cpp
|
||||||
|
utilities/drawing.cpp
|
||||||
|
utilities/widgets.cpp
|
||||||
|
)
|
1835
3rdparty/imgui-node-editor/examples/blueprints-example/blueprints-example.cpp
vendored
Normal file
1835
3rdparty/imgui-node-editor/examples/blueprints-example/blueprints-example.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
3rdparty/imgui-node-editor/examples/blueprints-example/data/BlueprintBackground.png
vendored
Normal file
BIN
3rdparty/imgui-node-editor/examples/blueprints-example/data/BlueprintBackground.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
BIN
3rdparty/imgui-node-editor/examples/blueprints-example/data/ic_restore_white_24dp.png
vendored
Normal file
BIN
3rdparty/imgui-node-editor/examples/blueprints-example/data/ic_restore_white_24dp.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 332 B |
BIN
3rdparty/imgui-node-editor/examples/blueprints-example/data/ic_save_white_24dp.png
vendored
Normal file
BIN
3rdparty/imgui-node-editor/examples/blueprints-example/data/ic_save_white_24dp.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 B |
310
3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.cpp
vendored
Normal file
310
3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.cpp
vendored
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
# include "builders.h"
|
||||||
|
# include <imgui_internal.h>
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
namespace ed = ax::NodeEditor;
|
||||||
|
namespace util = ax::NodeEditor::Utilities;
|
||||||
|
|
||||||
|
util::BlueprintNodeBuilder::BlueprintNodeBuilder(ImTextureID texture, int textureWidth, int textureHeight):
|
||||||
|
HeaderTextureId(texture),
|
||||||
|
HeaderTextureWidth(textureWidth),
|
||||||
|
HeaderTextureHeight(textureHeight),
|
||||||
|
CurrentNodeId(0),
|
||||||
|
CurrentStage(Stage::Invalid),
|
||||||
|
HasHeader(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::Begin(ed::NodeId id)
|
||||||
|
{
|
||||||
|
HasHeader = false;
|
||||||
|
HeaderMin = HeaderMax = ImVec2();
|
||||||
|
|
||||||
|
ed::PushStyleVar(StyleVar_NodePadding, ImVec4(8, 4, 8, 8));
|
||||||
|
|
||||||
|
ed::BeginNode(id);
|
||||||
|
|
||||||
|
ImGui::PushID(id.AsPointer());
|
||||||
|
CurrentNodeId = id;
|
||||||
|
|
||||||
|
SetStage(Stage::Begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::End()
|
||||||
|
{
|
||||||
|
SetStage(Stage::End);
|
||||||
|
|
||||||
|
ed::EndNode();
|
||||||
|
|
||||||
|
if (ImGui::IsItemVisible())
|
||||||
|
{
|
||||||
|
auto alpha = static_cast<int>(255 * ImGui::GetStyle().Alpha);
|
||||||
|
|
||||||
|
auto drawList = ed::GetNodeBackgroundDrawList(CurrentNodeId);
|
||||||
|
|
||||||
|
const auto halfBorderWidth = ed::GetStyle().NodeBorderWidth * 0.5f;
|
||||||
|
|
||||||
|
auto headerColor = IM_COL32(0, 0, 0, alpha) | (HeaderColor & IM_COL32(255, 255, 255, 0));
|
||||||
|
if ((HeaderMax.x > HeaderMin.x) && (HeaderMax.y > HeaderMin.y) && HeaderTextureId)
|
||||||
|
{
|
||||||
|
const auto uv = ImVec2(
|
||||||
|
(HeaderMax.x - HeaderMin.x) / (float)(4.0f * HeaderTextureWidth),
|
||||||
|
(HeaderMax.y - HeaderMin.y) / (float)(4.0f * HeaderTextureHeight));
|
||||||
|
|
||||||
|
drawList->AddImageRounded(HeaderTextureId,
|
||||||
|
HeaderMin - ImVec2(8 - halfBorderWidth, 4 - halfBorderWidth),
|
||||||
|
HeaderMax + ImVec2(8 - halfBorderWidth, 0),
|
||||||
|
ImVec2(0.0f, 0.0f), uv,
|
||||||
|
#if IMGUI_VERSION_NUM > 18101
|
||||||
|
headerColor, GetStyle().NodeRounding, ImDrawFlags_RoundCornersTop);
|
||||||
|
#else
|
||||||
|
headerColor, GetStyle().NodeRounding, 1 | 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ContentMin.y > HeaderMax.y)
|
||||||
|
{
|
||||||
|
drawList->AddLine(
|
||||||
|
ImVec2(HeaderMin.x - (8 - halfBorderWidth), HeaderMax.y - 0.5f),
|
||||||
|
ImVec2(HeaderMax.x + (8 - halfBorderWidth), HeaderMax.y - 0.5f),
|
||||||
|
ImColor(255, 255, 255, 96 * alpha / (3 * 255)), 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentNodeId = 0;
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
ed::PopStyleVar();
|
||||||
|
|
||||||
|
SetStage(Stage::Invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::Header(const ImVec4& color)
|
||||||
|
{
|
||||||
|
HeaderColor = ImColor(color);
|
||||||
|
SetStage(Stage::Header);
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::EndHeader()
|
||||||
|
{
|
||||||
|
SetStage(Stage::Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::Input(ed::PinId id)
|
||||||
|
{
|
||||||
|
if (CurrentStage == Stage::Begin)
|
||||||
|
SetStage(Stage::Content);
|
||||||
|
|
||||||
|
const auto applyPadding = (CurrentStage == Stage::Input);
|
||||||
|
|
||||||
|
SetStage(Stage::Input);
|
||||||
|
|
||||||
|
if (applyPadding)
|
||||||
|
ImGui::Spring(0);
|
||||||
|
|
||||||
|
Pin(id, PinKind::Input);
|
||||||
|
|
||||||
|
ImGui::BeginHorizontal(id.AsPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::EndInput()
|
||||||
|
{
|
||||||
|
ImGui::EndHorizontal();
|
||||||
|
|
||||||
|
EndPin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::Middle()
|
||||||
|
{
|
||||||
|
if (CurrentStage == Stage::Begin)
|
||||||
|
SetStage(Stage::Content);
|
||||||
|
|
||||||
|
SetStage(Stage::Middle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::Output(ed::PinId id)
|
||||||
|
{
|
||||||
|
if (CurrentStage == Stage::Begin)
|
||||||
|
SetStage(Stage::Content);
|
||||||
|
|
||||||
|
const auto applyPadding = (CurrentStage == Stage::Output);
|
||||||
|
|
||||||
|
SetStage(Stage::Output);
|
||||||
|
|
||||||
|
if (applyPadding)
|
||||||
|
ImGui::Spring(0);
|
||||||
|
|
||||||
|
Pin(id, PinKind::Output);
|
||||||
|
|
||||||
|
ImGui::BeginHorizontal(id.AsPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::EndOutput()
|
||||||
|
{
|
||||||
|
ImGui::EndHorizontal();
|
||||||
|
|
||||||
|
EndPin();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool util::BlueprintNodeBuilder::SetStage(Stage stage)
|
||||||
|
{
|
||||||
|
if (stage == CurrentStage)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto oldStage = CurrentStage;
|
||||||
|
CurrentStage = stage;
|
||||||
|
|
||||||
|
ImVec2 cursor;
|
||||||
|
switch (oldStage)
|
||||||
|
{
|
||||||
|
case Stage::Begin:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Header:
|
||||||
|
ImGui::EndHorizontal();
|
||||||
|
HeaderMin = ImGui::GetItemRectMin();
|
||||||
|
HeaderMax = ImGui::GetItemRectMax();
|
||||||
|
|
||||||
|
// spacing between header and content
|
||||||
|
ImGui::Spring(0, ImGui::GetStyle().ItemSpacing.y * 2.0f);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Content:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Input:
|
||||||
|
ed::PopStyleVar(2);
|
||||||
|
|
||||||
|
ImGui::Spring(1, 0);
|
||||||
|
ImGui::EndVertical();
|
||||||
|
|
||||||
|
// #debug
|
||||||
|
// ImGui::GetWindowDrawList()->AddRect(
|
||||||
|
// ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Middle:
|
||||||
|
ImGui::EndVertical();
|
||||||
|
|
||||||
|
// #debug
|
||||||
|
// ImGui::GetWindowDrawList()->AddRect(
|
||||||
|
// ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Output:
|
||||||
|
ed::PopStyleVar(2);
|
||||||
|
|
||||||
|
ImGui::Spring(1, 0);
|
||||||
|
ImGui::EndVertical();
|
||||||
|
|
||||||
|
// #debug
|
||||||
|
// ImGui::GetWindowDrawList()->AddRect(
|
||||||
|
// ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::End:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Invalid:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (stage)
|
||||||
|
{
|
||||||
|
case Stage::Begin:
|
||||||
|
ImGui::BeginVertical("node");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Header:
|
||||||
|
HasHeader = true;
|
||||||
|
|
||||||
|
ImGui::BeginHorizontal("header");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Content:
|
||||||
|
if (oldStage == Stage::Begin)
|
||||||
|
ImGui::Spring(0);
|
||||||
|
|
||||||
|
ImGui::BeginHorizontal("content");
|
||||||
|
ImGui::Spring(0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Input:
|
||||||
|
ImGui::BeginVertical("inputs", ImVec2(0, 0), 0.0f);
|
||||||
|
|
||||||
|
ed::PushStyleVar(ed::StyleVar_PivotAlignment, ImVec2(0, 0.5f));
|
||||||
|
ed::PushStyleVar(ed::StyleVar_PivotSize, ImVec2(0, 0));
|
||||||
|
|
||||||
|
if (!HasHeader)
|
||||||
|
ImGui::Spring(1, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Middle:
|
||||||
|
ImGui::Spring(1);
|
||||||
|
ImGui::BeginVertical("middle", ImVec2(0, 0), 1.0f);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Output:
|
||||||
|
if (oldStage == Stage::Middle || oldStage == Stage::Input)
|
||||||
|
ImGui::Spring(1);
|
||||||
|
else
|
||||||
|
ImGui::Spring(1, 0);
|
||||||
|
ImGui::BeginVertical("outputs", ImVec2(0, 0), 1.0f);
|
||||||
|
|
||||||
|
ed::PushStyleVar(ed::StyleVar_PivotAlignment, ImVec2(1.0f, 0.5f));
|
||||||
|
ed::PushStyleVar(ed::StyleVar_PivotSize, ImVec2(0, 0));
|
||||||
|
|
||||||
|
if (!HasHeader)
|
||||||
|
ImGui::Spring(1, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::End:
|
||||||
|
if (oldStage == Stage::Input)
|
||||||
|
ImGui::Spring(1, 0);
|
||||||
|
if (oldStage != Stage::Begin)
|
||||||
|
ImGui::EndHorizontal();
|
||||||
|
ContentMin = ImGui::GetItemRectMin();
|
||||||
|
ContentMax = ImGui::GetItemRectMax();
|
||||||
|
|
||||||
|
//ImGui::Spring(0);
|
||||||
|
ImGui::EndVertical();
|
||||||
|
NodeMin = ImGui::GetItemRectMin();
|
||||||
|
NodeMax = ImGui::GetItemRectMax();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stage::Invalid:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::Pin(ed::PinId id, ed::PinKind kind)
|
||||||
|
{
|
||||||
|
ed::BeginPin(id, kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
void util::BlueprintNodeBuilder::EndPin()
|
||||||
|
{
|
||||||
|
ed::EndPin();
|
||||||
|
|
||||||
|
// #debug
|
||||||
|
// ImGui::GetWindowDrawList()->AddRectFilled(
|
||||||
|
// ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 64));
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include <imgui_node_editor.h>
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
namespace ax {
|
||||||
|
namespace NodeEditor {
|
||||||
|
namespace Utilities {
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
struct BlueprintNodeBuilder
|
||||||
|
{
|
||||||
|
BlueprintNodeBuilder(ImTextureID texture = nullptr, int textureWidth = 0, int textureHeight = 0);
|
||||||
|
|
||||||
|
void Begin(NodeId id);
|
||||||
|
void End();
|
||||||
|
|
||||||
|
void Header(const ImVec4& color = ImVec4(1, 1, 1, 1));
|
||||||
|
void EndHeader();
|
||||||
|
|
||||||
|
void Input(PinId id);
|
||||||
|
void EndInput();
|
||||||
|
|
||||||
|
void Middle();
|
||||||
|
|
||||||
|
void Output(PinId id);
|
||||||
|
void EndOutput();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class Stage
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
Begin,
|
||||||
|
Header,
|
||||||
|
Content,
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
Middle,
|
||||||
|
End
|
||||||
|
};
|
||||||
|
|
||||||
|
bool SetStage(Stage stage);
|
||||||
|
|
||||||
|
void Pin(PinId id, ax::NodeEditor::PinKind kind);
|
||||||
|
void EndPin();
|
||||||
|
|
||||||
|
ImTextureID HeaderTextureId;
|
||||||
|
int HeaderTextureWidth;
|
||||||
|
int HeaderTextureHeight;
|
||||||
|
NodeId CurrentNodeId;
|
||||||
|
Stage CurrentStage;
|
||||||
|
ImU32 HeaderColor;
|
||||||
|
ImVec2 NodeMin;
|
||||||
|
ImVec2 NodeMax;
|
||||||
|
ImVec2 HeaderMin;
|
||||||
|
ImVec2 HeaderMax;
|
||||||
|
ImVec2 ContentMin;
|
||||||
|
ImVec2 ContentMax;
|
||||||
|
bool HasHeader;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
} // namespace Utilities
|
||||||
|
} // namespace Editor
|
||||||
|
} // namespace ax
|
252
3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.cpp
vendored
Normal file
252
3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.cpp
vendored
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
# include "drawing.h"
|
||||||
|
# include <imgui_internal.h>
|
||||||
|
|
||||||
|
void ax::Drawing::DrawIcon(ImDrawList* drawList, const ImVec2& a, const ImVec2& b, IconType type, bool filled, ImU32 color, ImU32 innerColor)
|
||||||
|
{
|
||||||
|
auto rect = ImRect(a, b);
|
||||||
|
auto rect_x = rect.Min.x;
|
||||||
|
auto rect_y = rect.Min.y;
|
||||||
|
auto rect_w = rect.Max.x - rect.Min.x;
|
||||||
|
auto rect_h = rect.Max.y - rect.Min.y;
|
||||||
|
auto rect_center_x = (rect.Min.x + rect.Max.x) * 0.5f;
|
||||||
|
auto rect_center_y = (rect.Min.y + rect.Max.y) * 0.5f;
|
||||||
|
auto rect_center = ImVec2(rect_center_x, rect_center_y);
|
||||||
|
const auto outline_scale = rect_w / 24.0f;
|
||||||
|
const auto extra_segments = static_cast<int>(2 * outline_scale); // for full circle
|
||||||
|
|
||||||
|
if (type == IconType::Flow)
|
||||||
|
{
|
||||||
|
const auto origin_scale = rect_w / 24.0f;
|
||||||
|
|
||||||
|
const auto offset_x = 1.0f * origin_scale;
|
||||||
|
const auto offset_y = 0.0f * origin_scale;
|
||||||
|
const auto margin = (filled ? 2.0f : 2.0f) * origin_scale;
|
||||||
|
const auto rounding = 0.1f * origin_scale;
|
||||||
|
const auto tip_round = 0.7f; // percentage of triangle edge (for tip)
|
||||||
|
//const auto edge_round = 0.7f; // percentage of triangle edge (for corner)
|
||||||
|
const auto canvas = ImRect(
|
||||||
|
rect.Min.x + margin + offset_x,
|
||||||
|
rect.Min.y + margin + offset_y,
|
||||||
|
rect.Max.x - margin + offset_x,
|
||||||
|
rect.Max.y - margin + offset_y);
|
||||||
|
const auto canvas_x = canvas.Min.x;
|
||||||
|
const auto canvas_y = canvas.Min.y;
|
||||||
|
const auto canvas_w = canvas.Max.x - canvas.Min.x;
|
||||||
|
const auto canvas_h = canvas.Max.y - canvas.Min.y;
|
||||||
|
|
||||||
|
const auto left = canvas_x + canvas_w * 0.5f * 0.3f;
|
||||||
|
const auto right = canvas_x + canvas_w - canvas_w * 0.5f * 0.3f;
|
||||||
|
const auto top = canvas_y + canvas_h * 0.5f * 0.2f;
|
||||||
|
const auto bottom = canvas_y + canvas_h - canvas_h * 0.5f * 0.2f;
|
||||||
|
const auto center_y = (top + bottom) * 0.5f;
|
||||||
|
//const auto angle = AX_PI * 0.5f * 0.5f * 0.5f;
|
||||||
|
|
||||||
|
const auto tip_top = ImVec2(canvas_x + canvas_w * 0.5f, top);
|
||||||
|
const auto tip_right = ImVec2(right, center_y);
|
||||||
|
const auto tip_bottom = ImVec2(canvas_x + canvas_w * 0.5f, bottom);
|
||||||
|
|
||||||
|
drawList->PathLineTo(ImVec2(left, top) + ImVec2(0, rounding));
|
||||||
|
drawList->PathBezierCubicCurveTo(
|
||||||
|
ImVec2(left, top),
|
||||||
|
ImVec2(left, top),
|
||||||
|
ImVec2(left, top) + ImVec2(rounding, 0));
|
||||||
|
drawList->PathLineTo(tip_top);
|
||||||
|
drawList->PathLineTo(tip_top + (tip_right - tip_top) * tip_round);
|
||||||
|
drawList->PathBezierCubicCurveTo(
|
||||||
|
tip_right,
|
||||||
|
tip_right,
|
||||||
|
tip_bottom + (tip_right - tip_bottom) * tip_round);
|
||||||
|
drawList->PathLineTo(tip_bottom);
|
||||||
|
drawList->PathLineTo(ImVec2(left, bottom) + ImVec2(rounding, 0));
|
||||||
|
drawList->PathBezierCubicCurveTo(
|
||||||
|
ImVec2(left, bottom),
|
||||||
|
ImVec2(left, bottom),
|
||||||
|
ImVec2(left, bottom) - ImVec2(0, rounding));
|
||||||
|
|
||||||
|
if (!filled)
|
||||||
|
{
|
||||||
|
if (innerColor & 0xFF000000)
|
||||||
|
drawList->AddConvexPolyFilled(drawList->_Path.Data, drawList->_Path.Size, innerColor);
|
||||||
|
|
||||||
|
drawList->PathStroke(color, true, 2.0f * outline_scale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
drawList->PathFillConvex(color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto triangleStart = rect_center_x + 0.32f * rect_w;
|
||||||
|
|
||||||
|
auto rect_offset = -static_cast<int>(rect_w * 0.25f * 0.25f);
|
||||||
|
|
||||||
|
rect.Min.x += rect_offset;
|
||||||
|
rect.Max.x += rect_offset;
|
||||||
|
rect_x += rect_offset;
|
||||||
|
rect_center_x += rect_offset * 0.5f;
|
||||||
|
rect_center.x += rect_offset * 0.5f;
|
||||||
|
|
||||||
|
if (type == IconType::Circle)
|
||||||
|
{
|
||||||
|
const auto c = rect_center;
|
||||||
|
|
||||||
|
if (!filled)
|
||||||
|
{
|
||||||
|
const auto r = 0.5f * rect_w / 2.0f - 0.5f;
|
||||||
|
|
||||||
|
if (innerColor & 0xFF000000)
|
||||||
|
drawList->AddCircleFilled(c, r, innerColor, 12 + extra_segments);
|
||||||
|
drawList->AddCircle(c, r, color, 12 + extra_segments, 2.0f * outline_scale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drawList->AddCircleFilled(c, 0.5f * rect_w / 2.0f, color, 12 + extra_segments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == IconType::Square)
|
||||||
|
{
|
||||||
|
if (filled)
|
||||||
|
{
|
||||||
|
const auto r = 0.5f * rect_w / 2.0f;
|
||||||
|
const auto p0 = rect_center - ImVec2(r, r);
|
||||||
|
const auto p1 = rect_center + ImVec2(r, r);
|
||||||
|
|
||||||
|
#if IMGUI_VERSION_NUM > 18101
|
||||||
|
drawList->AddRectFilled(p0, p1, color, 0, ImDrawFlags_RoundCornersAll);
|
||||||
|
#else
|
||||||
|
drawList->AddRectFilled(p0, p1, color, 0, 15);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto r = 0.5f * rect_w / 2.0f - 0.5f;
|
||||||
|
const auto p0 = rect_center - ImVec2(r, r);
|
||||||
|
const auto p1 = rect_center + ImVec2(r, r);
|
||||||
|
|
||||||
|
if (innerColor & 0xFF000000)
|
||||||
|
{
|
||||||
|
#if IMGUI_VERSION_NUM > 18101
|
||||||
|
drawList->AddRectFilled(p0, p1, innerColor, 0, ImDrawFlags_RoundCornersAll);
|
||||||
|
#else
|
||||||
|
drawList->AddRectFilled(p0, p1, innerColor, 0, 15);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IMGUI_VERSION_NUM > 18101
|
||||||
|
drawList->AddRect(p0, p1, color, 0, ImDrawFlags_RoundCornersAll, 2.0f * outline_scale);
|
||||||
|
#else
|
||||||
|
drawList->AddRect(p0, p1, color, 0, 15, 2.0f * outline_scale);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == IconType::Grid)
|
||||||
|
{
|
||||||
|
const auto r = 0.5f * rect_w / 2.0f;
|
||||||
|
const auto w = ceilf(r / 3.0f);
|
||||||
|
|
||||||
|
const auto baseTl = ImVec2(floorf(rect_center_x - w * 2.5f), floorf(rect_center_y - w * 2.5f));
|
||||||
|
const auto baseBr = ImVec2(floorf(baseTl.x + w), floorf(baseTl.y + w));
|
||||||
|
|
||||||
|
auto tl = baseTl;
|
||||||
|
auto br = baseBr;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
tl.x = baseTl.x;
|
||||||
|
br.x = baseBr.x;
|
||||||
|
drawList->AddRectFilled(tl, br, color);
|
||||||
|
tl.x += w * 2;
|
||||||
|
br.x += w * 2;
|
||||||
|
if (i != 1 || filled)
|
||||||
|
drawList->AddRectFilled(tl, br, color);
|
||||||
|
tl.x += w * 2;
|
||||||
|
br.x += w * 2;
|
||||||
|
drawList->AddRectFilled(tl, br, color);
|
||||||
|
|
||||||
|
tl.y += w * 2;
|
||||||
|
br.y += w * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
triangleStart = br.x + w + 1.0f / 24.0f * rect_w;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == IconType::RoundSquare)
|
||||||
|
{
|
||||||
|
if (filled)
|
||||||
|
{
|
||||||
|
const auto r = 0.5f * rect_w / 2.0f;
|
||||||
|
const auto cr = r * 0.5f;
|
||||||
|
const auto p0 = rect_center - ImVec2(r, r);
|
||||||
|
const auto p1 = rect_center + ImVec2(r, r);
|
||||||
|
|
||||||
|
#if IMGUI_VERSION_NUM > 18101
|
||||||
|
drawList->AddRectFilled(p0, p1, color, cr, ImDrawFlags_RoundCornersAll);
|
||||||
|
#else
|
||||||
|
drawList->AddRectFilled(p0, p1, color, cr, 15);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto r = 0.5f * rect_w / 2.0f - 0.5f;
|
||||||
|
const auto cr = r * 0.5f;
|
||||||
|
const auto p0 = rect_center - ImVec2(r, r);
|
||||||
|
const auto p1 = rect_center + ImVec2(r, r);
|
||||||
|
|
||||||
|
if (innerColor & 0xFF000000)
|
||||||
|
{
|
||||||
|
#if IMGUI_VERSION_NUM > 18101
|
||||||
|
drawList->AddRectFilled(p0, p1, innerColor, cr, ImDrawFlags_RoundCornersAll);
|
||||||
|
#else
|
||||||
|
drawList->AddRectFilled(p0, p1, innerColor, cr, 15);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IMGUI_VERSION_NUM > 18101
|
||||||
|
drawList->AddRect(p0, p1, color, cr, ImDrawFlags_RoundCornersAll, 2.0f * outline_scale);
|
||||||
|
#else
|
||||||
|
drawList->AddRect(p0, p1, color, cr, 15, 2.0f * outline_scale);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == IconType::Diamond)
|
||||||
|
{
|
||||||
|
if (filled)
|
||||||
|
{
|
||||||
|
const auto r = 0.607f * rect_w / 2.0f;
|
||||||
|
const auto c = rect_center;
|
||||||
|
|
||||||
|
drawList->PathLineTo(c + ImVec2( 0, -r));
|
||||||
|
drawList->PathLineTo(c + ImVec2( r, 0));
|
||||||
|
drawList->PathLineTo(c + ImVec2( 0, r));
|
||||||
|
drawList->PathLineTo(c + ImVec2(-r, 0));
|
||||||
|
drawList->PathFillConvex(color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto r = 0.607f * rect_w / 2.0f - 0.5f;
|
||||||
|
const auto c = rect_center;
|
||||||
|
|
||||||
|
drawList->PathLineTo(c + ImVec2( 0, -r));
|
||||||
|
drawList->PathLineTo(c + ImVec2( r, 0));
|
||||||
|
drawList->PathLineTo(c + ImVec2( 0, r));
|
||||||
|
drawList->PathLineTo(c + ImVec2(-r, 0));
|
||||||
|
|
||||||
|
if (innerColor & 0xFF000000)
|
||||||
|
drawList->AddConvexPolyFilled(drawList->_Path.Data, drawList->_Path.Size, innerColor);
|
||||||
|
|
||||||
|
drawList->PathStroke(color, true, 2.0f * outline_scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto triangleTip = triangleStart + rect_w * (0.45f - 0.32f);
|
||||||
|
|
||||||
|
drawList->AddTriangleFilled(
|
||||||
|
ImVec2(ceilf(triangleTip), rect_y + rect_h * 0.5f),
|
||||||
|
ImVec2(triangleStart, rect_center_y + 0.15f * rect_h),
|
||||||
|
ImVec2(triangleStart, rect_center_y - 0.15f * rect_h),
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
# pragma once
|
||||||
|
# include <imgui.h>
|
||||||
|
|
||||||
|
namespace ax {
|
||||||
|
namespace Drawing {
|
||||||
|
|
||||||
|
enum class IconType: ImU32 { Flow, Circle, Square, Grid, RoundSquare, Diamond };
|
||||||
|
|
||||||
|
void DrawIcon(ImDrawList* drawList, const ImVec2& a, const ImVec2& b, IconType type, bool filled, ImU32 color, ImU32 innerColor);
|
||||||
|
|
||||||
|
} // namespace Drawing
|
||||||
|
} // namespace ax
|
16
3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.cpp
vendored
Normal file
16
3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.cpp
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
# include "widgets.h"
|
||||||
|
# include <imgui_internal.h>
|
||||||
|
|
||||||
|
void ax::Widgets::Icon(const ImVec2& size, IconType type, bool filled, const ImVec4& color/* = ImVec4(1, 1, 1, 1)*/, const ImVec4& innerColor/* = ImVec4(0, 0, 0, 0)*/)
|
||||||
|
{
|
||||||
|
if (ImGui::IsRectVisible(size))
|
||||||
|
{
|
||||||
|
auto cursorPos = ImGui::GetCursorScreenPos();
|
||||||
|
auto drawList = ImGui::GetWindowDrawList();
|
||||||
|
ax::Drawing::DrawIcon(drawList, cursorPos, cursorPos + size, type, filled, ImColor(color), ImColor(innerColor));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Dummy(size);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
#include <imgui.h>
|
||||||
|
#include "drawing.h"
|
||||||
|
|
||||||
|
namespace ax {
|
||||||
|
namespace Widgets {
|
||||||
|
|
||||||
|
using Drawing::IconType;
|
||||||
|
|
||||||
|
void Icon(const ImVec2& size, IconType type, bool filled, const ImVec4& color = ImVec4(1, 1, 1, 1), const ImVec4& innerColor = ImVec4(0, 0, 0, 0));
|
||||||
|
|
||||||
|
} // namespace Widgets
|
||||||
|
} // namespace ax
|
|
@ -0,0 +1,5 @@
|
||||||
|
add_example_executable(canvas-example
|
||||||
|
canvas-example.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
#target_link_libraries(Canvas PRIVATE imgui_canvas)
|
|
@ -0,0 +1,251 @@
|
||||||
|
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <imgui_internal.h>
|
||||||
|
# include <imgui_canvas.h>
|
||||||
|
# include <application.h>
|
||||||
|
|
||||||
|
static void DrawScale(const ImVec2& from, const ImVec2& to, float majorUnit, float minorUnit, float labelAlignment, float sign = 1.0f)
|
||||||
|
{
|
||||||
|
auto drawList = ImGui::GetWindowDrawList();
|
||||||
|
auto direction = (to - from) * ImInvLength(to - from, 0.0f);
|
||||||
|
auto normal = ImVec2(-direction.y, direction.x);
|
||||||
|
auto distance = sqrtf(ImLengthSqr(to - from));
|
||||||
|
|
||||||
|
if (ImDot(direction, direction) < FLT_EPSILON)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto minorSize = 5.0f;
|
||||||
|
auto majorSize = 10.0f;
|
||||||
|
auto labelDistance = 8.0f;
|
||||||
|
|
||||||
|
drawList->AddLine(from, to, IM_COL32(255, 255, 255, 255));
|
||||||
|
|
||||||
|
auto p = from;
|
||||||
|
for (auto d = 0.0f; d <= distance; d += minorUnit, p += direction * minorUnit)
|
||||||
|
drawList->AddLine(p - normal * minorSize, p + normal * minorSize, IM_COL32(255, 255, 255, 255));
|
||||||
|
|
||||||
|
for (auto d = 0.0f; d <= distance + majorUnit; d += majorUnit)
|
||||||
|
{
|
||||||
|
p = from + direction * d;
|
||||||
|
|
||||||
|
drawList->AddLine(p - normal * majorSize, p + normal * majorSize, IM_COL32(255, 255, 255, 255));
|
||||||
|
|
||||||
|
if (d == 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char label[16];
|
||||||
|
snprintf(label, 15, "%g", d * sign);
|
||||||
|
auto labelSize = ImGui::CalcTextSize(label);
|
||||||
|
|
||||||
|
auto labelPosition = p + ImVec2(fabsf(normal.x), fabsf(normal.y)) * labelDistance;
|
||||||
|
auto labelAlignedSize = ImDot(labelSize, direction);
|
||||||
|
labelPosition += direction * (-labelAlignedSize + labelAlignment * labelAlignedSize * 2.0f);
|
||||||
|
labelPosition = ImFloor(labelPosition + ImVec2(0.5f, 0.5f));
|
||||||
|
|
||||||
|
drawList->AddText(labelPosition, IM_COL32(255, 255, 255, 255), label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f)
|
||||||
|
{
|
||||||
|
using namespace ImGui;
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
ImGuiWindow* window = g.CurrentWindow;
|
||||||
|
ImGuiID id = window->GetID("##Splitter");
|
||||||
|
ImRect bb;
|
||||||
|
bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
|
||||||
|
bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f);
|
||||||
|
return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Example:
|
||||||
|
public Application
|
||||||
|
{
|
||||||
|
using Application::Application;
|
||||||
|
|
||||||
|
void OnFrame(float deltaTime) override
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
auto availableRegion = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
|
static float s_SplitterSize = 6.0f;
|
||||||
|
static float s_SplitterArea = 0.0f;
|
||||||
|
static float s_LeftPaneSize = 0.0f;
|
||||||
|
static float s_RightPaneSize = 0.0f;
|
||||||
|
|
||||||
|
if (s_SplitterArea != availableRegion.x)
|
||||||
|
{
|
||||||
|
if (s_SplitterArea == 0.0f)
|
||||||
|
{
|
||||||
|
s_SplitterArea = availableRegion.x;
|
||||||
|
s_LeftPaneSize = ImFloor(availableRegion.x * 0.25f);
|
||||||
|
s_RightPaneSize = availableRegion.x - s_LeftPaneSize - s_SplitterSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto ratio = availableRegion.x / s_SplitterArea;
|
||||||
|
s_SplitterArea = availableRegion.x;
|
||||||
|
s_LeftPaneSize = s_LeftPaneSize * ratio;
|
||||||
|
s_RightPaneSize = availableRegion.x - s_LeftPaneSize - s_SplitterSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImGuiEx::Canvas canvas;
|
||||||
|
static ImVec2 drawStartPoint;
|
||||||
|
static bool isDragging = false;
|
||||||
|
static ImRect panelRect;
|
||||||
|
|
||||||
|
Splitter(true, s_SplitterSize, &s_LeftPaneSize, &s_RightPaneSize, 100.0f, 100.0f);
|
||||||
|
|
||||||
|
auto canvasRect = canvas.Rect();
|
||||||
|
auto viewRect = canvas.ViewRect();
|
||||||
|
auto viewOrigin = canvas.ViewOrigin();
|
||||||
|
auto viewScale = canvas.ViewScale();
|
||||||
|
|
||||||
|
ImGui::BeginChild("##top", ImVec2(s_LeftPaneSize, -1), false, ImGuiWindowFlags_NoScrollWithMouse);
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("Rect:");
|
||||||
|
ImGui::BeginColumns("rect", 2, ImGuiOldColumnFlags_NoBorder);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x);
|
||||||
|
ImGui::Text("\tL: %.2f", canvasRect.Min.x); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tT: %.2f", canvasRect.Min.y); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tR: %.2f", canvasRect.Max.x); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tB: %.2f", canvasRect.Max.y); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tW: %.2f", canvasRect.GetWidth()); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tH: %.2f", canvasRect.GetHeight()); ImGui::NextColumn();
|
||||||
|
ImGui::EndColumns();
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("View Rect:");
|
||||||
|
ImGui::BeginColumns("viewrect", 2, ImGuiOldColumnFlags_NoBorder);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x);
|
||||||
|
ImGui::Text("\tL: %.2f", viewRect.Min.x); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tT: %.2f", viewRect.Min.y); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tR: %.2f", viewRect.Max.x); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tB: %.2f", viewRect.Max.y); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tW: %.2f", viewRect.GetWidth()); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tH: %.2f", viewRect.GetHeight()); ImGui::NextColumn();
|
||||||
|
ImGui::EndColumns();
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("Origin:");
|
||||||
|
ImGui::Indent();
|
||||||
|
auto originChanged = false;
|
||||||
|
ImGui::PushItemWidth(-ImGui::GetStyle().IndentSpacing);
|
||||||
|
originChanged |= ImGui::DragFloat("##originx", &viewOrigin.x, 1.0f);
|
||||||
|
originChanged |= ImGui::DragFloat("##originy", &viewOrigin.y, 1.0f);
|
||||||
|
if (originChanged) canvas.SetView(viewOrigin, viewScale);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::Unindent();
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("Scale:");
|
||||||
|
ImGui::Indent();
|
||||||
|
ImGui::PushItemWidth(-ImGui::GetStyle().IndentSpacing);
|
||||||
|
if (ImGui::DragFloat("##scale", &viewScale, 0.01f, 0.01f, 15.0f))
|
||||||
|
canvas.SetView(viewOrigin, viewScale);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::Unindent();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::Button("Center over Panel", ImVec2(s_LeftPaneSize, 0)))
|
||||||
|
canvas.CenterView(panelRect.GetCenter());
|
||||||
|
|
||||||
|
if (ImGui::Button("Center and zoom to Panel", ImVec2(s_LeftPaneSize, 0)))
|
||||||
|
canvas.CenterView(panelRect);
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("Panel Rect:");
|
||||||
|
ImGui::BeginColumns("panelrect", 2, ImGuiOldColumnFlags_NoBorder);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x);
|
||||||
|
ImGui::Text("\tL: %.2f", panelRect.Min.x); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tT: %.2f", panelRect.Min.y); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tR: %.2f", panelRect.Max.x); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tB: %.2f", panelRect.Max.y); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tW: %.2f", panelRect.GetWidth()); ImGui::NextColumn();
|
||||||
|
ImGui::Text("\tH: %.2f", panelRect.GetHeight()); ImGui::NextColumn();
|
||||||
|
ImGui::EndColumns();
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
ImGui::SameLine(0.0f, s_SplitterSize);
|
||||||
|
|
||||||
|
|
||||||
|
if (canvas.Begin("##mycanvas", ImVec2(s_RightPaneSize, 0.0f)))
|
||||||
|
{
|
||||||
|
//auto drawList = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
|
if ((isDragging || ImGui::IsItemHovered()) && ImGui::IsMouseDragging(1, 0.0f))
|
||||||
|
{
|
||||||
|
if (!isDragging)
|
||||||
|
{
|
||||||
|
isDragging = true;
|
||||||
|
drawStartPoint = viewOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.SetView(drawStartPoint + ImGui::GetMouseDragDelta(1, 0.0f) * viewScale, viewScale);
|
||||||
|
}
|
||||||
|
else if (isDragging)
|
||||||
|
isDragging = false;
|
||||||
|
|
||||||
|
viewRect = canvas.ViewRect();
|
||||||
|
|
||||||
|
if (viewRect.Max.x > 0.0f)
|
||||||
|
DrawScale(ImVec2(0.0f, 0.0f), ImVec2(viewRect.Max.x, 0.0f), 100.0f, 10.0f, 0.6f);
|
||||||
|
if (viewRect.Min.x < 0.0f)
|
||||||
|
DrawScale(ImVec2(0.0f, 0.0f), ImVec2(viewRect.Min.x, 0.0f), 100.0f, 10.0f, 0.6f, -1.0f);
|
||||||
|
if (viewRect.Max.y > 0.0f)
|
||||||
|
DrawScale(ImVec2(0.0f, 0.0f), ImVec2(0.0f, viewRect.Max.y), 100.0f, 10.0f, 0.6f);
|
||||||
|
if (viewRect.Min.y < 0.0f)
|
||||||
|
DrawScale(ImVec2(0.0f, 0.0f), ImVec2(0.0f, viewRect.Min.y), 100.0f, 10.0f, 0.6f, -1.0f);
|
||||||
|
|
||||||
|
ImGui::Text("Hovered: %d", ImGui::IsItemHovered() ? 1 : 0);
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("Hello World!");
|
||||||
|
|
||||||
|
ImGui::Bullet();
|
||||||
|
|
||||||
|
ImGui::Button("Panel", ImVec2(s_RightPaneSize * 0.75f, availableRegion.y * 0.5f) * 0.5f);
|
||||||
|
panelRect.Min = ImGui::GetItemRectMin();
|
||||||
|
panelRect.Max = ImGui::GetItemRectMax();
|
||||||
|
|
||||||
|
canvas.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//ed::SetCurrentEditor(g_Context);
|
||||||
|
//ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||||
|
//int uniqueId = 1;
|
||||||
|
//// Start drawing nodes.
|
||||||
|
//ed::BeginNode(uniqueId++);
|
||||||
|
// ImGui::Text("Node A");
|
||||||
|
// ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||||
|
// ImGui::Text("-> In");
|
||||||
|
// ed::EndPin();
|
||||||
|
// ImGui::SameLine();
|
||||||
|
// ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||||
|
// ImGui::Text("Out ->");
|
||||||
|
// ed::EndPin();
|
||||||
|
//ed::EndNode();
|
||||||
|
//ed::End();
|
||||||
|
//ed::SetCurrentEditor(nullptr);
|
||||||
|
|
||||||
|
//ImGui::ShowMetricsWindow();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int Main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
Example exampe("Canvas", argc, argv);
|
||||||
|
|
||||||
|
if (exampe.Create())
|
||||||
|
return exampe.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright 2010 The Cuprum Project Authors (lemonad@jovanny.ru), with Reserved Font Name "Cuprum".
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright 2016 The Oswald Project Authors (https://github.com/googlefonts/OswaldFont)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
Binary file not shown.
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright (c) 2011, Jonas Hecksher, Playtypes, e-types AS (lasse@e-types.com), with Reserved Font Name 'Play', 'Playtype', 'Playtype Sans'.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
add_example_executable(simple-example
|
||||||
|
simple-example.cpp
|
||||||
|
)
|
|
@ -0,0 +1,63 @@
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <imgui_node_editor.h>
|
||||||
|
# include <application.h>
|
||||||
|
|
||||||
|
namespace ed = ax::NodeEditor;
|
||||||
|
|
||||||
|
struct Example:
|
||||||
|
public Application
|
||||||
|
{
|
||||||
|
using Application::Application;
|
||||||
|
|
||||||
|
void OnStart() override
|
||||||
|
{
|
||||||
|
ed::Config config;
|
||||||
|
config.SettingsFile = "Simple.json";
|
||||||
|
m_Context = ed::CreateEditor(&config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnStop() override
|
||||||
|
{
|
||||||
|
ed::DestroyEditor(m_Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnFrame(float deltaTime) override
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ed::SetCurrentEditor(m_Context);
|
||||||
|
ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||||
|
int uniqueId = 1;
|
||||||
|
// Start drawing nodes.
|
||||||
|
ed::BeginNode(uniqueId++);
|
||||||
|
ImGui::Text("Node A");
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||||
|
ImGui::Text("Out ->");
|
||||||
|
ed::EndPin();
|
||||||
|
ed::EndNode();
|
||||||
|
ed::End();
|
||||||
|
ed::SetCurrentEditor(nullptr);
|
||||||
|
|
||||||
|
//ImGui::ShowMetricsWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
ed::EditorContext* m_Context = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
int Main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
Example exampe("Simple", argc, argv);
|
||||||
|
|
||||||
|
if (exampe.Create())
|
||||||
|
return exampe.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
add_example_executable(widgets-example
|
||||||
|
widgets-example.cpp
|
||||||
|
)
|
|
@ -0,0 +1,432 @@
|
||||||
|
// ===================================================================================================================
|
||||||
|
// Widget Example
|
||||||
|
// Drawing standard ImGui widgets inside the node body
|
||||||
|
//
|
||||||
|
// First, some unsorted notes about which widgets do and don't draw well inside nodes. Run the examples to see all the allowed widgets.
|
||||||
|
//
|
||||||
|
// - Child windows with scrolling doesn't work in the node. The child window appears in a normal node,
|
||||||
|
// and scrolls, but its contents are floating around in the wrong location, and they are not scaled.
|
||||||
|
// Note that you can put scrolling child windows into "deferred popups" (see next item).
|
||||||
|
// - Listboxes and combo-boxes only work in nodes with a work-around: deferring the popup calls until after the node drawing is
|
||||||
|
// completed. Look to the popup-demo for an example.
|
||||||
|
// - Headers and trees work inside the nodes only with hacks. This is because they attempt to span the "avaialbe width"
|
||||||
|
// and the nodes can't tell these widgets how wide it is. The work-around is to set up a fake
|
||||||
|
// table with a static column width, then draw your header and tree widgets in that column.
|
||||||
|
// - Clickable tabs don't work in nodes. Tabs appear, but you cannot actually change the tab, so they're functionally useless.
|
||||||
|
// - Editable text areas work, but you have to manually manage disabling the editor shorcuts while typing is detected.
|
||||||
|
// Look around for the call to ed::EnableShortcuts() for an example.
|
||||||
|
// - Most of the cool graph widgets can't be used because they are hard-coded in ImGui to spawn tooltips, which don't work.
|
||||||
|
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <imgui_internal.h>
|
||||||
|
# include <imgui_node_editor.h>
|
||||||
|
# include <application.h>
|
||||||
|
|
||||||
|
namespace ed = ax::NodeEditor;
|
||||||
|
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
# define portable_strcpy strcpy_s
|
||||||
|
# define portable_sprintf sprintf_s
|
||||||
|
# else
|
||||||
|
# define portable_strcpy strcpy
|
||||||
|
# define portable_sprintf sprintf
|
||||||
|
# endif
|
||||||
|
|
||||||
|
struct Example:
|
||||||
|
public Application
|
||||||
|
{
|
||||||
|
using Application::Application;
|
||||||
|
|
||||||
|
struct LinkInfo
|
||||||
|
{
|
||||||
|
ed::LinkId Id;
|
||||||
|
ed::PinId InputId;
|
||||||
|
ed::PinId OutputId;
|
||||||
|
};
|
||||||
|
|
||||||
|
void OnStart() override
|
||||||
|
{
|
||||||
|
ed::Config config;
|
||||||
|
config.SettingsFile = "Widgets.json";
|
||||||
|
m_Context = ed::CreateEditor(&config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnStop() override
|
||||||
|
{
|
||||||
|
ed::DestroyEditor(m_Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnFrame(float deltaTime) override
|
||||||
|
{
|
||||||
|
static bool firstframe = true; // Used to position the nodes on startup
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// FPS Counter Ribbon
|
||||||
|
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
// Node Editor Widget
|
||||||
|
ed::SetCurrentEditor(m_Context);
|
||||||
|
ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||||
|
int uniqueId = 1;
|
||||||
|
|
||||||
|
|
||||||
|
// Basic Widgets Demo ==============================================================================================
|
||||||
|
auto basic_id = uniqueId++;
|
||||||
|
ed::BeginNode(basic_id);
|
||||||
|
ImGui::Text("Basic Widget Demo");
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Dummy(ImVec2(250, 0)); // Hacky magic number to space out the output pin.
|
||||||
|
ImGui::SameLine();
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||||
|
ImGui::Text("Out ->");
|
||||||
|
ed::EndPin();
|
||||||
|
|
||||||
|
// Widget Demo from imgui_demo.cpp...
|
||||||
|
// Normal Button
|
||||||
|
static int clicked = 0;
|
||||||
|
if (ImGui::Button("Button"))
|
||||||
|
clicked++;
|
||||||
|
if (clicked & 1)
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("Thanks for clicking me!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checkbox
|
||||||
|
static bool check = true;
|
||||||
|
ImGui::Checkbox("checkbox", &check);
|
||||||
|
|
||||||
|
// Radio buttons
|
||||||
|
static int e = 0;
|
||||||
|
ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
|
||||||
|
ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
|
||||||
|
ImGui::RadioButton("radio c", &e, 2);
|
||||||
|
|
||||||
|
// Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PushID(i);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
|
||||||
|
ImGui::Button("Click");
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default)
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Hold to repeat:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
// Arrow buttons with Repeater
|
||||||
|
static int counter = 0;
|
||||||
|
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
|
||||||
|
ImGui::PushButtonRepeat(true);
|
||||||
|
if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
|
||||||
|
ImGui::SameLine(0.0f, spacing);
|
||||||
|
if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
|
||||||
|
ImGui::PopButtonRepeat();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("%d", counter);
|
||||||
|
|
||||||
|
// The input widgets also require you to manually disable the editor shortcuts so the view doesn't fly around.
|
||||||
|
// (note that this is a per-frame setting, so it disables it for all text boxes. I left it here so you could find it!)
|
||||||
|
ed::EnableShortcuts(!io.WantTextInput);
|
||||||
|
// The input widgets require some guidance on their widths, or else they're very large. (note matching pop at the end).
|
||||||
|
ImGui::PushItemWidth(200);
|
||||||
|
static char str1[128] = "";
|
||||||
|
ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
|
||||||
|
|
||||||
|
static float f0 = 0.001f;
|
||||||
|
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
|
||||||
|
|
||||||
|
static float f1 = 1.00f, f2 = 0.0067f;
|
||||||
|
ImGui::DragFloat("drag float", &f1, 0.005f);
|
||||||
|
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
ed::EndNode();
|
||||||
|
if (firstframe)
|
||||||
|
{
|
||||||
|
ed::SetNodePosition(basic_id, ImVec2(20, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headers and Trees Demo =======================================================================================================
|
||||||
|
// TreeNodes and Headers streatch to the entire remaining work area. To put them in nodes what we need to do is to tell
|
||||||
|
// ImGui out work area is shorter. We can achieve that right now only by using columns API.
|
||||||
|
//
|
||||||
|
// Relevent bugs: https://github.com/thedmd/imgui-node-editor/issues/30
|
||||||
|
auto header_id = uniqueId++;
|
||||||
|
ed::BeginNode(header_id);
|
||||||
|
ImGui::Text("Tree Widget Demo");
|
||||||
|
|
||||||
|
// Pins Row
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Dummy(ImVec2(35, 0)); // magic number - Crude & simple way to nudge over the output pin. Consider using layout and springs
|
||||||
|
ImGui::SameLine();
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||||
|
ImGui::Text("Out ->");
|
||||||
|
ed::EndPin();
|
||||||
|
|
||||||
|
// Tree column startup -------------------------------------------------------------------
|
||||||
|
// Push dummy widget to extend node size. Columns do not do that.
|
||||||
|
float width = 135; // bad magic numbers. used to define width of tree widget
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||||
|
ImGui::Dummy(ImVec2(width, 0));
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
// Start columns, but use only first one.
|
||||||
|
ImGui::BeginColumns("##TreeColumns", 2,
|
||||||
|
ImGuiOldColumnFlags_NoBorder |
|
||||||
|
ImGuiOldColumnFlags_NoResize |
|
||||||
|
ImGuiOldColumnFlags_NoPreserveWidths |
|
||||||
|
ImGuiOldColumnFlags_NoForceWithinWindow);
|
||||||
|
|
||||||
|
// Adjust column width to match requested one.
|
||||||
|
ImGui::SetColumnWidth(0, width
|
||||||
|
+ ImGui::GetStyle().WindowPadding.x
|
||||||
|
+ ImGui::GetStyle().ItemSpacing.x);
|
||||||
|
// End of tree column startup --------------------------------------------------------------
|
||||||
|
|
||||||
|
// Back to normal ImGui drawing, in our column.
|
||||||
|
if (ImGui::CollapsingHeader("Open Header"))
|
||||||
|
{
|
||||||
|
ImGui::Text("Hello There");
|
||||||
|
if (ImGui::TreeNode("Open Tree")) {
|
||||||
|
static bool OP1_Bool = false;
|
||||||
|
ImGui::Text("Checked: %s", OP1_Bool ? "true" : "false");
|
||||||
|
ImGui::Checkbox("Option 1", &OP1_Bool);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Tree Column Shutdown
|
||||||
|
ImGui::EndColumns();
|
||||||
|
ed::EndNode(); // End of Tree Node Demo
|
||||||
|
|
||||||
|
if (firstframe)
|
||||||
|
{
|
||||||
|
ed::SetNodePosition(header_id, ImVec2(420, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tool Tip & Pop-up Demo =====================================================================================
|
||||||
|
// Tooltips, combo-boxes, drop-down menus need to use a work-around to place the "overlay window" in the canvas.
|
||||||
|
// To do this, we must defer the popup calls until after we're done drawing the node material.
|
||||||
|
//
|
||||||
|
// Relevent bugs: https://github.com/thedmd/imgui-node-editor/issues/48
|
||||||
|
auto popup_id = uniqueId++;
|
||||||
|
ed::BeginNode(popup_id);
|
||||||
|
ImGui::Text("Tool Tip & Pop-up Demo");
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Dummy(ImVec2(85, 0)); // Hacky magic number to space out the output pin.
|
||||||
|
ImGui::SameLine();
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||||
|
ImGui::Text("Out ->");
|
||||||
|
ed::EndPin();
|
||||||
|
|
||||||
|
// Tooltip example
|
||||||
|
ImGui::Text("Hover over me");
|
||||||
|
static bool do_tooltip = false;
|
||||||
|
do_tooltip = ImGui::IsItemHovered() ? true : false;
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("- or me");
|
||||||
|
static bool do_adv_tooltip = false;
|
||||||
|
do_adv_tooltip = ImGui::IsItemHovered() ? true : false;
|
||||||
|
|
||||||
|
// Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements
|
||||||
|
// (otherwise a Text+SameLine+Button sequence will have the text a little too high by default)
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Option:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
static char popup_text[128] = "Pick one!";
|
||||||
|
static bool do_popup = false;
|
||||||
|
if (ImGui::Button(popup_text)) {
|
||||||
|
do_popup = true; // Instead of saying OpenPopup() here, we set this bool, which is used later in the Deferred Pop-up Section
|
||||||
|
}
|
||||||
|
ed::EndNode();
|
||||||
|
if (firstframe) {
|
||||||
|
ed::SetNodePosition(popup_id, ImVec2(610, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
// Deferred Pop-up Section
|
||||||
|
|
||||||
|
// This entire section needs to be bounded by Suspend/Resume! These calls pop us out of "node canvas coordinates"
|
||||||
|
// and draw the popups in a reasonable screen location.
|
||||||
|
ed::Suspend();
|
||||||
|
// There is some stately stuff happening here. You call "open popup" exactly once, and this
|
||||||
|
// causes it to stick open for many frames until the user makes a selection in the popup, or clicks off to dismiss.
|
||||||
|
// More importantly, this is done inside Suspend(), so it loads the popup with the correct screen coordinates!
|
||||||
|
if (do_popup) {
|
||||||
|
ImGui::OpenPopup("popup_button"); // Cause openpopup to stick open.
|
||||||
|
do_popup = false; // disable bool so that if we click off the popup, it doesn't open the next frame.
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the actual popup Gui drawing section.
|
||||||
|
if (ImGui::BeginPopup("popup_button")) {
|
||||||
|
// Note: if it weren't for the child window, we would have to PushItemWidth() here to avoid a crash!
|
||||||
|
ImGui::TextDisabled("Pick One:");
|
||||||
|
ImGui::BeginChild("popup_scroller", ImVec2(100, 100), true, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||||
|
if (ImGui::Button("Option 1")) {
|
||||||
|
portable_strcpy(popup_text, "Option 1");
|
||||||
|
ImGui::CloseCurrentPopup(); // These calls revoke the popup open state, which was set by OpenPopup above.
|
||||||
|
}
|
||||||
|
if (ImGui::Button("Option 2")) {
|
||||||
|
portable_strcpy(popup_text, "Option 2");
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
if (ImGui::Button("Option 3")) {
|
||||||
|
portable_strcpy(popup_text, "Option 3");
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
if (ImGui::Button("Option 4")) {
|
||||||
|
portable_strcpy(popup_text, "Option 4");
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::EndPopup(); // Note this does not do anything to the popup open/close state. It just terminates the content declaration.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the simple tooltip
|
||||||
|
if (do_tooltip)
|
||||||
|
ImGui::SetTooltip("I am a tooltip");
|
||||||
|
|
||||||
|
// Handle the advanced tooltip
|
||||||
|
if (do_adv_tooltip) {
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("I am a fancy tooltip");
|
||||||
|
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
|
||||||
|
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
ed::Resume();
|
||||||
|
// End of "Deferred Pop-up section"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Plot Widgets =========================================================================================
|
||||||
|
// Note: most of these plots can't be used in nodes missing, because they spawn tooltips automatically,
|
||||||
|
// so we can't trap them in our deferred pop-up mechanism. This causes them to fly into a random screen
|
||||||
|
// location.
|
||||||
|
auto plot_id = uniqueId++;
|
||||||
|
ed::BeginNode(plot_id);
|
||||||
|
ImGui::Text("Plot Demo");
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||||
|
ImGui::Text("-> In");
|
||||||
|
ed::EndPin();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Dummy(ImVec2(250, 0)); // Hacky magic number to space out the output pin.
|
||||||
|
ImGui::SameLine();
|
||||||
|
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||||
|
ImGui::Text("Out ->");
|
||||||
|
ed::EndPin();
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(300);
|
||||||
|
|
||||||
|
// Animate a simple progress bar
|
||||||
|
static float progress = 0.0f, progress_dir = 1.0f;
|
||||||
|
progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
|
||||||
|
if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
|
||||||
|
if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
|
||||||
|
|
||||||
|
|
||||||
|
// Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
|
||||||
|
// or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
|
||||||
|
ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::Text("Progress Bar");
|
||||||
|
|
||||||
|
float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress;
|
||||||
|
char buf[32];
|
||||||
|
portable_sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
|
||||||
|
ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ed::EndNode();
|
||||||
|
if (firstframe) {
|
||||||
|
ed::SetNodePosition(plot_id, ImVec2(850, 20));
|
||||||
|
}
|
||||||
|
// ==================================================================================================
|
||||||
|
// Link Drawing Section
|
||||||
|
|
||||||
|
for (auto& linkInfo : m_Links)
|
||||||
|
ed::Link(linkInfo.Id, linkInfo.InputId, linkInfo.OutputId);
|
||||||
|
|
||||||
|
// ==================================================================================================
|
||||||
|
// Interaction Handling Section
|
||||||
|
// This was coppied from BasicInteration.cpp. See that file for commented code.
|
||||||
|
|
||||||
|
// Handle creation action ---------------------------------------------------------------------------
|
||||||
|
if (ed::BeginCreate())
|
||||||
|
{
|
||||||
|
ed::PinId inputPinId, outputPinId;
|
||||||
|
if (ed::QueryNewLink(&inputPinId, &outputPinId))
|
||||||
|
{
|
||||||
|
if (inputPinId && outputPinId)
|
||||||
|
{
|
||||||
|
if (ed::AcceptNewItem())
|
||||||
|
{
|
||||||
|
m_Links.push_back({ ed::LinkId(m_NextLinkId++), inputPinId, outputPinId });
|
||||||
|
ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ed::EndCreate();
|
||||||
|
|
||||||
|
// Handle deletion action ---------------------------------------------------------------------------
|
||||||
|
if (ed::BeginDelete())
|
||||||
|
{
|
||||||
|
ed::LinkId deletedLinkId;
|
||||||
|
while (ed::QueryDeletedLink(&deletedLinkId))
|
||||||
|
{
|
||||||
|
if (ed::AcceptDeletedItem())
|
||||||
|
{
|
||||||
|
for (auto& link : m_Links)
|
||||||
|
{
|
||||||
|
if (link.Id == deletedLinkId)
|
||||||
|
{
|
||||||
|
m_Links.erase(&link);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ed::EndDelete();
|
||||||
|
|
||||||
|
ed::End();
|
||||||
|
ed::SetCurrentEditor(nullptr);
|
||||||
|
firstframe = false;
|
||||||
|
//ImGui::ShowMetricsWindow();
|
||||||
|
//ImGui::ShowDemoWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
ed::EditorContext* m_Context = nullptr;
|
||||||
|
|
||||||
|
ImVector<LinkInfo> m_Links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
|
||||||
|
int m_NextLinkId = 100; // Counter to help generate link ids. In real application this will probably based on pointer to user data structure.
|
||||||
|
};
|
||||||
|
|
||||||
|
int Main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
Example exampe("Widgets", argc, argv);
|
||||||
|
|
||||||
|
if (exampe.Create())
|
||||||
|
return exampe.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
project(ScopeGuard)
|
||||||
|
|
||||||
|
add_library(ScopeGuard INTERFACE)
|
||||||
|
|
||||||
|
set(_ScopeGuard_Sources
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ScopeGuard.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(ScopeGuard INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_sources(ScopeGuard INTERFACE ${_ScopeGuard_Sources})
|
||||||
|
|
||||||
|
source_group("ThirdParty\\ScopeGuard" FILES ${_ScopeGuard_Sources})
|
|
@ -0,0 +1,42 @@
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
# include <utility>
|
||||||
|
|
||||||
|
# define AX_CONCATENATE_IMPL(s1, s2) s1##s2
|
||||||
|
# define AX_CONCATENATE(s1, s2) AX_CONCATENATE_IMPL(s1, s2)
|
||||||
|
# ifdef __COUNTER__
|
||||||
|
# define AX_ANONYMOUS_VARIABLE(str) AX_CONCATENATE(str, __COUNTER__)
|
||||||
|
# else
|
||||||
|
# define AX_ANONYMOUS_VARIABLE(str) AX_CONCATENATE(str, __LINE__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
namespace ax {
|
||||||
|
namespace scopeguard_detail {
|
||||||
|
|
||||||
|
enum class ScopeGuardOnExit {};
|
||||||
|
template <typename F>
|
||||||
|
class ScopeGuard
|
||||||
|
{
|
||||||
|
F f_;
|
||||||
|
bool active_;
|
||||||
|
public:
|
||||||
|
ScopeGuard() = delete;
|
||||||
|
ScopeGuard(const ScopeGuard&) = delete;
|
||||||
|
ScopeGuard& operator=(const ScopeGuard&) = delete;
|
||||||
|
ScopeGuard(ScopeGuard&& rhs): f_(std::move(rhs.f_)), active_(rhs.active_) { rhs.dismiss(); }
|
||||||
|
ScopeGuard(F f): f_(std::move(f)), active_(true) {}
|
||||||
|
~ScopeGuard() { if (active_) f_(); }
|
||||||
|
void dismiss() { active_ = false; }
|
||||||
|
};
|
||||||
|
template <typename F>
|
||||||
|
inline ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f)
|
||||||
|
{
|
||||||
|
return ScopeGuard<F>(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace scopeguard_detail
|
||||||
|
} // namespace ax
|
||||||
|
|
||||||
|
# define AX_SCOPE_EXIT \
|
||||||
|
auto AX_ANONYMOUS_VARIABLE(AX_SCOPE_EXIT_STATE) \
|
||||||
|
= ::ax::scopeguard_detail::ScopeGuardOnExit() + [&]()
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
set(_gl3w_Sources
|
||||||
|
Include/GL/gl3w.h
|
||||||
|
Include/GL/glcorearb.h
|
||||||
|
Source/gl3w.c
|
||||||
|
)
|
||||||
|
|
||||||
|
source_group("" FILES ${_gl3w_Sources})
|
||||||
|
|
||||||
|
add_library(gl3w STATIC ${_gl3w_Sources})
|
||||||
|
|
||||||
|
target_include_directories(gl3w PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Include)
|
||||||
|
|
||||||
|
if (UNIX AND (NOT APPLE))
|
||||||
|
# Linux: GL is required to pull glXGetProcAddress
|
||||||
|
target_link_libraries(gl3w PRIVATE GL dl)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_property(TARGET gl3w PROPERTY FOLDER "external")
|
0
3rdparty/imgui/examples/libs/gl3w/GL/gl3w.h → 3rdparty/imgui-node-editor/external/gl3w/Include/GL/gl3w.h
vendored
Normal file → Executable file
0
3rdparty/imgui/examples/libs/gl3w/GL/gl3w.h → 3rdparty/imgui-node-editor/external/gl3w/Include/GL/gl3w.h
vendored
Normal file → Executable file
0
3rdparty/imgui/examples/libs/gl3w/GL/glcorearb.h → 3rdparty/imgui-node-editor/external/gl3w/Include/GL/glcorearb.h
vendored
Normal file → Executable file
0
3rdparty/imgui/examples/libs/gl3w/GL/glcorearb.h → 3rdparty/imgui-node-editor/external/gl3w/Include/GL/glcorearb.h
vendored
Normal file → Executable file
0
3rdparty/imgui/examples/libs/gl3w/GL/gl3w.c → 3rdparty/imgui-node-editor/external/gl3w/Source/gl3w.c
vendored
Normal file → Executable file
0
3rdparty/imgui/examples/libs/gl3w/GL/gl3w.c → 3rdparty/imgui-node-editor/external/gl3w/Source/gl3w.c
vendored
Normal file → Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
project(stb_image)
|
||||||
|
|
||||||
|
add_library(stb_image INTERFACE)
|
||||||
|
|
||||||
|
set(_stb_image_Sources
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/stb_image.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(stb_image INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_sources(stb_image INTERFACE ${_stb_image_Sources})
|
||||||
|
|
||||||
|
source_group("ThirdParty\\stb_image" FILES ${_stb_image_Sources})
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,144 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// VERSION 0.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# ifndef __IMGUI_BEZIER_MATH_H__
|
||||||
|
# define __IMGUI_BEZIER_MATH_H__
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include "imgui_extra_math.h"
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
struct ImCubicBezierPointsT
|
||||||
|
{
|
||||||
|
T P0;
|
||||||
|
T P1;
|
||||||
|
T P2;
|
||||||
|
T P3;
|
||||||
|
};
|
||||||
|
using ImCubicBezierPoints = ImCubicBezierPointsT<ImVec2>;
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Low-level Bezier curve sampling.
|
||||||
|
template <typename T> inline T ImLinearBezier(const T& p0, const T& p1, float t);
|
||||||
|
template <typename T> inline T ImLinearBezierDt(const T& p0, const T& p1, float t);
|
||||||
|
template <typename T> inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t);
|
||||||
|
template <typename T> inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t);
|
||||||
|
template <typename T> inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||||
|
template <typename T> inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||||
|
|
||||||
|
|
||||||
|
// High-level Bezier sampling, automatically collapse to lower level Bezier curves if control points overlap.
|
||||||
|
template <typename T> inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||||
|
template <typename T> inline T ImCubicBezierSample(const ImCubicBezierPointsT<T>& curve, float t);
|
||||||
|
template <typename T> inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||||
|
template <typename T> inline T ImCubicBezierTangent(const ImCubicBezierPointsT<T>& curve, float t);
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate approximate length of Cubic Bezier curve.
|
||||||
|
template <typename T> inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3);
|
||||||
|
template <typename T> inline float ImCubicBezierLength(const ImCubicBezierPointsT<T>& curve);
|
||||||
|
|
||||||
|
|
||||||
|
// Splits Cubic Bezier curve into two curves.
|
||||||
|
template <typename T>
|
||||||
|
struct ImCubicBezierSplitResultT
|
||||||
|
{
|
||||||
|
ImCubicBezierPointsT<T> Left;
|
||||||
|
ImCubicBezierPointsT<T> Right;
|
||||||
|
};
|
||||||
|
using ImCubicBezierSplitResult = ImCubicBezierSplitResultT<ImVec2>;
|
||||||
|
|
||||||
|
template <typename T> inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||||
|
template <typename T> inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const ImCubicBezierPointsT<T>& curve, float t);
|
||||||
|
|
||||||
|
|
||||||
|
// Returns bounding rectangle of Cubic Bezier curve.
|
||||||
|
inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3);
|
||||||
|
inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve);
|
||||||
|
|
||||||
|
|
||||||
|
// Project point on Cubic Bezier curve.
|
||||||
|
struct ImProjectResult
|
||||||
|
{
|
||||||
|
ImVec2 Point; // Point on curve
|
||||||
|
float Time; // [0 - 1]
|
||||||
|
float Distance; // Distance to curve
|
||||||
|
};
|
||||||
|
|
||||||
|
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions = 100);
|
||||||
|
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions = 100);
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate intersection between line and a Cubic Bezier curve.
|
||||||
|
struct ImCubicBezierIntersectResult
|
||||||
|
{
|
||||||
|
int Count;
|
||||||
|
ImVec2 Points[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1);
|
||||||
|
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line);
|
||||||
|
|
||||||
|
|
||||||
|
// Adaptive Cubic Bezier subdivision.
|
||||||
|
enum ImCubicBezierSubdivideFlags
|
||||||
|
{
|
||||||
|
ImCubicBezierSubdivide_None = 0,
|
||||||
|
ImCubicBezierSubdivide_SkipFirst = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImCubicBezierSubdivideSample
|
||||||
|
{
|
||||||
|
ImVec2 Point;
|
||||||
|
ImVec2 Tangent;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ImCubicBezierSubdivideCallback = void (*)(const ImCubicBezierSubdivideSample& p, void* user_pointer);
|
||||||
|
|
||||||
|
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
|
||||||
|
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
|
||||||
|
|
||||||
|
|
||||||
|
// F has signature void(const ImCubicBezierSubdivideSample& p)
|
||||||
|
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
|
||||||
|
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
|
||||||
|
|
||||||
|
// Fixed step Cubic Bezier subdivision.
|
||||||
|
struct ImCubicBezierFixedStepSample
|
||||||
|
{
|
||||||
|
float T;
|
||||||
|
float Length;
|
||||||
|
ImVec2 Point;
|
||||||
|
bool BreakSearch;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ImCubicBezierFixedStepCallback = void (*)(ImCubicBezierFixedStepSample& sample, void* user_pointer);
|
||||||
|
|
||||||
|
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
|
||||||
|
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
|
||||||
|
|
||||||
|
|
||||||
|
// F has signature void(const ImCubicBezierFixedStepSample& p)
|
||||||
|
template <typename F> inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
|
||||||
|
template <typename F> inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include "imgui_bezier_math.inl"
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# endif // __IMGUI_BEZIER_MATH_H__
|
|
@ -0,0 +1,675 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// VERSION 0.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# ifndef __IMGUI_BEZIER_MATH_INL__
|
||||||
|
# define __IMGUI_BEZIER_MATH_INL__
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include "imgui_bezier_math.h"
|
||||||
|
# include <map> // used in ImCubicBezierFixedStep
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
inline T ImLinearBezier(const T& p0, const T& p1, float t)
|
||||||
|
{
|
||||||
|
return p0 + t * (p1 - p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImLinearBezierDt(const T& p0, const T& p1, float t)
|
||||||
|
{
|
||||||
|
IM_UNUSED(t);
|
||||||
|
|
||||||
|
return p1 - p0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t)
|
||||||
|
{
|
||||||
|
const auto a = 1 - t;
|
||||||
|
|
||||||
|
return a * a * p0 + 2 * t * a * p1 + t * t * p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t)
|
||||||
|
{
|
||||||
|
return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||||
|
{
|
||||||
|
const auto a = 1 - t;
|
||||||
|
const auto b = a * a * a;
|
||||||
|
const auto c = t * t * t;
|
||||||
|
|
||||||
|
return b * p0 + 3 * t * a * a * p1 + 3 * t * t * a * p2 + c * p3;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||||
|
{
|
||||||
|
const auto a = 1 - t;
|
||||||
|
const auto b = a * a;
|
||||||
|
const auto c = t * t;
|
||||||
|
const auto d = 2 * t * a;
|
||||||
|
|
||||||
|
return -3 * p0 * b + 3 * p1 * (b - d) + 3 * p2 * (d - c) + 3 * p3 * c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||||
|
{
|
||||||
|
const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f;
|
||||||
|
const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f;
|
||||||
|
|
||||||
|
if (cp0_zero && cp1_zero)
|
||||||
|
return ImLinearBezier(p0, p3, t);
|
||||||
|
else if (cp0_zero)
|
||||||
|
return ImQuadraticBezier(p0, p2, p3, t);
|
||||||
|
else if (cp1_zero)
|
||||||
|
return ImQuadraticBezier(p0, p1, p3, t);
|
||||||
|
else
|
||||||
|
return ImCubicBezier(p0, p1, p2, p3, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImCubicBezierSample(const ImCubicBezierPointsT<T>& curve, float t)
|
||||||
|
{
|
||||||
|
return ImCubicBezierSample(curve.P0, curve.P1, curve.P2, curve.P3, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||||
|
{
|
||||||
|
const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f;
|
||||||
|
const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f;
|
||||||
|
|
||||||
|
if (cp0_zero && cp1_zero)
|
||||||
|
return ImLinearBezierDt(p0, p3, t);
|
||||||
|
else if (cp0_zero)
|
||||||
|
return ImQuadraticBezierDt(p0, p2, p3, t);
|
||||||
|
else if (cp1_zero)
|
||||||
|
return ImQuadraticBezierDt(p0, p1, p3, t);
|
||||||
|
else
|
||||||
|
return ImCubicBezierDt(p0, p1, p2, p3, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T ImCubicBezierTangent(const ImCubicBezierPointsT<T>& curve, float t)
|
||||||
|
{
|
||||||
|
return ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3)
|
||||||
|
{
|
||||||
|
// Legendre-Gauss abscissae with n=24 (x_i values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x))
|
||||||
|
static const float t_values[] =
|
||||||
|
{
|
||||||
|
-0.0640568928626056260850430826247450385909f,
|
||||||
|
0.0640568928626056260850430826247450385909f,
|
||||||
|
-0.1911188674736163091586398207570696318404f,
|
||||||
|
0.1911188674736163091586398207570696318404f,
|
||||||
|
-0.3150426796961633743867932913198102407864f,
|
||||||
|
0.3150426796961633743867932913198102407864f,
|
||||||
|
-0.4337935076260451384870842319133497124524f,
|
||||||
|
0.4337935076260451384870842319133497124524f,
|
||||||
|
-0.5454214713888395356583756172183723700107f,
|
||||||
|
0.5454214713888395356583756172183723700107f,
|
||||||
|
-0.6480936519369755692524957869107476266696f,
|
||||||
|
0.6480936519369755692524957869107476266696f,
|
||||||
|
-0.7401241915785543642438281030999784255232f,
|
||||||
|
0.7401241915785543642438281030999784255232f,
|
||||||
|
-0.8200019859739029219539498726697452080761f,
|
||||||
|
0.8200019859739029219539498726697452080761f,
|
||||||
|
-0.8864155270044010342131543419821967550873f,
|
||||||
|
0.8864155270044010342131543419821967550873f,
|
||||||
|
-0.9382745520027327585236490017087214496548f,
|
||||||
|
0.9382745520027327585236490017087214496548f,
|
||||||
|
-0.9747285559713094981983919930081690617411f,
|
||||||
|
0.9747285559713094981983919930081690617411f,
|
||||||
|
-0.9951872199970213601799974097007368118745f,
|
||||||
|
0.9951872199970213601799974097007368118745f
|
||||||
|
};
|
||||||
|
|
||||||
|
// Legendre-Gauss weights with n=24 (w_i values, defined by a function linked to in the Bezier primer article)
|
||||||
|
static const float c_values[] =
|
||||||
|
{
|
||||||
|
0.1279381953467521569740561652246953718517f,
|
||||||
|
0.1279381953467521569740561652246953718517f,
|
||||||
|
0.1258374563468282961213753825111836887264f,
|
||||||
|
0.1258374563468282961213753825111836887264f,
|
||||||
|
0.1216704729278033912044631534762624256070f,
|
||||||
|
0.1216704729278033912044631534762624256070f,
|
||||||
|
0.1155056680537256013533444839067835598622f,
|
||||||
|
0.1155056680537256013533444839067835598622f,
|
||||||
|
0.1074442701159656347825773424466062227946f,
|
||||||
|
0.1074442701159656347825773424466062227946f,
|
||||||
|
0.0976186521041138882698806644642471544279f,
|
||||||
|
0.0976186521041138882698806644642471544279f,
|
||||||
|
0.0861901615319532759171852029837426671850f,
|
||||||
|
0.0861901615319532759171852029837426671850f,
|
||||||
|
0.0733464814110803057340336152531165181193f,
|
||||||
|
0.0733464814110803057340336152531165181193f,
|
||||||
|
0.0592985849154367807463677585001085845412f,
|
||||||
|
0.0592985849154367807463677585001085845412f,
|
||||||
|
0.0442774388174198061686027482113382288593f,
|
||||||
|
0.0442774388174198061686027482113382288593f,
|
||||||
|
0.0285313886289336631813078159518782864491f,
|
||||||
|
0.0285313886289336631813078159518782864491f,
|
||||||
|
0.0123412297999871995468056670700372915759f,
|
||||||
|
0.0123412297999871995468056670700372915759f
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(t_values) / sizeof(*t_values) == sizeof(c_values) / sizeof(*c_values), "");
|
||||||
|
|
||||||
|
auto arc = [p0, p1, p2, p3](float t)
|
||||||
|
{
|
||||||
|
const auto p = ImCubicBezierDt(p0, p1, p2, p3, t);
|
||||||
|
const auto l = ImLength(p);
|
||||||
|
return l;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto z = 0.5f;
|
||||||
|
const auto n = sizeof(t_values) / sizeof(*t_values);
|
||||||
|
|
||||||
|
auto accumulator = 0.0f;
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
const auto t = z * t_values[i] + z;
|
||||||
|
accumulator += c_values[i] * arc(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return z * accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline float ImCubicBezierLength(const ImCubicBezierPointsT<T>& curve)
|
||||||
|
{
|
||||||
|
return ImCubicBezierLength(curve.P0, curve.P1, curve.P2, curve.P3);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||||
|
{
|
||||||
|
const auto z1 = t;
|
||||||
|
const auto z2 = z1 * z1;
|
||||||
|
const auto z3 = z1 * z1 * z1;
|
||||||
|
const auto s1 = z1 - 1;
|
||||||
|
const auto s2 = s1 * s1;
|
||||||
|
const auto s3 = s1 * s1 * s1;
|
||||||
|
|
||||||
|
return ImCubicBezierSplitResultT<T>
|
||||||
|
{
|
||||||
|
ImCubicBezierPointsT<T>
|
||||||
|
{
|
||||||
|
p0,
|
||||||
|
z1 * p1 - s1 * p0,
|
||||||
|
z2 * p2 - 2 * z1 * s1 * p1 + s2 * p0,
|
||||||
|
z3 * p3 - 3 * z2 * s1 * p2 + 3 * z1 * s2 * p1 - s3 * p0
|
||||||
|
},
|
||||||
|
ImCubicBezierPointsT<T>
|
||||||
|
{
|
||||||
|
z3 * p0 - 3 * z2 * s1 * p1 + 3 * z1 * s2 * p2 - s3 * p3,
|
||||||
|
z2 * p1 - 2 * z1 * s1 * p2 + s2 * p3,
|
||||||
|
z1 * p2 - s1 * p3,
|
||||||
|
p3,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const ImCubicBezierPointsT<T>& curve, float t)
|
||||||
|
{
|
||||||
|
return ImCubicBezierSplit(curve.P0, curve.P1, curve.P2, curve.P3, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3)
|
||||||
|
{
|
||||||
|
auto a = 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0;
|
||||||
|
auto b = 6 * p0 - 12 * p1 + 6 * p2;
|
||||||
|
auto c = 3 * p1 - 3 * p0;
|
||||||
|
auto delta_squared = ImMul(b, b) - 4 * ImMul(a, c);
|
||||||
|
|
||||||
|
auto tl = ImMin(p0, p3);
|
||||||
|
auto rb = ImMax(p0, p3);
|
||||||
|
|
||||||
|
# define IM_VEC2_INDEX(v, i) *(&v.x + i)
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
if (IM_VEC2_INDEX(a, i) == 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (IM_VEC2_INDEX(delta_squared, i) >= 0)
|
||||||
|
{
|
||||||
|
auto delta = ImSqrt(IM_VEC2_INDEX(delta_squared, i));
|
||||||
|
|
||||||
|
auto t0 = (-IM_VEC2_INDEX(b, i) + delta) / (2 * IM_VEC2_INDEX(a, i));
|
||||||
|
if (t0 > 0 && t0 < 1)
|
||||||
|
{
|
||||||
|
auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t0);
|
||||||
|
IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p);
|
||||||
|
IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto t1 = (-IM_VEC2_INDEX(b, i) - delta) / (2 * IM_VEC2_INDEX(a, i));
|
||||||
|
if (t1 > 0 && t1 < 1)
|
||||||
|
{
|
||||||
|
auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t1);
|
||||||
|
IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p);
|
||||||
|
IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# undef IM_VEC2_INDEX
|
||||||
|
|
||||||
|
return ImRect(tl, rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve)
|
||||||
|
{
|
||||||
|
return ImCubicBezierBoundingRect(curve.P0, curve.P1, curve.P2, curve.P3);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& point, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions)
|
||||||
|
{
|
||||||
|
// http://pomax.github.io/bezierinfo/#projections
|
||||||
|
|
||||||
|
const float epsilon = 1e-5f;
|
||||||
|
const float fixed_step = 1.0f / static_cast<float>(subdivisions - 1);
|
||||||
|
|
||||||
|
ImProjectResult result;
|
||||||
|
result.Point = point;
|
||||||
|
result.Time = 0.0f;
|
||||||
|
result.Distance = FLT_MAX;
|
||||||
|
|
||||||
|
// Step 1: Coarse check
|
||||||
|
for (int i = 0; i < subdivisions; ++i)
|
||||||
|
{
|
||||||
|
auto t = i * fixed_step;
|
||||||
|
auto p = ImCubicBezier(p0, p1, p2, p3, t);
|
||||||
|
auto s = point - p;
|
||||||
|
auto d = ImDot(s, s);
|
||||||
|
|
||||||
|
if (d < result.Distance)
|
||||||
|
{
|
||||||
|
result.Point = p;
|
||||||
|
result.Time = t;
|
||||||
|
result.Distance = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Time == 0.0f || ImFabs(result.Time - 1.0f) <= epsilon)
|
||||||
|
{
|
||||||
|
result.Distance = ImSqrt(result.Distance);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Fine check
|
||||||
|
auto left = result.Time - fixed_step;
|
||||||
|
auto right = result.Time + fixed_step;
|
||||||
|
auto step = fixed_step * 0.1f;
|
||||||
|
|
||||||
|
for (auto t = left; t < right + step; t += step)
|
||||||
|
{
|
||||||
|
auto p = ImCubicBezier(p0, p1, p2, p3, t);
|
||||||
|
auto s = point - p;
|
||||||
|
auto d = ImDot(s, s);
|
||||||
|
|
||||||
|
if (d < result.Distance)
|
||||||
|
{
|
||||||
|
result.Point = p;
|
||||||
|
result.Time = t;
|
||||||
|
result.Distance = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Distance = ImSqrt(result.Distance);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions)
|
||||||
|
{
|
||||||
|
return ImProjectOnCubicBezier(p, curve.P0, curve.P1, curve.P2, curve.P3, subdivisions);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1)
|
||||||
|
{
|
||||||
|
auto cubic_roots = [](float a, float b, float c, float d, float* roots) -> int
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
auto sign = [](float x) -> float { return x < 0 ? -1.0f : 1.0f; };
|
||||||
|
|
||||||
|
auto A = b / a;
|
||||||
|
auto B = c / a;
|
||||||
|
auto C = d / a;
|
||||||
|
|
||||||
|
auto Q = (3 * B - ImPow(A, 2)) / 9;
|
||||||
|
auto R = (9 * A * B - 27 * C - 2 * ImPow(A, 3)) / 54;
|
||||||
|
auto D = ImPow(Q, 3) + ImPow(R, 2); // polynomial discriminant
|
||||||
|
|
||||||
|
if (D >= 0) // complex or duplicate roots
|
||||||
|
{
|
||||||
|
auto S = sign(R + ImSqrt(D)) * ImPow(ImFabs(R + ImSqrt(D)), (1.0f / 3.0f));
|
||||||
|
auto T = sign(R - ImSqrt(D)) * ImPow(ImFabs(R - ImSqrt(D)), (1.0f / 3.0f));
|
||||||
|
|
||||||
|
roots[0] = -A / 3 + (S + T); // real root
|
||||||
|
roots[1] = -A / 3 - (S + T) / 2; // real part of complex root
|
||||||
|
roots[2] = -A / 3 - (S + T) / 2; // real part of complex root
|
||||||
|
auto Im = ImFabs(ImSqrt(3) * (S - T) / 2); // complex part of root pair
|
||||||
|
|
||||||
|
// discard complex roots
|
||||||
|
if (Im != 0)
|
||||||
|
count = 1;
|
||||||
|
else
|
||||||
|
count = 3;
|
||||||
|
}
|
||||||
|
else // distinct real roots
|
||||||
|
{
|
||||||
|
auto th = ImAcos(R / ImSqrt(-ImPow(Q, 3)));
|
||||||
|
|
||||||
|
roots[0] = 2 * ImSqrt(-Q) * ImCos(th / 3) - A / 3;
|
||||||
|
roots[1] = 2 * ImSqrt(-Q) * ImCos((th + 2 * IM_PI) / 3) - A / 3;
|
||||||
|
roots[2] = 2 * ImSqrt(-Q) * ImCos((th + 4 * IM_PI) / 3) - A / 3;
|
||||||
|
|
||||||
|
count = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/kaishiqi/Geometric-Bezier/blob/master/GeometricBezier/src/kaishiqi/geometric/intersection/Intersection.as
|
||||||
|
//
|
||||||
|
// Start with Bezier using Bernstein polynomials for weighting functions:
|
||||||
|
// (1-t^3)P0 + 3t(1-t)^2P1 + 3t^2(1-t)P2 + t^3P3
|
||||||
|
//
|
||||||
|
// Expand and collect terms to form linear combinations of original Bezier
|
||||||
|
// controls. This ends up with a vector cubic in t:
|
||||||
|
// (-P0+3P1-3P2+P3)t^3 + (3P0-6P1+3P2)t^2 + (-3P0+3P1)t + P0
|
||||||
|
// /\ /\ /\ /\
|
||||||
|
// || || || ||
|
||||||
|
// c3 c2 c1 c0
|
||||||
|
|
||||||
|
// Calculate the coefficients
|
||||||
|
auto c3 = -p0 + 3 * p1 - 3 * p2 + p3;
|
||||||
|
auto c2 = 3 * p0 - 6 * p1 + 3 * p2;
|
||||||
|
auto c1 = -3 * p0 + 3 * p1;
|
||||||
|
auto c0 = p0;
|
||||||
|
|
||||||
|
// Convert line to normal form: ax + by + c = 0
|
||||||
|
auto a = a1.y - a0.y;
|
||||||
|
auto b = a0.x - a1.x;
|
||||||
|
auto c = a0.x * (a0.y - a1.y) + a0.y * (a1.x - a0.x);
|
||||||
|
|
||||||
|
// Rotate each cubic coefficient using line for new coordinate system?
|
||||||
|
// Find roots of rotated cubic
|
||||||
|
float roots[3];
|
||||||
|
auto rootCount = cubic_roots(
|
||||||
|
a * c3.x + b * c3.y,
|
||||||
|
a * c2.x + b * c2.y,
|
||||||
|
a * c1.x + b * c1.y,
|
||||||
|
a * c0.x + b * c0.y + c,
|
||||||
|
roots);
|
||||||
|
|
||||||
|
// Any roots in closed interval [0,1] are intersections on Bezier, but
|
||||||
|
// might not be on the line segment.
|
||||||
|
// Find intersections and calculate point coordinates
|
||||||
|
|
||||||
|
auto min = ImMin(a0, a1);
|
||||||
|
auto max = ImMax(a0, a1);
|
||||||
|
|
||||||
|
ImCubicBezierIntersectResult result;
|
||||||
|
auto points = result.Points;
|
||||||
|
|
||||||
|
for (int i = 0; i < rootCount; ++i)
|
||||||
|
{
|
||||||
|
auto root = roots[i];
|
||||||
|
|
||||||
|
if (0 <= root && root <= 1)
|
||||||
|
{
|
||||||
|
// We're within the Bezier curve
|
||||||
|
// Find point on Bezier
|
||||||
|
auto p = ImCubicBezier(p0, p1, p2, p3, root);
|
||||||
|
|
||||||
|
// See if point is on line segment
|
||||||
|
// Had to make special cases for vertical and horizontal lines due
|
||||||
|
// to slight errors in calculation of p00
|
||||||
|
if (a0.x == a1.x)
|
||||||
|
{
|
||||||
|
if (min.y <= p.y && p.y <= max.y)
|
||||||
|
*points++ = p;
|
||||||
|
}
|
||||||
|
else if (a0.y == a1.y)
|
||||||
|
{
|
||||||
|
if (min.x <= p.x && p.x <= max.x)
|
||||||
|
*points++ = p;
|
||||||
|
}
|
||||||
|
else if (p.x >= min.x && p.y >= min.y && p.x <= max.x && p.y <= max.y)
|
||||||
|
{
|
||||||
|
*points++ = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Count = static_cast<int>(points - result.Points);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line)
|
||||||
|
{
|
||||||
|
return ImCubicBezierLineIntersect(curve.P0, curve.P1, curve.P2, curve.P3, line.A, line.B);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags)
|
||||||
|
{
|
||||||
|
return ImCubicBezierSubdivide(callback, user_pointer, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags)
|
||||||
|
{
|
||||||
|
struct Tesselator
|
||||||
|
{
|
||||||
|
ImCubicBezierSubdivideCallback Callback;
|
||||||
|
void* UserPointer;
|
||||||
|
float TesselationTollerance;
|
||||||
|
ImCubicBezierSubdivideFlags Flags;
|
||||||
|
|
||||||
|
void Commit(const ImVec2& p, const ImVec2& t)
|
||||||
|
{
|
||||||
|
ImCubicBezierSubdivideSample sample;
|
||||||
|
sample.Point = p;
|
||||||
|
sample.Tangent = t;
|
||||||
|
Callback(sample, UserPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Subdivide(const ImCubicBezierPoints& curve, int level = 0)
|
||||||
|
{
|
||||||
|
float dx = curve.P3.x - curve.P0.x;
|
||||||
|
float dy = curve.P3.y - curve.P0.y;
|
||||||
|
float d2 = ((curve.P1.x - curve.P3.x) * dy - (curve.P1.y - curve.P3.y) * dx);
|
||||||
|
float d3 = ((curve.P2.x - curve.P3.x) * dy - (curve.P2.y - curve.P3.y) * dx);
|
||||||
|
d2 = (d2 >= 0) ? d2 : -d2;
|
||||||
|
d3 = (d3 >= 0) ? d3 : -d3;
|
||||||
|
if ((d2 + d3) * (d2 + d3) < TesselationTollerance * (dx * dx + dy * dy))
|
||||||
|
{
|
||||||
|
Commit(curve.P3, ImCubicBezierTangent(curve, 1.0f));
|
||||||
|
}
|
||||||
|
else if (level < 10)
|
||||||
|
{
|
||||||
|
const auto p12 = (curve.P0 + curve.P1) * 0.5f;
|
||||||
|
const auto p23 = (curve.P1 + curve.P2) * 0.5f;
|
||||||
|
const auto p34 = (curve.P2 + curve.P3) * 0.5f;
|
||||||
|
const auto p123 = (p12 + p23) * 0.5f;
|
||||||
|
const auto p234 = (p23 + p34) * 0.5f;
|
||||||
|
const auto p1234 = (p123 + p234) * 0.5f;
|
||||||
|
|
||||||
|
Subdivide(ImCubicBezierPoints { curve.P0, p12, p123, p1234 }, level + 1);
|
||||||
|
Subdivide(ImCubicBezierPoints { p1234, p234, p34, curve.P3 }, level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tess_tol < 0)
|
||||||
|
tess_tol = 1.118f; // sqrtf(1.25f)
|
||||||
|
|
||||||
|
Tesselator tesselator;
|
||||||
|
tesselator.Callback = callback;
|
||||||
|
tesselator.UserPointer = user_pointer;
|
||||||
|
tesselator.TesselationTollerance = tess_tol * tess_tol;
|
||||||
|
tesselator.Flags = flags;
|
||||||
|
|
||||||
|
if (!(tesselator.Flags & ImCubicBezierSubdivide_SkipFirst))
|
||||||
|
tesselator.Commit(curve.P0, ImCubicBezierTangent(curve, 0.0f));
|
||||||
|
|
||||||
|
tesselator.Subdivide(curve, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags)
|
||||||
|
{
|
||||||
|
auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer)
|
||||||
|
{
|
||||||
|
auto& callback = *reinterpret_cast<F*>(user_pointer);
|
||||||
|
callback(p);
|
||||||
|
};
|
||||||
|
|
||||||
|
ImCubicBezierSubdivide(handler, &callback, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags)
|
||||||
|
{
|
||||||
|
auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer)
|
||||||
|
{
|
||||||
|
auto& callback = *reinterpret_cast<F*>(user_pointer);
|
||||||
|
callback(p);
|
||||||
|
};
|
||||||
|
|
||||||
|
ImCubicBezierSubdivide(handler, &callback, curve, tess_tol, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error)
|
||||||
|
{
|
||||||
|
if (step <= 0.0f || !callback || max_value_error <= 0 || max_t_error <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImCubicBezierFixedStepSample sample;
|
||||||
|
sample.T = 0.0f;
|
||||||
|
sample.Length = 0.0f;
|
||||||
|
sample.Point = p0;
|
||||||
|
sample.BreakSearch = false;
|
||||||
|
|
||||||
|
callback(sample, user_pointer);
|
||||||
|
if (sample.BreakSearch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto total_length = ImCubicBezierLength(p0, p1, p2, p3);
|
||||||
|
const auto point_count = static_cast<int>(total_length / step) + (overshoot ? 2 : 1);
|
||||||
|
const auto t_min = 0.0f;
|
||||||
|
const auto t_max = step * point_count / total_length;
|
||||||
|
const auto t_0 = (t_min + t_max) * 0.5f;
|
||||||
|
|
||||||
|
// #todo: replace map with ImVector + binary search
|
||||||
|
std::map<float, float> cache;
|
||||||
|
for (int point_index = 1; point_index < point_count; ++point_index)
|
||||||
|
{
|
||||||
|
const auto targetLength = point_index * step;
|
||||||
|
|
||||||
|
float t_start = t_min;
|
||||||
|
float t_end = t_max;
|
||||||
|
float t = t_0;
|
||||||
|
|
||||||
|
float t_best = t;
|
||||||
|
float error_best = total_length;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto cacheIt = cache.find(t);
|
||||||
|
if (cacheIt == cache.end())
|
||||||
|
{
|
||||||
|
const auto front = ImCubicBezierSplit(p0, p1, p2, p3, t).Left;
|
||||||
|
const auto split_length = ImCubicBezierLength(front);
|
||||||
|
|
||||||
|
cacheIt = cache.emplace(t, split_length).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto length = cacheIt->second;
|
||||||
|
const auto error = targetLength - length;
|
||||||
|
|
||||||
|
if (error < error_best)
|
||||||
|
{
|
||||||
|
error_best = error;
|
||||||
|
t_best = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImFabs(error) <= max_value_error || ImFabs(t_start - t_end) <= max_t_error)
|
||||||
|
{
|
||||||
|
sample.T = t;
|
||||||
|
sample.Length = length;
|
||||||
|
sample.Point = ImCubicBezier(p0, p1, p2, p3, t);
|
||||||
|
|
||||||
|
callback(sample, user_pointer);
|
||||||
|
if (sample.BreakSearch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (error < 0.0f)
|
||||||
|
t_end = t;
|
||||||
|
else // if (error > 0.0f)
|
||||||
|
t_start = t;
|
||||||
|
|
||||||
|
t = (t_start + t_end) * 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error)
|
||||||
|
{
|
||||||
|
ImCubicBezierFixedStep(callback, user_pointer, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// F has signature void(const ImCubicBezierFixedStepSample& p)
|
||||||
|
template <typename F>
|
||||||
|
inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error)
|
||||||
|
{
|
||||||
|
auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer)
|
||||||
|
{
|
||||||
|
auto& callback = *reinterpret_cast<F*>(user_pointer);
|
||||||
|
callback(sample);
|
||||||
|
};
|
||||||
|
|
||||||
|
ImCubicBezierFixedStep(handler, &callback, p0, p1, p2, p3, step, overshoot, max_value_error, max_t_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error)
|
||||||
|
{
|
||||||
|
auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer)
|
||||||
|
{
|
||||||
|
auto& callback = *reinterpret_cast<F*>(user_pointer);
|
||||||
|
callback(sample);
|
||||||
|
};
|
||||||
|
|
||||||
|
ImCubicBezierFixedStep(handler, &callback, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# endif // __IMGUI_BEZIER_MATH_INL__
|
|
@ -0,0 +1,574 @@
|
||||||
|
# ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
# endif
|
||||||
|
# include "imgui_canvas.h"
|
||||||
|
# include <type_traits>
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/36079786
|
||||||
|
# define DECLARE_HAS_MEMBER(__trait_name__, __member_name__) \
|
||||||
|
\
|
||||||
|
template <typename __boost_has_member_T__> \
|
||||||
|
class __trait_name__ \
|
||||||
|
{ \
|
||||||
|
using check_type = ::std::remove_const_t<__boost_has_member_T__>; \
|
||||||
|
struct no_type {char x[2];}; \
|
||||||
|
using yes_type = char; \
|
||||||
|
\
|
||||||
|
struct base { void __member_name__() {}}; \
|
||||||
|
struct mixin : public base, public check_type {}; \
|
||||||
|
\
|
||||||
|
template <void (base::*)()> struct aux {}; \
|
||||||
|
\
|
||||||
|
template <typename U> static no_type test(aux<&U::__member_name__>*); \
|
||||||
|
template <typename U> static yes_type test(...); \
|
||||||
|
\
|
||||||
|
public: \
|
||||||
|
\
|
||||||
|
static constexpr bool value = (sizeof(yes_type) == sizeof(test<mixin>(0))); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special sentinel value. This needs to be unique, so allow it to be overridden in the user's ImGui config
|
||||||
|
# ifndef ImDrawCallback_ImCanvas
|
||||||
|
# define ImDrawCallback_ImCanvas (ImDrawCallback)(-2)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
namespace ImCanvasDetails {
|
||||||
|
|
||||||
|
DECLARE_HAS_MEMBER(HasFringeScale, _FringeScale);
|
||||||
|
|
||||||
|
struct FringeScaleRef
|
||||||
|
{
|
||||||
|
// Overload is present when ImDrawList does have _FringeScale member variable.
|
||||||
|
template <typename T>
|
||||||
|
static float& Get(typename std::enable_if<HasFringeScale<T>::value, T>::type* drawList)
|
||||||
|
{
|
||||||
|
return drawList->_FringeScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload is present when ImDrawList does not have _FringeScale member variable.
|
||||||
|
template <typename T>
|
||||||
|
static float& Get(typename std::enable_if<!HasFringeScale<T>::value, T>::type*)
|
||||||
|
{
|
||||||
|
static float placeholder = 1.0f;
|
||||||
|
return placeholder;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_HAS_MEMBER(HasVtxCurrentOffset, _VtxCurrentOffset);
|
||||||
|
|
||||||
|
struct VtxCurrentOffsetRef
|
||||||
|
{
|
||||||
|
// Overload is present when ImDrawList does have _FringeScale member variable.
|
||||||
|
template <typename T>
|
||||||
|
static unsigned int& Get(typename std::enable_if<HasVtxCurrentOffset<T>::value, T>::type* drawList)
|
||||||
|
{
|
||||||
|
return drawList->_VtxCurrentOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload is present when ImDrawList does not have _FringeScale member variable.
|
||||||
|
template <typename T>
|
||||||
|
static unsigned int& Get(typename std::enable_if<!HasVtxCurrentOffset<T>::value, T>::type* drawList)
|
||||||
|
{
|
||||||
|
return drawList->_CmdHeader.VtxOffset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ImCanvasDetails
|
||||||
|
|
||||||
|
// Returns a reference to _FringeScale extension to ImDrawList
|
||||||
|
//
|
||||||
|
// If ImDrawList does not have _FringeScale a placeholder is returned.
|
||||||
|
static inline float& ImFringeScaleRef(ImDrawList* drawList)
|
||||||
|
{
|
||||||
|
using namespace ImCanvasDetails;
|
||||||
|
return FringeScaleRef::Get<ImDrawList>(drawList);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int& ImVtxOffsetRef(ImDrawList* drawList)
|
||||||
|
{
|
||||||
|
using namespace ImCanvasDetails;
|
||||||
|
return VtxCurrentOffsetRef::Get<ImDrawList>(drawList);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ImVec2 ImSelectPositive(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x > 0.0f ? lhs.x : rhs.x, lhs.y > 0.0f ? lhs.y : rhs.y); }
|
||||||
|
|
||||||
|
bool ImGuiEx::Canvas::Begin(const char* id, const ImVec2& size)
|
||||||
|
{
|
||||||
|
return Begin(ImGui::GetID(id), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiEx::Canvas::Begin(ImGuiID id, const ImVec2& size)
|
||||||
|
{
|
||||||
|
IM_ASSERT(m_InBeginEnd == false);
|
||||||
|
|
||||||
|
m_WidgetPosition = ImGui::GetCursorScreenPos();
|
||||||
|
m_WidgetSize = ImSelectPositive(size, ImGui::GetContentRegionAvail());
|
||||||
|
m_WidgetRect = ImRect(m_WidgetPosition, m_WidgetPosition + m_WidgetSize);
|
||||||
|
m_DrawList = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
|
UpdateViewTransformPosition();
|
||||||
|
|
||||||
|
# if IMGUI_VERSION_NUM > 18415
|
||||||
|
if (ImGui::IsClippedEx(m_WidgetRect, id))
|
||||||
|
return false;
|
||||||
|
# else
|
||||||
|
if (ImGui::IsClippedEx(m_WidgetRect, id, false))
|
||||||
|
return false;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Save current channel, so we can assert when user
|
||||||
|
// call canvas API with different one.
|
||||||
|
m_ExpectedChannel = m_DrawList->_Splitter._Current;
|
||||||
|
|
||||||
|
// #debug: Canvas content.
|
||||||
|
//m_DrawList->AddRectFilled(m_StartPos, m_StartPos + m_CurrentSize, IM_COL32(0, 0, 0, 64));
|
||||||
|
//m_DrawList->AddRect(m_WidgetRect.Min, m_WidgetRect.Max, IM_COL32(255, 0, 255, 64));
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos(ImVec2(0.0f, 0.0f));
|
||||||
|
|
||||||
|
# if IMGUI_EX_CANVAS_DEFERED()
|
||||||
|
m_Ranges.resize(0);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
SaveInputState();
|
||||||
|
SaveViewportState();
|
||||||
|
|
||||||
|
// Record cursor max to prevent scrollbars from appearing.
|
||||||
|
m_WindowCursorMaxBackup = ImGui::GetCurrentWindow()->DC.CursorMaxPos;
|
||||||
|
|
||||||
|
EnterLocalSpace();
|
||||||
|
|
||||||
|
# if IMGUI_VERSION_NUM >= 18967
|
||||||
|
ImGui::SetNextItemAllowOverlap();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Emit dummy widget matching bounds of the canvas.
|
||||||
|
ImGui::SetCursorScreenPos(m_ViewRect.Min);
|
||||||
|
ImGui::Dummy(m_ViewRect.GetSize());
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos(ImVec2(0.0f, 0.0f));
|
||||||
|
|
||||||
|
m_InBeginEnd = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::End()
|
||||||
|
{
|
||||||
|
// If you're here your call to Begin() returned false,
|
||||||
|
// or Begin() wasn't called at all.
|
||||||
|
IM_ASSERT(m_InBeginEnd == true);
|
||||||
|
|
||||||
|
// If you're here, please make sure you do not interleave
|
||||||
|
// channel splitter with canvas.
|
||||||
|
// Always call canvas function with using same channel.
|
||||||
|
IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel);
|
||||||
|
|
||||||
|
//auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Check: Unmatched calls to Suspend() / Resume(). Please check your code.
|
||||||
|
IM_ASSERT(m_SuspendCounter == 0);
|
||||||
|
|
||||||
|
LeaveLocalSpace();
|
||||||
|
|
||||||
|
ImGui::GetCurrentWindow()->DC.CursorMaxPos = m_WindowCursorMaxBackup;
|
||||||
|
|
||||||
|
# if IMGUI_VERSION_NUM < 18967
|
||||||
|
ImGui::SetItemAllowOverlap();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Emit dummy widget matching bounds of the canvas.
|
||||||
|
ImGui::SetCursorScreenPos(m_WidgetPosition);
|
||||||
|
ImGui::Dummy(m_WidgetSize);
|
||||||
|
|
||||||
|
// #debug: Rect around canvas. Content should be inside these bounds.
|
||||||
|
//m_DrawList->AddRect(m_WidgetPosition - ImVec2(1.0f, 1.0f), m_WidgetPosition + m_WidgetSize + ImVec2(1.0f, 1.0f), IM_COL32(196, 0, 0, 255));
|
||||||
|
|
||||||
|
m_InBeginEnd = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::SetView(const ImVec2& origin, float scale)
|
||||||
|
{
|
||||||
|
SetView(CanvasView(origin, scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::SetView(const CanvasView& view)
|
||||||
|
{
|
||||||
|
if (m_InBeginEnd)
|
||||||
|
LeaveLocalSpace();
|
||||||
|
|
||||||
|
if (m_View.Origin.x != view.Origin.x || m_View.Origin.y != view.Origin.y)
|
||||||
|
{
|
||||||
|
m_View.Origin = view.Origin;
|
||||||
|
|
||||||
|
UpdateViewTransformPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_View.Scale != view.Scale)
|
||||||
|
{
|
||||||
|
m_View.Scale = view.Scale;
|
||||||
|
m_View.InvScale = view.InvScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_InBeginEnd)
|
||||||
|
EnterLocalSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::CenterView(const ImVec2& canvasPoint)
|
||||||
|
{
|
||||||
|
auto view = CalcCenterView(canvasPoint);
|
||||||
|
SetView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiEx::CanvasView ImGuiEx::Canvas::CalcCenterView(const ImVec2& canvasPoint) const
|
||||||
|
{
|
||||||
|
auto localCenter = ToLocal(m_WidgetPosition + m_WidgetSize * 0.5f);
|
||||||
|
auto localOffset = canvasPoint - localCenter;
|
||||||
|
auto offset = FromLocalV(localOffset);
|
||||||
|
|
||||||
|
return CanvasView{ m_View.Origin - offset, m_View.Scale };
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::CenterView(const ImRect& canvasRect)
|
||||||
|
{
|
||||||
|
auto view = CalcCenterView(canvasRect);
|
||||||
|
|
||||||
|
SetView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiEx::CanvasView ImGuiEx::Canvas::CalcCenterView(const ImRect& canvasRect) const
|
||||||
|
{
|
||||||
|
auto canvasRectSize = canvasRect.GetSize();
|
||||||
|
|
||||||
|
if (canvasRectSize.x <= 0.0f || canvasRectSize.y <= 0.0f)
|
||||||
|
return View();
|
||||||
|
|
||||||
|
auto widgetAspectRatio = m_WidgetSize.y > 0.0f ? m_WidgetSize.x / m_WidgetSize.y : 0.0f;
|
||||||
|
auto canvasRectAspectRatio = canvasRectSize.y > 0.0f ? canvasRectSize.x / canvasRectSize.y : 0.0f;
|
||||||
|
|
||||||
|
if (widgetAspectRatio <= 0.0f || canvasRectAspectRatio <= 0.0f)
|
||||||
|
return View();
|
||||||
|
|
||||||
|
auto newOrigin = m_View.Origin;
|
||||||
|
auto newScale = m_View.Scale;
|
||||||
|
if (canvasRectAspectRatio > widgetAspectRatio)
|
||||||
|
{
|
||||||
|
// width span across view
|
||||||
|
newScale = m_WidgetSize.x / canvasRectSize.x;
|
||||||
|
newOrigin = canvasRect.Min * -newScale;
|
||||||
|
newOrigin.y += (m_WidgetSize.y - canvasRectSize.y * newScale) * 0.5f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// height span across view
|
||||||
|
newScale = m_WidgetSize.y / canvasRectSize.y;
|
||||||
|
newOrigin = canvasRect.Min * -newScale;
|
||||||
|
newOrigin.x += (m_WidgetSize.x - canvasRectSize.x * newScale) * 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CanvasView{ newOrigin, newScale };
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::Suspend()
|
||||||
|
{
|
||||||
|
// If you're here, please make sure you do not interleave
|
||||||
|
// channel splitter with canvas.
|
||||||
|
// Always call canvas function with using same channel.
|
||||||
|
IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel);
|
||||||
|
|
||||||
|
if (m_SuspendCounter == 0)
|
||||||
|
LeaveLocalSpace();
|
||||||
|
|
||||||
|
++m_SuspendCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::Resume()
|
||||||
|
{
|
||||||
|
// If you're here, please make sure you do not interleave
|
||||||
|
// channel splitter with canvas.
|
||||||
|
// Always call canvas function with using same channel.
|
||||||
|
IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel);
|
||||||
|
|
||||||
|
// Check: Number of calls to Resume() do not match calls to Suspend(). Please check your code.
|
||||||
|
IM_ASSERT(m_SuspendCounter > 0);
|
||||||
|
if (--m_SuspendCounter == 0)
|
||||||
|
EnterLocalSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiEx::Canvas::FromLocal(const ImVec2& point) const
|
||||||
|
{
|
||||||
|
return point * m_View.Scale + m_ViewTransformPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiEx::Canvas::FromLocal(const ImVec2& point, const CanvasView& view) const
|
||||||
|
{
|
||||||
|
return point * view.Scale + view.Origin + m_WidgetPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiEx::Canvas::FromLocalV(const ImVec2& vector) const
|
||||||
|
{
|
||||||
|
return vector * m_View.Scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiEx::Canvas::FromLocalV(const ImVec2& vector, const CanvasView& view) const
|
||||||
|
{
|
||||||
|
return vector * view.Scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiEx::Canvas::ToLocal(const ImVec2& point) const
|
||||||
|
{
|
||||||
|
return (point - m_ViewTransformPosition) * m_View.InvScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiEx::Canvas::ToLocal(const ImVec2& point, const CanvasView& view) const
|
||||||
|
{
|
||||||
|
return (point - view.Origin - m_WidgetPosition) * view.InvScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiEx::Canvas::ToLocalV(const ImVec2& vector) const
|
||||||
|
{
|
||||||
|
return vector * m_View.InvScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiEx::Canvas::ToLocalV(const ImVec2& vector, const CanvasView& view) const
|
||||||
|
{
|
||||||
|
return vector * view.InvScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImRect ImGuiEx::Canvas::CalcViewRect(const CanvasView& view) const
|
||||||
|
{
|
||||||
|
ImRect result;
|
||||||
|
result.Min = ImVec2(-view.Origin.x, -view.Origin.y) * view.InvScale;
|
||||||
|
result.Max = (m_WidgetSize - view.Origin) * view.InvScale;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::UpdateViewTransformPosition()
|
||||||
|
{
|
||||||
|
m_ViewTransformPosition = m_View.Origin + m_WidgetPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::SaveInputState()
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
m_MousePosBackup = io.MousePos;
|
||||||
|
m_MousePosPrevBackup = io.MousePosPrev;
|
||||||
|
for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i)
|
||||||
|
m_MouseClickedPosBackup[i] = io.MouseClickedPos[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::RestoreInputState()
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
io.MousePos = m_MousePosBackup;
|
||||||
|
io.MousePosPrev = m_MousePosPrevBackup;
|
||||||
|
for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i)
|
||||||
|
io.MouseClickedPos[i] = m_MouseClickedPosBackup[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::SaveViewportState()
|
||||||
|
{
|
||||||
|
# if defined(IMGUI_HAS_VIEWPORT)
|
||||||
|
auto window = ImGui::GetCurrentWindow();
|
||||||
|
auto viewport = ImGui::GetWindowViewport();
|
||||||
|
|
||||||
|
m_WindowPosBackup = window->Pos;
|
||||||
|
m_ViewportPosBackup = viewport->Pos;
|
||||||
|
m_ViewportSizeBackup = viewport->Size;
|
||||||
|
# if IMGUI_VERSION_NUM > 18002
|
||||||
|
m_ViewportWorkPosBackup = viewport->WorkPos;
|
||||||
|
m_ViewportWorkSizeBackup = viewport->WorkSize;
|
||||||
|
# else
|
||||||
|
m_ViewportWorkOffsetMinBackup = viewport->WorkOffsetMin;
|
||||||
|
m_ViewportWorkOffsetMaxBackup = viewport->WorkOffsetMax;
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::RestoreViewportState()
|
||||||
|
{
|
||||||
|
# if defined(IMGUI_HAS_VIEWPORT)
|
||||||
|
auto window = ImGui::GetCurrentWindow();
|
||||||
|
auto viewport = ImGui::GetWindowViewport();
|
||||||
|
|
||||||
|
window->Pos = m_WindowPosBackup;
|
||||||
|
viewport->Pos = m_ViewportPosBackup;
|
||||||
|
viewport->Size = m_ViewportSizeBackup;
|
||||||
|
# if IMGUI_VERSION_NUM > 18002
|
||||||
|
viewport->WorkPos = m_ViewportWorkPosBackup;
|
||||||
|
viewport->WorkSize = m_ViewportWorkSizeBackup;
|
||||||
|
# else
|
||||||
|
viewport->WorkOffsetMin = m_ViewportWorkOffsetMinBackup;
|
||||||
|
viewport->WorkOffsetMax = m_ViewportWorkOffsetMaxBackup;
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::EnterLocalSpace()
|
||||||
|
{
|
||||||
|
// Prepare ImDrawList for drawing in local coordinate system:
|
||||||
|
// - determine visible part of the canvas
|
||||||
|
// - start unique draw command
|
||||||
|
// - add clip rect matching canvas size
|
||||||
|
// - record current command index
|
||||||
|
// - record current vertex write index
|
||||||
|
|
||||||
|
// Determine visible part of the canvas. Make it before
|
||||||
|
// adding new command, to avoid round rip where command
|
||||||
|
// is removed in PopClipRect() and added again next PushClipRect().
|
||||||
|
ImGui::PushClipRect(m_WidgetPosition, m_WidgetPosition + m_WidgetSize, true);
|
||||||
|
auto clipped_clip_rect = m_DrawList->_ClipRectStack.back();
|
||||||
|
ImGui::PopClipRect();
|
||||||
|
|
||||||
|
# if IMGUI_EX_CANVAS_DEFERED()
|
||||||
|
m_Ranges.resize(m_Ranges.Size + 1);
|
||||||
|
m_CurrentRange = &m_Ranges.back();
|
||||||
|
m_CurrentRange->BeginComandIndex = ImMax(m_DrawList->CmdBuffer.Size, 0);
|
||||||
|
m_CurrentRange->BeginVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList);
|
||||||
|
# endif
|
||||||
|
m_DrawListCommadBufferSize = ImMax(m_DrawList->CmdBuffer.Size, 0);
|
||||||
|
m_DrawListStartVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList);
|
||||||
|
|
||||||
|
// Make sure we do not share draw command with anyone. We don't want to mess
|
||||||
|
// with someones clip rectangle.
|
||||||
|
|
||||||
|
// #FIXME:
|
||||||
|
// This condition is not enough to avoid when user choose
|
||||||
|
// to use channel splitter.
|
||||||
|
//
|
||||||
|
// To deal with Suspend()/Resume() calls empty draw command
|
||||||
|
// is always added then splitter is active. Otherwise
|
||||||
|
// channel merger will collapse our draw command one with
|
||||||
|
// different clip rectangle.
|
||||||
|
//
|
||||||
|
// More investigation is needed. To get to the bottom of this.
|
||||||
|
if ((!m_DrawList->CmdBuffer.empty() && m_DrawList->CmdBuffer.back().ElemCount > 0) || m_DrawList->_Splitter._Count > 1)
|
||||||
|
m_DrawList->AddCallback(ImDrawCallback_ImCanvas, nullptr);
|
||||||
|
|
||||||
|
m_DrawListFirstCommandIndex = ImMax(m_DrawList->CmdBuffer.Size - 1, 0);
|
||||||
|
|
||||||
|
# if defined(IMGUI_HAS_VIEWPORT)
|
||||||
|
auto window = ImGui::GetCurrentWindow();
|
||||||
|
window->Pos = ImVec2(0.0f, 0.0f);
|
||||||
|
|
||||||
|
auto viewport_min = m_ViewportPosBackup;
|
||||||
|
auto viewport_max = m_ViewportPosBackup + m_ViewportSizeBackup;
|
||||||
|
|
||||||
|
viewport_min.x = (viewport_min.x - m_ViewTransformPosition.x) * m_View.InvScale;
|
||||||
|
viewport_min.y = (viewport_min.y - m_ViewTransformPosition.y) * m_View.InvScale;
|
||||||
|
viewport_max.x = (viewport_max.x - m_ViewTransformPosition.x) * m_View.InvScale;
|
||||||
|
viewport_max.y = (viewport_max.y - m_ViewTransformPosition.y) * m_View.InvScale;
|
||||||
|
|
||||||
|
auto viewport = ImGui::GetWindowViewport();
|
||||||
|
viewport->Pos = viewport_min;
|
||||||
|
viewport->Size = viewport_max - viewport_min;
|
||||||
|
|
||||||
|
# if IMGUI_VERSION_NUM > 18002
|
||||||
|
viewport->WorkPos = m_ViewportWorkPosBackup * m_View.InvScale;
|
||||||
|
viewport->WorkSize = m_ViewportWorkSizeBackup * m_View.InvScale;
|
||||||
|
# else
|
||||||
|
viewport->WorkOffsetMin = m_ViewportWorkOffsetMinBackup * m_View.InvScale;
|
||||||
|
viewport->WorkOffsetMax = m_ViewportWorkOffsetMaxBackup * m_View.InvScale;
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Clip rectangle in parent canvas space and move it to local space.
|
||||||
|
clipped_clip_rect.x = (clipped_clip_rect.x - m_ViewTransformPosition.x) * m_View.InvScale;
|
||||||
|
clipped_clip_rect.y = (clipped_clip_rect.y - m_ViewTransformPosition.y) * m_View.InvScale;
|
||||||
|
clipped_clip_rect.z = (clipped_clip_rect.z - m_ViewTransformPosition.x) * m_View.InvScale;
|
||||||
|
clipped_clip_rect.w = (clipped_clip_rect.w - m_ViewTransformPosition.y) * m_View.InvScale;
|
||||||
|
ImGui::PushClipRect(ImVec2(clipped_clip_rect.x, clipped_clip_rect.y), ImVec2(clipped_clip_rect.z, clipped_clip_rect.w), false);
|
||||||
|
|
||||||
|
// Transform mouse position to local space.
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
io.MousePos = (m_MousePosBackup - m_ViewTransformPosition) * m_View.InvScale;
|
||||||
|
io.MousePosPrev = (m_MousePosPrevBackup - m_ViewTransformPosition) * m_View.InvScale;
|
||||||
|
for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i)
|
||||||
|
io.MouseClickedPos[i] = (m_MouseClickedPosBackup[i] - m_ViewTransformPosition) * m_View.InvScale;
|
||||||
|
|
||||||
|
m_ViewRect = CalcViewRect(m_View);;
|
||||||
|
|
||||||
|
auto& fringeScale = ImFringeScaleRef(m_DrawList);
|
||||||
|
m_LastFringeScale = fringeScale;
|
||||||
|
fringeScale *= m_View.InvScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::LeaveLocalSpace()
|
||||||
|
{
|
||||||
|
IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel);
|
||||||
|
|
||||||
|
# if IMGUI_EX_CANVAS_DEFERED()
|
||||||
|
IM_ASSERT(m_CurrentRange != nullptr);
|
||||||
|
|
||||||
|
m_CurrentRange->EndVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList);
|
||||||
|
m_CurrentRange->EndCommandIndex = m_DrawList->CmdBuffer.size();
|
||||||
|
if (m_CurrentRange->BeginVertexIndex == m_CurrentRange->EndVertexIndex)
|
||||||
|
{
|
||||||
|
// Drop empty range
|
||||||
|
m_Ranges.resize(m_Ranges.Size - 1);
|
||||||
|
}
|
||||||
|
m_CurrentRange = nullptr;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Move vertices to screen space.
|
||||||
|
auto vertex = m_DrawList->VtxBuffer.Data + m_DrawListStartVertexIndex;
|
||||||
|
auto vertexEnd = m_DrawList->VtxBuffer.Data + m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList);
|
||||||
|
|
||||||
|
// If canvas view is not scaled take a faster path.
|
||||||
|
if (m_View.Scale != 1.0f)
|
||||||
|
{
|
||||||
|
while (vertex < vertexEnd)
|
||||||
|
{
|
||||||
|
vertex->pos.x = vertex->pos.x * m_View.Scale + m_ViewTransformPosition.x;
|
||||||
|
vertex->pos.y = vertex->pos.y * m_View.Scale + m_ViewTransformPosition.y;
|
||||||
|
++vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move clip rectangles to screen space.
|
||||||
|
for (int i = m_DrawListFirstCommandIndex; i < m_DrawList->CmdBuffer.size(); ++i)
|
||||||
|
{
|
||||||
|
auto& command = m_DrawList->CmdBuffer[i];
|
||||||
|
command.ClipRect.x = command.ClipRect.x * m_View.Scale + m_ViewTransformPosition.x;
|
||||||
|
command.ClipRect.y = command.ClipRect.y * m_View.Scale + m_ViewTransformPosition.y;
|
||||||
|
command.ClipRect.z = command.ClipRect.z * m_View.Scale + m_ViewTransformPosition.x;
|
||||||
|
command.ClipRect.w = command.ClipRect.w * m_View.Scale + m_ViewTransformPosition.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (vertex < vertexEnd)
|
||||||
|
{
|
||||||
|
vertex->pos.x = vertex->pos.x + m_ViewTransformPosition.x;
|
||||||
|
vertex->pos.y = vertex->pos.y + m_ViewTransformPosition.y;
|
||||||
|
++vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move clip rectangles to screen space.
|
||||||
|
for (int i = m_DrawListFirstCommandIndex; i < m_DrawList->CmdBuffer.size(); ++i)
|
||||||
|
{
|
||||||
|
auto& command = m_DrawList->CmdBuffer[i];
|
||||||
|
command.ClipRect.x = command.ClipRect.x + m_ViewTransformPosition.x;
|
||||||
|
command.ClipRect.y = command.ClipRect.y + m_ViewTransformPosition.y;
|
||||||
|
command.ClipRect.z = command.ClipRect.z + m_ViewTransformPosition.x;
|
||||||
|
command.ClipRect.w = command.ClipRect.w + m_ViewTransformPosition.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove sentinel draw command if present
|
||||||
|
if (m_DrawListCommadBufferSize > 0)
|
||||||
|
{
|
||||||
|
if (m_DrawList->CmdBuffer.size() > m_DrawListCommadBufferSize && m_DrawList->CmdBuffer[m_DrawListCommadBufferSize].UserCallback == ImDrawCallback_ImCanvas)
|
||||||
|
m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + m_DrawListCommadBufferSize);
|
||||||
|
else if (m_DrawList->CmdBuffer.size() >= m_DrawListCommadBufferSize && m_DrawList->CmdBuffer[m_DrawListCommadBufferSize - 1].UserCallback == ImDrawCallback_ImCanvas)
|
||||||
|
m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + m_DrawListCommadBufferSize - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& fringeScale = ImFringeScaleRef(m_DrawList);
|
||||||
|
fringeScale = m_LastFringeScale;
|
||||||
|
|
||||||
|
// And pop \o/
|
||||||
|
ImGui::PopClipRect();
|
||||||
|
|
||||||
|
RestoreInputState();
|
||||||
|
RestoreViewportState();
|
||||||
|
}
|
|
@ -0,0 +1,273 @@
|
||||||
|
// Canvas widget - view over infinite virtual space.
|
||||||
|
//
|
||||||
|
// Canvas allows you to draw your widgets anywhere over infinite space and provide
|
||||||
|
// view over it with support for panning and scaling.
|
||||||
|
//
|
||||||
|
// When you enter a canvas ImGui is moved to virtual space which mean:
|
||||||
|
// - ImGui::GetCursorScreenPos() return (0, 0) and which correspond to top left corner
|
||||||
|
// of the canvas on the screen (this can be changed using CanvasView()).
|
||||||
|
// - Mouse input is brought to canvas space, so widgets works as usual.
|
||||||
|
// - Everything you draw with ImDrawList will be in virtual space.
|
||||||
|
//
|
||||||
|
// By default origin point is on top left corner of canvas widget. It can be
|
||||||
|
// changed with call to CanvasView() where you can specify what part of space
|
||||||
|
// should be viewed by setting viewport origin point and scale. Current state
|
||||||
|
// can be queried with CanvasViewOrigin() and CanvasViewScale().
|
||||||
|
//
|
||||||
|
// Viewport size is controlled by 'size' parameter in BeginCanvas(). You can query
|
||||||
|
// it using CanvasContentMin/Max/Size functions. They are useful if you to not specify
|
||||||
|
// canvas size in which case all free space is used.
|
||||||
|
//
|
||||||
|
// Bounds of visible region of infinite space can be queried using CanvasViewMin/Max/Size
|
||||||
|
// functions. Everything that is drawn outside of this region will be clipped
|
||||||
|
// as usual in ImGui.
|
||||||
|
//
|
||||||
|
// While drawing inside canvas you can translate position from world (usual ImGui space)
|
||||||
|
// to virtual space and back using CanvasFromWorld()/CanvasToWorld().
|
||||||
|
//
|
||||||
|
// Canvas can be nested in each other (they are regular widgets after all). There
|
||||||
|
// is a way to transform position between current and parent canvas with
|
||||||
|
// CanvasFromParent()/CanvasToParent().
|
||||||
|
//
|
||||||
|
// Sometimes in more elaborate scenarios you want to move out canvas virtual space,
|
||||||
|
// do something and came back. You can do that with SuspendCanvas() and ResumeCanvas().
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// It is not valid to call canvas API outside of BeginCanvas() / EndCanvas() scope.
|
||||||
|
//
|
||||||
|
// VERSION 0.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
# ifndef __IMGUI_EX_CANVAS_H__
|
||||||
|
# define __IMGUI_EX_CANVAS_H__
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <imgui_internal.h> // ImRect, ImFloor
|
||||||
|
|
||||||
|
#ifndef IMGUIEX_CANVAS_API
|
||||||
|
#define IMGUIEX_CANVAS_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ImGuiEx {
|
||||||
|
|
||||||
|
struct CanvasView
|
||||||
|
{
|
||||||
|
ImVec2 Origin;
|
||||||
|
float Scale = 1.0f;
|
||||||
|
float InvScale = 1.0f;
|
||||||
|
|
||||||
|
CanvasView() = default;
|
||||||
|
CanvasView(const ImVec2& origin, float scale)
|
||||||
|
: Origin(origin)
|
||||||
|
, Scale(scale)
|
||||||
|
, InvScale(scale ? 1.0f / scale : 0.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(const ImVec2& origin, float scale)
|
||||||
|
{
|
||||||
|
*this = CanvasView(origin, scale);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Canvas widget represent view over infinite plane.
|
||||||
|
//
|
||||||
|
// It acts like a child window without scroll bars with
|
||||||
|
// ability to zoom to specific part of canvas plane.
|
||||||
|
//
|
||||||
|
// Widgets are clipped according to current view exactly
|
||||||
|
// same way ImGui do. To avoid `missing widgets` artifacts first
|
||||||
|
// setup visible region with SetView() then draw content.
|
||||||
|
//
|
||||||
|
// Everything drawn with ImDrawList betwen calls to Begin()/End()
|
||||||
|
// will be drawn on canvas plane. This behavior can be suspended
|
||||||
|
// by calling Suspend() and resumed by calling Resume().
|
||||||
|
//
|
||||||
|
// Warning:
|
||||||
|
// Please do not interleave canvas with use of channel splitter.
|
||||||
|
// Keep channel splitter contained inside canvas or always
|
||||||
|
// call canvas functions from same channel.
|
||||||
|
struct Canvas
|
||||||
|
{
|
||||||
|
// Begins drawing content of canvas plane.
|
||||||
|
//
|
||||||
|
// When false is returned that mean canvas is not visible to the
|
||||||
|
// user can drawing should be skipped and End() not called.
|
||||||
|
// When true is returned drawing must be ended with call to End().
|
||||||
|
//
|
||||||
|
// If any size component is equal to zero or less canvas will
|
||||||
|
// automatically expand to all available area on that axis.
|
||||||
|
// So (0, 300) will take horizontal space and have height
|
||||||
|
// of 300 points. (0, 0) will take all remaining space of
|
||||||
|
// the window.
|
||||||
|
//
|
||||||
|
// You can query size of the canvas while it is being drawn
|
||||||
|
// by calling Rect().
|
||||||
|
IMGUIEX_CANVAS_API bool Begin(const char* id, const ImVec2& size);
|
||||||
|
IMGUIEX_CANVAS_API bool Begin(ImGuiID id, const ImVec2& size);
|
||||||
|
|
||||||
|
// Ends interaction with canvas plane.
|
||||||
|
//
|
||||||
|
// Must be called only when Begin() retuned true.
|
||||||
|
IMGUIEX_CANVAS_API void End();
|
||||||
|
|
||||||
|
// Sets visible region of canvas plane.
|
||||||
|
//
|
||||||
|
// Origin is an offset of infinite plane origin from top left
|
||||||
|
// corner of the canvas.
|
||||||
|
//
|
||||||
|
// Scale greater than 1 make canvas content be bigger, less than 1 smaller.
|
||||||
|
IMGUIEX_CANVAS_API void SetView(const ImVec2& origin, float scale);
|
||||||
|
IMGUIEX_CANVAS_API void SetView(const CanvasView& view);
|
||||||
|
|
||||||
|
// Centers view over specific point on canvas plane.
|
||||||
|
//
|
||||||
|
// View will be centered on specific point by changing origin
|
||||||
|
// but not scale.
|
||||||
|
IMGUIEX_CANVAS_API void CenterView(const ImVec2& canvasPoint);
|
||||||
|
|
||||||
|
// Calculates view over specific point on canvas plane.
|
||||||
|
IMGUIEX_CANVAS_API CanvasView CalcCenterView(const ImVec2& canvasPoint) const;
|
||||||
|
|
||||||
|
// Centers view over specific rectangle on canvas plane.
|
||||||
|
//
|
||||||
|
// Whole rectangle will fit in canvas view. This will affect both
|
||||||
|
// origin and scale.
|
||||||
|
IMGUIEX_CANVAS_API void CenterView(const ImRect& canvasRect);
|
||||||
|
|
||||||
|
// Calculates view over specific rectangle on canvas plane.
|
||||||
|
IMGUIEX_CANVAS_API CanvasView CalcCenterView(const ImRect& canvasRect) const;
|
||||||
|
|
||||||
|
// Suspends canvas by returning to normal ImGui transformation space.
|
||||||
|
// While suspended UI will not be drawn on canvas plane.
|
||||||
|
//
|
||||||
|
// Calls to Suspend()/Resume() are symetrical. Each call to Suspend()
|
||||||
|
// must be matched with call to Resume().
|
||||||
|
IMGUIEX_CANVAS_API void Suspend();
|
||||||
|
IMGUIEX_CANVAS_API void Resume();
|
||||||
|
|
||||||
|
// Transforms point from canvas plane to ImGui.
|
||||||
|
IMGUIEX_CANVAS_API ImVec2 FromLocal(const ImVec2& point) const;
|
||||||
|
IMGUIEX_CANVAS_API ImVec2 FromLocal(const ImVec2& point, const CanvasView& view) const;
|
||||||
|
|
||||||
|
// Transforms vector from canvas plant to ImGui.
|
||||||
|
IMGUIEX_CANVAS_API ImVec2 FromLocalV(const ImVec2& vector) const;
|
||||||
|
IMGUIEX_CANVAS_API ImVec2 FromLocalV(const ImVec2& vector, const CanvasView& view) const;
|
||||||
|
|
||||||
|
// Transforms point from ImGui to canvas plane.
|
||||||
|
IMGUIEX_CANVAS_API ImVec2 ToLocal(const ImVec2& point) const;
|
||||||
|
IMGUIEX_CANVAS_API ImVec2 ToLocal(const ImVec2& point, const CanvasView& view) const;
|
||||||
|
|
||||||
|
// Transforms vector from ImGui to canvas plane.
|
||||||
|
IMGUIEX_CANVAS_API ImVec2 ToLocalV(const ImVec2& vector) const;
|
||||||
|
IMGUIEX_CANVAS_API ImVec2 ToLocalV(const ImVec2& vector, const CanvasView& view) const;
|
||||||
|
|
||||||
|
// Returns widget bounds.
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// Rect is valid after call to Begin().
|
||||||
|
const ImRect& Rect() const { return m_WidgetRect; }
|
||||||
|
|
||||||
|
// Returns visible region on canvas plane (in canvas plane coordinates).
|
||||||
|
const ImRect& ViewRect() const { return m_ViewRect; }
|
||||||
|
|
||||||
|
// Calculates visible region for view.
|
||||||
|
IMGUIEX_CANVAS_API ImRect CalcViewRect(const CanvasView& view) const;
|
||||||
|
|
||||||
|
// Returns current view.
|
||||||
|
const CanvasView& View() const { return m_View; }
|
||||||
|
|
||||||
|
// Returns origin of the view.
|
||||||
|
//
|
||||||
|
// Origin is an offset of infinite plane origin from top left
|
||||||
|
// corner of the canvas.
|
||||||
|
const ImVec2& ViewOrigin() const { return m_View.Origin; }
|
||||||
|
|
||||||
|
// Returns scale of the view.
|
||||||
|
float ViewScale() const { return m_View.Scale; }
|
||||||
|
|
||||||
|
// Returns true if canvas is suspended.
|
||||||
|
//
|
||||||
|
// See: Suspend()/Resume()
|
||||||
|
bool IsSuspended() const { return m_SuspendCounter > 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
# define IMGUI_EX_CANVAS_DEFERED() 0
|
||||||
|
|
||||||
|
# if IMGUI_EX_CANVAS_DEFERED()
|
||||||
|
struct Range
|
||||||
|
{
|
||||||
|
int BeginVertexIndex = 0;
|
||||||
|
int EndVertexIndex = 0;
|
||||||
|
int BeginComandIndex = 0;
|
||||||
|
int EndCommandIndex = 0;
|
||||||
|
};
|
||||||
|
# endif
|
||||||
|
|
||||||
|
void UpdateViewTransformPosition();
|
||||||
|
|
||||||
|
void SaveInputState();
|
||||||
|
void RestoreInputState();
|
||||||
|
|
||||||
|
void SaveViewportState();
|
||||||
|
void RestoreViewportState();
|
||||||
|
|
||||||
|
void EnterLocalSpace();
|
||||||
|
void LeaveLocalSpace();
|
||||||
|
|
||||||
|
bool m_InBeginEnd = false;
|
||||||
|
|
||||||
|
ImVec2 m_WidgetPosition;
|
||||||
|
ImVec2 m_WidgetSize;
|
||||||
|
ImRect m_WidgetRect;
|
||||||
|
|
||||||
|
ImDrawList* m_DrawList = nullptr;
|
||||||
|
int m_ExpectedChannel = 0;
|
||||||
|
|
||||||
|
# if IMGUI_EX_CANVAS_DEFERED()
|
||||||
|
ImVector<Range> m_Ranges;
|
||||||
|
Range* m_CurrentRange = nullptr;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
int m_DrawListFirstCommandIndex = 0;
|
||||||
|
int m_DrawListCommadBufferSize = 0;
|
||||||
|
int m_DrawListStartVertexIndex = 0;
|
||||||
|
|
||||||
|
CanvasView m_View;
|
||||||
|
ImRect m_ViewRect;
|
||||||
|
|
||||||
|
ImVec2 m_ViewTransformPosition;
|
||||||
|
|
||||||
|
int m_SuspendCounter = 0;
|
||||||
|
|
||||||
|
float m_LastFringeScale = 1.0f;
|
||||||
|
|
||||||
|
ImVec2 m_MousePosBackup;
|
||||||
|
ImVec2 m_MousePosPrevBackup;
|
||||||
|
ImVec2 m_MouseClickedPosBackup[IM_ARRAYSIZE(ImGuiIO::MouseClickedPos)];
|
||||||
|
ImVec2 m_WindowCursorMaxBackup;
|
||||||
|
|
||||||
|
# if defined(IMGUI_HAS_VIEWPORT)
|
||||||
|
ImVec2 m_WindowPosBackup;
|
||||||
|
ImVec2 m_ViewportPosBackup;
|
||||||
|
ImVec2 m_ViewportSizeBackup;
|
||||||
|
# if IMGUI_VERSION_NUM > 18002
|
||||||
|
ImVec2 m_ViewportWorkPosBackup;
|
||||||
|
ImVec2 m_ViewportWorkSizeBackup;
|
||||||
|
# else
|
||||||
|
ImVec2 m_ViewportWorkOffsetMinBackup;
|
||||||
|
ImVec2 m_ViewportWorkOffsetMaxBackup;
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ImGuiEx
|
||||||
|
|
||||||
|
# endif // __IMGUI_EX_CANVAS_H__
|
|
@ -0,0 +1,77 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// VERSION 0.9.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# ifndef __IMGUI_EXTRA_MATH_H__
|
||||||
|
# define __IMGUI_EXTRA_MATH_H__
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
# endif
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <imgui_internal.h>
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
struct ImLine
|
||||||
|
{
|
||||||
|
ImVec2 A, B;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# if IMGUI_VERSION_NUM < 19002
|
||||||
|
inline bool operator==(const ImVec2& lhs, const ImVec2& rhs);
|
||||||
|
inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs);
|
||||||
|
# endif
|
||||||
|
inline ImVec2 operator*(const float lhs, const ImVec2& rhs);
|
||||||
|
# if IMGUI_VERSION_NUM < 18955
|
||||||
|
inline ImVec2 operator-(const ImVec2& lhs);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline float ImLength(float v);
|
||||||
|
inline float ImLength(const ImVec2& v);
|
||||||
|
inline float ImLengthSqr(float v);
|
||||||
|
inline ImVec2 ImNormalized(const ImVec2& v);
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline bool ImRect_IsEmpty(const ImRect& rect);
|
||||||
|
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge);
|
||||||
|
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius);
|
||||||
|
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& b);
|
||||||
|
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b);
|
||||||
|
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
namespace ImEasing {
|
||||||
|
|
||||||
|
template <typename V, typename T>
|
||||||
|
inline V EaseOutQuad(V b, V c, T t)
|
||||||
|
{
|
||||||
|
return b - c * (t * (t - 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ImEasing
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include "imgui_extra_math.inl"
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# endif // __IMGUI_EXTRA_MATH_H__
|
|
@ -0,0 +1,193 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// VERSION 0.9.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# ifndef __IMGUI_EXTRA_MATH_INL__
|
||||||
|
# define __IMGUI_EXTRA_MATH_INL__
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include "imgui_extra_math.h"
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# if IMGUI_VERSION_NUM < 19002
|
||||||
|
inline bool operator==(const ImVec2& lhs, const ImVec2& rhs)
|
||||||
|
{
|
||||||
|
return lhs.x == rhs.x && lhs.y == rhs.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs)
|
||||||
|
{
|
||||||
|
return lhs.x != rhs.x || lhs.y != rhs.y;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
inline ImVec2 operator*(const float lhs, const ImVec2& rhs)
|
||||||
|
{
|
||||||
|
return ImVec2(lhs * rhs.x, lhs * rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
# if IMGUI_VERSION_NUM < 18955
|
||||||
|
inline ImVec2 operator-(const ImVec2& lhs)
|
||||||
|
{
|
||||||
|
return ImVec2(-lhs.x, -lhs.y);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline float ImLength(float v)
|
||||||
|
{
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float ImLength(const ImVec2& v)
|
||||||
|
{
|
||||||
|
return ImSqrt(ImLengthSqr(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float ImLengthSqr(float v)
|
||||||
|
{
|
||||||
|
return v * v;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImVec2 ImNormalized(const ImVec2& v)
|
||||||
|
{
|
||||||
|
return v * ImInvLength(v, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline bool ImRect_IsEmpty(const ImRect& rect)
|
||||||
|
{
|
||||||
|
return rect.Min.x >= rect.Max.x
|
||||||
|
|| rect.Min.y >= rect.Max.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge)
|
||||||
|
{
|
||||||
|
if (!snap_to_edge && rect.Contains(p))
|
||||||
|
return p;
|
||||||
|
|
||||||
|
return ImVec2(
|
||||||
|
(p.x > rect.Max.x) ? rect.Max.x : (p.x < rect.Min.x ? rect.Min.x : p.x),
|
||||||
|
(p.y > rect.Max.y) ? rect.Max.y : (p.y < rect.Min.y ? rect.Min.y : p.y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius)
|
||||||
|
{
|
||||||
|
auto point = ImRect_ClosestPoint(rect, p, snap_to_edge);
|
||||||
|
|
||||||
|
const auto offset = p - point;
|
||||||
|
const auto distance_sq = offset.x * offset.x + offset.y * offset.y;
|
||||||
|
if (distance_sq <= 0)
|
||||||
|
return point;
|
||||||
|
|
||||||
|
const auto distance = ImSqrt(distance_sq);
|
||||||
|
|
||||||
|
return point + offset * (ImMin(distance, radius) * (1.0f / distance));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& other)
|
||||||
|
{
|
||||||
|
ImVec2 result;
|
||||||
|
if (other.Min.x >= rect.Max.x)
|
||||||
|
result.x = rect.Max.x;
|
||||||
|
else if (other.Max.x <= rect.Min.x)
|
||||||
|
result.x = rect.Min.x;
|
||||||
|
else
|
||||||
|
result.x = (ImMax(rect.Min.x, other.Min.x) + ImMin(rect.Max.x, other.Max.x)) / 2;
|
||||||
|
|
||||||
|
if (other.Min.y >= rect.Max.y)
|
||||||
|
result.y = rect.Max.y;
|
||||||
|
else if (other.Max.y <= rect.Min.y)
|
||||||
|
result.y = rect.Min.y;
|
||||||
|
else
|
||||||
|
result.y = (ImMax(rect.Min.y, other.Min.y) + ImMin(rect.Max.y, other.Max.y)) / 2;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b)
|
||||||
|
{
|
||||||
|
ImLine result;
|
||||||
|
result.A = ImRect_ClosestPoint(rect_a, rect_b);
|
||||||
|
result.B = ImRect_ClosestPoint(rect_b, rect_a);
|
||||||
|
|
||||||
|
auto distribute = [](float& a, float& b, float a0, float a1, float b0, float b1)
|
||||||
|
{
|
||||||
|
if (a0 >= b1 || a1 <= b0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto aw = a1 - a0;
|
||||||
|
const auto bw = b1 - b0;
|
||||||
|
|
||||||
|
if (aw > bw)
|
||||||
|
{
|
||||||
|
b = b0 + bw - bw * (a - a0) / aw;
|
||||||
|
a = b;
|
||||||
|
}
|
||||||
|
else if (aw < bw)
|
||||||
|
{
|
||||||
|
a = a0 + aw - aw * (b - b0) / bw;
|
||||||
|
b = a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
distribute(result.A.x, result.B.x, rect_a.Min.x, rect_a.Max.x, rect_b.Min.x, rect_b.Max.x);
|
||||||
|
distribute(result.A.y, result.B.y, rect_a.Min.y, rect_a.Max.y, rect_b.Min.y, rect_b.Max.y);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b)
|
||||||
|
{
|
||||||
|
auto line = ImRect_ClosestLine(rect_a, rect_b);
|
||||||
|
if (radius_a < 0)
|
||||||
|
radius_a = 0;
|
||||||
|
if (radius_b < 0)
|
||||||
|
radius_b = 0;
|
||||||
|
|
||||||
|
if (radius_a == 0 && radius_b == 0)
|
||||||
|
return line;
|
||||||
|
|
||||||
|
const auto offset = line.B - line.A;
|
||||||
|
const auto length_sq = offset.x * offset.x + offset.y * offset.y;
|
||||||
|
const auto radius_a_sq = radius_a * radius_a;
|
||||||
|
const auto radius_b_sq = radius_b * radius_b;
|
||||||
|
|
||||||
|
if (length_sq <= 0)
|
||||||
|
return line;
|
||||||
|
|
||||||
|
const auto length = ImSqrt(length_sq);
|
||||||
|
const auto direction = ImVec2(offset.x / length, offset.y / length);
|
||||||
|
|
||||||
|
const auto total_radius_sq = radius_a_sq + radius_b_sq;
|
||||||
|
if (total_radius_sq > length_sq)
|
||||||
|
{
|
||||||
|
const auto scale = length / (radius_a + radius_b);
|
||||||
|
radius_a *= scale;
|
||||||
|
radius_b *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.A = line.A + (direction * radius_a);
|
||||||
|
line.B = line.B - (direction * radius_b);
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# endif // __IMGUI_EXTRA_MATH_INL__
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,530 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// VERSION 0.9.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# ifndef __IMGUI_NODE_EDITOR_H__
|
||||||
|
# define __IMGUI_NODE_EDITOR_H__
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include <imgui.h>
|
||||||
|
# include <cstdint> // std::uintXX_t
|
||||||
|
# include <utility> // std::move
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# define IMGUI_NODE_EDITOR_VERSION "0.9.4"
|
||||||
|
# define IMGUI_NODE_EDITOR_VERSION_NUM 000904
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#ifndef IMGUI_NODE_EDITOR_API
|
||||||
|
#define IMGUI_NODE_EDITOR_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
namespace ax {
|
||||||
|
namespace NodeEditor {
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
struct NodeId;
|
||||||
|
struct LinkId;
|
||||||
|
struct PinId;
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
enum class PinKind
|
||||||
|
{
|
||||||
|
Input,
|
||||||
|
Output
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class FlowDirection
|
||||||
|
{
|
||||||
|
Forward,
|
||||||
|
Backward
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CanvasSizeMode
|
||||||
|
{
|
||||||
|
FitVerticalView, // Previous view will be scaled to fit new view on Y axis
|
||||||
|
FitHorizontalView, // Previous view will be scaled to fit new view on X axis
|
||||||
|
CenterOnly, // Previous view will be centered on new view
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
enum class SaveReasonFlags: uint32_t
|
||||||
|
{
|
||||||
|
None = 0x00000000,
|
||||||
|
Navigation = 0x00000001,
|
||||||
|
Position = 0x00000002,
|
||||||
|
Size = 0x00000004,
|
||||||
|
Selection = 0x00000008,
|
||||||
|
AddNode = 0x00000010,
|
||||||
|
RemoveNode = 0x00000020,
|
||||||
|
User = 0x00000040
|
||||||
|
};
|
||||||
|
|
||||||
|
inline SaveReasonFlags operator |(SaveReasonFlags lhs, SaveReasonFlags rhs) { return static_cast<SaveReasonFlags>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs)); }
|
||||||
|
inline SaveReasonFlags operator &(SaveReasonFlags lhs, SaveReasonFlags rhs) { return static_cast<SaveReasonFlags>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs)); }
|
||||||
|
|
||||||
|
using ConfigSaveSettings = bool (*)(const char* data, size_t size, SaveReasonFlags reason, void* userPointer);
|
||||||
|
using ConfigLoadSettings = size_t (*)(char* data, void* userPointer);
|
||||||
|
|
||||||
|
using ConfigSaveNodeSettings = bool (*)(NodeId nodeId, const char* data, size_t size, SaveReasonFlags reason, void* userPointer);
|
||||||
|
using ConfigLoadNodeSettings = size_t (*)(NodeId nodeId, char* data, void* userPointer);
|
||||||
|
|
||||||
|
using ConfigSession = void (*)(void* userPointer);
|
||||||
|
|
||||||
|
struct Config
|
||||||
|
{
|
||||||
|
using CanvasSizeModeAlias = ax::NodeEditor::CanvasSizeMode;
|
||||||
|
|
||||||
|
const char* SettingsFile;
|
||||||
|
ConfigSession BeginSaveSession;
|
||||||
|
ConfigSession EndSaveSession;
|
||||||
|
ConfigSaveSettings SaveSettings;
|
||||||
|
ConfigLoadSettings LoadSettings;
|
||||||
|
ConfigSaveNodeSettings SaveNodeSettings;
|
||||||
|
ConfigLoadNodeSettings LoadNodeSettings;
|
||||||
|
void* UserPointer;
|
||||||
|
ImVector<float> CustomZoomLevels;
|
||||||
|
CanvasSizeModeAlias CanvasSizeMode;
|
||||||
|
int DragButtonIndex; // Mouse button index drag action will react to (0-left, 1-right, 2-middle)
|
||||||
|
int SelectButtonIndex; // Mouse button index select action will react to (0-left, 1-right, 2-middle)
|
||||||
|
int NavigateButtonIndex; // Mouse button index navigate action will react to (0-left, 1-right, 2-middle)
|
||||||
|
int ContextMenuButtonIndex; // Mouse button index context menu action will react to (0-left, 1-right, 2-middle)
|
||||||
|
bool EnableSmoothZoom;
|
||||||
|
float SmoothZoomPower;
|
||||||
|
|
||||||
|
Config()
|
||||||
|
: SettingsFile("NodeEditor.json")
|
||||||
|
, BeginSaveSession(nullptr)
|
||||||
|
, EndSaveSession(nullptr)
|
||||||
|
, SaveSettings(nullptr)
|
||||||
|
, LoadSettings(nullptr)
|
||||||
|
, SaveNodeSettings(nullptr)
|
||||||
|
, LoadNodeSettings(nullptr)
|
||||||
|
, UserPointer(nullptr)
|
||||||
|
, CustomZoomLevels()
|
||||||
|
, CanvasSizeMode(CanvasSizeModeAlias::FitVerticalView)
|
||||||
|
, DragButtonIndex(0)
|
||||||
|
, SelectButtonIndex(0)
|
||||||
|
, NavigateButtonIndex(1)
|
||||||
|
, ContextMenuButtonIndex(1)
|
||||||
|
, EnableSmoothZoom(false)
|
||||||
|
# ifdef __APPLE__
|
||||||
|
, SmoothZoomPower(1.1f)
|
||||||
|
# else
|
||||||
|
, SmoothZoomPower(1.3f)
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
enum StyleColor
|
||||||
|
{
|
||||||
|
StyleColor_Bg,
|
||||||
|
StyleColor_Grid,
|
||||||
|
StyleColor_NodeBg,
|
||||||
|
StyleColor_NodeBorder,
|
||||||
|
StyleColor_HovNodeBorder,
|
||||||
|
StyleColor_SelNodeBorder,
|
||||||
|
StyleColor_NodeSelRect,
|
||||||
|
StyleColor_NodeSelRectBorder,
|
||||||
|
StyleColor_HovLinkBorder,
|
||||||
|
StyleColor_SelLinkBorder,
|
||||||
|
StyleColor_HighlightLinkBorder,
|
||||||
|
StyleColor_LinkSelRect,
|
||||||
|
StyleColor_LinkSelRectBorder,
|
||||||
|
StyleColor_PinRect,
|
||||||
|
StyleColor_PinRectBorder,
|
||||||
|
StyleColor_Flow,
|
||||||
|
StyleColor_FlowMarker,
|
||||||
|
StyleColor_GroupBg,
|
||||||
|
StyleColor_GroupBorder,
|
||||||
|
|
||||||
|
StyleColor_Count
|
||||||
|
};
|
||||||
|
|
||||||
|
enum StyleVar
|
||||||
|
{
|
||||||
|
StyleVar_NodePadding,
|
||||||
|
StyleVar_NodeRounding,
|
||||||
|
StyleVar_NodeBorderWidth,
|
||||||
|
StyleVar_HoveredNodeBorderWidth,
|
||||||
|
StyleVar_SelectedNodeBorderWidth,
|
||||||
|
StyleVar_PinRounding,
|
||||||
|
StyleVar_PinBorderWidth,
|
||||||
|
StyleVar_LinkStrength,
|
||||||
|
StyleVar_SourceDirection,
|
||||||
|
StyleVar_TargetDirection,
|
||||||
|
StyleVar_ScrollDuration,
|
||||||
|
StyleVar_FlowMarkerDistance,
|
||||||
|
StyleVar_FlowSpeed,
|
||||||
|
StyleVar_FlowDuration,
|
||||||
|
StyleVar_PivotAlignment,
|
||||||
|
StyleVar_PivotSize,
|
||||||
|
StyleVar_PivotScale,
|
||||||
|
StyleVar_PinCorners,
|
||||||
|
StyleVar_PinRadius,
|
||||||
|
StyleVar_PinArrowSize,
|
||||||
|
StyleVar_PinArrowWidth,
|
||||||
|
StyleVar_GroupRounding,
|
||||||
|
StyleVar_GroupBorderWidth,
|
||||||
|
StyleVar_HighlightConnectedLinks,
|
||||||
|
StyleVar_SnapLinkToPinDir,
|
||||||
|
StyleVar_HoveredNodeBorderOffset,
|
||||||
|
StyleVar_SelectedNodeBorderOffset,
|
||||||
|
|
||||||
|
StyleVar_Count
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Style
|
||||||
|
{
|
||||||
|
ImVec4 NodePadding;
|
||||||
|
float NodeRounding;
|
||||||
|
float NodeBorderWidth;
|
||||||
|
float HoveredNodeBorderWidth;
|
||||||
|
float HoverNodeBorderOffset;
|
||||||
|
float SelectedNodeBorderWidth;
|
||||||
|
float SelectedNodeBorderOffset;
|
||||||
|
float PinRounding;
|
||||||
|
float PinBorderWidth;
|
||||||
|
float LinkStrength;
|
||||||
|
ImVec2 SourceDirection;
|
||||||
|
ImVec2 TargetDirection;
|
||||||
|
float ScrollDuration;
|
||||||
|
float FlowMarkerDistance;
|
||||||
|
float FlowSpeed;
|
||||||
|
float FlowDuration;
|
||||||
|
ImVec2 PivotAlignment;
|
||||||
|
ImVec2 PivotSize;
|
||||||
|
ImVec2 PivotScale;
|
||||||
|
float PinCorners;
|
||||||
|
float PinRadius;
|
||||||
|
float PinArrowSize;
|
||||||
|
float PinArrowWidth;
|
||||||
|
float GroupRounding;
|
||||||
|
float GroupBorderWidth;
|
||||||
|
float HighlightConnectedLinks;
|
||||||
|
float SnapLinkToPinDir; // when true link will start on the line defined by pin direction
|
||||||
|
ImVec4 Colors[StyleColor_Count];
|
||||||
|
|
||||||
|
Style()
|
||||||
|
{
|
||||||
|
NodePadding = ImVec4(8, 8, 8, 8);
|
||||||
|
NodeRounding = 12.0f;
|
||||||
|
NodeBorderWidth = 1.5f;
|
||||||
|
HoveredNodeBorderWidth = 3.5f;
|
||||||
|
HoverNodeBorderOffset = 0.0f;
|
||||||
|
SelectedNodeBorderWidth = 3.5f;
|
||||||
|
SelectedNodeBorderOffset = 0.0f;
|
||||||
|
PinRounding = 4.0f;
|
||||||
|
PinBorderWidth = 0.0f;
|
||||||
|
LinkStrength = 100.0f;
|
||||||
|
SourceDirection = ImVec2(1.0f, 0.0f);
|
||||||
|
TargetDirection = ImVec2(-1.0f, 0.0f);
|
||||||
|
ScrollDuration = 0.35f;
|
||||||
|
FlowMarkerDistance = 30.0f;
|
||||||
|
FlowSpeed = 150.0f;
|
||||||
|
FlowDuration = 2.0f;
|
||||||
|
PivotAlignment = ImVec2(0.5f, 0.5f);
|
||||||
|
PivotSize = ImVec2(0.0f, 0.0f);
|
||||||
|
PivotScale = ImVec2(1, 1);
|
||||||
|
#if IMGUI_VERSION_NUM > 18101
|
||||||
|
PinCorners = ImDrawFlags_RoundCornersAll;
|
||||||
|
#else
|
||||||
|
PinCorners = ImDrawCornerFlags_All;
|
||||||
|
#endif
|
||||||
|
PinRadius = 0.0f;
|
||||||
|
PinArrowSize = 0.0f;
|
||||||
|
PinArrowWidth = 0.0f;
|
||||||
|
GroupRounding = 6.0f;
|
||||||
|
GroupBorderWidth = 1.0f;
|
||||||
|
HighlightConnectedLinks = 0.0f;
|
||||||
|
SnapLinkToPinDir = 0.0f;
|
||||||
|
|
||||||
|
Colors[StyleColor_Bg] = ImColor( 60, 60, 70, 200);
|
||||||
|
Colors[StyleColor_Grid] = ImColor(120, 120, 120, 40);
|
||||||
|
Colors[StyleColor_NodeBg] = ImColor( 32, 32, 32, 200);
|
||||||
|
Colors[StyleColor_NodeBorder] = ImColor(255, 255, 255, 96);
|
||||||
|
Colors[StyleColor_HovNodeBorder] = ImColor( 50, 176, 255, 255);
|
||||||
|
Colors[StyleColor_SelNodeBorder] = ImColor(255, 176, 50, 255);
|
||||||
|
Colors[StyleColor_NodeSelRect] = ImColor( 5, 130, 255, 64);
|
||||||
|
Colors[StyleColor_NodeSelRectBorder] = ImColor( 5, 130, 255, 128);
|
||||||
|
Colors[StyleColor_HovLinkBorder] = ImColor( 50, 176, 255, 255);
|
||||||
|
Colors[StyleColor_SelLinkBorder] = ImColor(255, 176, 50, 255);
|
||||||
|
Colors[StyleColor_HighlightLinkBorder]= ImColor(204, 105, 0, 255);
|
||||||
|
Colors[StyleColor_LinkSelRect] = ImColor( 5, 130, 255, 64);
|
||||||
|
Colors[StyleColor_LinkSelRectBorder] = ImColor( 5, 130, 255, 128);
|
||||||
|
Colors[StyleColor_PinRect] = ImColor( 60, 180, 255, 100);
|
||||||
|
Colors[StyleColor_PinRectBorder] = ImColor( 60, 180, 255, 128);
|
||||||
|
Colors[StyleColor_Flow] = ImColor(255, 128, 64, 255);
|
||||||
|
Colors[StyleColor_FlowMarker] = ImColor(255, 128, 64, 255);
|
||||||
|
Colors[StyleColor_GroupBg] = ImColor( 0, 0, 0, 160);
|
||||||
|
Colors[StyleColor_GroupBorder] = ImColor(255, 255, 255, 32);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
struct EditorContext;
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
IMGUI_NODE_EDITOR_API void SetCurrentEditor(EditorContext* ctx);
|
||||||
|
IMGUI_NODE_EDITOR_API EditorContext* GetCurrentEditor();
|
||||||
|
IMGUI_NODE_EDITOR_API EditorContext* CreateEditor(const Config* config = nullptr);
|
||||||
|
IMGUI_NODE_EDITOR_API void DestroyEditor(EditorContext* ctx);
|
||||||
|
IMGUI_NODE_EDITOR_API const Config& GetConfig(EditorContext* ctx = nullptr);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API Style& GetStyle();
|
||||||
|
IMGUI_NODE_EDITOR_API const char* GetStyleColorName(StyleColor colorIndex);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void PushStyleColor(StyleColor colorIndex, const ImVec4& color);
|
||||||
|
IMGUI_NODE_EDITOR_API void PopStyleColor(int count = 1);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void PushStyleVar(StyleVar varIndex, float value);
|
||||||
|
IMGUI_NODE_EDITOR_API void PushStyleVar(StyleVar varIndex, const ImVec2& value);
|
||||||
|
IMGUI_NODE_EDITOR_API void PushStyleVar(StyleVar varIndex, const ImVec4& value);
|
||||||
|
IMGUI_NODE_EDITOR_API void PopStyleVar(int count = 1);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void Begin(const char* id, const ImVec2& size = ImVec2(0, 0));
|
||||||
|
IMGUI_NODE_EDITOR_API void End();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void BeginNode(NodeId id);
|
||||||
|
IMGUI_NODE_EDITOR_API void BeginPin(PinId id, PinKind kind);
|
||||||
|
IMGUI_NODE_EDITOR_API void PinRect(const ImVec2& a, const ImVec2& b);
|
||||||
|
IMGUI_NODE_EDITOR_API void PinPivotRect(const ImVec2& a, const ImVec2& b);
|
||||||
|
IMGUI_NODE_EDITOR_API void PinPivotSize(const ImVec2& size);
|
||||||
|
IMGUI_NODE_EDITOR_API void PinPivotScale(const ImVec2& scale);
|
||||||
|
IMGUI_NODE_EDITOR_API void PinPivotAlignment(const ImVec2& alignment);
|
||||||
|
IMGUI_NODE_EDITOR_API void EndPin();
|
||||||
|
IMGUI_NODE_EDITOR_API void Group(const ImVec2& size);
|
||||||
|
IMGUI_NODE_EDITOR_API void EndNode();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool BeginGroupHint(NodeId nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API ImVec2 GetGroupMin();
|
||||||
|
IMGUI_NODE_EDITOR_API ImVec2 GetGroupMax();
|
||||||
|
IMGUI_NODE_EDITOR_API ImDrawList* GetHintForegroundDrawList();
|
||||||
|
IMGUI_NODE_EDITOR_API ImDrawList* GetHintBackgroundDrawList();
|
||||||
|
IMGUI_NODE_EDITOR_API void EndGroupHint();
|
||||||
|
|
||||||
|
// TODO: Add a way to manage node background channels
|
||||||
|
IMGUI_NODE_EDITOR_API ImDrawList* GetNodeBackgroundDrawList(NodeId nodeId);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool Link(LinkId id, PinId startPinId, PinId endPinId, const ImVec4& color = ImVec4(1, 1, 1, 1), float thickness = 1.0f);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void Flow(LinkId linkId, FlowDirection direction = FlowDirection::Forward);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool BeginCreate(const ImVec4& color = ImVec4(1, 1, 1, 1), float thickness = 1.0f);
|
||||||
|
IMGUI_NODE_EDITOR_API bool QueryNewLink(PinId* startId, PinId* endId);
|
||||||
|
IMGUI_NODE_EDITOR_API bool QueryNewLink(PinId* startId, PinId* endId, const ImVec4& color, float thickness = 1.0f);
|
||||||
|
IMGUI_NODE_EDITOR_API bool QueryNewNode(PinId* pinId);
|
||||||
|
IMGUI_NODE_EDITOR_API bool QueryNewNode(PinId* pinId, const ImVec4& color, float thickness = 1.0f);
|
||||||
|
IMGUI_NODE_EDITOR_API bool AcceptNewItem();
|
||||||
|
IMGUI_NODE_EDITOR_API bool AcceptNewItem(const ImVec4& color, float thickness = 1.0f);
|
||||||
|
IMGUI_NODE_EDITOR_API void RejectNewItem();
|
||||||
|
IMGUI_NODE_EDITOR_API void RejectNewItem(const ImVec4& color, float thickness = 1.0f);
|
||||||
|
IMGUI_NODE_EDITOR_API void EndCreate();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool BeginDelete();
|
||||||
|
IMGUI_NODE_EDITOR_API bool QueryDeletedLink(LinkId* linkId, PinId* startId = nullptr, PinId* endId = nullptr);
|
||||||
|
IMGUI_NODE_EDITOR_API bool QueryDeletedNode(NodeId* nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API bool AcceptDeletedItem(bool deleteDependencies = true);
|
||||||
|
IMGUI_NODE_EDITOR_API void RejectDeletedItem();
|
||||||
|
IMGUI_NODE_EDITOR_API void EndDelete();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void SetNodePosition(NodeId nodeId, const ImVec2& editorPosition);
|
||||||
|
IMGUI_NODE_EDITOR_API void SetGroupSize(NodeId nodeId, const ImVec2& size);
|
||||||
|
IMGUI_NODE_EDITOR_API ImVec2 GetNodePosition(NodeId nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API ImVec2 GetNodeSize(NodeId nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API void CenterNodeOnScreen(NodeId nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API void SetNodeZPosition(NodeId nodeId, float z); // Sets node z position, nodes with higher value are drawn over nodes with lower value
|
||||||
|
IMGUI_NODE_EDITOR_API float GetNodeZPosition(NodeId nodeId); // Returns node z position, defaults is 0.0f
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void RestoreNodeState(NodeId nodeId);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void Suspend();
|
||||||
|
IMGUI_NODE_EDITOR_API void Resume();
|
||||||
|
IMGUI_NODE_EDITOR_API bool IsSuspended();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool IsActive();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool HasSelectionChanged();
|
||||||
|
IMGUI_NODE_EDITOR_API int GetSelectedObjectCount();
|
||||||
|
IMGUI_NODE_EDITOR_API int GetSelectedNodes(NodeId* nodes, int size);
|
||||||
|
IMGUI_NODE_EDITOR_API int GetSelectedLinks(LinkId* links, int size);
|
||||||
|
IMGUI_NODE_EDITOR_API bool IsNodeSelected(NodeId nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API bool IsLinkSelected(LinkId linkId);
|
||||||
|
IMGUI_NODE_EDITOR_API void ClearSelection();
|
||||||
|
IMGUI_NODE_EDITOR_API void SelectNode(NodeId nodeId, bool append = false);
|
||||||
|
IMGUI_NODE_EDITOR_API void SelectLink(LinkId linkId, bool append = false);
|
||||||
|
IMGUI_NODE_EDITOR_API void DeselectNode(NodeId nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API void DeselectLink(LinkId linkId);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool DeleteNode(NodeId nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API bool DeleteLink(LinkId linkId);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool HasAnyLinks(NodeId nodeId); // Returns true if node has any link connected
|
||||||
|
IMGUI_NODE_EDITOR_API bool HasAnyLinks(PinId pinId); // Return true if pin has any link connected
|
||||||
|
IMGUI_NODE_EDITOR_API int BreakLinks(NodeId nodeId); // Break all links connected to this node
|
||||||
|
IMGUI_NODE_EDITOR_API int BreakLinks(PinId pinId); // Break all links connected to this pin
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void NavigateToContent(float duration = -1);
|
||||||
|
IMGUI_NODE_EDITOR_API void NavigateToSelection(bool zoomIn = false, float duration = -1);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool ShowNodeContextMenu(NodeId* nodeId);
|
||||||
|
IMGUI_NODE_EDITOR_API bool ShowPinContextMenu(PinId* pinId);
|
||||||
|
IMGUI_NODE_EDITOR_API bool ShowLinkContextMenu(LinkId* linkId);
|
||||||
|
IMGUI_NODE_EDITOR_API bool ShowBackgroundContextMenu();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API void EnableShortcuts(bool enable);
|
||||||
|
IMGUI_NODE_EDITOR_API bool AreShortcutsEnabled();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool BeginShortcut();
|
||||||
|
IMGUI_NODE_EDITOR_API bool AcceptCut();
|
||||||
|
IMGUI_NODE_EDITOR_API bool AcceptCopy();
|
||||||
|
IMGUI_NODE_EDITOR_API bool AcceptPaste();
|
||||||
|
IMGUI_NODE_EDITOR_API bool AcceptDuplicate();
|
||||||
|
IMGUI_NODE_EDITOR_API bool AcceptCreateNode();
|
||||||
|
IMGUI_NODE_EDITOR_API int GetActionContextSize();
|
||||||
|
IMGUI_NODE_EDITOR_API int GetActionContextNodes(NodeId* nodes, int size);
|
||||||
|
IMGUI_NODE_EDITOR_API int GetActionContextLinks(LinkId* links, int size);
|
||||||
|
IMGUI_NODE_EDITOR_API void EndShortcut();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API float GetCurrentZoom();
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API NodeId GetHoveredNode();
|
||||||
|
IMGUI_NODE_EDITOR_API PinId GetHoveredPin();
|
||||||
|
IMGUI_NODE_EDITOR_API LinkId GetHoveredLink();
|
||||||
|
IMGUI_NODE_EDITOR_API NodeId GetDoubleClickedNode();
|
||||||
|
IMGUI_NODE_EDITOR_API PinId GetDoubleClickedPin();
|
||||||
|
IMGUI_NODE_EDITOR_API LinkId GetDoubleClickedLink();
|
||||||
|
IMGUI_NODE_EDITOR_API bool IsBackgroundClicked();
|
||||||
|
IMGUI_NODE_EDITOR_API bool IsBackgroundDoubleClicked();
|
||||||
|
IMGUI_NODE_EDITOR_API ImGuiMouseButton GetBackgroundClickButtonIndex(); // -1 if none
|
||||||
|
IMGUI_NODE_EDITOR_API ImGuiMouseButton GetBackgroundDoubleClickButtonIndex(); // -1 if none
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId); // pass nullptr if particular pin do not interest you
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API bool PinHadAnyLinks(PinId pinId);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API ImVec2 GetScreenSize();
|
||||||
|
IMGUI_NODE_EDITOR_API ImVec2 ScreenToCanvas(const ImVec2& pos);
|
||||||
|
IMGUI_NODE_EDITOR_API ImVec2 CanvasToScreen(const ImVec2& pos);
|
||||||
|
|
||||||
|
IMGUI_NODE_EDITOR_API int GetNodeCount(); // Returns number of submitted nodes since Begin() call
|
||||||
|
IMGUI_NODE_EDITOR_API int GetOrderedNodeIds(NodeId* nodes, int size); // Fills an array with node id's in order they're drawn; up to 'size` elements are set. Returns actual size of filled id's.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
namespace Details {
|
||||||
|
|
||||||
|
template <typename T, typename Tag>
|
||||||
|
struct SafeType
|
||||||
|
{
|
||||||
|
SafeType(T t)
|
||||||
|
: m_Value(std::move(t))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeType(const SafeType&) = default;
|
||||||
|
|
||||||
|
template <typename T2, typename Tag2>
|
||||||
|
SafeType(
|
||||||
|
const SafeType
|
||||||
|
<
|
||||||
|
typename std::enable_if<!std::is_same<T, T2>::value, T2>::type,
|
||||||
|
typename std::enable_if<!std::is_same<Tag, Tag2>::value, Tag2>::type
|
||||||
|
>&) = delete;
|
||||||
|
|
||||||
|
SafeType& operator=(const SafeType&) = default;
|
||||||
|
|
||||||
|
explicit operator T() const { return Get(); }
|
||||||
|
|
||||||
|
T Get() const { return m_Value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_Value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Tag>
|
||||||
|
struct SafePointerType
|
||||||
|
: SafeType<uintptr_t, Tag>
|
||||||
|
{
|
||||||
|
static const Tag Invalid;
|
||||||
|
|
||||||
|
using SafeType<uintptr_t, Tag>::SafeType;
|
||||||
|
|
||||||
|
SafePointerType()
|
||||||
|
: SafePointerType(Invalid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void> explicit SafePointerType(T* ptr): SafePointerType(reinterpret_cast<uintptr_t>(ptr)) {}
|
||||||
|
template <typename T = void> T* AsPointer() const { return reinterpret_cast<T*>(this->Get()); }
|
||||||
|
|
||||||
|
explicit operator bool() const { return *this != Invalid; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Tag>
|
||||||
|
const Tag SafePointerType<Tag>::Invalid = { 0 };
|
||||||
|
|
||||||
|
template <typename Tag>
|
||||||
|
inline bool operator==(const SafePointerType<Tag>& lhs, const SafePointerType<Tag>& rhs)
|
||||||
|
{
|
||||||
|
return lhs.Get() == rhs.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Tag>
|
||||||
|
inline bool operator!=(const SafePointerType<Tag>& lhs, const SafePointerType<Tag>& rhs)
|
||||||
|
{
|
||||||
|
return lhs.Get() != rhs.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Details
|
||||||
|
|
||||||
|
struct NodeId final: Details::SafePointerType<NodeId>
|
||||||
|
{
|
||||||
|
using SafePointerType::SafePointerType;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LinkId final: Details::SafePointerType<LinkId>
|
||||||
|
{
|
||||||
|
using SafePointerType::SafePointerType;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PinId final: Details::SafePointerType<PinId>
|
||||||
|
{
|
||||||
|
using SafePointerType::SafePointerType;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
} // namespace Editor
|
||||||
|
} // namespace ax
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# endif // __IMGUI_NODE_EDITOR_H__
|
|
@ -0,0 +1,762 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// VERSION 0.9.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include "imgui_node_editor_internal.h"
|
||||||
|
# include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static ax::NodeEditor::Detail::EditorContext* s_Editor = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
template <typename C, typename I, typename F>
|
||||||
|
static int BuildIdList(C& container, I* list, int listSize, F&& accept)
|
||||||
|
{
|
||||||
|
if (list != nullptr)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (auto object : container)
|
||||||
|
{
|
||||||
|
if (listSize <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (accept(object))
|
||||||
|
{
|
||||||
|
list[count] = I(object->ID().AsPointer());
|
||||||
|
++count;
|
||||||
|
--listSize;}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return static_cast<int>(std::count_if(container.begin(), container.end(), accept));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
ax::NodeEditor::EditorContext* ax::NodeEditor::CreateEditor(const Config* config)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ax::NodeEditor::EditorContext*>(new ax::NodeEditor::Detail::EditorContext(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::DestroyEditor(EditorContext* ctx)
|
||||||
|
{
|
||||||
|
auto lastContext = GetCurrentEditor();
|
||||||
|
|
||||||
|
// Set context we're about to destroy as current, to give callback valid context
|
||||||
|
if (lastContext != ctx)
|
||||||
|
SetCurrentEditor(ctx);
|
||||||
|
|
||||||
|
auto editor = reinterpret_cast<ax::NodeEditor::Detail::EditorContext*>(ctx);
|
||||||
|
|
||||||
|
delete editor;
|
||||||
|
|
||||||
|
if (lastContext != ctx)
|
||||||
|
SetCurrentEditor(lastContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ax::NodeEditor::Config& ax::NodeEditor::GetConfig(EditorContext* ctx)
|
||||||
|
{
|
||||||
|
if (ctx == nullptr)
|
||||||
|
ctx = GetCurrentEditor();
|
||||||
|
|
||||||
|
if (ctx)
|
||||||
|
{
|
||||||
|
auto editor = reinterpret_cast<ax::NodeEditor::Detail::EditorContext*>(ctx);
|
||||||
|
|
||||||
|
return editor->GetConfig();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static Config s_EmptyConfig;
|
||||||
|
return s_EmptyConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::SetCurrentEditor(EditorContext* ctx)
|
||||||
|
{
|
||||||
|
s_Editor = reinterpret_cast<ax::NodeEditor::Detail::EditorContext*>(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ax::NodeEditor::EditorContext* ax::NodeEditor::GetCurrentEditor()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ax::NodeEditor::EditorContext*>(s_Editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ax::NodeEditor::Style& ax::NodeEditor::GetStyle()
|
||||||
|
{
|
||||||
|
return s_Editor->GetStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ax::NodeEditor::GetStyleColorName(StyleColor colorIndex)
|
||||||
|
{
|
||||||
|
return s_Editor->GetStyle().GetColorName(colorIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PushStyleColor(StyleColor colorIndex, const ImVec4& color)
|
||||||
|
{
|
||||||
|
s_Editor->GetStyle().PushColor(colorIndex, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PopStyleColor(int count)
|
||||||
|
{
|
||||||
|
s_Editor->GetStyle().PopColor(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PushStyleVar(StyleVar varIndex, float value)
|
||||||
|
{
|
||||||
|
s_Editor->GetStyle().PushVar(varIndex, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PushStyleVar(StyleVar varIndex, const ImVec2& value)
|
||||||
|
{
|
||||||
|
s_Editor->GetStyle().PushVar(varIndex, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PushStyleVar(StyleVar varIndex, const ImVec4& value)
|
||||||
|
{
|
||||||
|
s_Editor->GetStyle().PushVar(varIndex, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PopStyleVar(int count)
|
||||||
|
{
|
||||||
|
s_Editor->GetStyle().PopVar(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::Begin(const char* id, const ImVec2& size)
|
||||||
|
{
|
||||||
|
s_Editor->Begin(id, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::End()
|
||||||
|
{
|
||||||
|
s_Editor->End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::BeginNode(NodeId id)
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().Begin(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::BeginPin(PinId id, PinKind kind)
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().BeginPin(id, kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PinRect(const ImVec2& a, const ImVec2& b)
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().PinRect(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PinPivotRect(const ImVec2& a, const ImVec2& b)
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().PinPivotRect(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PinPivotSize(const ImVec2& size)
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().PinPivotSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PinPivotScale(const ImVec2& scale)
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().PinPivotScale(scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::PinPivotAlignment(const ImVec2& alignment)
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().PinPivotAlignment(alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::EndPin()
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().EndPin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::Group(const ImVec2& size)
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().Group(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::EndNode()
|
||||||
|
{
|
||||||
|
s_Editor->GetNodeBuilder().End();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::BeginGroupHint(NodeId nodeId)
|
||||||
|
{
|
||||||
|
return s_Editor->GetHintBuilder().Begin(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ax::NodeEditor::GetGroupMin()
|
||||||
|
{
|
||||||
|
return s_Editor->GetHintBuilder().GetGroupMin();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ax::NodeEditor::GetGroupMax()
|
||||||
|
{
|
||||||
|
return s_Editor->GetHintBuilder().GetGroupMax();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImDrawList* ax::NodeEditor::GetHintForegroundDrawList()
|
||||||
|
{
|
||||||
|
return s_Editor->GetHintBuilder().GetForegroundDrawList();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImDrawList* ax::NodeEditor::GetHintBackgroundDrawList()
|
||||||
|
{
|
||||||
|
return s_Editor->GetHintBuilder().GetBackgroundDrawList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::EndGroupHint()
|
||||||
|
{
|
||||||
|
s_Editor->GetHintBuilder().End();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImDrawList* ax::NodeEditor::GetNodeBackgroundDrawList(NodeId nodeId)
|
||||||
|
{
|
||||||
|
if (auto node = s_Editor->FindNode(nodeId))
|
||||||
|
return s_Editor->GetNodeBuilder().GetUserBackgroundDrawList(node);
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::Link(LinkId id, PinId startPinId, PinId endPinId, const ImVec4& color/* = ImVec4(1, 1, 1, 1)*/, float thickness/* = 1.0f*/)
|
||||||
|
{
|
||||||
|
return s_Editor->DoLink(id, startPinId, endPinId, ImColor(color), thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::Flow(LinkId linkId, FlowDirection direction)
|
||||||
|
{
|
||||||
|
if (auto link = s_Editor->FindLink(linkId))
|
||||||
|
s_Editor->Flow(link, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::BeginCreate(const ImVec4& color, float thickness)
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
if (context.Begin())
|
||||||
|
{
|
||||||
|
context.SetStyle(ImColor(color), thickness);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::QueryNewLink(PinId* startId, PinId* endId)
|
||||||
|
{
|
||||||
|
using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
|
||||||
|
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
return context.QueryLink(startId, endId) == Result::True;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::QueryNewLink(PinId* startId, PinId* endId, const ImVec4& color, float thickness)
|
||||||
|
{
|
||||||
|
using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
|
||||||
|
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
auto result = context.QueryLink(startId, endId);
|
||||||
|
if (result != Result::Indeterminate)
|
||||||
|
context.SetStyle(ImColor(color), thickness);
|
||||||
|
|
||||||
|
return result == Result::True;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::QueryNewNode(PinId* pinId)
|
||||||
|
{
|
||||||
|
using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
|
||||||
|
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
return context.QueryNode(pinId) == Result::True;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::QueryNewNode(PinId* pinId, const ImVec4& color, float thickness)
|
||||||
|
{
|
||||||
|
using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
|
||||||
|
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
auto result = context.QueryNode(pinId);
|
||||||
|
if (result != Result::Indeterminate)
|
||||||
|
context.SetStyle(ImColor(color), thickness);
|
||||||
|
|
||||||
|
return result == Result::True;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AcceptNewItem()
|
||||||
|
{
|
||||||
|
using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
|
||||||
|
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
return context.AcceptItem() == Result::True;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AcceptNewItem(const ImVec4& color, float thickness)
|
||||||
|
{
|
||||||
|
using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
|
||||||
|
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
auto result = context.AcceptItem();
|
||||||
|
if (result != Result::Indeterminate)
|
||||||
|
context.SetStyle(ImColor(color), thickness);
|
||||||
|
|
||||||
|
return result == Result::True;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::RejectNewItem()
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
context.RejectItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::RejectNewItem(const ImVec4& color, float thickness)
|
||||||
|
{
|
||||||
|
using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
|
||||||
|
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
if (context.RejectItem() != Result::Indeterminate)
|
||||||
|
context.SetStyle(ImColor(color), thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::EndCreate()
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemCreator();
|
||||||
|
|
||||||
|
context.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::BeginDelete()
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemDeleter();
|
||||||
|
|
||||||
|
return context.Begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::QueryDeletedLink(LinkId* linkId, PinId* startId, PinId* endId)
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemDeleter();
|
||||||
|
|
||||||
|
return context.QueryLink(linkId, startId, endId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::QueryDeletedNode(NodeId* nodeId)
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemDeleter();
|
||||||
|
|
||||||
|
return context.QueryNode(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AcceptDeletedItem(bool deleteDependencies)
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemDeleter();
|
||||||
|
|
||||||
|
return context.AcceptItem(deleteDependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::RejectDeletedItem()
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemDeleter();
|
||||||
|
|
||||||
|
context.RejectItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::EndDelete()
|
||||||
|
{
|
||||||
|
auto& context = s_Editor->GetItemDeleter();
|
||||||
|
|
||||||
|
context.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::SetNodePosition(NodeId nodeId, const ImVec2& position)
|
||||||
|
{
|
||||||
|
s_Editor->SetNodePosition(nodeId, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::SetGroupSize(NodeId nodeId, const ImVec2& size)
|
||||||
|
{
|
||||||
|
s_Editor->SetGroupSize(nodeId, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ax::NodeEditor::GetNodePosition(NodeId nodeId)
|
||||||
|
{
|
||||||
|
return s_Editor->GetNodePosition(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ax::NodeEditor::GetNodeSize(NodeId nodeId)
|
||||||
|
{
|
||||||
|
return s_Editor->GetNodeSize(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::CenterNodeOnScreen(NodeId nodeId)
|
||||||
|
{
|
||||||
|
if (auto node = s_Editor->FindNode(nodeId))
|
||||||
|
node->CenterOnScreenInNextFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::SetNodeZPosition(NodeId nodeId, float z)
|
||||||
|
{
|
||||||
|
s_Editor->SetNodeZPosition(nodeId, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ax::NodeEditor::GetNodeZPosition(NodeId nodeId)
|
||||||
|
{
|
||||||
|
return s_Editor->GetNodeZPosition(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::RestoreNodeState(NodeId nodeId)
|
||||||
|
{
|
||||||
|
if (auto node = s_Editor->FindNode(nodeId))
|
||||||
|
s_Editor->MarkNodeToRestoreState(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::Suspend()
|
||||||
|
{
|
||||||
|
s_Editor->Suspend();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::Resume()
|
||||||
|
{
|
||||||
|
s_Editor->Resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::IsSuspended()
|
||||||
|
{
|
||||||
|
return s_Editor->IsSuspended();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::IsActive()
|
||||||
|
{
|
||||||
|
return s_Editor->IsFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::HasSelectionChanged()
|
||||||
|
{
|
||||||
|
return s_Editor->HasSelectionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::GetSelectedObjectCount()
|
||||||
|
{
|
||||||
|
return (int)s_Editor->GetSelectedObjects().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::GetSelectedNodes(NodeId* nodes, int size)
|
||||||
|
{
|
||||||
|
return BuildIdList(s_Editor->GetSelectedObjects(), nodes, size, [](auto object)
|
||||||
|
{
|
||||||
|
return object->AsNode() != nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::GetSelectedLinks(LinkId* links, int size)
|
||||||
|
{
|
||||||
|
return BuildIdList(s_Editor->GetSelectedObjects(), links, size, [](auto object)
|
||||||
|
{
|
||||||
|
return object->AsLink() != nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::IsNodeSelected(NodeId nodeId)
|
||||||
|
{
|
||||||
|
if (auto node = s_Editor->FindNode(nodeId))
|
||||||
|
return s_Editor->IsSelected(node);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::IsLinkSelected(LinkId linkId)
|
||||||
|
{
|
||||||
|
if (auto link = s_Editor->FindLink(linkId))
|
||||||
|
return s_Editor->IsSelected(link);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::ClearSelection()
|
||||||
|
{
|
||||||
|
s_Editor->ClearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::SelectNode(NodeId nodeId, bool append)
|
||||||
|
{
|
||||||
|
if (auto node = s_Editor->FindNode(nodeId))
|
||||||
|
{
|
||||||
|
if (append)
|
||||||
|
s_Editor->SelectObject(node);
|
||||||
|
else
|
||||||
|
s_Editor->SetSelectedObject(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::SelectLink(LinkId linkId, bool append)
|
||||||
|
{
|
||||||
|
if (auto link = s_Editor->FindLink(linkId))
|
||||||
|
{
|
||||||
|
if (append)
|
||||||
|
s_Editor->SelectObject(link);
|
||||||
|
else
|
||||||
|
s_Editor->SetSelectedObject(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::DeselectNode(NodeId nodeId)
|
||||||
|
{
|
||||||
|
if (auto node = s_Editor->FindNode(nodeId))
|
||||||
|
s_Editor->DeselectObject(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::DeselectLink(LinkId linkId)
|
||||||
|
{
|
||||||
|
if (auto link = s_Editor->FindLink(linkId))
|
||||||
|
s_Editor->DeselectObject(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::DeleteNode(NodeId nodeId)
|
||||||
|
{
|
||||||
|
if (auto node = s_Editor->FindNode(nodeId))
|
||||||
|
return s_Editor->GetItemDeleter().Add(node);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::DeleteLink(LinkId linkId)
|
||||||
|
{
|
||||||
|
if (auto link = s_Editor->FindLink(linkId))
|
||||||
|
return s_Editor->GetItemDeleter().Add(link);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::HasAnyLinks(NodeId nodeId)
|
||||||
|
{
|
||||||
|
return s_Editor->HasAnyLinks(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::HasAnyLinks(PinId pinId)
|
||||||
|
{
|
||||||
|
return s_Editor->HasAnyLinks(pinId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::BreakLinks(NodeId nodeId)
|
||||||
|
{
|
||||||
|
return s_Editor->BreakLinks(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::BreakLinks(PinId pinId)
|
||||||
|
{
|
||||||
|
return s_Editor->BreakLinks(pinId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::NavigateToContent(float duration)
|
||||||
|
{
|
||||||
|
s_Editor->NavigateTo(s_Editor->GetContentBounds(), true, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::NavigateToSelection(bool zoomIn, float duration)
|
||||||
|
{
|
||||||
|
s_Editor->NavigateTo(s_Editor->GetSelectionBounds(), zoomIn, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::ShowNodeContextMenu(NodeId* nodeId)
|
||||||
|
{
|
||||||
|
return s_Editor->GetContextMenu().ShowNodeContextMenu(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::ShowPinContextMenu(PinId* pinId)
|
||||||
|
{
|
||||||
|
return s_Editor->GetContextMenu().ShowPinContextMenu(pinId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::ShowLinkContextMenu(LinkId* linkId)
|
||||||
|
{
|
||||||
|
return s_Editor->GetContextMenu().ShowLinkContextMenu(linkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::ShowBackgroundContextMenu()
|
||||||
|
{
|
||||||
|
return s_Editor->GetContextMenu().ShowBackgroundContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::EnableShortcuts(bool enable)
|
||||||
|
{
|
||||||
|
s_Editor->EnableShortcuts(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AreShortcutsEnabled()
|
||||||
|
{
|
||||||
|
return s_Editor->AreShortcutsEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::BeginShortcut()
|
||||||
|
{
|
||||||
|
return s_Editor->GetShortcut().Begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AcceptCut()
|
||||||
|
{
|
||||||
|
return s_Editor->GetShortcut().AcceptCut();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AcceptCopy()
|
||||||
|
{
|
||||||
|
return s_Editor->GetShortcut().AcceptCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AcceptPaste()
|
||||||
|
{
|
||||||
|
return s_Editor->GetShortcut().AcceptPaste();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AcceptDuplicate()
|
||||||
|
{
|
||||||
|
return s_Editor->GetShortcut().AcceptDuplicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::AcceptCreateNode()
|
||||||
|
{
|
||||||
|
return s_Editor->GetShortcut().AcceptCreateNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::GetActionContextSize()
|
||||||
|
{
|
||||||
|
return static_cast<int>(s_Editor->GetShortcut().m_Context.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::GetActionContextNodes(NodeId* nodes, int size)
|
||||||
|
{
|
||||||
|
return BuildIdList(s_Editor->GetSelectedObjects(), nodes, size, [](auto object)
|
||||||
|
{
|
||||||
|
return object->AsNode() != nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::GetActionContextLinks(LinkId* links, int size)
|
||||||
|
{
|
||||||
|
return BuildIdList(s_Editor->GetSelectedObjects(), links, size, [](auto object)
|
||||||
|
{
|
||||||
|
return object->AsLink() != nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ax::NodeEditor::EndShortcut()
|
||||||
|
{
|
||||||
|
return s_Editor->GetShortcut().End();
|
||||||
|
}
|
||||||
|
|
||||||
|
float ax::NodeEditor::GetCurrentZoom()
|
||||||
|
{
|
||||||
|
return s_Editor->GetView().InvScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
ax::NodeEditor::NodeId ax::NodeEditor::GetHoveredNode()
|
||||||
|
{
|
||||||
|
return s_Editor->GetHoveredNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
ax::NodeEditor::PinId ax::NodeEditor::GetHoveredPin()
|
||||||
|
{
|
||||||
|
return s_Editor->GetHoveredPin();
|
||||||
|
}
|
||||||
|
|
||||||
|
ax::NodeEditor::LinkId ax::NodeEditor::GetHoveredLink()
|
||||||
|
{
|
||||||
|
return s_Editor->GetHoveredLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
ax::NodeEditor::NodeId ax::NodeEditor::GetDoubleClickedNode()
|
||||||
|
{
|
||||||
|
return s_Editor->GetDoubleClickedNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
ax::NodeEditor::PinId ax::NodeEditor::GetDoubleClickedPin()
|
||||||
|
{
|
||||||
|
return s_Editor->GetDoubleClickedPin();
|
||||||
|
}
|
||||||
|
|
||||||
|
ax::NodeEditor::LinkId ax::NodeEditor::GetDoubleClickedLink()
|
||||||
|
{
|
||||||
|
return s_Editor->GetDoubleClickedLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::IsBackgroundClicked()
|
||||||
|
{
|
||||||
|
return s_Editor->IsBackgroundClicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::IsBackgroundDoubleClicked()
|
||||||
|
{
|
||||||
|
return s_Editor->IsBackgroundDoubleClicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiMouseButton ax::NodeEditor::GetBackgroundClickButtonIndex()
|
||||||
|
{
|
||||||
|
return s_Editor->GetBackgroundClickButtonIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiMouseButton ax::NodeEditor::GetBackgroundDoubleClickButtonIndex()
|
||||||
|
{
|
||||||
|
return s_Editor->GetBackgroundDoubleClickButtonIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId)
|
||||||
|
{
|
||||||
|
auto link = s_Editor->FindLink(linkId);
|
||||||
|
if (!link)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (startPinId)
|
||||||
|
*startPinId = link->m_StartPin->m_ID;
|
||||||
|
if (endPinId)
|
||||||
|
*endPinId = link->m_EndPin->m_ID;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ax::NodeEditor::PinHadAnyLinks(PinId pinId)
|
||||||
|
{
|
||||||
|
return s_Editor->PinHadAnyLinks(pinId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ax::NodeEditor::GetScreenSize()
|
||||||
|
{
|
||||||
|
return s_Editor->GetRect().GetSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ax::NodeEditor::ScreenToCanvas(const ImVec2& pos)
|
||||||
|
{
|
||||||
|
return s_Editor->ToCanvas(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ax::NodeEditor::CanvasToScreen(const ImVec2& pos)
|
||||||
|
{
|
||||||
|
return s_Editor->ToScreen(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::GetNodeCount()
|
||||||
|
{
|
||||||
|
return s_Editor->CountLiveNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ax::NodeEditor::GetOrderedNodeIds(NodeId* nodes, int size)
|
||||||
|
{
|
||||||
|
return s_Editor->GetNodeIds(nodes, size);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,65 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// VERSION 0.9.1
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
// This software is dual-licensed to the public domain and under the following
|
||||||
|
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
// publish, and distribute this file as you see fit.
|
||||||
|
//
|
||||||
|
// CREDITS
|
||||||
|
// Written by Michal Cichon
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# ifndef __IMGUI_NODE_EDITOR_INTERNAL_INL__
|
||||||
|
# define __IMGUI_NODE_EDITOR_INTERNAL_INL__
|
||||||
|
# pragma once
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# include "imgui_node_editor_internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
namespace ax {
|
||||||
|
namespace NodeEditor {
|
||||||
|
namespace Detail {
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//inline ImRect ToRect(const ax::rectf& rect)
|
||||||
|
//{
|
||||||
|
// return ImRect(
|
||||||
|
// to_imvec(rect.top_left()),
|
||||||
|
// to_imvec(rect.bottom_right())
|
||||||
|
// );
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//inline ImRect ToRect(const ax::rect& rect)
|
||||||
|
//{
|
||||||
|
// return ImRect(
|
||||||
|
// to_imvec(rect.top_left()),
|
||||||
|
// to_imvec(rect.bottom_right())
|
||||||
|
// );
|
||||||
|
//}
|
||||||
|
|
||||||
|
inline ImRect ImGui_GetItemRect()
|
||||||
|
{
|
||||||
|
return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImVec2 ImGui_GetMouseClickPos(ImGuiMouseButton buttonIndex)
|
||||||
|
{
|
||||||
|
if (ImGui::IsMouseDown(buttonIndex))
|
||||||
|
return ImGui::GetIO().MouseClickedPos[buttonIndex];
|
||||||
|
else
|
||||||
|
return ImGui::GetMousePos();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Editor
|
||||||
|
} // namespace ax
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
# endif // __IMGUI_NODE_EDITOR_INTERNAL_INL__
|
|
@ -0,0 +1,17 @@
|
||||||
|
if (TARGET ScopeGuard)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_ScopeGuard_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/ScopeGuard)
|
||||||
|
set(_ScopeGuard_BinaryDir ${CMAKE_BINARY_DIR}/external/ScopeGuard)
|
||||||
|
|
||||||
|
add_subdirectory(${_ScopeGuard_SourceDir} ${_ScopeGuard_BinaryDir})
|
||||||
|
|
||||||
|
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(
|
||||||
|
ScopeGuard
|
||||||
|
REQUIRED_VARS
|
||||||
|
_ScopeGuard_SourceDir
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
if (TARGET gl3w)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_gl3w_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/gl3w)
|
||||||
|
set(_gl3w_BinaryDir ${CMAKE_BINARY_DIR}/external/gl3w)
|
||||||
|
|
||||||
|
add_subdirectory(${_gl3w_SourceDir} ${_gl3w_BinaryDir})
|
||||||
|
|
||||||
|
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(
|
||||||
|
gl3w
|
||||||
|
REQUIRED_VARS
|
||||||
|
_gl3w_SourceDir
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
if (TARGET imgui)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_imgui_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/imgui)
|
||||||
|
set(_imgui_BinaryDir ${CMAKE_BINARY_DIR}/external/imgui)
|
||||||
|
|
||||||
|
add_subdirectory(${_imgui_SourceDir} ${_imgui_BinaryDir})
|
||||||
|
|
||||||
|
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(
|
||||||
|
imgui
|
||||||
|
REQUIRED_VARS
|
||||||
|
_imgui_SourceDir
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
if (TARGET imgui_node_editor)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#set(_imgui_node_editor_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR})
|
||||||
|
#set(_imgui_node_editor_BinaryDir ${CMAKE_BINARY_DIR}/NodeEditor)
|
||||||
|
|
||||||
|
#add_subdirectory(${_imgui_node_editor_SourceDir} ${_imgui_node_editor_BinaryDir})
|
||||||
|
|
||||||
|
find_package(imgui REQUIRED)
|
||||||
|
|
||||||
|
set(_imgui_node_editor_Sources
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/crude_json.cpp
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/crude_json.h
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_bezier_math.h
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_bezier_math.inl
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_canvas.cpp
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_canvas.cpp
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_canvas.h
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_canvas.h
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_extra_math.h
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_extra_math.inl
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor_api.cpp
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor_internal.h
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor_internal.inl
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor.cpp
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor.h
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}/misc/imgui_node_editor.natvis
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(imgui_node_editor STATIC
|
||||||
|
${_imgui_node_editor_Sources}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(imgui_node_editor PUBLIC
|
||||||
|
${IMGUI_NODE_EDITOR_ROOT_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(imgui_node_editor PUBLIC imgui)
|
||||||
|
|
||||||
|
source_group(TREE ${IMGUI_NODE_EDITOR_ROOT_DIR} FILES ${_imgui_node_editor_Sources})
|
||||||
|
|
||||||
|
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(
|
||||||
|
imgui_node_editor
|
||||||
|
REQUIRED_VARS
|
||||||
|
IMGUI_NODE_EDITOR_ROOT_DIR
|
||||||
|
)
|
|
@ -0,0 +1,17 @@
|
||||||
|
if (TARGET stb_image)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_stb_image_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/stb_image)
|
||||||
|
set(_stb_image_BinaryDir ${CMAKE_BINARY_DIR}/external/stb_image)
|
||||||
|
|
||||||
|
add_subdirectory(${_stb_image_SourceDir} ${_stb_image_BinaryDir})
|
||||||
|
|
||||||
|
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(
|
||||||
|
stb_image
|
||||||
|
REQUIRED_VARS
|
||||||
|
_stb_image_SourceDir
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
|
||||||
|
<Type Name="crude_json::value">
|
||||||
|
<DisplayString Condition="m_Type == 1">{m_Type,en} {*(crude_json::object*)&m_Storage,view(simple)}</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == 2">{m_Type,en} {*(crude_json::array*)&m_Storage,view(simple)}</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == 3">{*(crude_json::string*)&m_Storage,view(simple)}</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == 4">{*(crude_json::boolean*)&m_Storage}</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == 5">{*(crude_json::number*)&m_Storage,g}</DisplayString>
|
||||||
|
<DisplayString>{m_Type,en}</DisplayString>
|
||||||
|
<StringView Condition="m_Type == 3">*(crude_json::string*)&m_Storage</StringView>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem Condition="m_Type == 1">*(crude_json::object*)&m_Storage,view(simple)</ExpandedItem>
|
||||||
|
<ExpandedItem Condition="m_Type == 2">*(crude_json::array*)&m_Storage,view(simple)</ExpandedItem>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
</AutoVisualizer>
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
|
||||||
|
<Type Name="ax::NodeEditor::Details::SafePointerType<*>">
|
||||||
|
<DisplayString>{m_Value}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[Value]">m_Value</Item>
|
||||||
|
<Item Name="[Pointer]">($T1*)m_Value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="ax::NodeEditor::NodeId">
|
||||||
|
<DisplayString>Node {m_Value}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[Value]">m_Value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="ax::NodeEditor::LinkId">
|
||||||
|
<DisplayString>Link {m_Value}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[Value]">m_Value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="ax::NodeEditor::PinId">
|
||||||
|
<DisplayString>Pin {m_Value}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[Value]">m_Value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="std::pair<*, crude_json::value>" IncludeView="MapHelper" Priority="High">
|
||||||
|
<DisplayString>{second}</DisplayString>
|
||||||
|
<Expand HideRawView="true">
|
||||||
|
<ExpandedItem>second</ExpandedItem>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="crude_json::value">
|
||||||
|
<Intrinsic Name="object_ptr" Expression="(crude_json::object*)&m_Storage" />
|
||||||
|
<Intrinsic Name="array_ptr" Expression="(crude_json::array*)&m_Storage" />
|
||||||
|
<Intrinsic Name="string_ptr" Expression="(crude_json::string*)&m_Storage" />
|
||||||
|
<Intrinsic Name="boolean_ptr" Expression="(crude_json::boolean*)&m_Storage" />
|
||||||
|
<Intrinsic Name="number_ptr" Expression="(crude_json::number*)&m_Storage" />
|
||||||
|
|
||||||
|
<DisplayString Condition="m_Type == crude_json::type_t::null">null</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == crude_json::type_t::object">{*object_ptr()} : object</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == crude_json::type_t::array">{*array_ptr()} : array</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == crude_json::type_t::string">{*string_ptr()} : string</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == crude_json::type_t::boolean">{*boolean_ptr()} : boolean</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == crude_json::type_t::number">{*number_ptr(),g} : number</DisplayString>
|
||||||
|
<DisplayString Condition="m_Type == crude_json::type_t::discarded">discarded</DisplayString>
|
||||||
|
<Expand HideRawView="true">
|
||||||
|
<!--<Synthetic Name="[type]"><DisplayString>{m_Type,en}</DisplayString></Synthetic>-->
|
||||||
|
<ExpandedItem Condition="m_Type == crude_json::type_t::object">*object_ptr(),view(simple)</ExpandedItem>
|
||||||
|
<ExpandedItem Condition="m_Type == crude_json::type_t::array">*array_ptr(),view(simple)</ExpandedItem>
|
||||||
|
<Item Name="[value]" Condition="m_Type == crude_json::type_t::string">*string_ptr(),view(simple)</Item>
|
||||||
|
<Item Name="[value]" Condition="m_Type == crude_json::type_t::boolean">*boolean_ptr()</Item>
|
||||||
|
<Item Name="[value]" Condition="m_Type == crude_json::type_t::number">*number_ptr()</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
</AutoVisualizer>
|
|
@ -1,6 +1,12 @@
|
||||||
# See http://editorconfig.org to read about the EditorConfig format.
|
# See http://editorconfig.org to read about the EditorConfig format.
|
||||||
# - Automatically supported by VS2017+ and most common IDE or text editors.
|
# - In theory automatically supported by VS2017+ and most common IDE or text editors.
|
||||||
# - For older VS2010 to VS2015, install https://marketplace.visualstudio.com/items?itemName=EditorConfigTeam.EditorConfig
|
# - In practice VS2019-VS2022 stills don't trim trailing whitespaces correctly :(
|
||||||
|
# - Suggest installing this to trim whitespaces:
|
||||||
|
# GitHub https://github.com/madskristensen/TrailingWhitespace
|
||||||
|
# VS2019 https://marketplace.visualstudio.com/items?itemName=MadsKristensen.TrailingWhitespaceVisualizer
|
||||||
|
# VS2022 https://marketplace.visualstudio.com/items?itemName=MadsKristensen.TrailingWhitespace64
|
||||||
|
# (in spite of its name doesn't only visualize but also trims)
|
||||||
|
# - Alternative for older VS2010 to VS2015: https://marketplace.visualstudio.com/items?itemName=EditorConfigTeam.EditorConfig
|
||||||
|
|
||||||
# top-most EditorConfig file
|
# top-most EditorConfig file
|
||||||
root = true
|
root = true
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
(Click "Preview" above ^ to turn URL into clickable links)
|
(Click "Preview" above ^ to turn URL into clickable links)
|
||||||
|
|
||||||
1. PLEASE CAREFULLY READ: [FAQ](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md)
|
1. FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING or LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions).
|
||||||
|
|
||||||
2. PLEASE CAREFULLY READ: [Issue Submitting Guidelines](https://github.com/ocornut/imgui/issues/2261)
|
2. PLEASE CAREFULLY READ: [FAQ](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md)
|
||||||
|
|
||||||
3. FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING/LOADING FONTS, please use the [Discord server](http://discord.dearimgui.org).
|
3. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md)
|
||||||
|
|
||||||
4. PLEASE MAKE SURE that you have: read the FAQ; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1) (2).
|
4. PLEASE MAKE SURE that you have: read the FAQ; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the links above.
|
||||||
|
|
||||||
5. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
|
5. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
(Click "Preview" to turn any http URL into a clickable link)
|
(Click "Preview" to turn any http URL into a clickable link)
|
||||||
|
|
||||||
PLEASE CAREFULLY READ:
|
1. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md)
|
||||||
https://github.com/ocornut/imgui/issues/2261
|
|
||||||
|
2. Clear this template before submitting your PR.
|
||||||
|
|
||||||
(Clear this template before submitting your PR)
|
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
name: build
|
name: build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push: {}
|
push:
|
||||||
pull_request: {}
|
pull_request:
|
||||||
schedule:
|
workflow_run:
|
||||||
- cron: '0 9 * * *'
|
# Use a workflow as a trigger of scheduled builds. Forked repositories can disable scheduled builds by disabling
|
||||||
|
# "scheduled" workflow, while maintaining ability to perform local CI builds.
|
||||||
|
workflows:
|
||||||
|
- scheduled
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- docking
|
||||||
|
types:
|
||||||
|
- requested
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Windows:
|
Windows:
|
||||||
|
@ -12,66 +20,36 @@ jobs:
|
||||||
env:
|
env:
|
||||||
VS_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\
|
VS_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\
|
||||||
MSBUILD_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\
|
MSBUILD_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\
|
||||||
# Until gh-actions allow us to use env variables inside other env variables (because we need %GITHUB_WORKSPACE%) we have to use relative path to imgui/examples/example_name directory.
|
|
||||||
SDL2_DIR: ..\..\SDL2-devel-2.0.10-VC\SDL2-2.0.10\
|
|
||||||
VULKAN_SDK: ..\..\vulkan-sdk-1.1.121.2\
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL2-devel-2.0.10-VC.zip" -OutFile "SDL2-devel-2.0.10-VC.zip"
|
Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL2-devel-2.26.3-VC.zip" -OutFile "SDL2-devel-2.26.3-VC.zip"
|
||||||
Expand-Archive -Path SDL2-devel-2.0.10-VC.zip
|
Expand-Archive -Path SDL2-devel-2.26.3-VC.zip
|
||||||
|
echo "SDL2_DIR=$(pwd)\SDL2-devel-2.26.3-VC\SDL2-2.26.3\" >>${env:GITHUB_ENV}
|
||||||
|
|
||||||
Invoke-WebRequest -Uri "https://github.com/ocornut/imgui/files/3789205/vulkan-sdk-1.1.121.2.zip" -OutFile vulkan-sdk-1.1.121.2.zip
|
Invoke-WebRequest -Uri "https://github.com/ocornut/imgui/files/3789205/vulkan-sdk-1.1.121.2.zip" -OutFile vulkan-sdk-1.1.121.2.zip
|
||||||
Expand-Archive -Path vulkan-sdk-1.1.121.2.zip
|
Expand-Archive -Path vulkan-sdk-1.1.121.2.zip
|
||||||
|
echo "VULKAN_SDK=$(pwd)\vulkan-sdk-1.1.121.2\" >>${env:GITHUB_ENV}
|
||||||
|
|
||||||
- name: Fix Projects
|
- name: Fix Projects
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
# WARNING: This will need updating if toolset/sdk change in project files!
|
# CI workers do not supporter older Visual Studio versions. Fix projects to target newer available version.
|
||||||
gci -recurse -filter "*.vcxproj" | ForEach-Object {
|
gci -recurse -filter "*.vcxproj" | ForEach-Object {
|
||||||
# Fix SDK and toolset for most samples.
|
(Get-Content $_.FullName) -Replace "<PlatformToolset>v\d{3}</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName
|
||||||
(Get-Content $_.FullName) -Replace "<PlatformToolset>v110</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName
|
(Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>[\d\.]+</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName
|
||||||
(Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName
|
|
||||||
# Fix SDK and toolset for samples that require newer SDK/toolset. At the moment it is only dx12.
|
|
||||||
(Get-Content $_.FullName) -Replace "<PlatformToolset>v140</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName
|
|
||||||
(Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long.
|
# Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long.
|
||||||
- name: Build example_null (extra warnings, mingw 64-bit)
|
- name: Build example_null (extra warnings, mingw 64-bit)
|
||||||
run: mingw32-make -C examples/example_null WITH_EXTRA_WARNINGS=1
|
run: mingw32-make -C examples/example_null WITH_EXTRA_WARNINGS=1
|
||||||
|
|
||||||
- name: Build example_null (extra warnings, msvc 64-bit)
|
- name: Build example_null (mingw 64-bit, as DLL)
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
cd examples\example_null
|
|
||||||
"%VS_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64 && .\build_win32.bat /W4
|
|
||||||
|
|
||||||
- name: Build example_null (single file build)
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_IMPLEMENTATION' > example_single_file.cpp
|
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
|
||||||
g++ -I. -Wall -Wformat -o example_single_file.exe example_single_file.cpp
|
|
||||||
|
|
||||||
- name: Build example_null (with IMGUI_DISABLE_WIN32_FUNCTIONS)
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo '#define IMGUI_DISABLE_WIN32_FUNCTIONS' > example_single_file.cpp
|
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
|
||||||
g++ -I. -Wall -Wformat -o example_single_file.exe example_single_file.cpp
|
|
||||||
|
|
||||||
- name: Build example_null (as DLL)
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
"%VS_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64
|
|
||||||
echo '#ifdef _EXPORT' > example_single_file.cpp
|
echo '#ifdef _EXPORT' > example_single_file.cpp
|
||||||
echo '# define IMGUI_API __declspec(dllexport)' >> example_single_file.cpp
|
echo '# define IMGUI_API __declspec(dllexport)' >> example_single_file.cpp
|
||||||
echo '#else' >> example_single_file.cpp
|
echo '#else' >> example_single_file.cpp
|
||||||
|
@ -79,6 +57,55 @@ jobs:
|
||||||
echo '#endif' >> example_single_file.cpp
|
echo '#endif' >> example_single_file.cpp
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
||||||
|
g++ -I. -Wall -Wformat -D_EXPORT -shared -o libimgui.dll -Wl,--out-implib,libimgui.a example_single_file.cpp -limm32
|
||||||
|
g++ -I. -Wall -Wformat -o example_null.exe examples/example_null/main.cpp -L. -limgui
|
||||||
|
rm -f example_null.exe libimgui.* example_single_file.*
|
||||||
|
|
||||||
|
- name: Build example_null (extra warnings, msvc 64-bit)
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
cd examples\example_null
|
||||||
|
call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat"
|
||||||
|
.\build_win32.bat /W4
|
||||||
|
|
||||||
|
- name: Build example_null (single file build)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cat > example_single_file.cpp <<'EOF'
|
||||||
|
|
||||||
|
#define IMGUI_IMPLEMENTATION
|
||||||
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -Wall -Wformat -o example_single_file.exe example_single_file.cpp -limm32
|
||||||
|
|
||||||
|
- name: Build example_null (with IMGUI_DISABLE_WIN32_FUNCTIONS)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cat > example_single_file.cpp <<'EOF'
|
||||||
|
|
||||||
|
#define IMGUI_DISABLE_WIN32_FUNCTIONS
|
||||||
|
#define IMGUI_IMPLEMENTATION
|
||||||
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -Wall -Wformat -o example_single_file.exe example_single_file.cpp -limm32
|
||||||
|
|
||||||
|
- name: Build example_null (as DLL)
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat"
|
||||||
|
|
||||||
|
echo #ifdef _EXPORT > example_single_file.cpp
|
||||||
|
echo # define IMGUI_API __declspec(dllexport) >> example_single_file.cpp
|
||||||
|
echo #else >> example_single_file.cpp
|
||||||
|
echo # define IMGUI_API __declspec(dllimport) >> example_single_file.cpp
|
||||||
|
echo #endif >> example_single_file.cpp
|
||||||
|
echo #define IMGUI_IMPLEMENTATION >> example_single_file.cpp
|
||||||
|
echo #include "misc/single_file/imgui_single_file.h" >> example_single_file.cpp
|
||||||
|
|
||||||
cl.exe /D_USRDLL /D_WINDLL /D_EXPORT /I. example_single_file.cpp /LD /FeImGui.dll /link
|
cl.exe /D_USRDLL /D_WINDLL /D_EXPORT /I. example_single_file.cpp /LD /FeImGui.dll /link
|
||||||
cl.exe /I. ImGui.lib /Feexample_null.exe examples/example_null/main.cpp
|
cl.exe /I. ImGui.lib /Feexample_null.exe examples/example_null/main.cpp
|
||||||
|
|
||||||
|
@ -89,31 +116,31 @@ jobs:
|
||||||
- name: Build Win32 example_glfw_opengl3
|
- name: Build Win32 example_glfw_opengl3
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build Win32 example_glfw_vulkan
|
- name: Build Win32 example_glfw_vulkan
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build Win32 example_sdl_vulkan
|
- name: Build Win32 example_sdl2_vulkan
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl_vulkan/example_sdl_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build Win32 example_sdl_opengl2
|
- name: Build Win32 example_sdl2_opengl2
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl_opengl2/example_sdl_opengl2.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build Win32 example_sdl_opengl3
|
- name: Build Win32 example_sdl2_opengl3
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl_opengl3/example_sdl_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
||||||
|
|
||||||
- name: Build Win32 example_sdl_directx11
|
- name: Build Win32 example_sdl2_directx11
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl_directx11/example_sdl_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build Win32 example_win32_directx9
|
- name: Build Win32 example_win32_directx9
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
@ -126,12 +153,12 @@ jobs:
|
||||||
- name: Build Win32 example_win32_directx11
|
- name: Build Win32 example_win32_directx11
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build x64 example_glfw_opengl2
|
- name: Build x64 example_glfw_opengl2
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build x64 example_glfw_opengl3
|
- name: Build x64 example_glfw_opengl3
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
@ -141,55 +168,53 @@ jobs:
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
|
|
||||||
- name: Build x64 example_sdl_vulkan
|
- name: Build x64 example_sdl2_vulkan
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl_vulkan/example_sdl_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build x64 example_sdl_opengl2
|
- name: Build x64 example_sdl2_opengl2
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl_opengl2/example_sdl_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build x64 example_sdl_opengl3
|
- name: Build x64 example_sdl2_opengl3
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl_opengl3/example_sdl_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build x64 example_sdl_directx11
|
- name: Build x64 example_sdl2_directx11
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl_directx11/example_sdl_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
|
|
||||||
- name: Build x64 example_win32_directx9
|
- name: Build x64 example_win32_directx9
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build x64 example_win32_directx10
|
- name: Build x64 example_win32_directx10
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx10/example_win32_directx10.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx10/example_win32_directx10.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build x64 example_win32_directx11
|
- name: Build x64 example_win32_directx11
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build x64 example_win32_directx12
|
- name: Build x64 example_win32_directx12
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx12/example_win32_directx12.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx12/example_win32_directx12.vcxproj /p:Platform=x64 /p:Configuration=Release'
|
||||||
|
|
||||||
Linux:
|
Linux:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libglfw3-dev libsdl2-dev gcc-multilib g++-multilib libfreetype6-dev
|
sudo apt-get install -y libglfw3-dev libsdl2-dev gcc-multilib g++-multilib libfreetype6-dev libvulkan-dev
|
||||||
|
|
||||||
- name: Build example_null (extra warnings, gcc 32-bit)
|
- name: Build example_null (extra warnings, gcc 32-bit)
|
||||||
run: |
|
run: |
|
||||||
|
@ -211,6 +236,18 @@ jobs:
|
||||||
make -C examples/example_null clean
|
make -C examples/example_null clean
|
||||||
CXXFLAGS="$CXXFLAGS -m64 -Werror" CXX=clang++ make -C examples/example_null WITH_EXTRA_WARNINGS=1
|
CXXFLAGS="$CXXFLAGS -m64 -Werror" CXX=clang++ make -C examples/example_null WITH_EXTRA_WARNINGS=1
|
||||||
|
|
||||||
|
- name: Build example_null (extra warnings, empty IM_ASSERT)
|
||||||
|
run: |
|
||||||
|
cat > example_single_file.cpp <<'EOF'
|
||||||
|
|
||||||
|
#define IM_ASSERT(x)
|
||||||
|
#define IMGUI_IMPLEMENTATION
|
||||||
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -Wextra -Werror -Wno-zero-as-null-pointer-constant -Wno-double-promotion -Wno-variadic-macros -Wno-empty-body -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_null (freetype)
|
- name: Build example_null (freetype)
|
||||||
run: |
|
run: |
|
||||||
make -C examples/example_null clean
|
make -C examples/example_null clean
|
||||||
|
@ -218,146 +255,203 @@ jobs:
|
||||||
|
|
||||||
- name: Build example_null (single file build)
|
- name: Build example_null (single file build)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_IMPLEMENTATION' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_null (with ImWchar32)
|
- name: Build example_null (with ImWchar32)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_USE_WCHAR32' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
|
||||||
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
|
||||||
|
|
||||||
- name: Build example_null (with large ImDrawIdx)
|
#define IMGUI_USE_WCHAR32
|
||||||
|
#define IMGUI_IMPLEMENTATION
|
||||||
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
|
- name: Build example_null (with large ImDrawIdx + pointer ImTextureID)
|
||||||
run: |
|
run: |
|
||||||
echo '#define ImDrawIdx unsigned int' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
#define ImTextureID void*
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#define ImDrawIdx unsigned int
|
||||||
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_null (with IMGUI_DISABLE_OBSOLETE_FUNCTIONS)
|
- name: Build example_null (with IMGUI_DISABLE_OBSOLETE_FUNCTIONS)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
|
||||||
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
|
||||||
|
|
||||||
- name: Build example_null (with IMGUI_DISABLE_DEMO_WINDOWS and IMGUI_DISABLE_METRICS_WINDOW)
|
#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
#define IMGUI_IMPLEMENTATION
|
||||||
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
|
- name: Build example_null (with IMGUI_DISABLE_OBSOLETE_KEYIO)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_DISABLE_DEMO_WINDOWS' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#define IMGUI_DISABLE_METRICS_WINDOW' >> example_single_file.cpp
|
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
#define IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
|
- name: Build example_null (with IMGUI_DISABLE_DEMO_WINDOWS and IMGUI_DISABLE_DEBUG_TOOLS)
|
||||||
|
run: |
|
||||||
|
cat > example_single_file.cpp <<'EOF'
|
||||||
|
|
||||||
|
#define IMGUI_DISABLE_DEMO_WINDOWS
|
||||||
|
#define IMGUI_DISABLE_DEBUG_TOOLS
|
||||||
|
#define IMGUI_IMPLEMENTATION
|
||||||
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_null (with IMGUI_DISABLE_FILE_FUNCTIONS)
|
- name: Build example_null (with IMGUI_DISABLE_FILE_FUNCTIONS)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_DISABLE_FILE_FUNCTIONS' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
#define IMGUI_DISABLE_FILE_FUNCTIONS
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_null (with IMGUI_USE_BGRA_PACKED_COLOR)
|
- name: Build example_null (with IMGUI_USE_BGRA_PACKED_COLOR)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_USE_BGRA_PACKED_COLOR' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_null (with IM_VEC2_CLASS_EXTRA and IM_VEC4_CLASS_EXTRA)
|
- name: Build example_null (with IM_VEC2_CLASS_EXTRA and IM_VEC4_CLASS_EXTRA)
|
||||||
run: |
|
run: |
|
||||||
echo 'struct MyVec2 { float x; float y; MyVec2(float x, float y) : x(x), y(y) { } };' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo 'struct MyVec4 { float x; float y; float z; float w;' >> example_single_file.cpp
|
|
||||||
echo 'MyVec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) { } };' >> example_single_file.cpp
|
struct MyVec2 { float x; float y; MyVec2(float x, float y) : x(x), y(y) { } };
|
||||||
echo '#define IM_VEC2_CLASS_EXTRA \' >> example_single_file.cpp
|
struct MyVec4 { float x; float y; float z; float w;
|
||||||
echo ' ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \' >> example_single_file.cpp
|
MyVec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) { } };
|
||||||
echo ' operator MyVec2() const { return MyVec2(x, y); }' >> example_single_file.cpp
|
#define IM_VEC2_CLASS_EXTRA \
|
||||||
echo '#define IM_VEC4_CLASS_EXTRA \' >> example_single_file.cpp
|
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
||||||
echo ' ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \' >> example_single_file.cpp
|
operator MyVec2() const { return MyVec2(x, y); }
|
||||||
echo ' operator MyVec4() const { return MyVec4(x, y, z, w); }' >> example_single_file.cpp
|
#define IM_VEC4_CLASS_EXTRA \
|
||||||
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
|
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
operator MyVec4() const { return MyVec4(x, y, z, w); }
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_null (without c++ runtime, Clang)
|
- name: Build example_null (without c++ runtime, Clang)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_IMPLEMENTATION' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#define IMGUI_DISABLE_DEMO_WINDOWS' >> example_single_file.cpp
|
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#define IMGUI_DISABLE_DEMO_WINDOWS
|
||||||
clang++ -I. -Wall -Wformat -nodefaultlibs -fno-rtti -fno-exceptions -fno-threadsafe-statics -lc -lm -o example_single_file example_single_file.cpp
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
clang++ -I. -std=c++11 -Wall -Wformat -nodefaultlibs -fno-rtti -fno-exceptions -fno-threadsafe-statics -lc -lm -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_glfw_opengl2
|
- name: Build example_glfw_opengl2
|
||||||
run: make -C examples/example_glfw_opengl2
|
run: make -C examples/example_glfw_opengl2
|
||||||
|
|
||||||
- name: Build example_glfw_opengl3
|
- name: Build example_glfw_opengl3
|
||||||
run: make -C examples/example_glfw_opengl3
|
run: make -C examples/example_glfw_opengl3
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build example_sdl_opengl2
|
- name: Build example_sdl2_opengl2
|
||||||
run: make -C examples/example_sdl_opengl2
|
run: make -C examples/example_sdl2_opengl2
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build example_sdl_opengl3
|
- name: Build example_sdl2_opengl3
|
||||||
run: make -C examples/example_sdl_opengl3
|
run: make -C examples/example_sdl2_opengl3
|
||||||
|
|
||||||
|
- name: Build with IMGUI_IMPL_VULKAN_NO_PROTOTYPES
|
||||||
|
run: g++ -c -I. -std=c++11 -DIMGUI_IMPL_VULKAN_NO_PROTOTYPES=1 backends/imgui_impl_vulkan.cpp
|
||||||
|
|
||||||
MacOS:
|
MacOS:
|
||||||
runs-on: macOS-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: |
|
run: |
|
||||||
brew install glfw3
|
brew install glfw3 sdl2
|
||||||
brew install sdl2
|
|
||||||
|
|
||||||
- name: Build example_null (extra warnings, clang 64-bit)
|
- name: Build example_null (extra warnings, clang 64-bit)
|
||||||
run: make -C examples/example_null WITH_EXTRA_WARNINGS=1
|
run: make -C examples/example_null WITH_EXTRA_WARNINGS=1
|
||||||
|
|
||||||
- name: Build example_null (single file build)
|
- name: Build example_null (single file build)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_IMPLEMENTATION' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
clang++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
clang++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_null (without c++ runtime)
|
- name: Build example_null (without c++ runtime)
|
||||||
run: |
|
run: |
|
||||||
echo '#define IMGUI_IMPLEMENTATION' > example_single_file.cpp
|
cat > example_single_file.cpp <<'EOF'
|
||||||
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
|
|
||||||
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
|
#define IMGUI_IMPLEMENTATION
|
||||||
clang++ -I. -Wall -Wformat -nodefaultlibs -fno-rtti -fno-exceptions -fno-threadsafe-statics -lc -lm -o example_single_file example_single_file.cpp
|
#include "misc/single_file/imgui_single_file.h"
|
||||||
|
#include "examples/example_null/main.cpp"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
clang++ -I. -std=c++11 -Wall -Wformat -nodefaultlibs -fno-rtti -fno-exceptions -fno-threadsafe-statics -lc -lm -o example_single_file example_single_file.cpp
|
||||||
|
|
||||||
- name: Build example_glfw_opengl2
|
- name: Build example_glfw_opengl2
|
||||||
run: make -C examples/example_glfw_opengl2
|
run: make -C examples/example_glfw_opengl2
|
||||||
|
|
||||||
- name: Build example_glfw_opengl3
|
- name: Build example_glfw_opengl3
|
||||||
run: make -C examples/example_glfw_opengl3
|
run: make -C examples/example_glfw_opengl3
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build example_glfw_metal
|
- name: Build example_glfw_metal
|
||||||
run: make -C examples/example_glfw_metal
|
run: make -C examples/example_glfw_metal
|
||||||
|
|
||||||
- name: Build example_sdl_metal
|
- name: Build example_sdl2_metal
|
||||||
run: make -C examples/example_sdl_metal
|
run: make -C examples/example_sdl2_metal
|
||||||
|
|
||||||
- name: Build example_sdl_opengl2
|
- name: Build example_sdl2_opengl2
|
||||||
run: make -C examples/example_sdl_opengl2
|
run: make -C examples/example_sdl2_opengl2
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'workflow_run'
|
||||||
|
|
||||||
- name: Build example_sdl_opengl3
|
- name: Build example_sdl2_opengl3
|
||||||
run: make -C examples/example_sdl_opengl3
|
run: make -C examples/example_sdl2_opengl3
|
||||||
|
|
||||||
- name: Build example_apple_metal
|
- name: Build example_apple_metal
|
||||||
run: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_macos
|
run: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_macos
|
||||||
|
@ -366,11 +460,9 @@ jobs:
|
||||||
run: xcodebuild -project examples/example_apple_opengl2/example_apple_opengl2.xcodeproj -target example_osx_opengl2
|
run: xcodebuild -project examples/example_apple_opengl2/example_apple_opengl2.xcodeproj -target example_osx_opengl2
|
||||||
|
|
||||||
iOS:
|
iOS:
|
||||||
runs-on: macOS-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Build example_apple_metal
|
- name: Build example_apple_metal
|
||||||
run: |
|
run: |
|
||||||
|
@ -378,11 +470,9 @@ jobs:
|
||||||
xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_ios CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
|
xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_ios CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
|
||||||
|
|
||||||
Emscripten:
|
Emscripten:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: |
|
run: |
|
||||||
|
@ -392,40 +482,26 @@ jobs:
|
||||||
emsdk-master/emsdk install latest
|
emsdk-master/emsdk install latest
|
||||||
emsdk-master/emsdk activate latest
|
emsdk-master/emsdk activate latest
|
||||||
|
|
||||||
- name: Build example_emscripten
|
- name: Build example_sdl2_opengl3 with Emscripten
|
||||||
run: |
|
run: |
|
||||||
pushd emsdk-master
|
pushd emsdk-master
|
||||||
source ./emsdk_env.sh
|
source ./emsdk_env.sh
|
||||||
popd
|
popd
|
||||||
make -C examples/example_emscripten
|
make -C examples/example_sdl2_opengl3 -f Makefile.emscripten
|
||||||
|
|
||||||
Discord-CI:
|
- name: Build example_emscripten_wgpu
|
||||||
runs-on: ubuntu-18.04
|
run: |
|
||||||
if: always()
|
pushd emsdk-master
|
||||||
needs: [Windows, Linux, MacOS, iOS, Emscripten]
|
source ./emsdk_env.sh
|
||||||
|
popd
|
||||||
|
make -C examples/example_emscripten_wgpu
|
||||||
|
|
||||||
|
Android:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: dearimgui/github_discord_notifier@latest
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
discord-webhook: ${{ secrets.DISCORD_CI_WEBHOOK }}
|
- name: Build example_android_opengl3
|
||||||
github-token: ${{ github.token }}
|
run: |
|
||||||
action-task: discord-jobs
|
cd examples/example_android_opengl3/android
|
||||||
discord-filter: "'{{ github.branch }}'.match(/master|docking|tables/g) != null && '{{ run.conclusion }}' != '{{ last_run.conclusion }}'"
|
gradle assembleDebug --stacktrace
|
||||||
discord-username: GitHub Actions
|
|
||||||
discord-job-new-failure-message: ''
|
|
||||||
discord-job-fixed-failure-message: ''
|
|
||||||
discord-job-new-failure-embed: |
|
|
||||||
{
|
|
||||||
"title": "`{{ job.name }}` job is failing on `{{ github.branch }}`!",
|
|
||||||
"description": "Commit [{{ github.context.payload.head_commit.title }}]({{ github.context.payload.head_commit.url }}) pushed to [{{ github.branch }}]({{ github.branch_url }}) broke [{{ job.name }}]({{ job.url }}) build job.\nFailing steps: {{ failing_steps }}",
|
|
||||||
"url": "{{ job.url }}",
|
|
||||||
"color": "0xFF0000",
|
|
||||||
"timestamp": "{{ run.updated_at }}"
|
|
||||||
}
|
|
||||||
discord-job-fixed-failure-embed: |
|
|
||||||
{
|
|
||||||
"title": "`{{ github.branch }}` branch is no longer failing!",
|
|
||||||
"description": "Build failures were fixed on [{{ github.branch }}]({{ github.branch_url }}) branch.",
|
|
||||||
"color": "0x00FF00",
|
|
||||||
"url": "{{ github.context.payload.head_commit.url }}",
|
|
||||||
"timestamp": "{{ run.completed_at }}"
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,31 +1,34 @@
|
||||||
name: static-analysis
|
name: static-analysis
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push: {}
|
workflow_run:
|
||||||
pull_request: {}
|
# Perform static analysis together with build workflow. Build triggers of "build" workflow do not need to be repeated here.
|
||||||
schedule:
|
workflows:
|
||||||
- cron: '0 9 * * *'
|
- build
|
||||||
|
types:
|
||||||
|
- requested
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
PVS-Studio:
|
PVS-Studio:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
env:
|
env:
|
||||||
|
# The Secret variable setup in GitHub must be in format: "name_or_email key", on a single line
|
||||||
PVS_STUDIO_LICENSE: ${{ secrets.PVS_STUDIO_LICENSE }}
|
PVS_STUDIO_LICENSE: ${{ secrets.PVS_STUDIO_LICENSE }}
|
||||||
run: |
|
run: |
|
||||||
if [[ "$PVS_STUDIO_LICENSE" != "" ]];
|
if [[ "$PVS_STUDIO_LICENSE" != "" ]];
|
||||||
then
|
then
|
||||||
echo "$PVS_STUDIO_LICENSE" > pvs-studio.lic
|
|
||||||
wget -q https://files.viva64.com/etc/pubkey.txt
|
wget -q https://files.viva64.com/etc/pubkey.txt
|
||||||
sudo apt-key add pubkey.txt
|
sudo apt-key add pubkey.txt
|
||||||
sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list
|
sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y pvs-studio
|
sudo apt-get install -y pvs-studio
|
||||||
|
pvs-studio-analyzer credentials -o pvs-studio.lic $PVS_STUDIO_LICENSE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: PVS-Studio static analysis
|
- name: PVS-Studio static analysis
|
||||||
|
@ -40,35 +43,4 @@ jobs:
|
||||||
cd examples/example_null
|
cd examples/example_null
|
||||||
pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
|
pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
|
||||||
pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
|
pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
|
||||||
plog-converter -a 'GA:1,2;OP:1' -t errorfile -w pvs-studio.log
|
plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log
|
||||||
|
|
||||||
Discord-CI:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
needs: [PVS-Studio]
|
|
||||||
if: always()
|
|
||||||
steps:
|
|
||||||
- uses: dearimgui/github_discord_notifier@latest
|
|
||||||
with:
|
|
||||||
discord-webhook: ${{ secrets.DISCORD_CI_WEBHOOK }}
|
|
||||||
github-token: ${{ github.token }}
|
|
||||||
action-task: discord-jobs
|
|
||||||
discord-filter: "'{{ github.branch }}'.match(/master|docking|tables/g) != null && '{{ run.conclusion }}' != '{{ last_run.conclusion }}'"
|
|
||||||
discord-username: GitHub Actions
|
|
||||||
discord-job-new-failure-message: ''
|
|
||||||
discord-job-fixed-failure-message: ''
|
|
||||||
discord-job-new-failure-embed: |
|
|
||||||
{
|
|
||||||
"title": "`{{ job.name }}` job is failing on `{{ github.branch }}`!",
|
|
||||||
"description": "Commit [{{ github.context.payload.head_commit.title }}]({{ github.context.payload.head_commit.url }}) pushed to [{{ github.branch }}]({{ github.branch_url }}) broke static analysis [{{ job.name }}]({{ job.url }}) job.\nFailing steps: {{ failing_steps }}",
|
|
||||||
"url": "{{ job.url }}",
|
|
||||||
"color": "0xFF0000",
|
|
||||||
"timestamp": "{{ run.updated_at }}"
|
|
||||||
}
|
|
||||||
discord-job-fixed-failure-embed: |
|
|
||||||
{
|
|
||||||
"title": "`{{ github.branch }}` branch is no longer failing!",
|
|
||||||
"description": "Static analysis failures were fixed on [{{ github.branch }}]({{ github.branch_url }}) branch.",
|
|
||||||
"color": "0x00FF00",
|
|
||||||
"url": "{{ github.context.payload.head_commit.url }}",
|
|
||||||
"timestamp": "{{ run.completed_at }}"
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,6 +26,12 @@ ipch
|
||||||
*.VC.db
|
*.VC.db
|
||||||
*.VC.VC.opendb
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
## Getting files created in JSON/Schemas/Catalog/ from a VS2022 update
|
||||||
|
JSON/
|
||||||
|
|
||||||
|
## Commonly used CMake directories
|
||||||
|
/build*/
|
||||||
|
|
||||||
## Xcode artifacts
|
## Xcode artifacts
|
||||||
project.xcworkspace
|
project.xcworkspace
|
||||||
xcuserdata
|
xcuserdata
|
||||||
|
@ -34,16 +40,21 @@ xcuserdata
|
||||||
examples/*.o.tmp
|
examples/*.o.tmp
|
||||||
examples/*.out.js
|
examples/*.out.js
|
||||||
examples/*.out.wasm
|
examples/*.out.wasm
|
||||||
examples/example_emscripten/example_emscripten.*
|
examples/example_glfw_opengl3/web/*
|
||||||
|
examples/example_sdl2_opengl3/web/*
|
||||||
|
examples/example_emscripten_wgpu/web/*
|
||||||
|
|
||||||
## JetBrains IDE artifacts
|
## JetBrains IDE artifacts
|
||||||
.idea
|
.idea
|
||||||
cmake-build-*
|
cmake-build-*
|
||||||
|
|
||||||
## Unix executables from our example Makefiles
|
## Unix executables from our example Makefiles
|
||||||
|
examples/example_glfw_metal/example_glfw_metal
|
||||||
examples/example_glfw_opengl2/example_glfw_opengl2
|
examples/example_glfw_opengl2/example_glfw_opengl2
|
||||||
examples/example_glfw_opengl3/example_glfw_opengl3
|
examples/example_glfw_opengl3/example_glfw_opengl3
|
||||||
examples/example_glut_opengl2/example_glut_opengl2
|
examples/example_glut_opengl2/example_glut_opengl2
|
||||||
examples/example_null/example_null
|
examples/example_null/example_null
|
||||||
examples/example_sdl_opengl2/example_sdl_opengl2
|
examples/example_sdl2_metal/example_sdl2_metal
|
||||||
examples/example_sdl_opengl3/example_sdl_opengl3
|
examples/example_sdl2_opengl2/example_sdl2_opengl2
|
||||||
|
examples/example_sdl2_opengl3/example_sdl2_opengl3
|
||||||
|
examples/example_sdl2_sdlrenderer/example_sdl2_sdlrenderer
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014-2020 Omar Cornut
|
Copyright (c) 2014-2023 Omar Cornut
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -3,18 +3,32 @@
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
|
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
// [X] Platform: Clipboard support (from Allegro 5.1.12)
|
// [X] Platform: Clipboard support (from Allegro 5.1.12)
|
||||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
// Issues:
|
// Issues:
|
||||||
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
// [ ] Renderer: The renderer is suboptimal as we need to convert vertices manually.
|
||||||
// [ ] Platform: Missing gamepad support.
|
// [ ] Platform: Missing gamepad support.
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2022-11-30: Renderer: Restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5.
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates.
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 2021-12-08: Renderer: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86.
|
||||||
|
// 2021-08-17: Calling io.AddFocusEvent() on ALLEGRO_EVENT_DISPLAY_SWITCH_OUT/ALLEGRO_EVENT_DISPLAY_SWITCH_IN events.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 2021-02-18: Change blending equation to preserve alpha in output buffer.
|
||||||
// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
|
// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
|
||||||
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||||
|
@ -24,6 +38,7 @@
|
||||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
|
||||||
// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
|
// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
|
||||||
// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-06-13: Renderer: Stopped using al_draw_indexed_prim() as it is buggy in Allegro's DX9 backend.
|
||||||
// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
|
// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
|
||||||
// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
|
// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
|
||||||
|
@ -44,20 +59,13 @@
|
||||||
#include <allegro5/allegro_windows.h>
|
#include <allegro5/allegro_windows.h>
|
||||||
#endif
|
#endif
|
||||||
#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
|
#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
|
||||||
|
#define ALLEGRO_HAS_DRAW_INDEXED_PRIM (ALLEGRO_VERSION_INT >= ((5 << 24) | (2 << 16) | ( 5 << 8))) // DX9 implementation of al_draw_indexed_prim() got fixed in Allegro 5.2.5
|
||||||
|
|
||||||
// Visual Studio warnings
|
// Visual Studio warnings
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning (disable: 4127) // condition expression is constant
|
#pragma warning (disable: 4127) // condition expression is constant
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Data
|
|
||||||
static ALLEGRO_DISPLAY* g_Display = NULL;
|
|
||||||
static ALLEGRO_BITMAP* g_Texture = NULL;
|
|
||||||
static double g_Time = 0.0;
|
|
||||||
static ALLEGRO_MOUSE_CURSOR* g_MouseCursorInvisible = NULL;
|
|
||||||
static ALLEGRO_VERTEX_DECL* g_VertexDecl = NULL;
|
|
||||||
static char* g_ClipboardTextData = NULL;
|
|
||||||
|
|
||||||
struct ImDrawVertAllegro
|
struct ImDrawVertAllegro
|
||||||
{
|
{
|
||||||
ImVec2 pos;
|
ImVec2 pos;
|
||||||
|
@ -65,10 +73,37 @@ struct ImDrawVertAllegro
|
||||||
ALLEGRO_COLOR col;
|
ALLEGRO_COLOR col;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
|
||||||
|
// FIXME-OPT: Consider inlining al_map_rgba()?
|
||||||
|
// see https://github.com/liballeg/allegro5/blob/master/src/pixels.c#L554
|
||||||
|
// and https://github.com/liballeg/allegro5/blob/master/include/allegro5/internal/aintern_pixels.h
|
||||||
|
#define DRAW_VERT_IMGUI_TO_ALLEGRO(DST, SRC) { (DST)->pos = (SRC)->pos; (DST)->uv = (SRC)->uv; unsigned char* c = (unsigned char*)&(SRC)->col; (DST)->col = al_map_rgba(c[0], c[1], c[2], c[3]); }
|
||||||
|
|
||||||
|
// Allegro Data
|
||||||
|
struct ImGui_ImplAllegro5_Data
|
||||||
|
{
|
||||||
|
ALLEGRO_DISPLAY* Display;
|
||||||
|
ALLEGRO_BITMAP* Texture;
|
||||||
|
double Time;
|
||||||
|
ALLEGRO_MOUSE_CURSOR* MouseCursorInvisible;
|
||||||
|
ALLEGRO_VERTEX_DECL* VertexDecl;
|
||||||
|
char* ClipboardTextData;
|
||||||
|
|
||||||
|
ImVector<ImDrawVertAllegro> BufVertices;
|
||||||
|
ImVector<int> BufIndices;
|
||||||
|
|
||||||
|
ImGui_ImplAllegro5_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||||
|
static ImGui_ImplAllegro5_Data* ImGui_ImplAllegro5_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplAllegro5_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; }
|
||||||
|
|
||||||
static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
|
static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
|
||||||
{
|
{
|
||||||
// Setup blending
|
// Setup blending
|
||||||
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
|
al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
|
||||||
|
|
||||||
// Setup orthographic projection matrix
|
// Setup orthographic projection matrix
|
||||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||||
|
@ -93,6 +128,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Backup Allegro state that will be modified
|
// Backup Allegro state that will be modified
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
|
ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
|
||||||
ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
|
ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
|
||||||
int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
|
int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
|
||||||
|
@ -108,38 +144,42 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
|
||||||
{
|
{
|
||||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
||||||
// Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves.
|
ImVector<ImDrawVertAllegro>& vertices = bd->BufVertices;
|
||||||
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
|
#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
|
||||||
static ImVector<ImDrawVertAllegro> vertices;
|
vertices.resize(cmd_list->VtxBuffer.Size);
|
||||||
vertices.resize(cmd_list->IdxBuffer.Size);
|
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++)
|
||||||
for (int i = 0; i < cmd_list->IdxBuffer.Size; i++)
|
|
||||||
{
|
{
|
||||||
const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]];
|
const ImDrawVert* src_v = &cmd_list->VtxBuffer[i];
|
||||||
ImDrawVertAllegro* dst_v = &vertices[i];
|
ImDrawVertAllegro* dst_v = &vertices[i];
|
||||||
dst_v->pos = src_v->pos;
|
DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v);
|
||||||
dst_v->uv = src_v->uv;
|
|
||||||
unsigned char* c = (unsigned char*)&src_v->col;
|
|
||||||
dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]);
|
|
||||||
}
|
}
|
||||||
|
const int* indices = nullptr;
|
||||||
const int* indices = NULL;
|
|
||||||
if (sizeof(ImDrawIdx) == 2)
|
if (sizeof(ImDrawIdx) == 2)
|
||||||
{
|
{
|
||||||
// FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
|
// FIXME-OPT: Allegro doesn't support 16-bit indices.
|
||||||
|
// You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
|
||||||
// Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
|
// Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
|
||||||
static ImVector<int> indices_converted;
|
bd->BufIndices.resize(cmd_list->IdxBuffer.Size);
|
||||||
indices_converted.resize(cmd_list->IdxBuffer.Size);
|
|
||||||
for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i)
|
for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i)
|
||||||
indices_converted[i] = (int)cmd_list->IdxBuffer.Data[i];
|
bd->BufIndices[i] = (int)cmd_list->IdxBuffer.Data[i];
|
||||||
indices = indices_converted.Data;
|
indices = bd->BufIndices.Data;
|
||||||
}
|
}
|
||||||
else if (sizeof(ImDrawIdx) == 4)
|
else if (sizeof(ImDrawIdx) == 4)
|
||||||
{
|
{
|
||||||
indices = (const int*)cmd_list->IdxBuffer.Data;
|
indices = (const int*)cmd_list->IdxBuffer.Data;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// Allegro's implementation of al_draw_indexed_prim() for DX9 was broken until 5.2.5. Unindex buffers ourselves while converting vertex format.
|
||||||
|
vertices.resize(cmd_list->IdxBuffer.Size);
|
||||||
|
for (int i = 0; i < cmd_list->IdxBuffer.Size; i++)
|
||||||
|
{
|
||||||
|
const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]];
|
||||||
|
ImDrawVertAllegro* dst_v = &vertices[i];
|
||||||
|
DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Render command lists
|
// Render command lists
|
||||||
int idx_offset = 0;
|
|
||||||
ImVec2 clip_off = draw_data->DisplayPos;
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
{
|
{
|
||||||
|
@ -155,12 +195,21 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Draw
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->TextureId;
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
al_set_clipping_rectangle(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y, pcmd->ClipRect.z - pcmd->ClipRect.x, pcmd->ClipRect.w - pcmd->ClipRect.y);
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
al_draw_prim(&vertices[0], g_VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle, Draw
|
||||||
|
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
|
||||||
|
al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
|
||||||
|
#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
|
||||||
|
al_draw_indexed_prim(&vertices[0], bd->VertexDecl, texture, &indices[pcmd->IdxOffset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
|
||||||
|
#else
|
||||||
|
al_draw_prim(&vertices[0], bd->VertexDecl, texture, pcmd->IdxOffset, pcmd->IdxOffset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
idx_offset += pcmd->ElemCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,12 +223,14 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
|
||||||
bool ImGui_ImplAllegro5_CreateDeviceObjects()
|
bool ImGui_ImplAllegro5_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
// Create texture
|
// Create texture
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
int flags = al_get_new_bitmap_flags();
|
int flags = al_get_new_bitmap_flags();
|
||||||
int fmt = al_get_new_bitmap_format();
|
int fmt = al_get_new_bitmap_format();
|
||||||
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
|
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
|
||||||
|
@ -206,13 +257,13 @@ bool ImGui_ImplAllegro5_CreateDeviceObjects()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
io.Fonts->TexID = (void*)cloned_img;
|
io.Fonts->SetTexID((ImTextureID)(intptr_t)cloned_img);
|
||||||
g_Texture = cloned_img;
|
bd->Texture = cloned_img;
|
||||||
|
|
||||||
// Create an invisible mouse cursor
|
// Create an invisible mouse cursor
|
||||||
// Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
|
// Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
|
||||||
ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8, 8);
|
ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8, 8);
|
||||||
g_MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
|
bd->MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
|
||||||
al_destroy_bitmap(mouse_cursor);
|
al_destroy_bitmap(mouse_cursor);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -220,42 +271,163 @@ bool ImGui_ImplAllegro5_CreateDeviceObjects()
|
||||||
|
|
||||||
void ImGui_ImplAllegro5_InvalidateDeviceObjects()
|
void ImGui_ImplAllegro5_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (g_Texture)
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
if (bd->Texture)
|
||||||
{
|
{
|
||||||
al_destroy_bitmap(g_Texture);
|
io.Fonts->SetTexID(0);
|
||||||
ImGui::GetIO().Fonts->TexID = NULL;
|
al_destroy_bitmap(bd->Texture);
|
||||||
g_Texture = NULL;
|
bd->Texture = nullptr;
|
||||||
}
|
}
|
||||||
if (g_MouseCursorInvisible)
|
if (bd->MouseCursorInvisible)
|
||||||
{
|
{
|
||||||
al_destroy_mouse_cursor(g_MouseCursorInvisible);
|
al_destroy_mouse_cursor(bd->MouseCursorInvisible);
|
||||||
g_MouseCursorInvisible = NULL;
|
bd->MouseCursorInvisible = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ALLEGRO_HAS_CLIPBOARD
|
#if ALLEGRO_HAS_CLIPBOARD
|
||||||
static const char* ImGui_ImplAllegro5_GetClipboardText(void*)
|
static const char* ImGui_ImplAllegro5_GetClipboardText(void*)
|
||||||
{
|
{
|
||||||
if (g_ClipboardTextData)
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
al_free(g_ClipboardTextData);
|
if (bd->ClipboardTextData)
|
||||||
g_ClipboardTextData = al_get_clipboard_text(g_Display);
|
al_free(bd->ClipboardTextData);
|
||||||
return g_ClipboardTextData;
|
bd->ClipboardTextData = al_get_clipboard_text(bd->Display);
|
||||||
|
return bd->ClipboardTextData;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text)
|
static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text)
|
||||||
{
|
{
|
||||||
al_set_clipboard_text(g_Display, text);
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
al_set_clipboard_text(bd->Display, text);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code)
|
||||||
|
{
|
||||||
|
switch (key_code)
|
||||||
|
{
|
||||||
|
case ALLEGRO_KEY_TAB: return ImGuiKey_Tab;
|
||||||
|
case ALLEGRO_KEY_LEFT: return ImGuiKey_LeftArrow;
|
||||||
|
case ALLEGRO_KEY_RIGHT: return ImGuiKey_RightArrow;
|
||||||
|
case ALLEGRO_KEY_UP: return ImGuiKey_UpArrow;
|
||||||
|
case ALLEGRO_KEY_DOWN: return ImGuiKey_DownArrow;
|
||||||
|
case ALLEGRO_KEY_PGUP: return ImGuiKey_PageUp;
|
||||||
|
case ALLEGRO_KEY_PGDN: return ImGuiKey_PageDown;
|
||||||
|
case ALLEGRO_KEY_HOME: return ImGuiKey_Home;
|
||||||
|
case ALLEGRO_KEY_END: return ImGuiKey_End;
|
||||||
|
case ALLEGRO_KEY_INSERT: return ImGuiKey_Insert;
|
||||||
|
case ALLEGRO_KEY_DELETE: return ImGuiKey_Delete;
|
||||||
|
case ALLEGRO_KEY_BACKSPACE: return ImGuiKey_Backspace;
|
||||||
|
case ALLEGRO_KEY_SPACE: return ImGuiKey_Space;
|
||||||
|
case ALLEGRO_KEY_ENTER: return ImGuiKey_Enter;
|
||||||
|
case ALLEGRO_KEY_ESCAPE: return ImGuiKey_Escape;
|
||||||
|
case ALLEGRO_KEY_QUOTE: return ImGuiKey_Apostrophe;
|
||||||
|
case ALLEGRO_KEY_COMMA: return ImGuiKey_Comma;
|
||||||
|
case ALLEGRO_KEY_MINUS: return ImGuiKey_Minus;
|
||||||
|
case ALLEGRO_KEY_FULLSTOP: return ImGuiKey_Period;
|
||||||
|
case ALLEGRO_KEY_SLASH: return ImGuiKey_Slash;
|
||||||
|
case ALLEGRO_KEY_SEMICOLON: return ImGuiKey_Semicolon;
|
||||||
|
case ALLEGRO_KEY_EQUALS: return ImGuiKey_Equal;
|
||||||
|
case ALLEGRO_KEY_OPENBRACE: return ImGuiKey_LeftBracket;
|
||||||
|
case ALLEGRO_KEY_BACKSLASH: return ImGuiKey_Backslash;
|
||||||
|
case ALLEGRO_KEY_CLOSEBRACE: return ImGuiKey_RightBracket;
|
||||||
|
case ALLEGRO_KEY_TILDE: return ImGuiKey_GraveAccent;
|
||||||
|
case ALLEGRO_KEY_CAPSLOCK: return ImGuiKey_CapsLock;
|
||||||
|
case ALLEGRO_KEY_SCROLLLOCK: return ImGuiKey_ScrollLock;
|
||||||
|
case ALLEGRO_KEY_NUMLOCK: return ImGuiKey_NumLock;
|
||||||
|
case ALLEGRO_KEY_PRINTSCREEN: return ImGuiKey_PrintScreen;
|
||||||
|
case ALLEGRO_KEY_PAUSE: return ImGuiKey_Pause;
|
||||||
|
case ALLEGRO_KEY_PAD_0: return ImGuiKey_Keypad0;
|
||||||
|
case ALLEGRO_KEY_PAD_1: return ImGuiKey_Keypad1;
|
||||||
|
case ALLEGRO_KEY_PAD_2: return ImGuiKey_Keypad2;
|
||||||
|
case ALLEGRO_KEY_PAD_3: return ImGuiKey_Keypad3;
|
||||||
|
case ALLEGRO_KEY_PAD_4: return ImGuiKey_Keypad4;
|
||||||
|
case ALLEGRO_KEY_PAD_5: return ImGuiKey_Keypad5;
|
||||||
|
case ALLEGRO_KEY_PAD_6: return ImGuiKey_Keypad6;
|
||||||
|
case ALLEGRO_KEY_PAD_7: return ImGuiKey_Keypad7;
|
||||||
|
case ALLEGRO_KEY_PAD_8: return ImGuiKey_Keypad8;
|
||||||
|
case ALLEGRO_KEY_PAD_9: return ImGuiKey_Keypad9;
|
||||||
|
case ALLEGRO_KEY_PAD_DELETE: return ImGuiKey_KeypadDecimal;
|
||||||
|
case ALLEGRO_KEY_PAD_SLASH: return ImGuiKey_KeypadDivide;
|
||||||
|
case ALLEGRO_KEY_PAD_ASTERISK: return ImGuiKey_KeypadMultiply;
|
||||||
|
case ALLEGRO_KEY_PAD_MINUS: return ImGuiKey_KeypadSubtract;
|
||||||
|
case ALLEGRO_KEY_PAD_PLUS: return ImGuiKey_KeypadAdd;
|
||||||
|
case ALLEGRO_KEY_PAD_ENTER: return ImGuiKey_KeypadEnter;
|
||||||
|
case ALLEGRO_KEY_PAD_EQUALS: return ImGuiKey_KeypadEqual;
|
||||||
|
case ALLEGRO_KEY_LCTRL: return ImGuiKey_LeftCtrl;
|
||||||
|
case ALLEGRO_KEY_LSHIFT: return ImGuiKey_LeftShift;
|
||||||
|
case ALLEGRO_KEY_ALT: return ImGuiKey_LeftAlt;
|
||||||
|
case ALLEGRO_KEY_LWIN: return ImGuiKey_LeftSuper;
|
||||||
|
case ALLEGRO_KEY_RCTRL: return ImGuiKey_RightCtrl;
|
||||||
|
case ALLEGRO_KEY_RSHIFT: return ImGuiKey_RightShift;
|
||||||
|
case ALLEGRO_KEY_ALTGR: return ImGuiKey_RightAlt;
|
||||||
|
case ALLEGRO_KEY_RWIN: return ImGuiKey_RightSuper;
|
||||||
|
case ALLEGRO_KEY_MENU: return ImGuiKey_Menu;
|
||||||
|
case ALLEGRO_KEY_0: return ImGuiKey_0;
|
||||||
|
case ALLEGRO_KEY_1: return ImGuiKey_1;
|
||||||
|
case ALLEGRO_KEY_2: return ImGuiKey_2;
|
||||||
|
case ALLEGRO_KEY_3: return ImGuiKey_3;
|
||||||
|
case ALLEGRO_KEY_4: return ImGuiKey_4;
|
||||||
|
case ALLEGRO_KEY_5: return ImGuiKey_5;
|
||||||
|
case ALLEGRO_KEY_6: return ImGuiKey_6;
|
||||||
|
case ALLEGRO_KEY_7: return ImGuiKey_7;
|
||||||
|
case ALLEGRO_KEY_8: return ImGuiKey_8;
|
||||||
|
case ALLEGRO_KEY_9: return ImGuiKey_9;
|
||||||
|
case ALLEGRO_KEY_A: return ImGuiKey_A;
|
||||||
|
case ALLEGRO_KEY_B: return ImGuiKey_B;
|
||||||
|
case ALLEGRO_KEY_C: return ImGuiKey_C;
|
||||||
|
case ALLEGRO_KEY_D: return ImGuiKey_D;
|
||||||
|
case ALLEGRO_KEY_E: return ImGuiKey_E;
|
||||||
|
case ALLEGRO_KEY_F: return ImGuiKey_F;
|
||||||
|
case ALLEGRO_KEY_G: return ImGuiKey_G;
|
||||||
|
case ALLEGRO_KEY_H: return ImGuiKey_H;
|
||||||
|
case ALLEGRO_KEY_I: return ImGuiKey_I;
|
||||||
|
case ALLEGRO_KEY_J: return ImGuiKey_J;
|
||||||
|
case ALLEGRO_KEY_K: return ImGuiKey_K;
|
||||||
|
case ALLEGRO_KEY_L: return ImGuiKey_L;
|
||||||
|
case ALLEGRO_KEY_M: return ImGuiKey_M;
|
||||||
|
case ALLEGRO_KEY_N: return ImGuiKey_N;
|
||||||
|
case ALLEGRO_KEY_O: return ImGuiKey_O;
|
||||||
|
case ALLEGRO_KEY_P: return ImGuiKey_P;
|
||||||
|
case ALLEGRO_KEY_Q: return ImGuiKey_Q;
|
||||||
|
case ALLEGRO_KEY_R: return ImGuiKey_R;
|
||||||
|
case ALLEGRO_KEY_S: return ImGuiKey_S;
|
||||||
|
case ALLEGRO_KEY_T: return ImGuiKey_T;
|
||||||
|
case ALLEGRO_KEY_U: return ImGuiKey_U;
|
||||||
|
case ALLEGRO_KEY_V: return ImGuiKey_V;
|
||||||
|
case ALLEGRO_KEY_W: return ImGuiKey_W;
|
||||||
|
case ALLEGRO_KEY_X: return ImGuiKey_X;
|
||||||
|
case ALLEGRO_KEY_Y: return ImGuiKey_Y;
|
||||||
|
case ALLEGRO_KEY_Z: return ImGuiKey_Z;
|
||||||
|
case ALLEGRO_KEY_F1: return ImGuiKey_F1;
|
||||||
|
case ALLEGRO_KEY_F2: return ImGuiKey_F2;
|
||||||
|
case ALLEGRO_KEY_F3: return ImGuiKey_F3;
|
||||||
|
case ALLEGRO_KEY_F4: return ImGuiKey_F4;
|
||||||
|
case ALLEGRO_KEY_F5: return ImGuiKey_F5;
|
||||||
|
case ALLEGRO_KEY_F6: return ImGuiKey_F6;
|
||||||
|
case ALLEGRO_KEY_F7: return ImGuiKey_F7;
|
||||||
|
case ALLEGRO_KEY_F8: return ImGuiKey_F8;
|
||||||
|
case ALLEGRO_KEY_F9: return ImGuiKey_F9;
|
||||||
|
case ALLEGRO_KEY_F10: return ImGuiKey_F10;
|
||||||
|
case ALLEGRO_KEY_F11: return ImGuiKey_F11;
|
||||||
|
case ALLEGRO_KEY_F12: return ImGuiKey_F12;
|
||||||
|
default: return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
|
bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
|
||||||
{
|
{
|
||||||
g_Display = display;
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
|
||||||
|
|
||||||
// Setup backend capabilities flags
|
// Setup backend capabilities flags
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGui_ImplAllegro5_Data* bd = IM_NEW(ImGui_ImplAllegro5_Data)();
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
io.BackendPlatformUserData = (void*)bd;
|
||||||
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
|
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
|
||||||
|
bd->Display = display;
|
||||||
|
|
||||||
// Create custom vertex declaration.
|
// Create custom vertex declaration.
|
||||||
// Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats.
|
// Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats.
|
||||||
|
@ -267,36 +439,12 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
|
||||||
{ ALLEGRO_PRIM_COLOR_ATTR, 0, IM_OFFSETOF(ImDrawVertAllegro, col) },
|
{ ALLEGRO_PRIM_COLOR_ATTR, 0, IM_OFFSETOF(ImDrawVertAllegro, col) },
|
||||||
{ 0, 0, 0 }
|
{ 0, 0, 0 }
|
||||||
};
|
};
|
||||||
g_VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
|
bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
|
||||||
|
|
||||||
io.KeyMap[ImGuiKey_Tab] = ALLEGRO_KEY_TAB;
|
|
||||||
io.KeyMap[ImGuiKey_LeftArrow] = ALLEGRO_KEY_LEFT;
|
|
||||||
io.KeyMap[ImGuiKey_RightArrow] = ALLEGRO_KEY_RIGHT;
|
|
||||||
io.KeyMap[ImGuiKey_UpArrow] = ALLEGRO_KEY_UP;
|
|
||||||
io.KeyMap[ImGuiKey_DownArrow] = ALLEGRO_KEY_DOWN;
|
|
||||||
io.KeyMap[ImGuiKey_PageUp] = ALLEGRO_KEY_PGUP;
|
|
||||||
io.KeyMap[ImGuiKey_PageDown] = ALLEGRO_KEY_PGDN;
|
|
||||||
io.KeyMap[ImGuiKey_Home] = ALLEGRO_KEY_HOME;
|
|
||||||
io.KeyMap[ImGuiKey_End] = ALLEGRO_KEY_END;
|
|
||||||
io.KeyMap[ImGuiKey_Insert] = ALLEGRO_KEY_INSERT;
|
|
||||||
io.KeyMap[ImGuiKey_Delete] = ALLEGRO_KEY_DELETE;
|
|
||||||
io.KeyMap[ImGuiKey_Backspace] = ALLEGRO_KEY_BACKSPACE;
|
|
||||||
io.KeyMap[ImGuiKey_Space] = ALLEGRO_KEY_SPACE;
|
|
||||||
io.KeyMap[ImGuiKey_Enter] = ALLEGRO_KEY_ENTER;
|
|
||||||
io.KeyMap[ImGuiKey_Escape] = ALLEGRO_KEY_ESCAPE;
|
|
||||||
io.KeyMap[ImGuiKey_KeyPadEnter] = ALLEGRO_KEY_PAD_ENTER;
|
|
||||||
io.KeyMap[ImGuiKey_A] = ALLEGRO_KEY_A;
|
|
||||||
io.KeyMap[ImGuiKey_C] = ALLEGRO_KEY_C;
|
|
||||||
io.KeyMap[ImGuiKey_V] = ALLEGRO_KEY_V;
|
|
||||||
io.KeyMap[ImGuiKey_X] = ALLEGRO_KEY_X;
|
|
||||||
io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y;
|
|
||||||
io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z;
|
|
||||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
|
||||||
|
|
||||||
#if ALLEGRO_HAS_CLIPBOARD
|
#if ALLEGRO_HAS_CLIPBOARD
|
||||||
io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
|
io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
|
||||||
io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
|
io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
|
||||||
io.ClipboardUserData = NULL;
|
io.ClipboardUserData = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -304,66 +452,97 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
|
||||||
|
|
||||||
void ImGui_ImplAllegro5_Shutdown()
|
void ImGui_ImplAllegro5_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImGui_ImplAllegro5_InvalidateDeviceObjects();
|
ImGui_ImplAllegro5_InvalidateDeviceObjects();
|
||||||
|
if (bd->VertexDecl)
|
||||||
|
al_destroy_vertex_decl(bd->VertexDecl);
|
||||||
|
if (bd->ClipboardTextData)
|
||||||
|
al_free(bd->ClipboardTextData);
|
||||||
|
|
||||||
g_Display = NULL;
|
io.BackendPlatformUserData = nullptr;
|
||||||
g_Time = 0.0;
|
io.BackendPlatformName = io.BackendRendererName = nullptr;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
if (g_VertexDecl)
|
// ev->keyboard.modifiers seems always zero so using that...
|
||||||
al_destroy_vertex_decl(g_VertexDecl);
|
static void ImGui_ImplAllegro5_UpdateKeyModifiers()
|
||||||
g_VertexDecl = NULL;
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
if (g_ClipboardTextData)
|
ALLEGRO_KEYBOARD_STATE keys;
|
||||||
al_free(g_ClipboardTextData);
|
al_get_keyboard_state(&keys);
|
||||||
g_ClipboardTextData = NULL;
|
io.AddKeyEvent(ImGuiMod_Ctrl, al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL));
|
||||||
|
io.AddKeyEvent(ImGuiMod_Shift, al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT));
|
||||||
|
io.AddKeyEvent(ImGuiMod_Alt, al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR));
|
||||||
|
io.AddKeyEvent(ImGuiMod_Super, al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
|
||||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||||
bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
|
bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
|
||||||
{
|
{
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
|
||||||
switch (ev->type)
|
switch (ev->type)
|
||||||
{
|
{
|
||||||
case ALLEGRO_EVENT_MOUSE_AXES:
|
case ALLEGRO_EVENT_MOUSE_AXES:
|
||||||
if (ev->mouse.display == g_Display)
|
if (ev->mouse.display == bd->Display)
|
||||||
{
|
{
|
||||||
io.MouseWheel += ev->mouse.dz;
|
io.AddMousePosEvent(ev->mouse.x, ev->mouse.y);
|
||||||
io.MouseWheelH -= ev->mouse.dw;
|
io.AddMouseWheelEvent(-ev->mouse.dw, ev->mouse.dz);
|
||||||
io.MousePos = ImVec2(ev->mouse.x, ev->mouse.y);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
|
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
|
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
|
||||||
if (ev->mouse.display == g_Display && ev->mouse.button <= 5)
|
if (ev->mouse.display == bd->Display && ev->mouse.button > 0 && ev->mouse.button <= 5)
|
||||||
io.MouseDown[ev->mouse.button - 1] = (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
|
io.AddMouseButtonEvent(ev->mouse.button - 1, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
|
||||||
return true;
|
return true;
|
||||||
case ALLEGRO_EVENT_TOUCH_MOVE:
|
case ALLEGRO_EVENT_TOUCH_MOVE:
|
||||||
if (ev->touch.display == g_Display)
|
if (ev->touch.display == bd->Display)
|
||||||
io.MousePos = ImVec2(ev->touch.x, ev->touch.y);
|
io.AddMousePosEvent(ev->touch.x, ev->touch.y);
|
||||||
return true;
|
return true;
|
||||||
case ALLEGRO_EVENT_TOUCH_BEGIN:
|
case ALLEGRO_EVENT_TOUCH_BEGIN:
|
||||||
case ALLEGRO_EVENT_TOUCH_END:
|
case ALLEGRO_EVENT_TOUCH_END:
|
||||||
case ALLEGRO_EVENT_TOUCH_CANCEL:
|
case ALLEGRO_EVENT_TOUCH_CANCEL:
|
||||||
if (ev->touch.display == g_Display && ev->touch.primary)
|
if (ev->touch.display == bd->Display && ev->touch.primary)
|
||||||
io.MouseDown[0] = (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
|
io.AddMouseButtonEvent(0, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
|
||||||
return true;
|
return true;
|
||||||
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
|
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
|
||||||
if (ev->mouse.display == g_Display)
|
if (ev->mouse.display == bd->Display)
|
||||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||||
return true;
|
return true;
|
||||||
case ALLEGRO_EVENT_KEY_CHAR:
|
case ALLEGRO_EVENT_KEY_CHAR:
|
||||||
if (ev->keyboard.display == g_Display)
|
if (ev->keyboard.display == bd->Display)
|
||||||
if (ev->keyboard.unichar != 0)
|
if (ev->keyboard.unichar != 0)
|
||||||
io.AddInputCharacter((unsigned int)ev->keyboard.unichar);
|
io.AddInputCharacter((unsigned int)ev->keyboard.unichar);
|
||||||
return true;
|
return true;
|
||||||
case ALLEGRO_EVENT_KEY_DOWN:
|
case ALLEGRO_EVENT_KEY_DOWN:
|
||||||
case ALLEGRO_EVENT_KEY_UP:
|
case ALLEGRO_EVENT_KEY_UP:
|
||||||
if (ev->keyboard.display == g_Display)
|
if (ev->keyboard.display == bd->Display)
|
||||||
io.KeysDown[ev->keyboard.keycode] = (ev->type == ALLEGRO_EVENT_KEY_DOWN);
|
{
|
||||||
|
ImGui_ImplAllegro5_UpdateKeyModifiers();
|
||||||
|
ImGuiKey key = ImGui_ImplAllegro5_KeyCodeToImGuiKey(ev->keyboard.keycode);
|
||||||
|
io.AddKeyEvent(key, (ev->type == ALLEGRO_EVENT_KEY_DOWN));
|
||||||
|
io.SetKeyEventNativeData(key, ev->keyboard.keycode, -1); // To support legacy indexing (<1.87 user code)
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
|
||||||
|
if (ev->display.source == bd->Display)
|
||||||
|
io.AddFocusEvent(false);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
|
||||||
|
if (ev->display.source == bd->Display)
|
||||||
|
{
|
||||||
|
io.AddFocusEvent(true);
|
||||||
|
#if defined(ALLEGRO_UNSTABLE)
|
||||||
|
al_clear_keyboard_state(bd->Display);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -375,11 +554,12 @@ static void ImGui_ImplAllegro5_UpdateMouseCursor()
|
||||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||||
{
|
{
|
||||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
al_set_mouse_cursor(g_Display, g_MouseCursorInvisible);
|
al_set_mouse_cursor(bd->Display, bd->MouseCursorInvisible);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -394,35 +574,31 @@ static void ImGui_ImplAllegro5_UpdateMouseCursor()
|
||||||
case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break;
|
case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break;
|
||||||
case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break;
|
case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break;
|
||||||
}
|
}
|
||||||
al_set_system_mouse_cursor(g_Display, cursor_id);
|
al_set_system_mouse_cursor(bd->Display, cursor_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplAllegro5_NewFrame()
|
void ImGui_ImplAllegro5_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_Texture)
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplAllegro5_Init()?");
|
||||||
|
|
||||||
|
if (!bd->Texture)
|
||||||
ImGui_ImplAllegro5_CreateDeviceObjects();
|
ImGui_ImplAllegro5_CreateDeviceObjects();
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
// Setup display size (every frame to accommodate for window resizing)
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
int w, h;
|
int w, h;
|
||||||
w = al_get_display_width(g_Display);
|
w = al_get_display_width(bd->Display);
|
||||||
h = al_get_display_height(g_Display);
|
h = al_get_display_height(bd->Display);
|
||||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
|
||||||
// Setup time step
|
// Setup time step
|
||||||
double current_time = al_get_time();
|
double current_time = al_get_time();
|
||||||
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
|
||||||
g_Time = current_time;
|
bd->Time = current_time;
|
||||||
|
|
||||||
// Setup inputs
|
|
||||||
ALLEGRO_KEYBOARD_STATE keys;
|
|
||||||
al_get_keyboard_state(&keys);
|
|
||||||
io.KeyCtrl = al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL);
|
|
||||||
io.KeyShift = al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT);
|
|
||||||
io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR);
|
|
||||||
io.KeySuper = al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN);
|
|
||||||
|
|
||||||
|
// Setup mouse cursor shape
|
||||||
ImGui_ImplAllegro5_UpdateMouseCursor();
|
ImGui_ImplAllegro5_UpdateMouseCursor();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
|
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
// [X] Platform: Clipboard support (from Allegro 5.1.12)
|
// [X] Platform: Clipboard support (from Allegro 5.1.12)
|
||||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
// Issues:
|
// Issues:
|
||||||
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
||||||
// [ ] Platform: Missing gamepad support.
|
// [ ] Platform: Missing gamepad support.
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,21 @@
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
// 2020-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
|
||||||
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
|
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
|
||||||
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
@ -39,32 +44,48 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DirectX data
|
// DirectX data
|
||||||
static ID3D10Device* g_pd3dDevice = NULL;
|
struct ImGui_ImplDX10_Data
|
||||||
static IDXGIFactory* g_pFactory = NULL;
|
{
|
||||||
static ID3D10Buffer* g_pVB = NULL;
|
ID3D10Device* pd3dDevice;
|
||||||
static ID3D10Buffer* g_pIB = NULL;
|
IDXGIFactory* pFactory;
|
||||||
static ID3D10VertexShader* g_pVertexShader = NULL;
|
ID3D10Buffer* pVB;
|
||||||
static ID3D10InputLayout* g_pInputLayout = NULL;
|
ID3D10Buffer* pIB;
|
||||||
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
|
ID3D10VertexShader* pVertexShader;
|
||||||
static ID3D10PixelShader* g_pPixelShader = NULL;
|
ID3D10InputLayout* pInputLayout;
|
||||||
static ID3D10SamplerState* g_pFontSampler = NULL;
|
ID3D10Buffer* pVertexConstantBuffer;
|
||||||
static ID3D10ShaderResourceView*g_pFontTextureView = NULL;
|
ID3D10PixelShader* pPixelShader;
|
||||||
static ID3D10RasterizerState* g_pRasterizerState = NULL;
|
ID3D10SamplerState* pFontSampler;
|
||||||
static ID3D10BlendState* g_pBlendState = NULL;
|
ID3D10ShaderResourceView* pFontTextureView;
|
||||||
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
|
ID3D10RasterizerState* pRasterizerState;
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
ID3D10BlendState* pBlendState;
|
||||||
|
ID3D10DepthStencilState* pDepthStencilState;
|
||||||
|
int VertexBufferSize;
|
||||||
|
int IndexBufferSize;
|
||||||
|
|
||||||
struct VERTEX_CONSTANT_BUFFER
|
ImGui_ImplDX10_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER_DX10
|
||||||
{
|
{
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Forward Declarations
|
// Forward Declarations
|
||||||
static void ImGui_ImplDX10_InitPlatformInterface();
|
static void ImGui_ImplDX10_InitPlatformInterface();
|
||||||
static void ImGui_ImplDX10_ShutdownPlatformInterface();
|
static void ImGui_ImplDX10_ShutdownPlatformInterface();
|
||||||
|
|
||||||
|
// Functions
|
||||||
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
|
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
D3D10_VIEWPORT vp;
|
D3D10_VIEWPORT vp;
|
||||||
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
|
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
|
||||||
|
@ -78,21 +99,21 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device*
|
||||||
// Bind shader and vertex buffers
|
// Bind shader and vertex buffers
|
||||||
unsigned int stride = sizeof(ImDrawVert);
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
ctx->IASetInputLayout(g_pInputLayout);
|
ctx->IASetInputLayout(bd->pInputLayout);
|
||||||
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
|
||||||
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||||
ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
ctx->VSSetShader(g_pVertexShader);
|
ctx->VSSetShader(bd->pVertexShader);
|
||||||
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
|
||||||
ctx->PSSetShader(g_pPixelShader);
|
ctx->PSSetShader(bd->pPixelShader);
|
||||||
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
|
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
|
||||||
ctx->GSSetShader(NULL);
|
ctx->GSSetShader(nullptr);
|
||||||
|
|
||||||
// Setup render state
|
// Setup render state
|
||||||
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||||
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
|
ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
|
||||||
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
|
ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
|
||||||
ctx->RSSetState(g_pRasterizerState);
|
ctx->RSSetState(bd->pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render function
|
// Render function
|
||||||
|
@ -102,43 +123,44 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ID3D10Device* ctx = g_pd3dDevice;
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
ID3D10Device* ctx = bd->pd3dDevice;
|
||||||
|
|
||||||
// Create and grow vertex/index buffers if needed
|
// Create and grow vertex/index buffers if needed
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
{
|
{
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
|
||||||
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
if (ctx->CreateBuffer(&desc, nullptr, &bd->pVB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
|
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
if (ctx->CreateBuffer(&desc, nullptr, &bd->pIB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy and convert all vertices into a single contiguous buffer
|
// Copy and convert all vertices into a single contiguous buffer
|
||||||
ImDrawVert* vtx_dst = NULL;
|
ImDrawVert* vtx_dst = nullptr;
|
||||||
ImDrawIdx* idx_dst = NULL;
|
ImDrawIdx* idx_dst = nullptr;
|
||||||
g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
|
bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
|
||||||
g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
|
bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
{
|
{
|
||||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
@ -147,16 +169,16 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
idx_dst += cmd_list->IdxBuffer.Size;
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
}
|
}
|
||||||
g_pVB->Unmap();
|
bd->pVB->Unmap();
|
||||||
g_pIB->Unmap();
|
bd->pIB->Unmap();
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
{
|
{
|
||||||
void* mapped_resource;
|
void* mapped_resource;
|
||||||
if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
|
VERTEX_CONSTANT_BUFFER_DX10* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX10*)mapped_resource;
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
float T = draw_data->DisplayPos.y;
|
float T = draw_data->DisplayPos.y;
|
||||||
|
@ -169,7 +191,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
};
|
};
|
||||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
g_pVertexConstantBuffer->Unmap();
|
bd->pVertexConstantBuffer->Unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||||
|
@ -195,7 +217,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
DXGI_FORMAT IndexBufferFormat;
|
DXGI_FORMAT IndexBufferFormat;
|
||||||
ID3D10InputLayout* InputLayout;
|
ID3D10InputLayout* InputLayout;
|
||||||
};
|
};
|
||||||
BACKUP_DX10_STATE old;
|
BACKUP_DX10_STATE old = {};
|
||||||
old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||||
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
||||||
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
||||||
|
@ -238,12 +260,18 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Apply scissor/clipping rectangle
|
// Apply scissor/clipping rectangle
|
||||||
const D3D10_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y)};
|
const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
ctx->RSSetScissorRects(1, &r);
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
// Bind texture, Draw
|
// Bind texture, Draw
|
||||||
ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->TextureId;
|
ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->GetTexID();
|
||||||
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
||||||
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||||
}
|
}
|
||||||
|
@ -273,6 +301,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
static void ImGui_ImplDX10_CreateFontsTexture()
|
static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
@ -292,12 +321,13 @@ static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
||||||
desc.CPUAccessFlags = 0;
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
ID3D10Texture2D* pTexture = NULL;
|
ID3D10Texture2D* pTexture = nullptr;
|
||||||
D3D10_SUBRESOURCE_DATA subResource;
|
D3D10_SUBRESOURCE_DATA subResource;
|
||||||
subResource.pSysMem = pixels;
|
subResource.pSysMem = pixels;
|
||||||
subResource.SysMemPitch = desc.Width * 4;
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
subResource.SysMemSlicePitch = 0;
|
subResource.SysMemSlicePitch = 0;
|
||||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
IM_ASSERT(pTexture != nullptr);
|
||||||
|
|
||||||
// Create texture view
|
// Create texture view
|
||||||
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||||
|
@ -306,14 +336,15 @@ static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
||||||
srv_desc.Texture2D.MipLevels = desc.MipLevels;
|
srv_desc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView);
|
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &bd->pFontTextureView);
|
||||||
pTexture->Release();
|
pTexture->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
io.Fonts->TexID = (ImTextureID)g_pFontTextureView;
|
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
|
||||||
|
|
||||||
// Create texture sampler
|
// Create texture sampler
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
{
|
{
|
||||||
D3D10_SAMPLER_DESC desc;
|
D3D10_SAMPLER_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
@ -325,15 +356,16 @@ static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
|
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
desc.MinLOD = 0.f;
|
desc.MinLOD = 0.f;
|
||||||
desc.MaxLOD = 0.f;
|
desc.MaxLOD = 0.f;
|
||||||
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX10_CreateDeviceObjects()
|
bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
if (!bd->pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (g_pFontSampler)
|
if (bd->pFontSampler)
|
||||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
|
|
||||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
|
@ -373,9 +405,9 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
}";
|
}";
|
||||||
|
|
||||||
ID3DBlob* vertexShaderBlob;
|
ID3DBlob* vertexShaderBlob;
|
||||||
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
|
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vertexShaderBlob, nullptr)))
|
||||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
if (g_pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &g_pVertexShader) != S_OK)
|
if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pVertexShader) != S_OK)
|
||||||
{
|
{
|
||||||
vertexShaderBlob->Release();
|
vertexShaderBlob->Release();
|
||||||
return false;
|
return false;
|
||||||
|
@ -388,7 +420,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
};
|
};
|
||||||
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
|
||||||
{
|
{
|
||||||
vertexShaderBlob->Release();
|
vertexShaderBlob->Release();
|
||||||
return false;
|
return false;
|
||||||
|
@ -398,12 +430,12 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
// Create the constant buffer
|
// Create the constant buffer
|
||||||
{
|
{
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX10);
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVertexConstantBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,9 +458,9 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
}";
|
}";
|
||||||
|
|
||||||
ID3DBlob* pixelShaderBlob;
|
ID3DBlob* pixelShaderBlob;
|
||||||
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
|
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr)))
|
||||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
if (g_pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), &g_pPixelShader) != S_OK)
|
if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), &bd->pPixelShader) != S_OK)
|
||||||
{
|
{
|
||||||
pixelShaderBlob->Release();
|
pixelShaderBlob->Release();
|
||||||
return false;
|
return false;
|
||||||
|
@ -445,11 +477,11 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
|
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
|
||||||
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
|
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
|
||||||
desc.BlendOp = D3D10_BLEND_OP_ADD;
|
desc.BlendOp = D3D10_BLEND_OP_ADD;
|
||||||
desc.SrcBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
desc.SrcBlendAlpha = D3D10_BLEND_ONE;
|
||||||
desc.DestBlendAlpha = D3D10_BLEND_ZERO;
|
desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
||||||
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
||||||
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
||||||
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the rasterizer state
|
// Create the rasterizer state
|
||||||
|
@ -460,7 +492,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
desc.CullMode = D3D10_CULL_NONE;
|
desc.CullMode = D3D10_CULL_NONE;
|
||||||
desc.ScissorEnable = true;
|
desc.ScissorEnable = true;
|
||||||
desc.DepthClipEnable = true;
|
desc.DepthClipEnable = true;
|
||||||
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create depth-stencil State
|
// Create depth-stencil State
|
||||||
|
@ -474,7 +506,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
|
||||||
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui_ImplDX10_CreateFontsTexture();
|
ImGui_ImplDX10_CreateFontsTexture();
|
||||||
|
@ -484,46 +516,49 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
|
|
||||||
void ImGui_ImplDX10_InvalidateDeviceObjects()
|
void ImGui_ImplDX10_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
if (!bd->pd3dDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; }
|
||||||
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||||
|
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; }
|
||||||
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = nullptr; }
|
||||||
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = nullptr; }
|
||||||
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = nullptr; }
|
||||||
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = nullptr; }
|
||||||
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = nullptr; }
|
||||||
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = nullptr; }
|
||||||
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||||
{
|
{
|
||||||
// Setup backend capabilities flags
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX10_Data* bd = IM_NEW(ImGui_ImplDX10_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_dx10";
|
io.BackendRendererName = "imgui_impl_dx10";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||||
|
|
||||||
// Get factory from device
|
// Get factory from device
|
||||||
IDXGIDevice* pDXGIDevice = NULL;
|
IDXGIDevice* pDXGIDevice = nullptr;
|
||||||
IDXGIAdapter* pDXGIAdapter = NULL;
|
IDXGIAdapter* pDXGIAdapter = nullptr;
|
||||||
IDXGIFactory* pFactory = NULL;
|
IDXGIFactory* pFactory = nullptr;
|
||||||
|
|
||||||
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
{
|
{
|
||||||
g_pd3dDevice = device;
|
bd->pd3dDevice = device;
|
||||||
g_pFactory = pFactory;
|
bd->pFactory = pFactory;
|
||||||
}
|
}
|
||||||
if (pDXGIDevice) pDXGIDevice->Release();
|
if (pDXGIDevice) pDXGIDevice->Release();
|
||||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||||
g_pd3dDevice->AddRef();
|
bd->pd3dDevice->AddRef();
|
||||||
|
|
||||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||||
ImGui_ImplDX10_InitPlatformInterface();
|
ImGui_ImplDX10_InitPlatformInterface();
|
||||||
|
@ -532,15 +567,25 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||||
|
|
||||||
void ImGui_ImplDX10_Shutdown()
|
void ImGui_ImplDX10_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImGui_ImplDX10_ShutdownPlatformInterface();
|
ImGui_ImplDX10_ShutdownPlatformInterface();
|
||||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
if (bd->pFactory) { bd->pFactory->Release(); }
|
||||||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||||
|
io.BackendRendererName = nullptr;
|
||||||
|
io.BackendRendererUserData = nullptr;
|
||||||
|
IM_DELETE(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX10_NewFrame()
|
void ImGui_ImplDX10_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_pFontSampler)
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX10_Init()?");
|
||||||
|
|
||||||
|
if (!bd->pFontSampler)
|
||||||
ImGui_ImplDX10_CreateDeviceObjects();
|
ImGui_ImplDX10_CreateDeviceObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,23 +595,24 @@ void ImGui_ImplDX10_NewFrame()
|
||||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
|
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||||
struct ImGuiViewportDataDx10
|
struct ImGui_ImplDX10_ViewportData
|
||||||
{
|
{
|
||||||
IDXGISwapChain* SwapChain;
|
IDXGISwapChain* SwapChain;
|
||||||
ID3D10RenderTargetView* RTView;
|
ID3D10RenderTargetView* RTView;
|
||||||
|
|
||||||
ImGuiViewportDataDx10() { SwapChain = NULL; RTView = NULL; }
|
ImGui_ImplDX10_ViewportData() { SwapChain = nullptr; RTView = nullptr; }
|
||||||
~ImGuiViewportDataDx10() { IM_ASSERT(SwapChain == NULL && RTView == NULL); }
|
~ImGui_ImplDX10_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ImGui_ImplDX10_CreateWindow(ImGuiViewport* viewport)
|
static void ImGui_ImplDX10_CreateWindow(ImGuiViewport* viewport)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx10* data = IM_NEW(ImGuiViewportDataDx10)();
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
viewport->RendererUserData = data;
|
ImGui_ImplDX10_ViewportData* vd = IM_NEW(ImGui_ImplDX10_ViewportData)();
|
||||||
|
viewport->RendererUserData = vd;
|
||||||
|
|
||||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
||||||
// Some backends will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
|
// Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
|
||||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||||
IM_ASSERT(hwnd != 0);
|
IM_ASSERT(hwnd != 0);
|
||||||
|
|
||||||
|
@ -585,68 +631,70 @@ static void ImGui_ImplDX10_CreateWindow(ImGuiViewport* viewport)
|
||||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||||
sd.Flags = 0;
|
sd.Flags = 0;
|
||||||
|
|
||||||
IM_ASSERT(data->SwapChain == NULL && data->RTView == NULL);
|
IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr);
|
||||||
g_pFactory->CreateSwapChain(g_pd3dDevice, &sd, &data->SwapChain);
|
bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain);
|
||||||
|
|
||||||
// Create the render target
|
// Create the render target
|
||||||
if (data->SwapChain)
|
if (vd->SwapChain)
|
||||||
{
|
{
|
||||||
ID3D10Texture2D* pBackBuffer;
|
ID3D10Texture2D* pBackBuffer;
|
||||||
data->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||||
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &data->RTView);
|
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
|
||||||
pBackBuffer->Release();
|
pBackBuffer->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX10_DestroyWindow(ImGuiViewport* viewport)
|
static void ImGui_ImplDX10_DestroyWindow(ImGuiViewport* viewport)
|
||||||
{
|
{
|
||||||
// The main viewport (owned by the application) will always have RendererUserData == NULL here since we didn't create the data for it.
|
// The main viewport (owned by the application) will always have RendererUserData == 0 here since we didn't create the data for it.
|
||||||
if (ImGuiViewportDataDx10* data = (ImGuiViewportDataDx10*)viewport->RendererUserData)
|
if (ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData)
|
||||||
{
|
{
|
||||||
if (data->SwapChain)
|
if (vd->SwapChain)
|
||||||
data->SwapChain->Release();
|
vd->SwapChain->Release();
|
||||||
data->SwapChain = NULL;
|
vd->SwapChain = nullptr;
|
||||||
if (data->RTView)
|
if (vd->RTView)
|
||||||
data->RTView->Release();
|
vd->RTView->Release();
|
||||||
data->RTView = NULL;
|
vd->RTView = nullptr;
|
||||||
IM_DELETE(data);
|
IM_DELETE(vd);
|
||||||
}
|
}
|
||||||
viewport->RendererUserData = NULL;
|
viewport->RendererUserData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX10_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
static void ImGui_ImplDX10_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx10* data = (ImGuiViewportDataDx10*)viewport->RendererUserData;
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
if (data->RTView)
|
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||||
|
if (vd->RTView)
|
||||||
{
|
{
|
||||||
data->RTView->Release();
|
vd->RTView->Release();
|
||||||
data->RTView = NULL;
|
vd->RTView = nullptr;
|
||||||
}
|
}
|
||||||
if (data->SwapChain)
|
if (vd->SwapChain)
|
||||||
{
|
{
|
||||||
ID3D10Texture2D* pBackBuffer = NULL;
|
ID3D10Texture2D* pBackBuffer = nullptr;
|
||||||
data->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
||||||
data->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||||
if (pBackBuffer == NULL) { fprintf(stderr, "ImGui_ImplDX10_SetWindowSize() failed creating buffers.\n"); return; }
|
if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX10_SetWindowSize() failed creating buffers.\n"); return; }
|
||||||
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &data->RTView);
|
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
|
||||||
pBackBuffer->Release();
|
pBackBuffer->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX10_RenderViewport(ImGuiViewport* viewport, void*)
|
static void ImGui_ImplDX10_RenderViewport(ImGuiViewport* viewport, void*)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx10* data = (ImGuiViewportDataDx10*)viewport->RendererUserData;
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
g_pd3dDevice->OMSetRenderTargets(1, &data->RTView, NULL);
|
bd->pd3dDevice->OMSetRenderTargets(1, &vd->RTView, nullptr);
|
||||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||||
g_pd3dDevice->ClearRenderTargetView(data->RTView, (float*)&clear_color);
|
bd->pd3dDevice->ClearRenderTargetView(vd->RTView, (float*)&clear_color);
|
||||||
ImGui_ImplDX10_RenderDrawData(viewport->DrawData);
|
ImGui_ImplDX10_RenderDrawData(viewport->DrawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX10_SwapBuffers(ImGuiViewport* viewport, void*)
|
static void ImGui_ImplDX10_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx10* data = (ImGuiViewportDataDx10*)viewport->RendererUserData;
|
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||||
data->SwapChain->Present(0, 0); // Present without vsync
|
vd->SwapChain->Present(0, 0); // Present without vsync
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX10_InitPlatformInterface()
|
void ImGui_ImplDX10_InitPlatformInterface()
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,21 @@
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
// 2020-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
|
||||||
// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
|
// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
|
||||||
// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
|
// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
|
||||||
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
@ -38,34 +43,50 @@
|
||||||
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DirectX data
|
// DirectX11 data
|
||||||
static ID3D11Device* g_pd3dDevice = NULL;
|
struct ImGui_ImplDX11_Data
|
||||||
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
|
{
|
||||||
static IDXGIFactory* g_pFactory = NULL;
|
ID3D11Device* pd3dDevice;
|
||||||
static ID3D11Buffer* g_pVB = NULL;
|
ID3D11DeviceContext* pd3dDeviceContext;
|
||||||
static ID3D11Buffer* g_pIB = NULL;
|
IDXGIFactory* pFactory;
|
||||||
static ID3D11VertexShader* g_pVertexShader = NULL;
|
ID3D11Buffer* pVB;
|
||||||
static ID3D11InputLayout* g_pInputLayout = NULL;
|
ID3D11Buffer* pIB;
|
||||||
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
|
ID3D11VertexShader* pVertexShader;
|
||||||
static ID3D11PixelShader* g_pPixelShader = NULL;
|
ID3D11InputLayout* pInputLayout;
|
||||||
static ID3D11SamplerState* g_pFontSampler = NULL;
|
ID3D11Buffer* pVertexConstantBuffer;
|
||||||
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
|
ID3D11PixelShader* pPixelShader;
|
||||||
static ID3D11RasterizerState* g_pRasterizerState = NULL;
|
ID3D11SamplerState* pFontSampler;
|
||||||
static ID3D11BlendState* g_pBlendState = NULL;
|
ID3D11ShaderResourceView* pFontTextureView;
|
||||||
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
|
ID3D11RasterizerState* pRasterizerState;
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
ID3D11BlendState* pBlendState;
|
||||||
|
ID3D11DepthStencilState* pDepthStencilState;
|
||||||
|
int VertexBufferSize;
|
||||||
|
int IndexBufferSize;
|
||||||
|
|
||||||
struct VERTEX_CONSTANT_BUFFER
|
ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER_DX11
|
||||||
{
|
{
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Forward Declarations
|
// Forward Declarations
|
||||||
static void ImGui_ImplDX11_InitPlatformInterface();
|
static void ImGui_ImplDX11_InitPlatformInterface();
|
||||||
static void ImGui_ImplDX11_ShutdownPlatformInterface();
|
static void ImGui_ImplDX11_ShutdownPlatformInterface();
|
||||||
|
|
||||||
|
// Functions
|
||||||
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
|
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
D3D11_VIEWPORT vp;
|
D3D11_VIEWPORT vp;
|
||||||
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
||||||
|
@ -79,24 +100,24 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC
|
||||||
// Setup shader and vertex buffers
|
// Setup shader and vertex buffers
|
||||||
unsigned int stride = sizeof(ImDrawVert);
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
ctx->IASetInputLayout(g_pInputLayout);
|
ctx->IASetInputLayout(bd->pInputLayout);
|
||||||
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
|
||||||
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||||
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
ctx->VSSetShader(g_pVertexShader, NULL, 0);
|
ctx->VSSetShader(bd->pVertexShader, nullptr, 0);
|
||||||
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
|
||||||
ctx->PSSetShader(g_pPixelShader, NULL, 0);
|
ctx->PSSetShader(bd->pPixelShader, nullptr, 0);
|
||||||
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
|
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
|
||||||
ctx->GSSetShader(NULL, NULL, 0);
|
ctx->GSSetShader(nullptr, nullptr, 0);
|
||||||
ctx->HSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
ctx->HSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||||
ctx->DSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
ctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||||
ctx->CSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
ctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||||
|
|
||||||
// Setup blend state
|
// Setup blend state
|
||||||
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||||
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
|
ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
|
||||||
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
|
ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
|
||||||
ctx->RSSetState(g_pRasterizerState);
|
ctx->RSSetState(bd->pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render function
|
// Render function
|
||||||
|
@ -106,42 +127,43 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
ID3D11DeviceContext* ctx = bd->pd3dDeviceContext;
|
||||||
|
|
||||||
// Create and grow vertex/index buffers if needed
|
// Create and grow vertex/index buffers if needed
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
{
|
{
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
|
||||||
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pIB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload vertex/index data into a single contiguous GPU buffer
|
// Upload vertex/index data into a single contiguous GPU buffer
|
||||||
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
|
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
|
||||||
if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
|
if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
||||||
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
||||||
|
@ -153,16 +175,16 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
idx_dst += cmd_list->IdxBuffer.Size;
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
}
|
}
|
||||||
ctx->Unmap(g_pVB, 0);
|
ctx->Unmap(bd->pVB, 0);
|
||||||
ctx->Unmap(g_pIB, 0);
|
ctx->Unmap(bd->pIB, 0);
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
{
|
{
|
||||||
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
||||||
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
|
VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData;
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
float T = draw_data->DisplayPos.y;
|
float T = draw_data->DisplayPos.y;
|
||||||
|
@ -175,7 +197,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
};
|
};
|
||||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
ctx->Unmap(g_pVertexConstantBuffer, 0);
|
ctx->Unmap(bd->pVertexConstantBuffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||||
|
@ -203,7 +225,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
DXGI_FORMAT IndexBufferFormat;
|
DXGI_FORMAT IndexBufferFormat;
|
||||||
ID3D11InputLayout* InputLayout;
|
ID3D11InputLayout* InputLayout;
|
||||||
};
|
};
|
||||||
BACKUP_DX11_STATE old;
|
BACKUP_DX11_STATE old = {};
|
||||||
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||||
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
||||||
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
||||||
|
@ -237,7 +259,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
{
|
{
|
||||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
if (pcmd->UserCallback != NULL)
|
if (pcmd->UserCallback != nullptr)
|
||||||
{
|
{
|
||||||
// User callback, registered via ImDrawList::AddCallback()
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
@ -248,12 +270,18 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Apply scissor/clipping rectangle
|
// Apply scissor/clipping rectangle
|
||||||
const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
|
const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
ctx->RSSetScissorRects(1, &r);
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
// Bind texture, Draw
|
// Bind texture, Draw
|
||||||
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->TextureId;
|
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
|
||||||
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
||||||
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||||
}
|
}
|
||||||
|
@ -286,6 +314,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
@ -304,12 +333,13 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
desc.CPUAccessFlags = 0;
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
ID3D11Texture2D* pTexture = NULL;
|
ID3D11Texture2D* pTexture = nullptr;
|
||||||
D3D11_SUBRESOURCE_DATA subResource;
|
D3D11_SUBRESOURCE_DATA subResource;
|
||||||
subResource.pSysMem = pixels;
|
subResource.pSysMem = pixels;
|
||||||
subResource.SysMemPitch = desc.Width * 4;
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
subResource.SysMemSlicePitch = 0;
|
subResource.SysMemSlicePitch = 0;
|
||||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
IM_ASSERT(pTexture != nullptr);
|
||||||
|
|
||||||
// Create texture view
|
// Create texture view
|
||||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||||
|
@ -318,14 +348,15 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
|
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
|
||||||
pTexture->Release();
|
pTexture->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
io.Fonts->TexID = (ImTextureID)g_pFontTextureView;
|
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
|
||||||
|
|
||||||
// Create texture sampler
|
// Create texture sampler
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
{
|
{
|
||||||
D3D11_SAMPLER_DESC desc;
|
D3D11_SAMPLER_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
@ -337,15 +368,16 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
desc.MinLOD = 0.f;
|
desc.MinLOD = 0.f;
|
||||||
desc.MaxLOD = 0.f;
|
desc.MaxLOD = 0.f;
|
||||||
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX11_CreateDeviceObjects()
|
bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
if (!bd->pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (g_pFontSampler)
|
if (bd->pFontSampler)
|
||||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
|
||||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
|
@ -385,9 +417,9 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
}";
|
}";
|
||||||
|
|
||||||
ID3DBlob* vertexShaderBlob;
|
ID3DBlob* vertexShaderBlob;
|
||||||
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
|
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vertexShaderBlob, nullptr)))
|
||||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
if (g_pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
|
if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &bd->pVertexShader) != S_OK)
|
||||||
{
|
{
|
||||||
vertexShaderBlob->Release();
|
vertexShaderBlob->Release();
|
||||||
return false;
|
return false;
|
||||||
|
@ -400,7 +432,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
};
|
};
|
||||||
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
|
||||||
{
|
{
|
||||||
vertexShaderBlob->Release();
|
vertexShaderBlob->Release();
|
||||||
return false;
|
return false;
|
||||||
|
@ -410,12 +442,12 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
// Create the constant buffer
|
// Create the constant buffer
|
||||||
{
|
{
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX11);
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVertexConstantBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,9 +470,9 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
}";
|
}";
|
||||||
|
|
||||||
ID3DBlob* pixelShaderBlob;
|
ID3DBlob* pixelShaderBlob;
|
||||||
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
|
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr)))
|
||||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
if (g_pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
|
if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &bd->pPixelShader) != S_OK)
|
||||||
{
|
{
|
||||||
pixelShaderBlob->Release();
|
pixelShaderBlob->Release();
|
||||||
return false;
|
return false;
|
||||||
|
@ -457,11 +489,11 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||||
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||||
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||||
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the rasterizer state
|
// Create the rasterizer state
|
||||||
|
@ -472,7 +504,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
desc.CullMode = D3D11_CULL_NONE;
|
desc.CullMode = D3D11_CULL_NONE;
|
||||||
desc.ScissorEnable = true;
|
desc.ScissorEnable = true;
|
||||||
desc.DepthClipEnable = true;
|
desc.DepthClipEnable = true;
|
||||||
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create depth-stencil State
|
// Create depth-stencil State
|
||||||
|
@ -486,7 +518,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||||
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui_ImplDX11_CreateFontsTexture();
|
ImGui_ImplDX11_CreateFontsTexture();
|
||||||
|
@ -496,48 +528,52 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
|
|
||||||
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
if (!bd->pd3dDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; }
|
||||||
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||||
|
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; }
|
||||||
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = nullptr; }
|
||||||
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = nullptr; }
|
||||||
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = nullptr; }
|
||||||
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = nullptr; }
|
||||||
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = nullptr; }
|
||||||
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = nullptr; }
|
||||||
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
||||||
{
|
{
|
||||||
// Setup backend capabilities flags
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_dx11";
|
io.BackendRendererName = "imgui_impl_dx11";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||||
|
|
||||||
// Get factory from device
|
// Get factory from device
|
||||||
IDXGIDevice* pDXGIDevice = NULL;
|
IDXGIDevice* pDXGIDevice = nullptr;
|
||||||
IDXGIAdapter* pDXGIAdapter = NULL;
|
IDXGIAdapter* pDXGIAdapter = nullptr;
|
||||||
IDXGIFactory* pFactory = NULL;
|
IDXGIFactory* pFactory = nullptr;
|
||||||
|
|
||||||
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
{
|
{
|
||||||
g_pd3dDevice = device;
|
bd->pd3dDevice = device;
|
||||||
g_pd3dDeviceContext = device_context;
|
bd->pd3dDeviceContext = device_context;
|
||||||
g_pFactory = pFactory;
|
bd->pFactory = pFactory;
|
||||||
}
|
}
|
||||||
if (pDXGIDevice) pDXGIDevice->Release();
|
if (pDXGIDevice) pDXGIDevice->Release();
|
||||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||||
g_pd3dDevice->AddRef();
|
bd->pd3dDevice->AddRef();
|
||||||
g_pd3dDeviceContext->AddRef();
|
bd->pd3dDeviceContext->AddRef();
|
||||||
|
|
||||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||||
ImGui_ImplDX11_InitPlatformInterface();
|
ImGui_ImplDX11_InitPlatformInterface();
|
||||||
|
@ -547,16 +583,26 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
|
||||||
|
|
||||||
void ImGui_ImplDX11_Shutdown()
|
void ImGui_ImplDX11_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImGui_ImplDX11_ShutdownPlatformInterface();
|
ImGui_ImplDX11_ShutdownPlatformInterface();
|
||||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
if (bd->pFactory) { bd->pFactory->Release(); }
|
||||||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||||
if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
|
if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
|
||||||
|
io.BackendRendererName = nullptr;
|
||||||
|
io.BackendRendererUserData = nullptr;
|
||||||
|
IM_DELETE(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX11_NewFrame()
|
void ImGui_ImplDX11_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_pFontSampler)
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX11_Init()?");
|
||||||
|
|
||||||
|
if (!bd->pFontSampler)
|
||||||
ImGui_ImplDX11_CreateDeviceObjects();
|
ImGui_ImplDX11_CreateDeviceObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,23 +612,24 @@ void ImGui_ImplDX11_NewFrame()
|
||||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
|
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||||
struct ImGuiViewportDataDx11
|
struct ImGui_ImplDX11_ViewportData
|
||||||
{
|
{
|
||||||
IDXGISwapChain* SwapChain;
|
IDXGISwapChain* SwapChain;
|
||||||
ID3D11RenderTargetView* RTView;
|
ID3D11RenderTargetView* RTView;
|
||||||
|
|
||||||
ImGuiViewportDataDx11() { SwapChain = NULL; RTView = NULL; }
|
ImGui_ImplDX11_ViewportData() { SwapChain = nullptr; RTView = nullptr; }
|
||||||
~ImGuiViewportDataDx11() { IM_ASSERT(SwapChain == NULL && RTView == NULL); }
|
~ImGui_ImplDX11_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport)
|
static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx11* data = IM_NEW(ImGuiViewportDataDx11)();
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
viewport->RendererUserData = data;
|
ImGui_ImplDX11_ViewportData* vd = IM_NEW(ImGui_ImplDX11_ViewportData)();
|
||||||
|
viewport->RendererUserData = vd;
|
||||||
|
|
||||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
||||||
// Some backend will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
|
// Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
|
||||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||||
IM_ASSERT(hwnd != 0);
|
IM_ASSERT(hwnd != 0);
|
||||||
|
|
||||||
|
@ -601,68 +648,70 @@ static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport)
|
||||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||||
sd.Flags = 0;
|
sd.Flags = 0;
|
||||||
|
|
||||||
IM_ASSERT(data->SwapChain == NULL && data->RTView == NULL);
|
IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr);
|
||||||
g_pFactory->CreateSwapChain(g_pd3dDevice, &sd, &data->SwapChain);
|
bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain);
|
||||||
|
|
||||||
// Create the render target
|
// Create the render target
|
||||||
if (data->SwapChain)
|
if (vd->SwapChain)
|
||||||
{
|
{
|
||||||
ID3D11Texture2D* pBackBuffer;
|
ID3D11Texture2D* pBackBuffer;
|
||||||
data->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||||
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &data->RTView);
|
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
|
||||||
pBackBuffer->Release();
|
pBackBuffer->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX11_DestroyWindow(ImGuiViewport* viewport)
|
static void ImGui_ImplDX11_DestroyWindow(ImGuiViewport* viewport)
|
||||||
{
|
{
|
||||||
// The main viewport (owned by the application) will always have RendererUserData == NULL since we didn't create the data for it.
|
// The main viewport (owned by the application) will always have RendererUserData == nullptr since we didn't create the data for it.
|
||||||
if (ImGuiViewportDataDx11* data = (ImGuiViewportDataDx11*)viewport->RendererUserData)
|
if (ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData)
|
||||||
{
|
{
|
||||||
if (data->SwapChain)
|
if (vd->SwapChain)
|
||||||
data->SwapChain->Release();
|
vd->SwapChain->Release();
|
||||||
data->SwapChain = NULL;
|
vd->SwapChain = nullptr;
|
||||||
if (data->RTView)
|
if (vd->RTView)
|
||||||
data->RTView->Release();
|
vd->RTView->Release();
|
||||||
data->RTView = NULL;
|
vd->RTView = nullptr;
|
||||||
IM_DELETE(data);
|
IM_DELETE(vd);
|
||||||
}
|
}
|
||||||
viewport->RendererUserData = NULL;
|
viewport->RendererUserData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX11_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
static void ImGui_ImplDX11_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx11* data = (ImGuiViewportDataDx11*)viewport->RendererUserData;
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
if (data->RTView)
|
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||||
|
if (vd->RTView)
|
||||||
{
|
{
|
||||||
data->RTView->Release();
|
vd->RTView->Release();
|
||||||
data->RTView = NULL;
|
vd->RTView = nullptr;
|
||||||
}
|
}
|
||||||
if (data->SwapChain)
|
if (vd->SwapChain)
|
||||||
{
|
{
|
||||||
ID3D11Texture2D* pBackBuffer = NULL;
|
ID3D11Texture2D* pBackBuffer = nullptr;
|
||||||
data->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
||||||
data->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||||
if (pBackBuffer == NULL) { fprintf(stderr, "ImGui_ImplDX11_SetWindowSize() failed creating buffers.\n"); return; }
|
if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX11_SetWindowSize() failed creating buffers.\n"); return; }
|
||||||
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &data->RTView);
|
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
|
||||||
pBackBuffer->Release();
|
pBackBuffer->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX11_RenderWindow(ImGuiViewport* viewport, void*)
|
static void ImGui_ImplDX11_RenderWindow(ImGuiViewport* viewport, void*)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx11* data = (ImGuiViewportDataDx11*)viewport->RendererUserData;
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
g_pd3dDeviceContext->OMSetRenderTargets(1, &data->RTView, NULL);
|
bd->pd3dDeviceContext->OMSetRenderTargets(1, &vd->RTView, nullptr);
|
||||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||||
g_pd3dDeviceContext->ClearRenderTargetView(data->RTView, (float*)&clear_color);
|
bd->pd3dDeviceContext->ClearRenderTargetView(vd->RTView, (float*)&clear_color);
|
||||||
ImGui_ImplDX11_RenderDrawData(viewport->DrawData);
|
ImGui_ImplDX11_RenderDrawData(viewport->DrawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*)
|
static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx11* data = (ImGuiViewportDataDx11*)viewport->RendererUserData;
|
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||||
data->SwapChain->Present(0, 0); // Present without vsync
|
vd->SwapChain->Present(0, 0); // Present without vsync
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX11_InitPlatformInterface()
|
static void ImGui_ImplDX11_InitPlatformInterface()
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
|
|
@ -3,21 +3,31 @@
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
|
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||||
|
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||||
// FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker.
|
// FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker.
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
|
||||||
|
|
||||||
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
|
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
|
||||||
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
||||||
// This define is done in the example .vcxproj file and need to be replicated in your app (by e.g. editing imconfig.h)
|
// To build this on 32-bit systems:
|
||||||
|
// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
|
||||||
|
// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
|
||||||
|
// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
|
||||||
|
// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
// 2020-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically.
|
||||||
// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
|
// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
|
||||||
// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
|
// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
|
||||||
// 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function.
|
// 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function.
|
||||||
|
@ -43,15 +53,27 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DirectX data
|
// DirectX data
|
||||||
static ID3D12Device* g_pd3dDevice = NULL;
|
struct ImGui_ImplDX12_Data
|
||||||
static ID3D12RootSignature* g_pRootSignature = NULL;
|
{
|
||||||
static ID3D12PipelineState* g_pPipelineState = NULL;
|
ID3D12Device* pd3dDevice;
|
||||||
static DXGI_FORMAT g_RTVFormat = DXGI_FORMAT_UNKNOWN;
|
ID3D12RootSignature* pRootSignature;
|
||||||
static ID3D12Resource* g_pFontTextureResource = NULL;
|
ID3D12PipelineState* pPipelineState;
|
||||||
static D3D12_CPU_DESCRIPTOR_HANDLE g_hFontSrvCpuDescHandle = {};
|
DXGI_FORMAT RTVFormat;
|
||||||
static D3D12_GPU_DESCRIPTOR_HANDLE g_hFontSrvGpuDescHandle = {};
|
ID3D12Resource* pFontTextureResource;
|
||||||
static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = NULL;
|
D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle;
|
||||||
static UINT g_numFramesInFlight = 0;
|
D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
|
||||||
|
ID3D12DescriptorHeap* pd3dSrvDescHeap;
|
||||||
|
UINT numFramesInFlight;
|
||||||
|
|
||||||
|
ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Buffers used during the rendering of a frame
|
// Buffers used during the rendering of a frame
|
||||||
struct ImGui_ImplDX12_RenderBuffers
|
struct ImGui_ImplDX12_RenderBuffers
|
||||||
|
@ -73,7 +95,7 @@ struct ImGui_ImplDX12_FrameContext
|
||||||
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||||
// Main viewport created by application will only use the Resources field.
|
// Main viewport created by application will only use the Resources field.
|
||||||
// Secondary viewports created by this backend will use all the fields (including Window fields),
|
// Secondary viewports created by this backend will use all the fields (including Window fields),
|
||||||
struct ImGuiViewportDataDx12
|
struct ImGui_ImplDX12_ViewportData
|
||||||
{
|
{
|
||||||
// Window
|
// Window
|
||||||
ID3D12CommandQueue* CommandQueue;
|
ID3D12CommandQueue* CommandQueue;
|
||||||
|
@ -83,72 +105,59 @@ struct ImGuiViewportDataDx12
|
||||||
ID3D12Fence* Fence;
|
ID3D12Fence* Fence;
|
||||||
UINT64 FenceSignaledValue;
|
UINT64 FenceSignaledValue;
|
||||||
HANDLE FenceEvent;
|
HANDLE FenceEvent;
|
||||||
|
UINT NumFramesInFlight;
|
||||||
ImGui_ImplDX12_FrameContext* FrameCtx;
|
ImGui_ImplDX12_FrameContext* FrameCtx;
|
||||||
|
|
||||||
// Render buffers
|
// Render buffers
|
||||||
UINT FrameIndex;
|
UINT FrameIndex;
|
||||||
ImGui_ImplDX12_RenderBuffers* FrameRenderBuffers;
|
ImGui_ImplDX12_RenderBuffers* FrameRenderBuffers;
|
||||||
|
|
||||||
ImGuiViewportDataDx12()
|
ImGui_ImplDX12_ViewportData(UINT num_frames_in_flight)
|
||||||
{
|
{
|
||||||
CommandQueue = NULL;
|
CommandQueue = nullptr;
|
||||||
CommandList = NULL;
|
CommandList = nullptr;
|
||||||
RtvDescHeap = NULL;
|
RtvDescHeap = nullptr;
|
||||||
SwapChain = NULL;
|
SwapChain = nullptr;
|
||||||
Fence = NULL;
|
Fence = nullptr;
|
||||||
FenceSignaledValue = 0;
|
FenceSignaledValue = 0;
|
||||||
FenceEvent = NULL;
|
FenceEvent = nullptr;
|
||||||
FrameCtx = new ImGui_ImplDX12_FrameContext[g_numFramesInFlight];
|
NumFramesInFlight = num_frames_in_flight;
|
||||||
|
FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight];
|
||||||
FrameIndex = UINT_MAX;
|
FrameIndex = UINT_MAX;
|
||||||
FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[g_numFramesInFlight];
|
FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight];
|
||||||
|
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; ++i)
|
for (UINT i = 0; i < NumFramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
FrameCtx[i].CommandAllocator = NULL;
|
FrameCtx[i].CommandAllocator = nullptr;
|
||||||
FrameCtx[i].RenderTarget = NULL;
|
FrameCtx[i].RenderTarget = nullptr;
|
||||||
|
|
||||||
// Create buffers with a default size (they will later be grown as needed)
|
// Create buffers with a default size (they will later be grown as needed)
|
||||||
FrameRenderBuffers[i].IndexBuffer = NULL;
|
FrameRenderBuffers[i].IndexBuffer = nullptr;
|
||||||
FrameRenderBuffers[i].VertexBuffer = NULL;
|
FrameRenderBuffers[i].VertexBuffer = nullptr;
|
||||||
FrameRenderBuffers[i].VertexBufferSize = 5000;
|
FrameRenderBuffers[i].VertexBufferSize = 5000;
|
||||||
FrameRenderBuffers[i].IndexBufferSize = 10000;
|
FrameRenderBuffers[i].IndexBufferSize = 10000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~ImGuiViewportDataDx12()
|
~ImGui_ImplDX12_ViewportData()
|
||||||
{
|
{
|
||||||
IM_ASSERT(CommandQueue == NULL && CommandList == NULL);
|
IM_ASSERT(CommandQueue == nullptr && CommandList == nullptr);
|
||||||
IM_ASSERT(RtvDescHeap == NULL);
|
IM_ASSERT(RtvDescHeap == nullptr);
|
||||||
IM_ASSERT(SwapChain == NULL);
|
IM_ASSERT(SwapChain == nullptr);
|
||||||
IM_ASSERT(Fence == NULL);
|
IM_ASSERT(Fence == nullptr);
|
||||||
IM_ASSERT(FenceEvent == NULL);
|
IM_ASSERT(FenceEvent == nullptr);
|
||||||
|
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; ++i)
|
for (UINT i = 0; i < NumFramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
IM_ASSERT(FrameCtx[i].CommandAllocator == NULL && FrameCtx[i].RenderTarget == NULL);
|
IM_ASSERT(FrameCtx[i].CommandAllocator == nullptr && FrameCtx[i].RenderTarget == nullptr);
|
||||||
IM_ASSERT(FrameRenderBuffers[i].IndexBuffer == NULL && FrameRenderBuffers[i].VertexBuffer == NULL);
|
IM_ASSERT(FrameRenderBuffers[i].IndexBuffer == nullptr && FrameRenderBuffers[i].VertexBuffer == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] FrameCtx; FrameCtx = NULL;
|
delete[] FrameCtx; FrameCtx = nullptr;
|
||||||
delete[] FrameRenderBuffers; FrameRenderBuffers = NULL;
|
delete[] FrameRenderBuffers; FrameRenderBuffers = nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
struct VERTEX_CONSTANT_BUFFER_DX12
|
||||||
static void SafeRelease(T*& res)
|
|
||||||
{
|
|
||||||
if (res)
|
|
||||||
res->Release();
|
|
||||||
res = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ImGui_ImplDX12_DestroyRenderBuffers(ImGui_ImplDX12_RenderBuffers* render_buffers)
|
|
||||||
{
|
|
||||||
SafeRelease(render_buffers->IndexBuffer);
|
|
||||||
SafeRelease(render_buffers->VertexBuffer);
|
|
||||||
render_buffers->IndexBufferSize = render_buffers->VertexBufferSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VERTEX_CONSTANT_BUFFER
|
|
||||||
{
|
{
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
@ -157,11 +166,14 @@ struct VERTEX_CONSTANT_BUFFER
|
||||||
static void ImGui_ImplDX12_InitPlatformInterface();
|
static void ImGui_ImplDX12_InitPlatformInterface();
|
||||||
static void ImGui_ImplDX12_ShutdownPlatformInterface();
|
static void ImGui_ImplDX12_ShutdownPlatformInterface();
|
||||||
|
|
||||||
|
// Functions
|
||||||
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, ImGui_ImplDX12_RenderBuffers* fr)
|
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, ImGui_ImplDX12_RenderBuffers* fr)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||||
VERTEX_CONSTANT_BUFFER vertex_constant_buffer;
|
VERTEX_CONSTANT_BUFFER_DX12 vertex_constant_buffer;
|
||||||
{
|
{
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
@ -203,8 +215,8 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
|
||||||
ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
||||||
ctx->IASetIndexBuffer(&ibv);
|
ctx->IASetIndexBuffer(&ibv);
|
||||||
ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
ctx->SetPipelineState(g_pPipelineState);
|
ctx->SetPipelineState(bd->pPipelineState);
|
||||||
ctx->SetGraphicsRootSignature(g_pRootSignature);
|
ctx->SetGraphicsRootSignature(bd->pRootSignature);
|
||||||
ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
|
ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
|
||||||
|
|
||||||
// Setup blend factor
|
// Setup blend factor
|
||||||
|
@ -212,6 +224,14 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
|
||||||
ctx->OMSetBlendFactor(blend_factor);
|
ctx->OMSetBlendFactor(blend_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline void SafeRelease(T*& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
res->Release();
|
||||||
|
res = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Render function
|
// Render function
|
||||||
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
|
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
|
||||||
{
|
{
|
||||||
|
@ -219,12 +239,13 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGuiViewportDataDx12* render_data = (ImGuiViewportDataDx12*)draw_data->OwnerViewport->RendererUserData;
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
render_data->FrameIndex++;
|
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)draw_data->OwnerViewport->RendererUserData;
|
||||||
ImGui_ImplDX12_RenderBuffers* fr = &render_data->FrameRenderBuffers[render_data->FrameIndex % g_numFramesInFlight];
|
vd->FrameIndex++;
|
||||||
|
ImGui_ImplDX12_RenderBuffers* fr = &vd->FrameRenderBuffers[vd->FrameIndex % bd->numFramesInFlight];
|
||||||
|
|
||||||
// Create and grow vertex/index buffers if needed
|
// Create and grow vertex/index buffers if needed
|
||||||
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
|
if (fr->VertexBuffer == nullptr || fr->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
{
|
{
|
||||||
SafeRelease(fr->VertexBuffer);
|
SafeRelease(fr->VertexBuffer);
|
||||||
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
@ -244,10 +265,10 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
|
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
if (fr->IndexBuffer == nullptr || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
SafeRelease(fr->IndexBuffer);
|
SafeRelease(fr->IndexBuffer);
|
||||||
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
@ -267,7 +288,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
|
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +327,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
{
|
{
|
||||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
if (pcmd->UserCallback != NULL)
|
if (pcmd->UserCallback != nullptr)
|
||||||
{
|
{
|
||||||
// User callback, registered via ImDrawList::AddCallback()
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
@ -317,16 +338,21 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Apply Scissor, Bind texture, Draw
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
const D3D12_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
if (r.right > r.left && r.bottom > r.top)
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
{
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
ctx->SetGraphicsRootDescriptorTable(1, *(D3D12_GPU_DESCRIPTOR_HANDLE*)&pcmd->TextureId);
|
continue;
|
||||||
|
|
||||||
|
// Apply Scissor/clipping rectangle, Bind texture, Draw
|
||||||
|
const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
|
||||||
|
texture_handle.ptr = (UINT64)pcmd->GetTexID();
|
||||||
|
ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
|
||||||
ctx->RSSetScissorRects(1, &r);
|
ctx->RSSetScissorRects(1, &r);
|
||||||
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||||
}
|
}
|
||||||
|
@ -336,6 +362,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
@ -362,9 +389,9 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
ID3D12Resource* pTexture = NULL;
|
ID3D12Resource* pTexture = nullptr;
|
||||||
g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
|
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture));
|
||||||
|
|
||||||
UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
|
UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
|
||||||
UINT uploadSize = height * uploadPitch;
|
UINT uploadSize = height * uploadPitch;
|
||||||
|
@ -384,12 +411,12 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
|
||||||
ID3D12Resource* uploadBuffer = NULL;
|
ID3D12Resource* uploadBuffer = nullptr;
|
||||||
HRESULT hr = g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
|
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadBuffer));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
void* mapped = NULL;
|
void* mapped = nullptr;
|
||||||
D3D12_RANGE range = { 0, uploadSize };
|
D3D12_RANGE range = { 0, uploadSize };
|
||||||
hr = uploadBuffer->Map(0, &range, &mapped);
|
hr = uploadBuffer->Map(0, &range, &mapped);
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
@ -419,31 +446,31 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||||
|
|
||||||
ID3D12Fence* fence = NULL;
|
ID3D12Fence* fence = nullptr;
|
||||||
hr = g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
|
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
HANDLE event = CreateEvent(0, 0, 0, 0);
|
HANDLE event = CreateEvent(0, 0, 0, 0);
|
||||||
IM_ASSERT(event != NULL);
|
IM_ASSERT(event != nullptr);
|
||||||
|
|
||||||
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||||
queueDesc.NodeMask = 1;
|
queueDesc.NodeMask = 1;
|
||||||
|
|
||||||
ID3D12CommandQueue* cmdQueue = NULL;
|
ID3D12CommandQueue* cmdQueue = nullptr;
|
||||||
hr = g_pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
|
hr = bd->pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
ID3D12CommandAllocator* cmdAlloc = NULL;
|
ID3D12CommandAllocator* cmdAlloc = nullptr;
|
||||||
hr = g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
ID3D12GraphicsCommandList* cmdList = NULL;
|
ID3D12GraphicsCommandList* cmdList = nullptr;
|
||||||
hr = g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
|
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
|
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, nullptr);
|
||||||
cmdList->ResourceBarrier(1, &barrier);
|
cmdList->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
hr = cmdList->Close();
|
hr = cmdList->Close();
|
||||||
|
@ -471,21 +498,29 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, g_hFontSrvCpuDescHandle);
|
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, bd->hFontSrvCpuDescHandle);
|
||||||
SafeRelease(g_pFontTextureResource);
|
SafeRelease(bd->pFontTextureResource);
|
||||||
g_pFontTextureResource = pTexture;
|
bd->pFontTextureResource = pTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
static_assert(sizeof(ImTextureID) >= sizeof(g_hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
|
// READ THIS IF THE STATIC_ASSERT() TRIGGERS:
|
||||||
io.Fonts->TexID = (ImTextureID)g_hFontSrvGpuDescHandle.ptr;
|
// - Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
|
||||||
|
// - This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
||||||
|
// [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
|
||||||
|
// [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
|
||||||
|
// [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
|
||||||
|
// [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
|
||||||
|
static_assert(sizeof(ImTextureID) >= sizeof(bd->hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
|
||||||
|
io.Fonts->SetTexID((ImTextureID)bd->hFontSrvGpuDescHandle.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX12_CreateDeviceObjects()
|
bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (g_pPipelineState)
|
if (bd->pPipelineState)
|
||||||
ImGui_ImplDX12_InvalidateDeviceObjects();
|
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
|
|
||||||
// Create the root signature
|
// Create the root signature
|
||||||
|
@ -510,6 +545,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
param[1].DescriptorTable.pDescriptorRanges = &descRange;
|
param[1].DescriptorTable.pDescriptorRanges = &descRange;
|
||||||
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||||
|
|
||||||
|
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
|
||||||
D3D12_STATIC_SAMPLER_DESC staticSampler = {};
|
D3D12_STATIC_SAMPLER_DESC staticSampler = {};
|
||||||
staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||||
|
@ -536,17 +572,43 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
||||||
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
||||||
|
|
||||||
ID3DBlob* blob = NULL;
|
// Load d3d12.dll and D3D12SerializeRootSignature() function address dynamically to facilitate using with D3D12On7.
|
||||||
if (D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, NULL) != S_OK)
|
// See if any version of d3d12.dll is already loaded in the process. If so, give preference to that.
|
||||||
|
static HINSTANCE d3d12_dll = ::GetModuleHandleA("d3d12.dll");
|
||||||
|
if (d3d12_dll == nullptr)
|
||||||
|
{
|
||||||
|
// Attempt to load d3d12.dll from local directories. This will only succeed if
|
||||||
|
// (1) the current OS is Windows 7, and
|
||||||
|
// (2) there exists a version of d3d12.dll for Windows 7 (D3D12On7) in one of the following directories.
|
||||||
|
// See https://github.com/ocornut/imgui/pull/3696 for details.
|
||||||
|
const char* localD3d12Paths[] = { ".\\d3d12.dll", ".\\d3d12on7\\d3d12.dll", ".\\12on7\\d3d12.dll" }; // A. current directory, B. used by some games, C. used in Microsoft D3D12On7 sample
|
||||||
|
for (int i = 0; i < IM_ARRAYSIZE(localD3d12Paths); i++)
|
||||||
|
if ((d3d12_dll = ::LoadLibraryA(localD3d12Paths[i])) != nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If failed, we are on Windows >= 10.
|
||||||
|
if (d3d12_dll == nullptr)
|
||||||
|
d3d12_dll = ::LoadLibraryA("d3d12.dll");
|
||||||
|
|
||||||
|
if (d3d12_dll == nullptr)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature");
|
||||||
|
if (D3D12SerializeRootSignatureFn == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
g_pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&g_pRootSignature));
|
ID3DBlob* blob = nullptr;
|
||||||
|
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature));
|
||||||
blob->Release();
|
blob->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
// If you would like to use this DX12 sample code but remove this dependency you can:
|
// If you would like to use this DX12 sample code but remove this dependency you can:
|
||||||
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
// 1) compile once, save the compiled shader blobs into a file or source code and assign them to psoDesc.VS/PS [preferred solution]
|
||||||
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||||
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||||
|
|
||||||
|
@ -554,10 +616,10 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
|
memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
|
||||||
psoDesc.NodeMask = 1;
|
psoDesc.NodeMask = 1;
|
||||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||||
psoDesc.pRootSignature = g_pRootSignature;
|
psoDesc.pRootSignature = bd->pRootSignature;
|
||||||
psoDesc.SampleMask = UINT_MAX;
|
psoDesc.SampleMask = UINT_MAX;
|
||||||
psoDesc.NumRenderTargets = 1;
|
psoDesc.NumRenderTargets = 1;
|
||||||
psoDesc.RTVFormats[0] = g_RTVFormat;
|
psoDesc.RTVFormats[0] = bd->RTVFormat;
|
||||||
psoDesc.SampleDesc.Count = 1;
|
psoDesc.SampleDesc.Count = 1;
|
||||||
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
|
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
|
||||||
|
|
||||||
|
@ -594,8 +656,8 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
return output;\
|
return output;\
|
||||||
}";
|
}";
|
||||||
|
|
||||||
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vertexShaderBlob, NULL)))
|
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_5_0", 0, 0, &vertexShaderBlob, nullptr)))
|
||||||
return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
|
psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
|
||||||
|
|
||||||
// Create the input layout
|
// Create the input layout
|
||||||
|
@ -626,10 +688,10 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
return out_col; \
|
return out_col; \
|
||||||
}";
|
}";
|
||||||
|
|
||||||
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &pixelShaderBlob, NULL)))
|
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr)))
|
||||||
{
|
{
|
||||||
vertexShaderBlob->Release();
|
vertexShaderBlob->Release();
|
||||||
return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
}
|
}
|
||||||
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
|
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
|
||||||
}
|
}
|
||||||
|
@ -642,8 +704,8 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
|
desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
|
||||||
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
|
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
|
||||||
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
|
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
||||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||||
}
|
}
|
||||||
|
@ -676,7 +738,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT result_pipeline_state = g_pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&g_pPipelineState));
|
HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
|
||||||
vertexShaderBlob->Release();
|
vertexShaderBlob->Release();
|
||||||
pixelShaderBlob->Release();
|
pixelShaderBlob->Release();
|
||||||
if (result_pipeline_state != S_OK)
|
if (result_pipeline_state != S_OK)
|
||||||
|
@ -687,75 +749,88 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX12_DestroyRenderBuffers(ImGui_ImplDX12_RenderBuffers* render_buffers)
|
||||||
|
{
|
||||||
|
SafeRelease(render_buffers->IndexBuffer);
|
||||||
|
SafeRelease(render_buffers->VertexBuffer);
|
||||||
|
render_buffers->IndexBufferSize = render_buffers->VertexBufferSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX12_InvalidateDeviceObjects()
|
void ImGui_ImplDX12_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SafeRelease(g_pRootSignature);
|
|
||||||
SafeRelease(g_pPipelineState);
|
|
||||||
SafeRelease(g_pFontTextureResource);
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.Fonts->TexID = NULL; // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
SafeRelease(bd->pRootSignature);
|
||||||
|
SafeRelease(bd->pPipelineState);
|
||||||
|
SafeRelease(bd->pFontTextureResource);
|
||||||
|
io.Fonts->SetTexID(0); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
|
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
|
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
|
||||||
{
|
{
|
||||||
// Setup backend capabilities flags
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_dx12";
|
io.BackendRendererName = "imgui_impl_dx12";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) // FIXME-VIEWPORT: Actually unfinished..
|
|
||||||
|
|
||||||
g_pd3dDevice = device;
|
|
||||||
g_RTVFormat = rtv_format;
|
|
||||||
g_hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
|
|
||||||
g_hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
|
|
||||||
g_numFramesInFlight = num_frames_in_flight;
|
|
||||||
g_pd3dSrvDescHeap = cbv_srv_heap;
|
|
||||||
|
|
||||||
// Create a dummy ImGuiViewportDataDx12 holder for the main viewport,
|
|
||||||
// Since this is created and managed by the application, we will only use the ->Resources[] fields.
|
|
||||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
|
||||||
main_viewport->RendererUserData = IM_NEW(ImGuiViewportDataDx12)();
|
|
||||||
|
|
||||||
// Setup backend capabilities flags
|
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||||
ImGui_ImplDX12_InitPlatformInterface();
|
ImGui_ImplDX12_InitPlatformInterface();
|
||||||
|
|
||||||
|
bd->pd3dDevice = device;
|
||||||
|
bd->RTVFormat = rtv_format;
|
||||||
|
bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
|
||||||
|
bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
|
||||||
|
bd->numFramesInFlight = num_frames_in_flight;
|
||||||
|
bd->pd3dSrvDescHeap = cbv_srv_heap;
|
||||||
|
|
||||||
|
// Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport,
|
||||||
|
// Since this is created and managed by the application, we will only use the ->Resources[] fields.
|
||||||
|
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||||
|
main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX12_Shutdown()
|
void ImGui_ImplDX12_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
// Manually delete main viewport render resources in-case we haven't initialized for viewports
|
// Manually delete main viewport render resources in-case we haven't initialized for viewports
|
||||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||||
if (ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)main_viewport->RendererUserData)
|
if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)main_viewport->RendererUserData)
|
||||||
{
|
{
|
||||||
// We could just call ImGui_ImplDX12_DestroyWindow(main_viewport) as a convenience but that would be misleading since we only use data->Resources[]
|
// We could just call ImGui_ImplDX12_DestroyWindow(main_viewport) as a convenience but that would be misleading since we only use data->Resources[]
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
ImGui_ImplDX12_DestroyRenderBuffers(&data->FrameRenderBuffers[i]);
|
ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
|
||||||
IM_DELETE(data);
|
IM_DELETE(vd);
|
||||||
main_viewport->RendererUserData = NULL;
|
main_viewport->RendererUserData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up windows and device objects
|
// Clean up windows and device objects
|
||||||
ImGui_ImplDX12_ShutdownPlatformInterface();
|
ImGui_ImplDX12_ShutdownPlatformInterface();
|
||||||
ImGui_ImplDX12_InvalidateDeviceObjects();
|
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
|
|
||||||
g_pd3dDevice = NULL;
|
io.BackendRendererName = nullptr;
|
||||||
g_hFontSrvCpuDescHandle.ptr = 0;
|
io.BackendRendererUserData = nullptr;
|
||||||
g_hFontSrvGpuDescHandle.ptr = 0;
|
IM_DELETE(bd);
|
||||||
g_numFramesInFlight = 0;
|
|
||||||
g_pd3dSrvDescHeap = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX12_NewFrame()
|
void ImGui_ImplDX12_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_pPipelineState)
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX12_Init()?");
|
||||||
|
|
||||||
|
if (!bd->pPipelineState)
|
||||||
ImGui_ImplDX12_CreateDeviceObjects();
|
ImGui_ImplDX12_CreateDeviceObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,15 +842,16 @@ void ImGui_ImplDX12_NewFrame()
|
||||||
|
|
||||||
static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx12* data = IM_NEW(ImGuiViewportDataDx12)();
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
viewport->RendererUserData = data;
|
ImGui_ImplDX12_ViewportData* vd = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight);
|
||||||
|
viewport->RendererUserData = vd;
|
||||||
|
|
||||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
||||||
// Some backends will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
|
// Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
|
||||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||||
IM_ASSERT(hwnd != 0);
|
IM_ASSERT(hwnd != 0);
|
||||||
|
|
||||||
data->FrameIndex = UINT_MAX;
|
vd->FrameIndex = UINT_MAX;
|
||||||
|
|
||||||
// Create command queue.
|
// Create command queue.
|
||||||
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
|
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
|
||||||
|
@ -783,36 +859,36 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
||||||
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
|
|
||||||
HRESULT res = S_OK;
|
HRESULT res = S_OK;
|
||||||
res = g_pd3dDevice->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&data->CommandQueue));
|
res = bd->pd3dDevice->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&vd->CommandQueue));
|
||||||
IM_ASSERT(res == S_OK);
|
IM_ASSERT(res == S_OK);
|
||||||
|
|
||||||
// Create command allocator.
|
// Create command allocator.
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; ++i)
|
for (UINT i = 0; i < bd->numFramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
res = g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&data->FrameCtx[i].CommandAllocator));
|
res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator));
|
||||||
IM_ASSERT(res == S_OK);
|
IM_ASSERT(res == S_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create command list.
|
// Create command list.
|
||||||
res = g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, data->FrameCtx[0].CommandAllocator, NULL, IID_PPV_ARGS(&data->CommandList));
|
res = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vd->FrameCtx[0].CommandAllocator, nullptr, IID_PPV_ARGS(&vd->CommandList));
|
||||||
IM_ASSERT(res == S_OK);
|
IM_ASSERT(res == S_OK);
|
||||||
data->CommandList->Close();
|
vd->CommandList->Close();
|
||||||
|
|
||||||
// Create fence.
|
// Create fence.
|
||||||
res = g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&data->Fence));
|
res = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&vd->Fence));
|
||||||
IM_ASSERT(res == S_OK);
|
IM_ASSERT(res == S_OK);
|
||||||
|
|
||||||
data->FenceEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
vd->FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
IM_ASSERT(data->FenceEvent != NULL);
|
IM_ASSERT(vd->FenceEvent != nullptr);
|
||||||
|
|
||||||
// Create swap chain
|
// Create swap chain
|
||||||
// FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application.
|
// FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application.
|
||||||
DXGI_SWAP_CHAIN_DESC1 sd1;
|
DXGI_SWAP_CHAIN_DESC1 sd1;
|
||||||
ZeroMemory(&sd1, sizeof(sd1));
|
ZeroMemory(&sd1, sizeof(sd1));
|
||||||
sd1.BufferCount = g_numFramesInFlight;
|
sd1.BufferCount = bd->numFramesInFlight;
|
||||||
sd1.Width = (UINT)viewport->Size.x;
|
sd1.Width = (UINT)viewport->Size.x;
|
||||||
sd1.Height = (UINT)viewport->Size.y;
|
sd1.Height = (UINT)viewport->Size.y;
|
||||||
sd1.Format = g_RTVFormat;
|
sd1.Format = bd->RTVFormat;
|
||||||
sd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
sd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||||
sd1.SampleDesc.Count = 1;
|
sd1.SampleDesc.Count = 1;
|
||||||
sd1.SampleDesc.Quality = 0;
|
sd1.SampleDesc.Quality = 0;
|
||||||
|
@ -821,143 +897,146 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
||||||
sd1.Scaling = DXGI_SCALING_STRETCH;
|
sd1.Scaling = DXGI_SCALING_STRETCH;
|
||||||
sd1.Stereo = FALSE;
|
sd1.Stereo = FALSE;
|
||||||
|
|
||||||
IDXGIFactory4* dxgi_factory = NULL;
|
IDXGIFactory4* dxgi_factory = nullptr;
|
||||||
res = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory));
|
res = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory));
|
||||||
IM_ASSERT(res == S_OK);
|
IM_ASSERT(res == S_OK);
|
||||||
|
|
||||||
IDXGISwapChain1* swap_chain = NULL;
|
IDXGISwapChain1* swap_chain = nullptr;
|
||||||
res = dxgi_factory->CreateSwapChainForHwnd(data->CommandQueue, hwnd, &sd1, NULL, NULL, &swap_chain);
|
res = dxgi_factory->CreateSwapChainForHwnd(vd->CommandQueue, hwnd, &sd1, nullptr, nullptr, &swap_chain);
|
||||||
IM_ASSERT(res == S_OK);
|
IM_ASSERT(res == S_OK);
|
||||||
|
|
||||||
dxgi_factory->Release();
|
dxgi_factory->Release();
|
||||||
|
|
||||||
// Or swapChain.As(&mSwapChain)
|
// Or swapChain.As(&mSwapChain)
|
||||||
IM_ASSERT(data->SwapChain == NULL);
|
IM_ASSERT(vd->SwapChain == nullptr);
|
||||||
swap_chain->QueryInterface(IID_PPV_ARGS(&data->SwapChain));
|
swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain));
|
||||||
swap_chain->Release();
|
swap_chain->Release();
|
||||||
|
|
||||||
// Create the render targets
|
// Create the render targets
|
||||||
if (data->SwapChain)
|
if (vd->SwapChain)
|
||||||
{
|
{
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
||||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||||
desc.NumDescriptors = g_numFramesInFlight;
|
desc.NumDescriptors = bd->numFramesInFlight;
|
||||||
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||||
desc.NodeMask = 1;
|
desc.NodeMask = 1;
|
||||||
|
|
||||||
HRESULT hr = g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&data->RtvDescHeap));
|
HRESULT hr = bd->pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&vd->RtvDescHeap));
|
||||||
IM_ASSERT(hr == S_OK);
|
IM_ASSERT(hr == S_OK);
|
||||||
|
|
||||||
SIZE_T rtv_descriptor_size = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = data->RtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
{
|
{
|
||||||
data->FrameCtx[i].RenderTargetCpuDescriptors = rtv_handle;
|
vd->FrameCtx[i].RenderTargetCpuDescriptors = rtv_handle;
|
||||||
rtv_handle.ptr += rtv_descriptor_size;
|
rtv_handle.ptr += rtv_descriptor_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D12Resource* back_buffer;
|
ID3D12Resource* back_buffer;
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
{
|
{
|
||||||
IM_ASSERT(data->FrameCtx[i].RenderTarget == NULL);
|
IM_ASSERT(vd->FrameCtx[i].RenderTarget == nullptr);
|
||||||
data->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
||||||
g_pd3dDevice->CreateRenderTargetView(back_buffer, NULL, data->FrameCtx[i].RenderTargetCpuDescriptors);
|
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
||||||
data->FrameCtx[i].RenderTarget = back_buffer;
|
vd->FrameCtx[i].RenderTarget = back_buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
ImGui_ImplDX12_DestroyRenderBuffers(&data->FrameRenderBuffers[i]);
|
ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_WaitForPendingOperations(ImGuiViewportDataDx12* data)
|
static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_FALSE;
|
HRESULT hr = S_FALSE;
|
||||||
if (data && data->CommandQueue && data->Fence && data->FenceEvent)
|
if (vd && vd->CommandQueue && vd->Fence && vd->FenceEvent)
|
||||||
{
|
{
|
||||||
hr = data->CommandQueue->Signal(data->Fence, ++data->FenceSignaledValue);
|
hr = vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue);
|
||||||
IM_ASSERT(hr == S_OK);
|
IM_ASSERT(hr == S_OK);
|
||||||
::WaitForSingleObject(data->FenceEvent, 0); // Reset any forgotten waits
|
::WaitForSingleObject(vd->FenceEvent, 0); // Reset any forgotten waits
|
||||||
hr = data->Fence->SetEventOnCompletion(data->FenceSignaledValue, data->FenceEvent);
|
hr = vd->Fence->SetEventOnCompletion(vd->FenceSignaledValue, vd->FenceEvent);
|
||||||
IM_ASSERT(hr == S_OK);
|
IM_ASSERT(hr == S_OK);
|
||||||
::WaitForSingleObject(data->FenceEvent, INFINITE);
|
::WaitForSingleObject(vd->FenceEvent, INFINITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
|
static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
|
||||||
{
|
{
|
||||||
// The main viewport (owned by the application) will always have RendererUserData == NULL since we didn't create the data for it.
|
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
|
||||||
if (ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)viewport->RendererUserData)
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData)
|
||||||
{
|
{
|
||||||
ImGui_WaitForPendingOperations(data);
|
ImGui_WaitForPendingOperations(vd);
|
||||||
|
|
||||||
SafeRelease(data->CommandQueue);
|
SafeRelease(vd->CommandQueue);
|
||||||
SafeRelease(data->CommandList);
|
SafeRelease(vd->CommandList);
|
||||||
SafeRelease(data->SwapChain);
|
SafeRelease(vd->SwapChain);
|
||||||
SafeRelease(data->RtvDescHeap);
|
SafeRelease(vd->RtvDescHeap);
|
||||||
SafeRelease(data->Fence);
|
SafeRelease(vd->Fence);
|
||||||
::CloseHandle(data->FenceEvent);
|
::CloseHandle(vd->FenceEvent);
|
||||||
data->FenceEvent = NULL;
|
vd->FenceEvent = nullptr;
|
||||||
|
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
{
|
{
|
||||||
SafeRelease(data->FrameCtx[i].RenderTarget);
|
SafeRelease(vd->FrameCtx[i].RenderTarget);
|
||||||
SafeRelease(data->FrameCtx[i].CommandAllocator);
|
SafeRelease(vd->FrameCtx[i].CommandAllocator);
|
||||||
ImGui_ImplDX12_DestroyRenderBuffers(&data->FrameRenderBuffers[i]);
|
ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
|
||||||
}
|
}
|
||||||
IM_DELETE(data);
|
IM_DELETE(vd);
|
||||||
}
|
}
|
||||||
viewport->RendererUserData = NULL;
|
viewport->RendererUserData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)viewport->RendererUserData;
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||||
|
|
||||||
ImGui_WaitForPendingOperations(data);
|
ImGui_WaitForPendingOperations(vd);
|
||||||
|
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
SafeRelease(data->FrameCtx[i].RenderTarget);
|
SafeRelease(vd->FrameCtx[i].RenderTarget);
|
||||||
|
|
||||||
if (data->SwapChain)
|
if (vd->SwapChain)
|
||||||
{
|
{
|
||||||
ID3D12Resource* back_buffer = NULL;
|
ID3D12Resource* back_buffer = nullptr;
|
||||||
data->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
||||||
for (UINT i = 0; i < g_numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
{
|
{
|
||||||
data->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
||||||
g_pd3dDevice->CreateRenderTargetView(back_buffer, NULL, data->FrameCtx[i].RenderTargetCpuDescriptors);
|
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
||||||
data->FrameCtx[i].RenderTarget = back_buffer;
|
vd->FrameCtx[i].RenderTarget = back_buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)viewport->RendererUserData;
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||||
|
|
||||||
ImGui_ImplDX12_FrameContext* frame_context = &data->FrameCtx[data->FrameIndex % g_numFramesInFlight];
|
ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % bd->numFramesInFlight];
|
||||||
UINT back_buffer_idx = data->SwapChain->GetCurrentBackBufferIndex();
|
UINT back_buffer_idx = vd->SwapChain->GetCurrentBackBufferIndex();
|
||||||
|
|
||||||
const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
D3D12_RESOURCE_BARRIER barrier = {};
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
barrier.Transition.pResource = data->FrameCtx[back_buffer_idx].RenderTarget;
|
barrier.Transition.pResource = vd->FrameCtx[back_buffer_idx].RenderTarget;
|
||||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
ID3D12GraphicsCommandList* cmd_list = data->CommandList;
|
ID3D12GraphicsCommandList* cmd_list = vd->CommandList;
|
||||||
|
|
||||||
frame_context->CommandAllocator->Reset();
|
frame_context->CommandAllocator->Reset();
|
||||||
cmd_list->Reset(frame_context->CommandAllocator, NULL);
|
cmd_list->Reset(frame_context->CommandAllocator, nullptr);
|
||||||
cmd_list->ResourceBarrier(1, &barrier);
|
cmd_list->ResourceBarrier(1, &barrier);
|
||||||
cmd_list->OMSetRenderTargets(1, &data->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, NULL);
|
cmd_list->OMSetRenderTargets(1, &vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr);
|
||||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||||
cmd_list->ClearRenderTargetView(data->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, (float*)&clear_color, 0, NULL);
|
cmd_list->ClearRenderTargetView(vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, (float*)&clear_color, 0, nullptr);
|
||||||
cmd_list->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap);
|
cmd_list->SetDescriptorHeaps(1, &bd->pd3dSrvDescHeap);
|
||||||
|
|
||||||
ImGui_ImplDX12_RenderDrawData(viewport->DrawData, cmd_list);
|
ImGui_ImplDX12_RenderDrawData(viewport->DrawData, cmd_list);
|
||||||
|
|
||||||
|
@ -966,17 +1045,17 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
||||||
cmd_list->ResourceBarrier(1, &barrier);
|
cmd_list->ResourceBarrier(1, &barrier);
|
||||||
cmd_list->Close();
|
cmd_list->Close();
|
||||||
|
|
||||||
data->CommandQueue->Wait(data->Fence, data->FenceSignaledValue);
|
vd->CommandQueue->Wait(vd->Fence, vd->FenceSignaledValue);
|
||||||
data->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
|
vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
|
||||||
data->CommandQueue->Signal(data->Fence, ++data->FenceSignaledValue);
|
vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||||
{
|
{
|
||||||
ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)viewport->RendererUserData;
|
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||||
|
|
||||||
data->SwapChain->Present(0, 0);
|
vd->SwapChain->Present(0, 0);
|
||||||
while (data->Fence->GetCompletedValue() < data->FenceSignaledValue)
|
while (vd->Fence->GetCompletedValue() < vd->FenceSignaledValue)
|
||||||
::SwitchToThread();
|
::SwitchToThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue