Compare commits
281 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f15c37c2e | ||
|
|
a7b9feaedc | ||
|
|
35a2297ab2 | ||
|
|
44bc283f4f | ||
|
|
822c60d839 | ||
|
|
0b279163de | ||
|
|
543534bf61 | ||
|
|
ba10834602 | ||
|
|
49c2cadb0a | ||
|
|
e10a494223 | ||
|
|
afad2c80e5 | ||
|
|
c41dc20132 | ||
|
|
03da5e41d6 | ||
|
|
b1ba1c2975 | ||
|
|
8c4ba37e59 | ||
|
|
c7496c7b42 | ||
|
|
96b293d1b5 | ||
|
|
e00dec67ba | ||
|
|
837d8dc507 | ||
|
|
d6025bc4e0 | ||
|
|
0ebbe75b6e | ||
|
|
5de5dbba23 | ||
|
|
c94f5144e7 | ||
|
|
a36386cc20 | ||
|
|
0b73f8037b | ||
|
|
9f9dcd5882 | ||
|
|
164359f6aa | ||
|
|
4b6e7da994 | ||
|
|
279cf58dff | ||
|
|
3f49ee11ae | ||
|
|
5e3f5594b8 | ||
|
|
860474654a | ||
|
|
3be2425665 | ||
|
|
3b27fe17c1 | ||
|
|
c3b563a032 | ||
|
|
aa141405c6 | ||
|
|
da6990ddc8 | ||
|
|
242cd93589 | ||
|
|
9cc4819524 | ||
|
|
fcd0209710 | ||
|
|
4a557d7e5c | ||
|
|
a55a5ec5cc | ||
|
|
c87e5a25d5 | ||
|
|
285ca80b4b | ||
|
|
5cc982fa00 | ||
|
|
2bc06cdd5a | ||
|
|
25236f82c3 | ||
|
|
22e6967ae2 | ||
|
|
aa7bf32940 | ||
|
|
8b54ca0216 | ||
|
|
351a5d842e | ||
|
|
39c3d88f7a | ||
|
|
5ac4d56d32 | ||
|
|
8bec5d1ab7 | ||
|
|
e32e5e77d1 | ||
|
|
938616d989 | ||
|
|
3bc43612ef | ||
|
|
5c90192c9f | ||
|
|
805c891557 | ||
|
|
3cc8dbc102 | ||
|
|
8bfe44b3cd | ||
|
|
bc29860385 | ||
|
|
b206e4444e | ||
|
|
60b5f08f65 | ||
|
|
1ec84044be | ||
|
|
6b77faced8 | ||
|
|
19f492dff1 | ||
|
|
0f8fb5c580 | ||
|
|
35cb553ecb | ||
|
|
1767b65c7e | ||
|
|
90244934d9 | ||
|
|
aa10424fbb | ||
|
|
0192d58fa4 | ||
|
|
db1a6b35ef | ||
|
|
92d8b04cf8 | ||
|
|
fc00a83f2e | ||
|
|
13bcbcb23f | ||
|
|
3148e2c020 | ||
|
|
4d381d62e4 | ||
|
|
715175085e | ||
|
|
714bdaef12 | ||
|
|
88b78d907a | ||
|
|
24f9d8acae | ||
|
|
cf3f8dbc9c | ||
|
|
ca1ae75b07 | ||
|
|
9e2e7f5809 | ||
|
|
c6260f7c48 | ||
|
|
f8c82b7e29 | ||
|
|
e78885d452 | ||
|
|
9d01ba2c8a | ||
|
|
89eec0e329 | ||
|
|
9054ed9f4a | ||
|
|
f10f04bac2 | ||
|
|
04f5ec30bc | ||
|
|
1756ca026d | ||
|
|
fa2d0aaa92 | ||
|
|
57d5591d4a | ||
|
|
26cf35807d | ||
|
|
e6e88193c2 | ||
|
|
9972960556 | ||
|
|
ee805fd3d7 | ||
|
|
ad6581cc18 | ||
|
|
9486cf0bee | ||
|
|
6d8c64ac33 | ||
|
|
689bee9afc | ||
|
|
8451c56e93 | ||
|
|
bfbdd0e33b | ||
|
|
5c18a10d11 | ||
|
|
a46a2167ba | ||
|
|
6d02137dca | ||
|
|
fb374e71e4 | ||
|
|
16af8dc809 | ||
|
|
25fd52294f | ||
|
|
84046e89be | ||
|
|
e331fc1a34 | ||
|
|
e0f92b32dc | ||
|
|
8eae09591d | ||
|
|
9fd3183961 | ||
|
|
e065dc736b | ||
|
|
cd8feaf2c0 | ||
|
|
1155067b26 | ||
|
|
3b389bdc17 | ||
|
|
2455f90550 | ||
|
|
f8c38a8a37 | ||
|
|
8866290d29 | ||
|
|
0eaf22cc46 | ||
|
|
69a17a609e | ||
|
|
afab59eb21 | ||
|
|
b8bcf58a29 | ||
|
|
79d018ffb4 | ||
|
|
5c7ee99d43 | ||
|
|
101ef375ef | ||
|
|
b56829ea26 | ||
|
|
0b3f780ec7 | ||
|
|
0494bf05af | ||
|
|
8cc5f2f9f7 | ||
|
|
69db2b82a4 | ||
|
|
72e034ca32 | ||
|
|
06f70f3d2f | ||
|
|
f5dbbc1330 | ||
|
|
d2dde03efb | ||
|
|
93266715c0 | ||
|
|
0f455dd33b | ||
|
|
3eadb0d726 | ||
|
|
6c92be58cd | ||
|
|
2484ea9d9c | ||
|
|
d4c85a3d86 | ||
|
|
87fb15ed13 | ||
|
|
b647271081 | ||
|
|
505b77da3f | ||
|
|
8dc73bc1d5 | ||
|
|
1293136343 | ||
|
|
8f87c3bc33 | ||
|
|
30d4f194ba | ||
|
|
aaeb6438a1 | ||
|
|
b2a1883369 | ||
|
|
7a685e0634 | ||
|
|
2ebf650381 | ||
|
|
b883f0029c | ||
|
|
70b6bf4d77 | ||
|
|
6279323a84 | ||
|
|
226c62f40b | ||
|
|
7121917a5d | ||
|
|
dbd53719b0 | ||
|
|
8f38095bec | ||
|
|
184f8dd1fe | ||
|
|
fb8202f385 | ||
|
|
56d63f2f18 | ||
|
|
b3e5bf0941 | ||
|
|
419ebb43d1 | ||
|
|
53b690dad9 | ||
|
|
aecad978ec | ||
|
|
b8f2380c60 | ||
|
|
73897f11df | ||
|
|
94d1bb7f41 | ||
|
|
782a041ba8 | ||
|
|
8955a02d05 | ||
|
|
36efa46848 | ||
|
|
5106cc3b71 | ||
|
|
466c0c36bd | ||
|
|
1a5d2934ae | ||
|
|
c34c41d0f5 | ||
|
|
0b63045503 | ||
|
|
b26310439d | ||
|
|
420bb37039 | ||
|
|
7660d58f26 | ||
|
|
1d48d390d3 | ||
|
|
5a3e07f4f3 | ||
|
|
d5a08acf6d | ||
|
|
cd451d1c2a | ||
|
|
cb09a6f5de | ||
|
|
98b5e4d182 | ||
|
|
b74c5bc5e5 | ||
|
|
a233b6a214 | ||
|
|
dd71eba0ec | ||
|
|
f6ba86aff8 | ||
|
|
fa72355799 | ||
|
|
ee8027055e | ||
|
|
4804e51ad7 | ||
|
|
90ce453b60 | ||
|
|
7e17b32a81 | ||
|
|
91fb72bd49 | ||
|
|
b4ae5dde77 | ||
|
|
e9daedd6ea | ||
|
|
97a99f84f5 | ||
|
|
15c5576273 | ||
|
|
4d00ef1296 | ||
|
|
77db3f4ab5 | ||
|
|
368ae81251 | ||
|
|
a84cfabd60 | ||
|
|
a3a79c87da | ||
|
|
a62e665623 | ||
|
|
bb2b0b926f | ||
|
|
d6c326b83d | ||
|
|
eb133745f9 | ||
|
|
b2fa4c4266 | ||
|
|
15b56a876a | ||
|
|
25b66804a4 | ||
|
|
74aaf9a0a1 | ||
|
|
be206950f0 | ||
|
|
7b276e1005 | ||
|
|
0e4f4228de | ||
|
|
16115b483a | ||
|
|
2c8151ec3e | ||
|
|
24d554abc3 | ||
|
|
ffb533ec9a | ||
|
|
d9ffb61712 | ||
|
|
f5e9b041cd | ||
|
|
259bf5a485 | ||
|
|
92e772cde1 | ||
|
|
a938bf9bb1 | ||
|
|
8feeb3d1c1 | ||
|
|
42ee676bc9 | ||
|
|
cef0db6fb1 | ||
|
|
4825d61486 | ||
|
|
64960c6aff | ||
|
|
17ad239692 | ||
|
|
f579a969ce | ||
|
|
3f4f2caf1f | ||
|
|
ab0edfc302 | ||
|
|
e0eb6e138d | ||
|
|
a679ab1c4b | ||
|
|
63029e6083 | ||
|
|
edf0548046 | ||
|
|
31e420b311 | ||
|
|
4a5877784b | ||
|
|
d3df3dde09 | ||
|
|
94057d2a66 | ||
|
|
0f639ba3b1 | ||
|
|
41f7d978a9 | ||
|
|
1e2ca13a15 | ||
|
|
8df79328cd | ||
|
|
c375472bbe | ||
|
|
aaa08e4495 | ||
|
|
f52b351cac | ||
|
|
98132ca2f5 | ||
|
|
e50cb9f0e2 | ||
|
|
8c600a1cdb | ||
|
|
f60e73fc32 | ||
|
|
58db6fe058 | ||
|
|
32c7512b69 | ||
|
|
038e6c58cf | ||
|
|
d5dfb1c304 | ||
|
|
bd1a6a44db | ||
|
|
f5cab30f21 | ||
|
|
3846b91662 | ||
|
|
e08f961707 | ||
|
|
29ab5fa8a6 | ||
|
|
54c44dbd6a | ||
|
|
53aa0e34a8 | ||
|
|
f91b45643d | ||
|
|
1aece0c617 | ||
|
|
6248c294b8 | ||
|
|
f676e84521 | ||
|
|
1310bb78ad | ||
|
|
0ec44ee2d1 | ||
|
|
ffa90323a4 | ||
|
|
f46ea7e0fb | ||
|
|
b7560534c1 | ||
|
|
eae8852832 | ||
|
|
2dff05d412 |
540 changed files with 280533 additions and 56027 deletions
21
.back/WidBack/CMakeLists.txt
Normal file
21
.back/WidBack/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
project(Widgets)
|
||||||
|
|
||||||
|
### ---------------------- Static Library --------------------- ###
|
||||||
|
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
|
||||||
|
file(GLOB HEADERS "./public/*.hpp")
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC Math Graphics Imgui)
|
||||||
|
|
||||||
|
### -------------------------- Applications -------------------------- ###
|
||||||
|
|
||||||
|
add_executable(SimpleGui examples/SimpleGUI.cpp)
|
||||||
|
target_link_libraries(SimpleGui ${PROJECT_NAME} ${GLEW_LIB})
|
||||||
|
target_include_directories(SimpleGui PUBLIC ../Externals/glfw/include ${GLEW_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_executable(ChatGui examples/ChatGUI.cpp)
|
||||||
|
target_link_libraries(ChatGui ${PROJECT_NAME} ${GLEW_LIB})
|
||||||
|
target_include_directories(ChatGui PUBLIC ../Externals/glfw/include ${GLEW_INCLUDE_DIR})
|
||||||
|
|
||||||
|
file(COPY "examples/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
|
||||||
34
.back/WidBack/examples/ChatGUI.cpp
Normal file
34
.back/WidBack/examples/ChatGUI.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
#include "ChatGUI.hpp"
|
||||||
|
|
||||||
|
#include "GraphicApplication.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
class ExampleGUI : public Application {
|
||||||
|
public:
|
||||||
|
ExampleGUI() = default;
|
||||||
|
|
||||||
|
void processFrame(EventHandler* eventHandler, halnf delta) override {
|
||||||
|
auto rec = RectF({ 0, 0 }, mWindow->getSize());
|
||||||
|
|
||||||
|
mGui.updateConfigWrapper(mWidgetManager);
|
||||||
|
mGui.setArea(rec);
|
||||||
|
mGui.setVisible(true);
|
||||||
|
|
||||||
|
mGui.procWrapper(*eventHandler, rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawFrame(Canvas* canvas) override { mGui.drawWrapper(*canvas); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
WidgetManager mWidgetManager;
|
||||||
|
ComplexWidget mGui;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
{
|
||||||
|
ExampleGUI gui;
|
||||||
|
gui.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
256
.back/WidBack/examples/ChatGUI.hpp
Normal file
256
.back/WidBack/examples/ChatGUI.hpp
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Widgets.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class UserWidget : public Widget {
|
||||||
|
public:
|
||||||
|
UserWidget() = default;
|
||||||
|
|
||||||
|
void eventDraw(Canvas& canvas) override {
|
||||||
|
if (this->isFocus()) canvas.rect(this->mArea, mAccentColor, mRounding);
|
||||||
|
else canvas.rect(this->mArea, mBaseColor, mRounding);
|
||||||
|
canvas.text(mUser.c_str(), this->mArea, mFontSize, Canvas::CC, mPadding, mUserColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override {
|
||||||
|
wm.setActiveId("UserWidget");
|
||||||
|
|
||||||
|
mBaseColor = wm.getColor("Base", "Base");
|
||||||
|
mFontSize = wm.getNumber("Size", "FontSize");
|
||||||
|
mPadding = wm.getNumber("Padding", "Padding");
|
||||||
|
mUserColor = wm.getColor("ColUser", "Front");
|
||||||
|
mAccentColor = wm.getColor("Accent", "Accent");
|
||||||
|
mRounding = wm.getNumber("Rounding", "Rounding");
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string mUser = "UserName";
|
||||||
|
bool mIsHover = false;
|
||||||
|
|
||||||
|
RGBA mBaseColor;
|
||||||
|
RGBA mUserColor;
|
||||||
|
RGBA mAccentColor;
|
||||||
|
halnf mPadding = 0;
|
||||||
|
halnf mFontSize = 0;
|
||||||
|
halnf mRounding = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MessageWidget : public Widget {
|
||||||
|
public:
|
||||||
|
MessageWidget() = default;
|
||||||
|
|
||||||
|
void eventDraw(Canvas& canvas) override {
|
||||||
|
if (this->isFocus()) canvas.rect(this->mArea, mBaseColor, mRounding);
|
||||||
|
|
||||||
|
auto userName = this->mArea;
|
||||||
|
userName.w = 25;
|
||||||
|
|
||||||
|
auto content = this->mArea;
|
||||||
|
content.y = userName.y + userName.w;
|
||||||
|
content.w = this->mArea.w - userName.w;
|
||||||
|
|
||||||
|
canvas.text(mContent.c_str(), content, mFontSize, Canvas::LC, mPadding, mUserColorDim);
|
||||||
|
canvas.text(mUser.c_str(), userName, mFontSizeDim, Canvas::LC, mPadding, mUserColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override {
|
||||||
|
wm.setActiveId("MessageWidget");
|
||||||
|
|
||||||
|
mBaseColor = wm.getColor("Base", "Base");
|
||||||
|
mFontSize = wm.getNumber("Size", "FontSize");
|
||||||
|
mFontSizeDim = wm.getNumber("SizeUser", "FontSizeDim");
|
||||||
|
mPadding = wm.getNumber("Padding", "Padding");
|
||||||
|
mUserColor = wm.getColor("UserColor", "Front");
|
||||||
|
mUserColorDim = wm.getColor("UserColorDim", "FrontDim");
|
||||||
|
mRounding = wm.getNumber("Rounding", "Rounding");
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string mContent = "Message Content";
|
||||||
|
std::string mUser = "UserName";
|
||||||
|
bool mIsHover = false;
|
||||||
|
|
||||||
|
RGBA mBaseColor;
|
||||||
|
RGBA mUserColor;
|
||||||
|
RGBA mUserColorDim;
|
||||||
|
halnf mPadding = 0;
|
||||||
|
halnf mFontSize = 0;
|
||||||
|
halnf mFontSizeDim = 0;
|
||||||
|
halnf mRounding = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoginWidget : public Widget {
|
||||||
|
public:
|
||||||
|
explicit LoginWidget() {
|
||||||
|
mPass.mId = "pass";
|
||||||
|
mUser.mId = "user";
|
||||||
|
mButton.mLabel.mLabel = "Login";
|
||||||
|
|
||||||
|
this->mChildWidgets.pushBack(&mPass);
|
||||||
|
this->mChildWidgets.pushBack(&mUser);
|
||||||
|
this->mChildWidgets.pushBack(&mButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventProcess(const Events& events) override {
|
||||||
|
mLogged = false;
|
||||||
|
|
||||||
|
const auto xval = this->mArea.z / 2 - 100;
|
||||||
|
|
||||||
|
mUser.setArea({ xval, 10, 200, 30 });
|
||||||
|
mPass.setArea({ xval, 50, 200, 30 });
|
||||||
|
mButton.setArea({ xval, 90, 200, 30 });
|
||||||
|
|
||||||
|
if (mButton.isFired()) {
|
||||||
|
mLogged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, mBGColor); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override {
|
||||||
|
wm.setActiveId("LoginWidget");
|
||||||
|
mBGColor = wm.getColor("Back", "Base");
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
TextInputWidget mUser;
|
||||||
|
TextInputWidget mPass;
|
||||||
|
ButtonWidget mButton;
|
||||||
|
bool mLogged = false;
|
||||||
|
|
||||||
|
RGBA mBGColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ActiveChatWidget : public Widget {
|
||||||
|
public:
|
||||||
|
ActiveChatWidget() {
|
||||||
|
mSend.mLabel.mLabel = "Send";
|
||||||
|
mMessage.mId = "Message";
|
||||||
|
|
||||||
|
this->mChildWidgets.pushBack(&mHistoryView);
|
||||||
|
this->mChildWidgets.pushBack(&mMessage);
|
||||||
|
this->mChildWidgets.pushBack(&mSend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventProcess(const Events& events) override {
|
||||||
|
auto history = this->mArea;
|
||||||
|
history.w -= 50;
|
||||||
|
|
||||||
|
auto input = this->mArea;
|
||||||
|
input.y = history.w + 10;
|
||||||
|
input.w = 40 - mPadding;
|
||||||
|
input.x += mPadding;
|
||||||
|
input.z -= mPadding;
|
||||||
|
|
||||||
|
auto inputMessage = input;
|
||||||
|
inputMessage.z -= 100;
|
||||||
|
|
||||||
|
auto inputSend = input;
|
||||||
|
inputSend.x = inputMessage.x + inputMessage.z + mPadding;
|
||||||
|
inputSend.z = 100 - mPadding * 2;
|
||||||
|
|
||||||
|
mSend.setArea(inputSend);
|
||||||
|
mMessage.setArea(inputMessage);
|
||||||
|
|
||||||
|
mHistoryView.setArea(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, mBGColor); }
|
||||||
|
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override {
|
||||||
|
wm.setActiveId("ActiveChat");
|
||||||
|
mBGColor = wm.getColor("Back", "Background");
|
||||||
|
mPadding = wm.getNumber("Padding", "Padding");
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buffer<MessageWidget> mMessages;
|
||||||
|
ScrollableWindow mHistoryView;
|
||||||
|
TextInputWidget mMessage;
|
||||||
|
ButtonWidget mSend;
|
||||||
|
|
||||||
|
RGBA mBGColor;
|
||||||
|
halnf mPadding = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChattingWidget : public DockWidget {
|
||||||
|
public:
|
||||||
|
ChattingWidget() {
|
||||||
|
// todo : fetch code
|
||||||
|
mUsers.append(UserWidget());
|
||||||
|
mUsers.append(UserWidget());
|
||||||
|
mUsers.append(UserWidget());
|
||||||
|
|
||||||
|
mUsers[0].mArea = { 0, 0, 100, 100 };
|
||||||
|
mUsers[1].mArea = { 0, 0, 100, 100 };
|
||||||
|
mUsers[2].mArea = { 0, 0, 100, 100 };
|
||||||
|
|
||||||
|
for (auto message : mUsers) {
|
||||||
|
mSideView.addWidget(&message.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
mActive.mMessages.append(MessageWidget());
|
||||||
|
mActive.mMessages.append(MessageWidget());
|
||||||
|
mActive.mMessages.append(MessageWidget());
|
||||||
|
|
||||||
|
mActive.mMessages[0].mArea = { 0, 0, 100, 50 };
|
||||||
|
mActive.mMessages[1].mArea = { 0, 0, 100, 50 };
|
||||||
|
mActive.mMessages[2].mArea = { 0, 0, 100, 50 };
|
||||||
|
|
||||||
|
for (auto message : mActive.mMessages) {
|
||||||
|
mActive.mHistoryView.addWidget(&message.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
addSideWidget(&mSideView, DockWidget::RIGHT);
|
||||||
|
setCenterWidget(&mActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override {
|
||||||
|
wm.setActiveId("ChattingWidget");
|
||||||
|
mBGColor = wm.getColor("Back", "Background");
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buffer<UserWidget> mUsers;
|
||||||
|
ScrollableWindow mSideView;
|
||||||
|
ActiveChatWidget mActive;
|
||||||
|
|
||||||
|
RGBA mBGColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ComplexWidget : public Widget {
|
||||||
|
public:
|
||||||
|
ComplexWidget() {
|
||||||
|
this->mChildWidgets.pushBack(&mLogin);
|
||||||
|
this->mChildWidgets.pushBack(&mChatting);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventProcess(const Events& events) override {
|
||||||
|
mLogged = mLogin.mLogged;
|
||||||
|
|
||||||
|
mLogin.setEnable(!mLogged);
|
||||||
|
mChatting.setEnable(mLogged);
|
||||||
|
|
||||||
|
mLogin.setArea(this->mArea);
|
||||||
|
mChatting.setArea(this->mArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, mBGColor); }
|
||||||
|
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override {
|
||||||
|
wm.setActiveId("ChatGui");
|
||||||
|
mBGColor = wm.getColor("Back", "Background");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mLogged = false;
|
||||||
|
LoginWidget mLogin;
|
||||||
|
ChattingWidget mChatting;
|
||||||
|
|
||||||
|
RGBA mBGColor;
|
||||||
|
};
|
||||||
|
}
|
||||||
BIN
.back/WidBack/examples/Font.ttf
Normal file
BIN
.back/WidBack/examples/Font.ttf
Normal file
Binary file not shown.
40
.back/WidBack/examples/SimpleGUI.cpp
Normal file
40
.back/WidBack/examples/SimpleGUI.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
#include "SimpleGUI.hpp"
|
||||||
|
|
||||||
|
#include "GraphicApplication.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
class SimpleGUI : public Application {
|
||||||
|
public:
|
||||||
|
SimpleGUI() {
|
||||||
|
// mGui.mPreview = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void processFrame(EventHandler* eventHandler, halnf) override {
|
||||||
|
const auto rec = RectF({ 0, 0 }, mWindow->getSize());
|
||||||
|
|
||||||
|
mGui.setArea(rec);
|
||||||
|
mGui.updateConfigWrapper(mWidgetManager);
|
||||||
|
mGui.procWrapper(*eventHandler, rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawFrame(Canvas* canvas) override {
|
||||||
|
canvas->rect(mGui.mArea, { 0.1f, 0.1f, 0.1f, 1.f });
|
||||||
|
mGui.drawWrapper(*canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
WidgetManager mWidgetManager;
|
||||||
|
|
||||||
|
// DockSpaceWidget mGui;
|
||||||
|
SimpleWidget3 mGui;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
{
|
||||||
|
SimpleGUI gui;
|
||||||
|
gui.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
69
.back/WidBack/examples/SimpleGUI.hpp
Normal file
69
.back/WidBack/examples/SimpleGUI.hpp
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include "Widgets.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class SimpleWidget : public CollapsableMenu {
|
||||||
|
public:
|
||||||
|
SimpleWidget() {
|
||||||
|
this->addWidgetToMenu(&mSlider);
|
||||||
|
|
||||||
|
this->addWidgetToMenu(&mInMenuButton1);
|
||||||
|
this->addWidgetToMenu(&mInMenuButton2);
|
||||||
|
|
||||||
|
this->addWidgetToMenu(&mLabel);
|
||||||
|
|
||||||
|
mInMenuButton1.mLabel.mLabel = "Button1";
|
||||||
|
|
||||||
|
mInMenuButton1.mCallback = []() {
|
||||||
|
printf("asd\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
mInMenuButton2.mLabel.mLabel = "Button2";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ButtonWidget mInMenuButton1;
|
||||||
|
ButtonWidget mInMenuButton2;
|
||||||
|
|
||||||
|
LabelWidget mLabel;
|
||||||
|
NamedSliderWidget mSlider;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SimpleWidget3 : public WorkspaceWidget {
|
||||||
|
public:
|
||||||
|
SimpleWidget3() {
|
||||||
|
|
||||||
|
mDockSpace.addSideWidget(&mButtons[0], DockWidget::BOTTOM);
|
||||||
|
mDockSpace.addSideWidget(&mButtons[1], DockWidget::RIGHT);
|
||||||
|
|
||||||
|
mDockSpace.removeSideWidget(DockWidget::BOTTOM);
|
||||||
|
|
||||||
|
mDockSpace.addSideWidget(&mButtons[0], DockWidget::TOP);
|
||||||
|
mDockSpace.addSideWidget(&mButtons[2], DockWidget::LEFT);
|
||||||
|
|
||||||
|
mDockSpace.removeSideWidget(DockWidget::TOP);
|
||||||
|
|
||||||
|
mDockSpace.addSideWidget(&mButtons[0], DockWidget::BOTTOM);
|
||||||
|
|
||||||
|
mDockSpace.addSideWidget(&mButtons[3], DockWidget::TOP);
|
||||||
|
mDockSpace.setCenterWidget(&mButtons[4]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
mButtons[4].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::BOTTOM); };
|
||||||
|
mButtons[0].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::TOP); };
|
||||||
|
mButtons[2].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::RIGHT); };
|
||||||
|
mButtons[3].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::LEFT); };
|
||||||
|
*/
|
||||||
|
|
||||||
|
mButtons[0].addWidgetToMenu(&mWidget);
|
||||||
|
mButtons[1].addWidgetToMenu(&mWidget2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FloatingWidget mButtons[5];
|
||||||
|
|
||||||
|
SimpleWidget mWidget;
|
||||||
|
SimpleWidget mWidget2;
|
||||||
|
SimpleWidget mWidget3;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,104 +1,103 @@
|
||||||
|
|
||||||
#include "Animations.hpp"
|
#include "Animations.hpp"
|
||||||
|
|
||||||
using namespace tp;
|
using namespace tp;
|
||||||
|
|
||||||
bool AnimValue::gInTransition = false;
|
bool AnimValue::gInTransition = false;
|
||||||
|
|
||||||
halnf AnimValue::interpolate() const {
|
halnf AnimValue::interpolate() const {
|
||||||
if (!mTimeAnim) {
|
if (!mTimeAnim) {
|
||||||
return mVal;
|
return mVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dt = gCurrentTime - mTimeStart;
|
auto dt = gCurrentTime - mTimeStart;
|
||||||
if (dt > mTimeAnim) dt = mTimeAnim;
|
if (dt > mTimeAnim) dt = mTimeAnim;
|
||||||
auto t = (halnf)dt / (halnf)mTimeAnim;
|
auto t = (halnf) dt / (halnf) mTimeAnim;
|
||||||
t = (halnf)(0.511 + atan((t - 0.36) * 28) / 2.9);
|
t = (halnf) (0.511 + atan((t - 0.36) * 28) / 2.9);
|
||||||
t = clamp(t, 0.f, 1.f);
|
t = clamp(t, 0.f, 1.f);
|
||||||
auto out = mValPrev + (mVal - mValPrev) * t;
|
auto out = mValPrev + (mVal - mValPrev) * t;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimValue::AnimValue() = default;
|
AnimValue::AnimValue() {
|
||||||
|
mTimeStart = gCurrentTime;
|
||||||
void AnimValue::setAnimTime(halni time) {
|
}
|
||||||
mTimeAnim = time;
|
|
||||||
}
|
void AnimValue::setAnimTime(halni time) { mTimeAnim = time; }
|
||||||
|
|
||||||
AnimValue::AnimValue(halnf val) {
|
AnimValue::AnimValue(halnf val) {
|
||||||
mVal = val;
|
mVal = val;
|
||||||
mValPrev = mVal;
|
mValPrev = mVal;
|
||||||
mTimeStart = gCurrentTime;
|
mTimeStart = gCurrentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnimValue::inTransition() const {
|
bool AnimValue::inTransition() const {
|
||||||
auto timePassed = gCurrentTime - mTimeStart >= mTimeAnim;
|
auto timePassed = gCurrentTime - mTimeStart >= mTimeAnim;
|
||||||
return !timePassed;
|
return !timePassed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimValue::set(halnf val) {
|
void AnimValue::set(halnf val) {
|
||||||
if (!inTransition()) mValPrev = mVal;
|
if (!inTransition()) mValPrev = mVal;
|
||||||
if (val == mVal) return;
|
if (val == mVal) return;
|
||||||
mValPrev = get();
|
mValPrev = get();
|
||||||
mVal = val;
|
mVal = val;
|
||||||
if (!inTransition()) mTimeStart = (halni)gCurrentTime;
|
if (!inTransition()) {
|
||||||
}
|
mTimeStart = gCurrentTime;
|
||||||
|
}
|
||||||
halnf AnimValue::getTarget() const {
|
}
|
||||||
return mVal;
|
|
||||||
}
|
halnf AnimValue::getTarget() const { return mVal; }
|
||||||
|
|
||||||
void AnimValue::setNoTransition(halnf val) {
|
void AnimValue::setNoTransition(halnf val) {
|
||||||
mValPrev = val;
|
mValPrev = val;
|
||||||
mVal = val;
|
mVal = val;
|
||||||
mTimeStart -= mTimeStart;
|
mTimeStart = gCurrentTime - mTimeAnim;
|
||||||
}
|
}
|
||||||
|
|
||||||
halnf AnimValue::get() const {
|
halnf AnimValue::get() const {
|
||||||
if (inTransition()) {
|
if (inTransition()) {
|
||||||
gInTransition = true;
|
gInTransition = true;
|
||||||
}
|
return interpolate();
|
||||||
return interpolate();
|
}
|
||||||
}
|
return mVal;
|
||||||
|
}
|
||||||
AnimValue::operator halnf() const {
|
|
||||||
return get();
|
void AnimValue::operator=(halnf val) {
|
||||||
}
|
setNoTransition(val);
|
||||||
|
}
|
||||||
RectF AnimRect::get() const {
|
|
||||||
return { x.get(), y.get() , z.get(), w.get() };
|
AnimValue::operator halnf() const { return get(); }
|
||||||
}
|
|
||||||
|
RectF AnimRect::get() const { return { x.get(), y.get(), z.get(), w.get() }; }
|
||||||
RectF AnimRect::getTarget() const {
|
|
||||||
return { x.getTarget(), y.getTarget() , z.getTarget(), w.getTarget() };
|
RectF AnimRect::getTarget() const { return { x.getTarget(), y.getTarget(), z.getTarget(), w.getTarget() }; }
|
||||||
}
|
|
||||||
|
void AnimRect::setNoTransition(RectF rec) {
|
||||||
void AnimRect::setNoTransition(RectF rec) {
|
x.setNoTransition(rec.x);
|
||||||
x.setNoTransition(rec.x);
|
y.setNoTransition(rec.y);
|
||||||
y.setNoTransition(rec.y);
|
z.setNoTransition(rec.z);
|
||||||
z.setNoTransition(rec.z);
|
w.setNoTransition(rec.w);
|
||||||
w.setNoTransition(rec.w);
|
}
|
||||||
}
|
|
||||||
|
void AnimRect::setAnimTime(const halni time) {
|
||||||
void AnimRect::setAnimTime(const halni time) {
|
x.setAnimTime(time);
|
||||||
x.setAnimTime(time);
|
y.setAnimTime(time);
|
||||||
y.setAnimTime(time);
|
z.setAnimTime(time);
|
||||||
z.setAnimTime(time);
|
w.setAnimTime(time);
|
||||||
w.setAnimTime(time);
|
}
|
||||||
}
|
|
||||||
|
void AnimRect::set(const RectF& in) {
|
||||||
void AnimRect::set(const RectF& in) {
|
x.set(in.x);
|
||||||
x.set(in.x);
|
y.set(in.y);
|
||||||
y.set(in.y);
|
z.set(in.z);
|
||||||
z.set(in.z);
|
w.set(in.w);
|
||||||
w.set(in.w);
|
}
|
||||||
}
|
|
||||||
|
AnimColor::AnimColor() : mColor() {}
|
||||||
RGBA AnimColor::get() const {
|
|
||||||
auto col = mColor.get();
|
RGBA AnimColor::get() const {
|
||||||
return {col.x, col.y, col.z, col.w};
|
auto col = mColor.get();
|
||||||
}
|
return { col.x, col.y, col.z, col.w };
|
||||||
|
}
|
||||||
void AnimColor::set(const RGBA& col) {
|
|
||||||
mColor.set(RectF(col.r, col.g, col.b, col.a));
|
void AnimColor::set(const RGBA& col) { mColor.set(RectF(col.r, col.g, col.b, col.a)); }
|
||||||
}
|
|
||||||
46
.back/WidBack/private/ButtonWidget.cpp
Normal file
46
.back/WidBack/private/ButtonWidget.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
#include "ButtonWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
ButtonWidget::ButtonWidget() {
|
||||||
|
this->setArea({ 0, 0, 100, 30 });
|
||||||
|
this->mChildWidgets.pushBack(&mLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonWidget::ButtonWidget(const std::string& label, const tp::RectF& aArea) {
|
||||||
|
this->setArea(aArea);
|
||||||
|
mLabel.mLabel = label;
|
||||||
|
this->mChildWidgets.pushBack(&mLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ButtonWidget::isFired() { return this->isReleased(); }
|
||||||
|
|
||||||
|
void ButtonWidget::eventProcess(const Events&) {
|
||||||
|
mLabel.setArea(this->mArea);
|
||||||
|
|
||||||
|
if (isFired()) {
|
||||||
|
mCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ButtonWidget::eventDraw(Canvas& canvas) {
|
||||||
|
if (this->isHolding()) {
|
||||||
|
canvas.rect(this->mArea, pressedColor, rounding);
|
||||||
|
} else if (this->isFocus()) {
|
||||||
|
canvas.rect(this->mArea, hoveredColor, rounding);
|
||||||
|
} else {
|
||||||
|
canvas.rect(this->mArea, accentColor, rounding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ButtonWidget::setLabel(const std::string& string) { mLabel.mLabel = string; }
|
||||||
|
|
||||||
|
void ButtonWidget::eventUpdateConfiguration(WidgetManager& wm) {
|
||||||
|
wm.setActiveId("Button");
|
||||||
|
|
||||||
|
pressedColor = wm.getColor("Pressed", "Action");
|
||||||
|
hoveredColor = wm.getColor("Hovered", "Interaction");
|
||||||
|
accentColor = wm.getColor("Default", "Accent");
|
||||||
|
rounding = wm.getNumber("Rounding", "Rounding");
|
||||||
|
}
|
||||||
96
.back/WidBack/private/CollapsableMenu.cpp
Normal file
96
.back/WidBack/private/CollapsableMenu.cpp
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
|
||||||
|
#include "CollapsableMenu.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
CollapsableMenu::CollapsableMenu() {
|
||||||
|
this->mChildWidgets.pushBack(&mHeader);
|
||||||
|
this->mChildWidgets.pushBack(&mBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollapsableMenu::eventProcess(const Events&) {
|
||||||
|
if (mHeader.isReleased()) {
|
||||||
|
toggleCollapsed();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollapsableMenu::eventDraw(Canvas& canvas) {
|
||||||
|
if (mBorders) {
|
||||||
|
canvas.rect(this->mArea, mBorderColor, rounding);
|
||||||
|
canvas.rect(this->mArea.shrink(mBorderSize), mMenuColor, rounding);
|
||||||
|
} else {
|
||||||
|
canvas.rect(this->mArea, mMenuColor, rounding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollapsableMenu::addWidgetToMenu(Widget* widget) {
|
||||||
|
mBody.addWidget(widget);
|
||||||
|
|
||||||
|
EventHandler ev;
|
||||||
|
mBody.procWrapper(ev, this->mArea);
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollapsableMenu::setLabel(const std::string& string) { mHeader.mLabel = string; }
|
||||||
|
|
||||||
|
void CollapsableMenu::toggleCollapsed() { setCollapsed(!getCollapsed()); }
|
||||||
|
|
||||||
|
void CollapsableMenu::setCollapsed(bool collapsed) {
|
||||||
|
if (mLocked) return;
|
||||||
|
if (collapsed && !mCollapsed) mPrevHeight = this->mArea.size.y;
|
||||||
|
if (!collapsed && mCollapsed) this->mArea.size.y = mPrevHeight;
|
||||||
|
mCollapsed = collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CollapsableMenu::getCollapsed() const { return mCollapsed; }
|
||||||
|
|
||||||
|
void CollapsableMenu::updateGeometry() {
|
||||||
|
mHeader.setArea(getHeaderRect());
|
||||||
|
|
||||||
|
mBody.mEnable = !mCollapsed;
|
||||||
|
|
||||||
|
if (mCollapsed) {
|
||||||
|
this->mArea.size.y = headerHeight;
|
||||||
|
} else {
|
||||||
|
if (mAdjustHeight) {
|
||||||
|
this->mArea.size.y = headerHeight + getBodyRect().size.y + mPadding * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
mBody.setArea(getBodyRect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF CollapsableMenu::getHeaderRect() {
|
||||||
|
RectF out = { this->mArea.pos, { this->mArea.size.x, headerHeight } };
|
||||||
|
if (mBorders) out = out.shrink(mPadding);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF CollapsableMenu::getBodyRect() {
|
||||||
|
RectF out = { Vec2F{ this->mArea.pos.x, this->mArea.pos.y + headerHeight },
|
||||||
|
Vec2F{ this->mArea.size.x, this->mArea.size.y - headerHeight - mPadding } };
|
||||||
|
|
||||||
|
out.size.y -= mBorderSize * 2;
|
||||||
|
|
||||||
|
if (mAdjustHeight) out.size.y = mBody.getContentSize();
|
||||||
|
|
||||||
|
if (mBody.getContentSize() && mBorders) {
|
||||||
|
out = out.shrink(mPadding);
|
||||||
|
out.size.y += mPadding * 2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollapsableMenu::eventUpdateConfiguration(WidgetManager& wm) {
|
||||||
|
wm.setActiveId("CollapsableMenu");
|
||||||
|
|
||||||
|
headerHeight = wm.getNumber("HeaderHeight", 35);
|
||||||
|
mMenuColor = wm.getColor("MenuColor", RGBA(0, 0, 0, 1.f));
|
||||||
|
rounding = wm.getNumber("Rounding", "Rounding");
|
||||||
|
mBorderColor = wm.getColor("BorderColor", RGBA(0.16, 0.16, 0.16, 1.f));
|
||||||
|
mBorderSize = wm.getNumber("BorderSize", 2.f);
|
||||||
|
mPadding = wm.getNumber("Padding", "Padding");
|
||||||
|
}
|
||||||
47
.back/WidBack/private/FloatSpaceWidget.cpp
Normal file
47
.back/WidBack/private/FloatSpaceWidget.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "FloatingLayoutWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
FloatingLayoutWidget::FloatingLayoutWidget() = default;
|
||||||
|
|
||||||
|
void FloatingLayoutWidget::eventProcess(const tp::Events& events) {
|
||||||
|
updateActiveWindow(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingLayoutWidget::updateActiveWindow(const tp::Events& events) {
|
||||||
|
mIsPassThrough = true;
|
||||||
|
for (auto childNode = this->mChildWidgets.firstNode(); childNode; childNode = childNode->next) {
|
||||||
|
auto child = childNode->data;
|
||||||
|
if (child->mArea.isInside(events.getPointer())) {
|
||||||
|
mIsPassThrough = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events.isPressed(InputID::MOUSE1)) {
|
||||||
|
|
||||||
|
Widget* activeChild = nullptr;
|
||||||
|
|
||||||
|
for (auto childNode = this->mChildWidgets.firstNode(); childNode; childNode = childNode->next) {
|
||||||
|
auto child = childNode->data;
|
||||||
|
|
||||||
|
if (child->mArea.isInside(events.getPointer())) {
|
||||||
|
|
||||||
|
mChildWidgets.detach(childNode);
|
||||||
|
mChildWidgets.pushFront(childNode);
|
||||||
|
|
||||||
|
child->mHandlesEvents = true;
|
||||||
|
activeChild = child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeChild) {
|
||||||
|
for (auto child : this->mChildWidgets) {
|
||||||
|
if (activeChild != child.data() && !child->mIsDocked) child->mHandlesEvents = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloatingLayoutWidget::handlesEvent() const { return !mIsPassThrough; }
|
||||||
89
.back/WidBack/private/FloatingWidget.cpp
Normal file
89
.back/WidBack/private/FloatingWidget.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
#include "FloatingWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
FloatingWidget::FloatingWidget() {
|
||||||
|
this->mArea = { 0, 0, 300, 300 };
|
||||||
|
this->mAdjustHeight = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingWidget::eventProcess(const Events& events) {
|
||||||
|
mActionStartRelativePos = events.getPointerPrev() - this->mArea.pos;
|
||||||
|
|
||||||
|
checkFloating(events);
|
||||||
|
if (mResizable) checkResizing(events);
|
||||||
|
|
||||||
|
CollapsableMenu::eventProcess(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingWidget::eventDraw(Canvas& canvas) {
|
||||||
|
CollapsableMenu::eventDraw(canvas);
|
||||||
|
|
||||||
|
if (!this->getCollapsed() && mResizable) {
|
||||||
|
auto rect = getResizeHandle();
|
||||||
|
canvas.rect(rect, mResizeHandleColor, 0);
|
||||||
|
canvas.circle(rect.pos - this->mBorderSize, rect.w, this->mMenuColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingWidget::eventUpdateConfiguration(WidgetManager& wm) {
|
||||||
|
CollapsableMenu::eventUpdateConfiguration(wm);
|
||||||
|
|
||||||
|
wm.setActiveId("FloatingWidget");
|
||||||
|
|
||||||
|
mResizeHandleSize = wm.getNumber("ResizeHandleSize", 15);
|
||||||
|
mResizeHandleColor = wm.getColor("ResizeHandleColor", RGBA(0.16, 0.16, 0.16, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingWidget::checkFloating(const Events& events) {
|
||||||
|
mDropped = false;
|
||||||
|
|
||||||
|
if (this->mHeader.isHolding() && events.getPointerDelta().length2() > 4) {
|
||||||
|
mFloating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFloating && this->mHeader.isReleased()) {
|
||||||
|
mFloating = false;
|
||||||
|
this->mHeader.clearEvents();
|
||||||
|
mDropped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFloating) {
|
||||||
|
auto relativePos = events.getPointer() - this->mArea.pos;
|
||||||
|
this->mArea.pos += relativePos - mActionStartRelativePos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingWidget::checkResizing(const Events& events) {
|
||||||
|
if (this->getCollapsed()) return;
|
||||||
|
|
||||||
|
if (events.isPressed(InputID::MOUSE1) && getResizeHandle().isInside(events.getPointer())) {
|
||||||
|
mResizing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events.isReleased(InputID::MOUSE1)) {
|
||||||
|
mResizing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mResizing) {
|
||||||
|
auto relativePos = events.getPointer() - this->mArea.pos;
|
||||||
|
this->mArea.size += relativePos - mActionStartRelativePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->mCollapsed) {
|
||||||
|
this->mArea.size.clamp(mMinSize, { FLT_MAX, FLT_MAX });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF FloatingWidget::getResizeHandle() {
|
||||||
|
auto size = Vec2F(mResizeHandleSize);
|
||||||
|
auto pos = this->mArea.pos + this->mArea.size - size;
|
||||||
|
return { pos, size };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloatingWidget::isFloating() const { return mFloating; }
|
||||||
|
|
||||||
|
void FloatingWidget::stopFloating() {
|
||||||
|
mFloating = false;
|
||||||
|
}
|
||||||
328
.back/WidBack/private/GridLayoutWidget.cpp
Normal file
328
.back/WidBack/private/GridLayoutWidget.cpp
Normal file
|
|
@ -0,0 +1,328 @@
|
||||||
|
#include "GridLayoutWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
DockWidget::DockWidget() {
|
||||||
|
mSideWidgets[0].side = LEFT;
|
||||||
|
mSideWidgets[1].side = TOP;
|
||||||
|
mSideWidgets[2].side = RIGHT;
|
||||||
|
mSideWidgets[3].side = BOTTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::addSideWidget(Widget* widget, Side side) {
|
||||||
|
if (sideExists(side)) return;
|
||||||
|
|
||||||
|
auto& sideWidget = mSideWidgets[side];
|
||||||
|
sideWidget.widget = widget;
|
||||||
|
for (auto& order : mSideWidgets) {
|
||||||
|
if (order.order == -1) {
|
||||||
|
order.order = side;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sideWidget.hidden = false;
|
||||||
|
|
||||||
|
mChildWidgets.pushBack(widget);
|
||||||
|
widget->mIsDocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::removeSideWidget(Side side) {
|
||||||
|
if (!sideExists(side)) return;
|
||||||
|
|
||||||
|
bool removed = false;
|
||||||
|
for (ualni i = 0; i < 3; i++) {
|
||||||
|
if (mSideWidgets[i].order == side) {
|
||||||
|
removed = true;
|
||||||
|
}
|
||||||
|
if (removed) {
|
||||||
|
swapV(mSideWidgets[i].order, mSideWidgets[i + 1].order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mSideWidgets[3].order = -1;
|
||||||
|
|
||||||
|
auto widget = mSideWidgets[side].widget;
|
||||||
|
widget->mIsDocked = false;
|
||||||
|
mChildWidgets.removeNode(mChildWidgets.find(widget));
|
||||||
|
|
||||||
|
mSideWidgets[side].widget = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::setCenterWidget(Widget* widget) {
|
||||||
|
mChildWidgets.removeNode(mChildWidgets.find(mCenterWidget));
|
||||||
|
mCenterWidget = widget;
|
||||||
|
mChildWidgets.pushBack(mCenterWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::toggleHiddenState(DockWidget::Side side) {
|
||||||
|
if (!sideExists(side)) return;
|
||||||
|
mSideWidgets[side].hidden = !mSideWidgets[side].hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::eventProcess(const tp::Events& events) {
|
||||||
|
calculateSideAreas();
|
||||||
|
calculateResizeHandles();
|
||||||
|
// calculateHeaderAreas();
|
||||||
|
|
||||||
|
handlePreview(events);
|
||||||
|
handleResizeEvents(events);
|
||||||
|
|
||||||
|
updateChildSideWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::eventDraw(Canvas& canvas) {
|
||||||
|
canvas.rect(this->mArea, mBackgroundColor, 0);
|
||||||
|
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
if (!isSideVisible(sideWidget.side)) continue;
|
||||||
|
auto& handle = sideWidget.resizeHandle;
|
||||||
|
if (handle.active) {
|
||||||
|
canvas.rect(handle.area.shrink(mPadding / 1.5f), mResizeHandleColorActive, 0);
|
||||||
|
} else if (handle.hover) {
|
||||||
|
canvas.rect(handle.area.shrink(mPadding / 1.5f), mResizeHandleColorHovered, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
if (!isSideVisible(sideWidget.side)) continue;
|
||||||
|
canvas.rect(sideWidget.headerArea, mResizeHandleColorActive, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::eventDrawOver(Canvas& canvas) {
|
||||||
|
if (!mPreview) return;
|
||||||
|
|
||||||
|
if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding);
|
||||||
|
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
if (sideWidget.widget) continue;
|
||||||
|
canvas.rect(sideWidget.previewHandleArea, mPreviewColor, mRounding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::calculateSideAreas() {
|
||||||
|
auto startArea = this->mArea;
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
const auto side = sideWidget.order;
|
||||||
|
|
||||||
|
if (side == -1) break;
|
||||||
|
if (!isSideVisible(Side(side))) continue;
|
||||||
|
|
||||||
|
bool vertical = side == TOP || side == BOTTOM;
|
||||||
|
bool opposite = side == BOTTOM || side == RIGHT;
|
||||||
|
|
||||||
|
auto& sideSize = mSideWidgets[side].absoluteSize;
|
||||||
|
|
||||||
|
auto factor = sideSize / startArea.size[vertical];
|
||||||
|
if (opposite) factor = factor * -1 + 1;
|
||||||
|
auto& area = mSideWidgets[side].area;
|
||||||
|
|
||||||
|
if (!vertical) {
|
||||||
|
const auto first = startArea.splitByFactorHL(factor);
|
||||||
|
const auto second = startArea.splitByFactorHR(factor);
|
||||||
|
area = side == LEFT ? first : second;
|
||||||
|
startArea = side == LEFT ? second : first;
|
||||||
|
} else {
|
||||||
|
const auto first = startArea.splitByFactorVT(factor);
|
||||||
|
const auto second = startArea.splitByFactorVB(factor);
|
||||||
|
area = side == TOP ? first : second;
|
||||||
|
startArea = side == TOP ? second : first;
|
||||||
|
}
|
||||||
|
|
||||||
|
area = area.shrink(mPadding);
|
||||||
|
}
|
||||||
|
|
||||||
|
mCenterArea = startArea.shrink(mPadding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::calculateResizeHandles() {
|
||||||
|
RectF rec;
|
||||||
|
|
||||||
|
if (isSideVisible(LEFT)) {
|
||||||
|
auto& side = mSideWidgets[LEFT];
|
||||||
|
rec = { side.area.p4(), { mPadding * 2, side.area.size.y } };
|
||||||
|
side.resizeHandle = { rec, 0, mCenterArea.p3().x };
|
||||||
|
}
|
||||||
|
if (isSideVisible(RIGHT)) {
|
||||||
|
auto& side = mSideWidgets[RIGHT];
|
||||||
|
rec = { side.area.p1(), { mPadding * 2, side.area.size.y } };
|
||||||
|
rec.x -= mPadding * 2;
|
||||||
|
side.resizeHandle = { rec, 0, (this->mArea.p3() - mCenterArea.p1()).x };
|
||||||
|
}
|
||||||
|
if (isSideVisible(TOP)) {
|
||||||
|
auto& side = mSideWidgets[TOP];
|
||||||
|
rec = { side.area.p2(), { side.area.size.x, mPadding * 2 } };
|
||||||
|
side.resizeHandle = { rec, 0, mCenterArea.p2().y };
|
||||||
|
}
|
||||||
|
if (isSideVisible(BOTTOM)) {
|
||||||
|
auto& side = mSideWidgets[BOTTOM];
|
||||||
|
rec = { side.area.p1(), { side.area.size.x, mPadding * 2 } };
|
||||||
|
rec.y -= mPadding * 2;
|
||||||
|
side.resizeHandle = { rec, 0, (this->mArea.p3() - mCenterArea.p1()).y };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::handleResizeEvents(const Events& events) {
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
auto& sideSize = sideWidget.absoluteSize;
|
||||||
|
auto& resizeHandle = sideWidget.resizeHandle;
|
||||||
|
if (resizeHandle.end < mSideSizePadding * 2) {
|
||||||
|
sideSize = resizeHandle.end / 2.f;
|
||||||
|
} else {
|
||||||
|
sideSize = clamp(sideSize, resizeHandle.start + mSideSizePadding, resizeHandle.end - mSideSizePadding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
sideWidget.resizeHandle.hover = false;
|
||||||
|
if (sideWidget.resizeHandle.area.isInside(events.getPointerPrev())) {
|
||||||
|
sideWidget.resizeHandle.hover = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
sideWidget.resizeHandle.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPreview) return;
|
||||||
|
|
||||||
|
auto resizeSideWidget = [&events](SideWidgetData& sideWidget, Vec2F deltaVec) {
|
||||||
|
halnf delta = deltaVec[(sideWidget.side == TOP || sideWidget.side == BOTTOM)];
|
||||||
|
if (sideWidget.side == BOTTOM || sideWidget.side == RIGHT) delta *= -1;
|
||||||
|
sideWidget.absoluteSize += delta;
|
||||||
|
sideWidget.resizeHandle.active = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (events.isDown(InputID::MOUSE1)) {
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
if (sideWidget.resizeHandle.area.isInside(events.getPointerPrev())) {
|
||||||
|
resizeSideWidget(sideWidget, events.getPointerDelta());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events.isDown(InputID::LEFT_ALT)) {
|
||||||
|
const auto pointer = events.getPointerPrev();
|
||||||
|
if (!mCenterArea.isInside(pointer)) return;
|
||||||
|
|
||||||
|
if (events.isPressed(InputID::MOUSE1)) {
|
||||||
|
for (auto i : { 0, 1 }) {
|
||||||
|
const auto step = mCenterArea.size[i] / 3.f;
|
||||||
|
const auto rec1 = mCenterArea.pos[i];
|
||||||
|
const auto pos = pointer[i];
|
||||||
|
if (pos > rec1 && pos < rec1 + step) resizeType[i] = 0;
|
||||||
|
if (pos > rec1 + step && pos < rec1 + step * 2) resizeType[i] = 1;
|
||||||
|
if (pos > rec1 + step * 2) resizeType[i] = 2;
|
||||||
|
}
|
||||||
|
} else if (events.isDown(InputID::MOUSE1)) {
|
||||||
|
const auto deltaVec = events.getPointerDelta();
|
||||||
|
|
||||||
|
if (resizeType[0] == 0) resizeSideWidget(mSideWidgets[LEFT], deltaVec);
|
||||||
|
if (resizeType[1] == 0) resizeSideWidget(mSideWidgets[TOP], deltaVec);
|
||||||
|
if (resizeType[0] == 2) resizeSideWidget(mSideWidgets[RIGHT], deltaVec);
|
||||||
|
if (resizeType[1] == 2) resizeSideWidget(mSideWidgets[BOTTOM], deltaVec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::updateChildSideWidgets() {
|
||||||
|
// Update Child Widgets
|
||||||
|
{
|
||||||
|
for (ualni i = 0; i < 4; i++) {
|
||||||
|
if (!sideExists(Side(i))) continue;
|
||||||
|
auto widget = mSideWidgets[i].widget;
|
||||||
|
|
||||||
|
if (!isSideVisible(Side(i))) {
|
||||||
|
widget->mEnable = false;
|
||||||
|
} else {
|
||||||
|
widget->setArea(mSideWidgets[i].area);
|
||||||
|
widget->mEnable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCenterWidget) mCenterWidget->setArea(mCenterArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update depth order
|
||||||
|
/*
|
||||||
|
if (mChildWidgets.size() > 1) {
|
||||||
|
for (auto sideChild : mSideWidgets) {
|
||||||
|
if (!sideChild) continue;
|
||||||
|
|
||||||
|
for (auto childNode = mChildWidgets.firstNode(); childNode; childNode = childNode->next) {
|
||||||
|
if (childNode->data == sideChild) {
|
||||||
|
mChildWidgets.detach(childNode);
|
||||||
|
mChildWidgets.pushBack(childNode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockWidget::calculateHeaderAreas() {
|
||||||
|
for (ualni i = 0; i < 4; i++) {
|
||||||
|
if (!isSideVisible(Side(i))) continue;
|
||||||
|
auto& area = mSideWidgets[i].area;
|
||||||
|
const auto factor = mHeaderSize / area.size.y;
|
||||||
|
mSideWidgets[i].headerArea = area.splitByFactorVT(factor);
|
||||||
|
area = area.splitByFactorVB(factor);
|
||||||
|
|
||||||
|
mSideWidgets[i].headerArea.size.y -= mPadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DockWidget::isSideVisible(DockWidget::Side side) {
|
||||||
|
return sideExists(side) && !mSideWidgets[side].hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DockWidget::sideExists(DockWidget::Side side) { return mSideWidgets[side].widget; }
|
||||||
|
|
||||||
|
ualni DockWidget::getVisibleSidesSize() {
|
||||||
|
ualni out = 0;
|
||||||
|
for (ualni i = 0; i < 4; i++) {
|
||||||
|
if (isSideVisible(Side(i))) out++;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
DockWidget::Side DockWidget::getPreviewSide() { return mPreviewSide; }
|
||||||
|
|
||||||
|
void DockWidget::handlePreview(const Events& events) {
|
||||||
|
if (!mPreview) {
|
||||||
|
mPreviewSide = NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const halnf factor = 0.3;
|
||||||
|
const halnf handleFactor = 0.1;
|
||||||
|
|
||||||
|
const auto handleSize = min(mCenterArea.size.x, mCenterArea.size.y) * handleFactor;
|
||||||
|
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
if (sideWidget.widget) continue;
|
||||||
|
|
||||||
|
switch (sideWidget.side) {
|
||||||
|
case TOP: sideWidget.area = mCenterArea.splitByFactorVT(factor); break;
|
||||||
|
case BOTTOM: sideWidget.area = mCenterArea.splitByFactorVB(1 - factor); break;
|
||||||
|
case LEFT: sideWidget.area = mCenterArea.splitByFactorHL(factor); break;
|
||||||
|
case RIGHT: sideWidget.area = mCenterArea.splitByFactorHR(1 - factor); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sideWidget.area = sideWidget.area.shrink(mPadding * 2);
|
||||||
|
sideWidget.previewHandleArea = sideWidget.area.getSizedFromCenter({ handleSize, handleSize });
|
||||||
|
}
|
||||||
|
|
||||||
|
mPreviewArea = {};
|
||||||
|
mPreviewSide = NONE;
|
||||||
|
for (auto& sideWidget : mSideWidgets) {
|
||||||
|
if (sideWidget.widget) continue;
|
||||||
|
|
||||||
|
if (sideWidget.previewHandleArea.isInside(events.getPointer())) {
|
||||||
|
mPreviewArea = sideWidget.area;
|
||||||
|
mPreviewSide = sideWidget.side;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
.back/WidBack/private/LabelWidget.cpp
Normal file
17
.back/WidBack/private/LabelWidget.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include "LabelWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
LabelWidget::LabelWidget() { this->mArea = { 0, 0, 100, 30 }; }
|
||||||
|
|
||||||
|
void LabelWidget::eventDraw(Canvas& canvas) {
|
||||||
|
canvas.text(mLabel.c_str(), this->mArea, fontSize, Canvas::LC, padding, fontColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabelWidget::eventUpdateConfiguration(WidgetManager& wm) {
|
||||||
|
wm.setActiveId("Label");
|
||||||
|
|
||||||
|
fontSize = wm.getNumber("Size", "FontSize");
|
||||||
|
padding = wm.getNumber("Padding", "Padding");
|
||||||
|
fontColor = wm.getColor("Default", "Front");
|
||||||
|
}
|
||||||
179
.back/WidBack/private/ScrollableWidget.cpp
Normal file
179
.back/WidBack/private/ScrollableWidget.cpp
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
#include "ScrollableWidget.hpp"
|
||||||
|
#include "../../WidgetsNew/public/widgets/ScrollableWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
ScrollBarWidget::ScrollBarWidget() = default;
|
||||||
|
|
||||||
|
void ScrollBarWidget::eventProcess(const Events& events) {
|
||||||
|
auto area = getHandle();
|
||||||
|
mHovered = getHandleHandle().isInside(events.getPointer());
|
||||||
|
|
||||||
|
if (mSizeFraction > 1.f) {
|
||||||
|
mPositionFraction = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events.getScrollY() != 0 && mArea.isInside(events.getPointer())) {
|
||||||
|
auto offset = events.getScrollY() < 0 ? 1.0f : -1.0f;
|
||||||
|
mPositionFraction += mSizeFraction * offset * 0.3f;
|
||||||
|
mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events.isPressed(InputID::MOUSE1) && area.isInside(events.getPointer())) {
|
||||||
|
mIsScrolling = true;
|
||||||
|
} else if (events.isReleased(InputID::MOUSE1)) {
|
||||||
|
mIsScrolling = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mIsScrolling) {
|
||||||
|
tp::halnf pos = events.getPointer().y;
|
||||||
|
pos = (pos - area.y - mSizeFraction * area.w / 2.f) / area.w;
|
||||||
|
mPositionFraction = tp::clamp(pos, 0.f, 1.f - mSizeFraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollBarWidget::eventDraw(Canvas& canvas) {
|
||||||
|
auto area = getHandle();
|
||||||
|
|
||||||
|
if (mSizeFraction > 1.f) return;
|
||||||
|
// if (!areaParent.isOverlap(getHandle())) return;
|
||||||
|
|
||||||
|
tp::RGBA col = mHandleColor;
|
||||||
|
|
||||||
|
if (mIsScrolling) {
|
||||||
|
col = mScrollingColor;
|
||||||
|
} else if (mHovered) {
|
||||||
|
col = mHoveredColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.rect(area, mDefaultColor, mRounding);
|
||||||
|
canvas.rect(getHandleHandle(), col, mRounding);
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF ScrollBarWidget::getHandleHandle() const {
|
||||||
|
auto area = getHandle();
|
||||||
|
auto sliderSize = tp::clamp(area.w * mSizeFraction, mMinSize * 2, area.w);
|
||||||
|
auto diffSize = sliderSize - area.w * mSizeFraction;
|
||||||
|
return { area.x, area.y + (area.w - diffSize) * mPositionFraction, area.z, sliderSize };
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF ScrollBarWidget::getViewport() const {
|
||||||
|
if (mSizeFraction > 1.f) {
|
||||||
|
return this->mArea;
|
||||||
|
}
|
||||||
|
return { this->mArea.x, this->mArea.y, this->mArea.z - mHandleSize, this->mArea.w };
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF ScrollBarWidget::getHandle() const {
|
||||||
|
return { this->mArea.x + this->mArea.z - mHandleSize + mPadding,
|
||||||
|
this->mArea.y + mPadding,
|
||||||
|
mHandleSize - mPadding * 2,
|
||||||
|
this->mArea.w - mPadding * 2 };
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollBarWidget::eventUpdateConfiguration(WidgetManager& wm) {
|
||||||
|
wm.setActiveId("Scrollbar");
|
||||||
|
|
||||||
|
mDefaultColor = wm.getColor("Default", "Base");
|
||||||
|
mHandleColor = wm.getColor("Handle", "Accent");
|
||||||
|
mHoveredColor = wm.getColor("Hovered", "Interaction");
|
||||||
|
mScrollingColor = wm.getColor("Scrolling", "Action");
|
||||||
|
mPadding = wm.getNumber("Padding", "Padding");
|
||||||
|
mHandleSize = wm.getNumber("HandleSize", 20.f);
|
||||||
|
mMinSize = wm.getNumber("MinSize", 20.f);
|
||||||
|
mRounding = wm.getNumber("Rounding", "Rounding");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollableWindow::ScrollableWindow() {
|
||||||
|
this->mChildWidgets.pushBack(&mScroller);
|
||||||
|
this->mChildWidgets.pushBack(&mContentWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollableWindow::~ScrollableWindow() = default;
|
||||||
|
|
||||||
|
void ScrollableWindow::eventProcess(const Events& events) {
|
||||||
|
List<Widget*>& content = mContentWidget.mChildWidgets;
|
||||||
|
|
||||||
|
// to account all changed geometry of child widgets
|
||||||
|
for (auto widget : content) {
|
||||||
|
widget->procWrapper(events, mContentWidget.mVisibleArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateContents(content);
|
||||||
|
updateContentSize(content);
|
||||||
|
|
||||||
|
const auto padding = mPadding;
|
||||||
|
|
||||||
|
mScroller.mSizeFraction = mContentWidget.mArea.w / mContentSize;
|
||||||
|
mScroller.setArea(this->mArea);
|
||||||
|
mContentWidget.setArea(mScroller.getViewport());
|
||||||
|
|
||||||
|
if (mScroller.mSizeFraction > 1.f) {
|
||||||
|
setOffset(content, 0);
|
||||||
|
} else {
|
||||||
|
setOffset(content, (-mScroller.mPositionFraction) * mContentSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto widget : content) {
|
||||||
|
widget->setArea({ mContentWidget.mArea.x + padding,
|
||||||
|
mContentWidget.mArea.y + widget->mArea.y,
|
||||||
|
mScroller.getViewport().z - padding * 2,
|
||||||
|
widget->mArea.w });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollableWindow::addWidget(Widget* widget) {
|
||||||
|
mContentWidget.mChildWidgets.pushBack(widget);
|
||||||
|
|
||||||
|
List<Widget*>& content = mContentWidget.mChildWidgets;
|
||||||
|
updateContents(content);
|
||||||
|
updateContentSize(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollableWindow::clearContent() { mContentWidget.mChildWidgets.removeAll(); }
|
||||||
|
List<Widget*>& ScrollableWindow::getContent() { return mContentWidget.mChildWidgets; }
|
||||||
|
|
||||||
|
void ScrollableWindow::eventUpdateConfiguration(WidgetManager& wm) {
|
||||||
|
wm.setActiveId("ScrollableWidget");
|
||||||
|
mPadding = wm.getNumber("Padding", "Padding");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] halnf ScrollableWindow::getContentSize() const { return mContentSize; }
|
||||||
|
|
||||||
|
void ScrollableWindow::updateContents(List<Widget*>& contentWidgets) {
|
||||||
|
if (!contentWidgets.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const halnf offset = contentWidgets.first()->mArea.y + mPadding;
|
||||||
|
|
||||||
|
halnf start = 0;
|
||||||
|
for (auto widget : contentWidgets) {
|
||||||
|
widget->mArea.y = start;
|
||||||
|
start += widget->mArea.w + mPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto widget : contentWidgets) {
|
||||||
|
widget->mArea.y += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollableWindow::updateContentSize(List<Widget*>& contentWidgets) {
|
||||||
|
mContentSize = 0;
|
||||||
|
if (contentWidgets.size()) {
|
||||||
|
mContentSize = contentWidgets.last()->mArea.y - contentWidgets.first()->mArea.y;
|
||||||
|
mContentSize += contentWidgets.last()->mArea.w;
|
||||||
|
mContentSize += 2 * mPadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollableWindow::setOffset(List<Widget*>& contentWidgets, const halnf offset) {
|
||||||
|
if (!contentWidgets.size()) return;
|
||||||
|
auto newOffset = offset - contentWidgets.first()->mArea.y + mPadding;
|
||||||
|
for (auto widget : contentWidgets) {
|
||||||
|
widget->mArea.y += newOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
62
.back/WidBack/private/SliderWidget.cpp
Normal file
62
.back/WidBack/private/SliderWidget.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include "SliderWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
SliderWidget::SliderWidget() = default;
|
||||||
|
|
||||||
|
void SliderWidget::eventProcess(const Events& events) {
|
||||||
|
if (this->isPressed()) {
|
||||||
|
mIsSliding = true;
|
||||||
|
} else if (events.isReleased(InputID::MOUSE1)) {
|
||||||
|
mIsSliding = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mIsSliding) {
|
||||||
|
mFactor = (events.getPointer().x - this->mArea.x - handleSize / 2.f) / (this->mArea.z - handleSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
mFactor = tp::clamp(mFactor, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SliderWidget::eventDraw(Canvas& canvas) {
|
||||||
|
canvas.rect(this->mArea, handleColor, rounding);
|
||||||
|
canvas.rect(this->mArea.shrink(borderSize), defaultColor, rounding);
|
||||||
|
canvas.rect(getHandle(), handleColor, rounding);
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF SliderWidget::getHandle() const {
|
||||||
|
const auto left = this->mArea.x + (this->mArea.z - handleSize) * mFactor;
|
||||||
|
return { left, this->mArea.y, handleSize, this->mArea.w };
|
||||||
|
}
|
||||||
|
|
||||||
|
void SliderWidget::eventUpdateConfiguration(WidgetManager& wm) {
|
||||||
|
wm.setActiveId("Slider");
|
||||||
|
defaultColor = wm.getColor("Default", "Base");
|
||||||
|
handleColor = wm.getColor("Handle", RGBA(0.3f, 0.3f, 0.3f, 1.f));
|
||||||
|
borderSize = wm.getNumber("BorderSize", 2);
|
||||||
|
handleSize = wm.getNumber("HandleSize", 15.f);
|
||||||
|
rounding = wm.getNumber("Rounding", "Rounding");
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedSliderWidget::NamedSliderWidget(const char* name) {
|
||||||
|
mLabel.mLabel = name;
|
||||||
|
this->mArea = { 0, 0, 100, 30 };
|
||||||
|
|
||||||
|
this->mChildWidgets.pushBack(&mSlider);
|
||||||
|
this->mChildWidgets.pushBack(&mLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NamedSliderWidget::eventProcess(const Events& events) {
|
||||||
|
const auto widthFirst = this->mArea.z * mFactor;
|
||||||
|
const auto widthSecond = this->mArea.z * (1.f - mFactor);
|
||||||
|
|
||||||
|
RectF rec = this->mArea;
|
||||||
|
rec.size.x = widthFirst;
|
||||||
|
|
||||||
|
mLabel.setArea(rec);
|
||||||
|
|
||||||
|
rec.pos.x += widthFirst;
|
||||||
|
rec.size.x = widthSecond;
|
||||||
|
|
||||||
|
mSlider.setArea(rec);
|
||||||
|
}
|
||||||
57
.back/WidBack/private/TextInputWidget.cpp
Normal file
57
.back/WidBack/private/TextInputWidget.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include "TextInputWidget.hpp"
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
TextInputWidget::TextInputWidget() = default;
|
||||||
|
|
||||||
|
void TextInputWidget::eventDraw(Canvas&) {
|
||||||
|
nChanged = false;
|
||||||
|
|
||||||
|
const auto col = mAccentColor;
|
||||||
|
const auto colSel = mHoveredColor;
|
||||||
|
|
||||||
|
ImGui::GetStyle().Colors[ImGuiCol_FrameBg] = { col.r, col.g, col.b, col.a };
|
||||||
|
ImGui::GetStyle().Colors[ImGuiCol_TextSelectedBg] = { colSel.r, colSel.g, colSel.b, colSel.a };
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos({ this->mArea.x, this->mArea.y });
|
||||||
|
ImGui::SetNextWindowSize({ this->mArea.z, this->mArea.w });
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0, 0 });
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, mRounding * 1.5f);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { mPadding, mPadding });
|
||||||
|
|
||||||
|
// ImGui::PushID((int) alni(this));
|
||||||
|
ImGui::Begin(
|
||||||
|
mId.c_str(),
|
||||||
|
0,
|
||||||
|
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground |
|
||||||
|
ImGuiWindowFlags_NoResize
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mMultiline) {
|
||||||
|
if (ImGui::InputTextMultiline("input", mBuff, mMaxBufferSize, { this->mArea.z, this->mArea.w })) {
|
||||||
|
mValue = mBuff;
|
||||||
|
nChanged = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::InputTextEx("input", mId.c_str(), mBuff, mMaxBufferSize, { this->mArea.z, this->mArea.w }, 0)) {
|
||||||
|
mValue = mBuff;
|
||||||
|
nChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
ImGui::PopStyleVar(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputWidget::eventUpdateConfiguration(WidgetManager& wm) {
|
||||||
|
wm.setActiveId("TextInput");
|
||||||
|
|
||||||
|
mAccentColor = wm.getColor("Accent", "Accent");
|
||||||
|
mBaseColor = wm.getColor("Base", "Base");
|
||||||
|
mRounding = wm.getNumber("Rounding", "Rounding");
|
||||||
|
mHoveredColor = wm.getColor("Hovered", "Accent");
|
||||||
|
mPadding = wm.getNumber("Padding", "Padding");
|
||||||
|
}
|
||||||
140
.back/WidBack/private/WidgetBase.cpp
Normal file
140
.back/WidBack/private/WidgetBase.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include "WidgetBase.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
Widget::Widget() { mArea = { 0, 0, 100, 100 }; }
|
||||||
|
|
||||||
|
Widget::~Widget() = default;
|
||||||
|
|
||||||
|
void Widget::procWrapper(const Events& events, const RectF& parentArea) {
|
||||||
|
if (!mEnable) return;
|
||||||
|
|
||||||
|
checkVisibility(events, parentArea);
|
||||||
|
|
||||||
|
if (!mVisible) return;
|
||||||
|
|
||||||
|
checkFocus(events);
|
||||||
|
|
||||||
|
checkClicked(events);
|
||||||
|
|
||||||
|
if (mHandlesEvents) {
|
||||||
|
|
||||||
|
for (auto child : mChildWidgets) {
|
||||||
|
child->procWrapper(events, mVisibleArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
eventProcess(events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::drawWrapper(Canvas& canvas) {
|
||||||
|
if (!mEnable || !mVisible) return;
|
||||||
|
|
||||||
|
eventDraw(canvas);
|
||||||
|
|
||||||
|
// draw child widgets
|
||||||
|
canvas.pushClamp(this->mArea);
|
||||||
|
for (auto child = mChildWidgets.lastNode(); child; child = child->prev) {
|
||||||
|
child->data->drawWrapper(canvas);
|
||||||
|
}
|
||||||
|
canvas.popClamp();
|
||||||
|
|
||||||
|
eventDrawOver(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::updateConfigWrapper(WidgetManager& wm) {
|
||||||
|
wm.setActiveId("Global");
|
||||||
|
|
||||||
|
eventUpdateConfiguration(wm);
|
||||||
|
|
||||||
|
for (auto child : mChildWidgets) {
|
||||||
|
child->updateConfigWrapper(wm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::eventProcess(const Events& events) {}
|
||||||
|
void Widget::eventDraw(Canvas& canvas) {}
|
||||||
|
void Widget::eventDrawOver(Canvas& canvas) {}
|
||||||
|
void Widget::eventUpdateConfiguration(WidgetManager& wm) {}
|
||||||
|
|
||||||
|
void Widget::eventVisible(const Events& events) {}
|
||||||
|
void Widget::eventNotVisible(const Events& events) {}
|
||||||
|
|
||||||
|
void Widget::eventFocusEnter(const Events& events) {}
|
||||||
|
void Widget::eventFocusLeave(const Events& events) {}
|
||||||
|
|
||||||
|
void Widget::eventPressed(const Events& events) {}
|
||||||
|
void Widget::eventReleased(const Events& events) {}
|
||||||
|
|
||||||
|
void Widget::checkVisibility(const Events& events, const RectF& parentArea) {
|
||||||
|
const bool currentVisibility = parentArea.isOverlap(getArea());
|
||||||
|
|
||||||
|
parentArea.calcIntersection(mArea, mVisibleArea);
|
||||||
|
|
||||||
|
if (currentVisibility != mVisible) {
|
||||||
|
if (currentVisibility) eventVisible(events);
|
||||||
|
else eventNotVisible(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
mVisible = currentVisibility;
|
||||||
|
|
||||||
|
if (!mVisible) {
|
||||||
|
mHolding = false;
|
||||||
|
mPressed = false;
|
||||||
|
mReleased = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::checkFocus(const Events& events) {
|
||||||
|
const bool currentFocus = mVisibleArea.isInside(events.getPointerPrev());
|
||||||
|
|
||||||
|
if (currentFocus != mInFocus) {
|
||||||
|
if (currentFocus) eventFocusEnter(events);
|
||||||
|
else eventFocusLeave(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
mInFocus = currentFocus;
|
||||||
|
|
||||||
|
if (!mInFocus) {
|
||||||
|
mHolding = false;
|
||||||
|
mPressed = false;
|
||||||
|
mReleased = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::checkClicked(const Events& events) {
|
||||||
|
mPressed = false;
|
||||||
|
mReleased = false;
|
||||||
|
|
||||||
|
if (!mInFocus) return;
|
||||||
|
|
||||||
|
if (mHolding) {
|
||||||
|
if (events.isReleased(InputID::MOUSE1)) {
|
||||||
|
eventReleased(events);
|
||||||
|
mReleased = true;
|
||||||
|
mHolding = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (events.isPressed(InputID::MOUSE1) && mVisibleArea.isInside(events.getPointer())) {
|
||||||
|
eventPressed(events);
|
||||||
|
mHolding = true;
|
||||||
|
mPressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setEnable(bool enable) { mEnable = enable; }
|
||||||
|
void Widget::setVisible(bool visible) { mVisible = visible; }
|
||||||
|
void Widget::setArea(const RectF& area) { mArea = area; }
|
||||||
|
|
||||||
|
const RectF& Widget::getArea() const { return mArea; }
|
||||||
|
bool Widget::isFocus() const { return mInFocus; }
|
||||||
|
bool Widget::isPressed() const { return mPressed; }
|
||||||
|
bool Widget::isReleased() const { return mReleased; }
|
||||||
|
bool Widget::isHolding() const { return mHolding; }
|
||||||
|
|
||||||
|
void Widget::clearEvents() {
|
||||||
|
mReleased = false;
|
||||||
|
mPressed = false;
|
||||||
|
mHolding = false;
|
||||||
|
}
|
||||||
74
.back/WidBack/private/WidgetManager.cpp
Normal file
74
.back/WidBack/private/WidgetManager.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
#include "WidgetManager.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
WidgetManager::WidgetManager() { initGlobalParameters(); }
|
||||||
|
WidgetManager::~WidgetManager() { mConfigurations.removeAll(); }
|
||||||
|
|
||||||
|
const RGBA& WidgetManager::getColor(const std::string& parameterId, const RGBA& defaultValue) {
|
||||||
|
WidgetConfig& config = getWidgetConfig(mActiveId);
|
||||||
|
Parameter& parameter = getParameter(config, parameterId, Parameter(defaultValue));
|
||||||
|
return parameter.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RGBA& WidgetManager::getColor(const std::string& parameterId, const char* globalRef) {
|
||||||
|
WidgetConfig& config = getWidgetConfig(mActiveId);
|
||||||
|
Parameter& parameter = getParameter(config, parameterId, Parameter(globalRef, Parameter::COL));
|
||||||
|
return parameter.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
halnf WidgetManager::getNumber(const std::string& parameterId, halnf defaultValue) {
|
||||||
|
WidgetConfig& config = getWidgetConfig(mActiveId);
|
||||||
|
Parameter& parameter = getParameter(config, parameterId, Parameter(defaultValue));
|
||||||
|
return parameter.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
halnf WidgetManager::getNumber(const std::string& parameterId, const char* globalRef) {
|
||||||
|
WidgetConfig& config = getWidgetConfig(mActiveId);
|
||||||
|
Parameter& parameter = getParameter(config, parameterId, Parameter(globalRef, Parameter::VAL));
|
||||||
|
return parameter.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetManager::setActiveId(const std::string& id) { mActiveId = id; }
|
||||||
|
|
||||||
|
WidgetConfig& WidgetManager::getWidgetConfig(const std::string& id) {
|
||||||
|
auto idx = mConfigurations.presents(id);
|
||||||
|
if (idx) return mConfigurations.getSlotVal(idx);
|
||||||
|
mConfigurations.put(id, {});
|
||||||
|
return mConfigurations.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetManager::Parameter& WidgetManager::getParameter(WidgetConfig& config, const std::string& id, const Parameter& defaultValue) {
|
||||||
|
auto idx = config.mParameters.presents(id);
|
||||||
|
|
||||||
|
if (!idx) {
|
||||||
|
config.mParameters.put(id, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter& parameter = config.mParameters.get(id);
|
||||||
|
|
||||||
|
if (parameter.globalReference) {
|
||||||
|
return mGlobalConfig.mParameters.get(parameter.globalId);
|
||||||
|
} else {
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetManager::initGlobalParameters() {
|
||||||
|
auto& params = mGlobalConfig.mParameters;
|
||||||
|
|
||||||
|
params.put("FontSize", Parameter(15.f));
|
||||||
|
|
||||||
|
params.put("FontSizeDim", Parameter(12.f));
|
||||||
|
params.put("Rounding", Parameter(5.f));
|
||||||
|
params.put("Padding", Parameter(5.f));
|
||||||
|
params.put("HandleSize", Parameter(5.f));
|
||||||
|
|
||||||
|
params.put("Background", Parameter(RGBA{ 0.03f, 0.03f, 0.03f, 1.f }));
|
||||||
|
params.put("Base", Parameter(RGBA{ 0.07f, 0.07f, 0.07f, 1.f }));
|
||||||
|
params.put("Accent", Parameter(RGBA{ 0.13f, 0.13f, 0.13f, 1.f }));
|
||||||
|
params.put("Interaction", Parameter(RGBA{ 0.33f, 0.33f, 0.3f, 1.f }));
|
||||||
|
params.put("Action", Parameter(RGBA{ 0.44f, 0.44f, 0.4f, 1.f }));
|
||||||
|
params.put("Front", Parameter(RGBA{ 1.f, 1.f, 1.f, 1.f }));
|
||||||
|
params.put("FrontDim", Parameter(RGBA{ 0.7f, 0.7f, 0.7f, 1.f }));
|
||||||
|
}
|
||||||
73
.back/WidBack/private/WorkspaceWidget.cpp
Normal file
73
.back/WidBack/private/WorkspaceWidget.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include "WorkspaceWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
WorkspaceWidget::WorkspaceWidget() {
|
||||||
|
this->mChildWidgets.pushBack(&mFloatingLayer);
|
||||||
|
this->mChildWidgets.pushBack(&mDockSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkspaceWidget::eventProcess(const Events& events) {
|
||||||
|
mDockSpace.setArea(this->mArea);
|
||||||
|
mFloatingLayer.setArea(this->mArea);
|
||||||
|
|
||||||
|
mDockSpace.mPreview = false;
|
||||||
|
mDockSpace.mHandlesEvents = !mFloatingLayer.handlesEvent();
|
||||||
|
|
||||||
|
for (auto floatingChild : mFloatingLayer.mChildWidgets) {
|
||||||
|
auto widget = dynamic_cast<FloatingWidget*>(floatingChild.data());
|
||||||
|
if (!widget) continue;
|
||||||
|
|
||||||
|
if (widget->mDropped) {
|
||||||
|
auto side = mDockSpace.getPreviewSide();
|
||||||
|
if (side != DockWidget::NONE) {
|
||||||
|
mFloatingLayer.mChildWidgets.removeNode(mFloatingLayer.mChildWidgets.find(widget));
|
||||||
|
widget->setCollapsed(false);
|
||||||
|
widget->stopFloating();
|
||||||
|
mDockSpace.addSideWidget(widget, side);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget->isFloating()) {
|
||||||
|
mDockSpace.mHandlesEvents = true;
|
||||||
|
mDockSpace.mPreview = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& dockedChild : mDockSpace.mSideWidgets) {
|
||||||
|
auto widget = dynamic_cast<FloatingWidget*>(dockedChild.widget);
|
||||||
|
if (!widget) continue;
|
||||||
|
|
||||||
|
if (widget->isFloating()) {
|
||||||
|
mDockSpace.removeSideWidget(dockedChild.side);
|
||||||
|
mFloatingLayer.mChildWidgets.pushBack(widget);
|
||||||
|
widget->mArea.pos = events.getPointer() - 20;
|
||||||
|
widget->mArea.size = mDefaultFloatSize;
|
||||||
|
|
||||||
|
widget->mResizable = true;
|
||||||
|
// widget->mBorders = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// toggle hide state
|
||||||
|
if (events.isDown(InputID::LEFT_ALT)) {
|
||||||
|
if (events.isPressed(InputID::N1)) {
|
||||||
|
mDockSpace.toggleHiddenState(DockWidget::LEFT);
|
||||||
|
} else if (events.isPressed(InputID::N2)) {
|
||||||
|
mDockSpace.toggleHiddenState(DockWidget::TOP);
|
||||||
|
} else if (events.isPressed(InputID::N3)) {
|
||||||
|
mDockSpace.toggleHiddenState(DockWidget::RIGHT);
|
||||||
|
} else if (events.isPressed(InputID::N4)) {
|
||||||
|
mDockSpace.toggleHiddenState(DockWidget::BOTTOM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& dockedChild : mDockSpace.mSideWidgets) {
|
||||||
|
auto widget = dynamic_cast<FloatingWidget*>(dockedChild.widget);
|
||||||
|
if (!widget) continue;
|
||||||
|
|
||||||
|
widget->setCollapsed(false);
|
||||||
|
widget->mResizable = false;
|
||||||
|
// widget->mBorders = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,53 +1,57 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GraphicsCommon.hpp"
|
#include "Color.hpp"
|
||||||
|
#include "Rect.hpp"
|
||||||
namespace tp {
|
#include "Timing.hpp"
|
||||||
|
|
||||||
class AnimValue {
|
namespace tp {
|
||||||
halnf mValPrev = 0;
|
|
||||||
halnf mVal = 0;
|
class AnimValue {
|
||||||
time_ms mTimeStart = 0;
|
halnf mValPrev = 0;
|
||||||
halni mTimeAnim = 250;
|
halnf mVal = 0;
|
||||||
|
time_ms mTimeStart = 0;
|
||||||
static bool gInTransition;
|
halni mTimeAnim = 250;
|
||||||
|
|
||||||
private:
|
static bool gInTransition;
|
||||||
[[nodiscard]] halnf interpolate() const;
|
|
||||||
|
private:
|
||||||
public:
|
[[nodiscard]] halnf interpolate() const;
|
||||||
AnimValue();
|
|
||||||
explicit AnimValue(halnf val);
|
public:
|
||||||
|
AnimValue();
|
||||||
[[nodiscard]] halnf prev() const { return mValPrev; }
|
explicit AnimValue(halnf val);
|
||||||
void set(halnf val);
|
|
||||||
void setNoTransition(halnf);
|
[[nodiscard]] halnf prev() const { return mValPrev; }
|
||||||
void setAnimTime(halni time);
|
void set(halnf val);
|
||||||
[[nodiscard]] halnf get() const;
|
void setNoTransition(halnf);
|
||||||
[[nodiscard]] halnf getTarget() const;
|
void setAnimTime(halni time);
|
||||||
[[nodiscard]] bool inTransition() const;
|
[[nodiscard]] halnf get() const;
|
||||||
explicit operator halnf() const;
|
[[nodiscard]] halnf getTarget() const;
|
||||||
void operator=(halnf val);
|
[[nodiscard]] bool inTransition() const;
|
||||||
};
|
explicit operator halnf() const;
|
||||||
|
void operator=(halnf val);
|
||||||
class AnimRect : Rect<AnimValue> {
|
};
|
||||||
public:
|
|
||||||
AnimRect() {
|
class AnimRect : Rect<AnimValue> {
|
||||||
set({ 0, 0, 0, 0 });
|
public:
|
||||||
setAnimTime(450);
|
AnimRect() {
|
||||||
}
|
setAnimTime(450);
|
||||||
|
setNoTransition({ 0, 0, 0, 0 });
|
||||||
[[nodiscard]] RectF get() const;
|
}
|
||||||
[[nodiscard]] RectF getTarget() const;
|
|
||||||
void setNoTransition(RectF);
|
[[nodiscard]] RectF get() const;
|
||||||
void set(const RectF&);
|
[[nodiscard]] RectF getTarget() const;
|
||||||
void setAnimTime(halni time_ms);
|
void setNoTransition(RectF);
|
||||||
};
|
void set(const RectF&);
|
||||||
|
void setAnimTime(halni time_ms);
|
||||||
class AnimColor {
|
};
|
||||||
AnimRect mColor;
|
|
||||||
public:
|
class AnimColor {
|
||||||
[[nodiscard]] RGBA get() const;
|
public:
|
||||||
void set(const RGBA&);
|
AnimColor();
|
||||||
};
|
AnimRect mColor;
|
||||||
|
|
||||||
|
[[nodiscard]] RGBA get() const;
|
||||||
|
void set(const RGBA&);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
35
.back/WidBack/public/ButtonWidget.hpp
Normal file
35
.back/WidBack/public/ButtonWidget.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "LabelWidget.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class ButtonWidget : public Widget {
|
||||||
|
public:
|
||||||
|
// enum State { NONE, ANTICIPATION, ACTIVATED, CONFIRMED };
|
||||||
|
|
||||||
|
public:
|
||||||
|
ButtonWidget();
|
||||||
|
ButtonWidget(const std::string& label, const tp::RectF& aArea);
|
||||||
|
bool isFired();
|
||||||
|
void eventProcess(const Events&) override;
|
||||||
|
void eventDraw(Canvas& canvas) override;
|
||||||
|
void setLabel(const std::string& string);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LabelWidget mLabel;
|
||||||
|
// State mStat = NONE;
|
||||||
|
|
||||||
|
RGBA pressedColor;
|
||||||
|
RGBA hoveredColor;
|
||||||
|
RGBA accentColor;
|
||||||
|
halnf rounding = 0;
|
||||||
|
|
||||||
|
std::function<void()> mCallback = [](){};
|
||||||
|
};
|
||||||
|
}
|
||||||
51
.back/WidBack/public/CollapsableMenu.hpp
Normal file
51
.back/WidBack/public/CollapsableMenu.hpp
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ScrollableWidget.hpp"
|
||||||
|
#include "ButtonWidget.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class CollapsableMenu : public Widget {
|
||||||
|
public:
|
||||||
|
CollapsableMenu();
|
||||||
|
void eventProcess(const Events&) override;
|
||||||
|
void eventDraw(Canvas& canvas) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void addWidgetToMenu(Widget* widget);
|
||||||
|
void setLabel(const std::string& string);
|
||||||
|
|
||||||
|
void toggleCollapsed();
|
||||||
|
void setCollapsed(bool collapsed);
|
||||||
|
[[nodiscard]] bool getCollapsed() const;
|
||||||
|
void updateGeometry();
|
||||||
|
|
||||||
|
private:
|
||||||
|
RectF getHeaderRect();
|
||||||
|
RectF getBodyRect();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ScrollableWindow mBody;
|
||||||
|
LabelWidget mHeader;
|
||||||
|
|
||||||
|
RGBA mMenuColor;
|
||||||
|
RGBA mBorderColor;
|
||||||
|
|
||||||
|
halnf headerHeight = 30;
|
||||||
|
halnf rounding = 0;
|
||||||
|
halnf mBorderSize = 0;
|
||||||
|
halnf mPadding = 0;
|
||||||
|
|
||||||
|
halnf mPrevHeight = 200;
|
||||||
|
|
||||||
|
bool mCollapsed = true;
|
||||||
|
bool mLocked = false;
|
||||||
|
bool mAdjustHeight = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool mBorders = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
18
.back/WidBack/public/FloatingLayoutWidget.hpp
Normal file
18
.back/WidBack/public/FloatingLayoutWidget.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include "FloatingWidget.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
class FloatingLayoutWidget : public Widget {
|
||||||
|
public:
|
||||||
|
FloatingLayoutWidget();
|
||||||
|
|
||||||
|
void eventProcess(const Events& events) override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool handlesEvent() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateActiveWindow(const tp::Events& events);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mIsPassThrough = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
38
.back/WidBack/public/FloatingWidget.hpp
Normal file
38
.back/WidBack/public/FloatingWidget.hpp
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CollapsableMenu.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
class FloatingWidget : public CollapsableMenu {
|
||||||
|
public:
|
||||||
|
FloatingWidget();
|
||||||
|
|
||||||
|
void eventProcess(const Events& events) override;
|
||||||
|
void eventDraw(Canvas& canvas) override;
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isFloating() const;
|
||||||
|
void stopFloating();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkFloating(const Events& events);
|
||||||
|
void checkResizing(const Events& events);
|
||||||
|
RectF getResizeHandle();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vec2F mMinSize = { 70, 70 };
|
||||||
|
|
||||||
|
halnf mResizeHandleSize = 10;
|
||||||
|
RGBA mResizeHandleColor = {};
|
||||||
|
|
||||||
|
bool mFloating = false;
|
||||||
|
bool mResizing = false;
|
||||||
|
|
||||||
|
Vec2F mActionStartRelativePos = {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool mResizable = true;
|
||||||
|
|
||||||
|
bool mDropped = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
88
.back/WidBack/public/GridLayoutWidget.hpp
Normal file
88
.back/WidBack/public/GridLayoutWidget.hpp
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include "WidgetBase.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
class DockWidget : public Widget {
|
||||||
|
public:
|
||||||
|
enum Side { LEFT, TOP, RIGHT, BOTTOM, NONE };
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ResizeHandle {
|
||||||
|
RectF area{ 0, 0, 0, 0 };
|
||||||
|
halnf start{ 0 };
|
||||||
|
halnf end{ 0 };
|
||||||
|
bool active = false;
|
||||||
|
bool hover = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SideWidgetData {
|
||||||
|
Widget* widget = nullptr;
|
||||||
|
bool hidden = false;
|
||||||
|
halnf absoluteSize = 200;
|
||||||
|
alni order = -1;
|
||||||
|
|
||||||
|
Side side = { TOP };
|
||||||
|
|
||||||
|
RectF area = {};
|
||||||
|
RectF headerArea = {};
|
||||||
|
RectF previewHandleArea = {};
|
||||||
|
|
||||||
|
ResizeHandle resizeHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
DockWidget();
|
||||||
|
|
||||||
|
void eventProcess(const Events& events) override;
|
||||||
|
void eventDraw(Canvas& canvas) override;
|
||||||
|
void eventDrawOver(Canvas& canvas) override;
|
||||||
|
|
||||||
|
void addSideWidget(Widget* widget, Side side);
|
||||||
|
void removeSideWidget(Side side);
|
||||||
|
|
||||||
|
void toggleHiddenState(Side side);
|
||||||
|
|
||||||
|
void setCenterWidget(Widget* widget);
|
||||||
|
|
||||||
|
Side getPreviewSide();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void calculateSideAreas();
|
||||||
|
void calculateResizeHandles();
|
||||||
|
void handleResizeEvents(const Events& events);
|
||||||
|
void updateChildSideWidgets();
|
||||||
|
|
||||||
|
void calculateHeaderAreas();
|
||||||
|
|
||||||
|
bool isSideVisible(Side side);
|
||||||
|
bool sideExists(DockWidget::Side side);
|
||||||
|
ualni getVisibleSidesSize();
|
||||||
|
void handlePreview(const Events& events);
|
||||||
|
|
||||||
|
private:
|
||||||
|
RectF mPreviewArea = {};
|
||||||
|
Side mPreviewSide = NONE;
|
||||||
|
int resizeType[2] = { 0, 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
SideWidgetData mSideWidgets[4];
|
||||||
|
|
||||||
|
private:
|
||||||
|
Widget* mCenterWidget = nullptr;
|
||||||
|
RectF mCenterArea {};
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
halnf mSideSizePadding = 150.f;
|
||||||
|
halnf mPadding = 4;
|
||||||
|
halnf mHeaderSize = 27;
|
||||||
|
halnf mRounding = 10;
|
||||||
|
Vec2F mPreviewHandleSize = { 50, 50 };
|
||||||
|
|
||||||
|
RGBA mResizeHandleColorHovered = RGBA(0.3, 0.3, 0.3, 1);
|
||||||
|
RGBA mResizeHandleColorActive = RGBA(0.6, 0.6, 0.6, 1);
|
||||||
|
RGBA mBackgroundColor = RGBA(0, 0, 0, 1);
|
||||||
|
RGBA mPreviewColor = RGBA(0.6, 0.6, 0.6, 1);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool mPreview = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
23
.back/WidBack/public/LabelWidget.hpp
Normal file
23
.back/WidBack/public/LabelWidget.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WidgetBase.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class LabelWidget : public Widget {
|
||||||
|
public:
|
||||||
|
LabelWidget();
|
||||||
|
|
||||||
|
void eventDraw(Canvas& canvas) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string mLabel = "Label";
|
||||||
|
|
||||||
|
halnf fontSize = 10;
|
||||||
|
halnf padding = 0;
|
||||||
|
RGBA fontColor = { 1, 1, 1, 1 };
|
||||||
|
};
|
||||||
|
}
|
||||||
71
.back/WidBack/public/ScrollableWidget.hpp
Normal file
71
.back/WidBack/public/ScrollableWidget.hpp
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WidgetBase.hpp"
|
||||||
|
#include "Buffer.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class ScrollBarWidget : public Widget {
|
||||||
|
public:
|
||||||
|
ScrollBarWidget();
|
||||||
|
|
||||||
|
// takes whole area
|
||||||
|
void eventProcess(const Events& events) override;
|
||||||
|
void eventDraw(Canvas& canvas) override;
|
||||||
|
|
||||||
|
RectF getHandleHandle() const;
|
||||||
|
RectF getViewport() const;
|
||||||
|
RectF getHandle() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool mIsScrolling = false;
|
||||||
|
halnf mSizeFraction = 1.f;
|
||||||
|
halnf mPositionFraction = 0.f;
|
||||||
|
bool mHovered = false;
|
||||||
|
|
||||||
|
RGBA mDefaultColor;
|
||||||
|
RGBA mHandleColor;
|
||||||
|
RGBA mHoveredColor;
|
||||||
|
RGBA mScrollingColor;
|
||||||
|
halnf mPadding = 0;
|
||||||
|
halnf mHandleSize = 10;
|
||||||
|
halnf mMinSize = 10;
|
||||||
|
halnf mRounding = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScrollableWindow : public Widget {
|
||||||
|
public:
|
||||||
|
ScrollableWindow();
|
||||||
|
|
||||||
|
virtual ~ScrollableWindow();
|
||||||
|
|
||||||
|
// takes whole area
|
||||||
|
void eventProcess(const Events& events) override;
|
||||||
|
|
||||||
|
void addWidget(Widget* widget);
|
||||||
|
void clearContent();
|
||||||
|
List<Widget*>& getContent();
|
||||||
|
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||||
|
|
||||||
|
[[nodiscard]] halnf getContentSize() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateContents(List<Widget*>& contentWidgets);
|
||||||
|
|
||||||
|
// ready content size
|
||||||
|
void updateContentSize(List<Widget*>& contentWidgets);
|
||||||
|
void setOffset(List<Widget*>& contentWidgets, const halnf offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Widget mContentWidget;
|
||||||
|
ScrollBarWidget mScroller;
|
||||||
|
|
||||||
|
halnf mContentSize = 0;
|
||||||
|
|
||||||
|
halnf mPadding = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
41
.back/WidBack/public/SliderWidget.hpp
Normal file
41
.back/WidBack/public/SliderWidget.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "LabelWidget.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class SliderWidget : public Widget {
|
||||||
|
public:
|
||||||
|
SliderWidget();
|
||||||
|
|
||||||
|
void eventProcess(const Events& events) override;
|
||||||
|
void eventDraw(Canvas& canvas) override;
|
||||||
|
|
||||||
|
RectF getHandle() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
halnf mFactor = 0.f;
|
||||||
|
bool mIsSliding = false;
|
||||||
|
|
||||||
|
RGBA defaultColor;
|
||||||
|
RGBA handleColor;
|
||||||
|
halnf handleSize = 0;
|
||||||
|
halnf rounding = 0;
|
||||||
|
halnf borderSize = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NamedSliderWidget : public Widget {
|
||||||
|
public:
|
||||||
|
explicit NamedSliderWidget(const char* name = "Value");
|
||||||
|
void eventProcess(const Events& events) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SliderWidget mSlider;
|
||||||
|
LabelWidget mLabel;
|
||||||
|
|
||||||
|
halnf mFactor = 0.5f;
|
||||||
|
};
|
||||||
|
}
|
||||||
29
.back/WidBack/public/TextInputWidget.hpp
Normal file
29
.back/WidBack/public/TextInputWidget.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WidgetBase.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
class TextInputWidget : public Widget {
|
||||||
|
public:
|
||||||
|
TextInputWidget();
|
||||||
|
|
||||||
|
void eventDraw(Canvas&) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { mMaxBufferSize = 512 };
|
||||||
|
char mBuff[mMaxBufferSize] = "";
|
||||||
|
bool nChanged = false;
|
||||||
|
std::string mValue;
|
||||||
|
std::string mId = "id";
|
||||||
|
bool mMultiline = false;
|
||||||
|
|
||||||
|
RGBA mAccentColor;
|
||||||
|
RGBA mHoveredColor;
|
||||||
|
RGBA mBaseColor;
|
||||||
|
halnf mRounding = 0;
|
||||||
|
halnf mPadding = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
78
.back/WidBack/public/WidgetBase.hpp
Normal file
78
.back/WidBack/public/WidgetBase.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Graphics.hpp"
|
||||||
|
|
||||||
|
#include "EventHandler.hpp"
|
||||||
|
#include "WidgetManager.hpp"
|
||||||
|
#include "List.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
using Events = EventHandler;
|
||||||
|
|
||||||
|
class Widget {
|
||||||
|
public:
|
||||||
|
Widget();
|
||||||
|
virtual ~Widget();
|
||||||
|
|
||||||
|
void procWrapper(const Events& events, const RectF& parentArea);
|
||||||
|
void drawWrapper(Canvas& canvas);
|
||||||
|
void updateConfigWrapper(WidgetManager& wm);
|
||||||
|
|
||||||
|
virtual void eventProcess(const Events& events);
|
||||||
|
|
||||||
|
// draws before child widgets
|
||||||
|
virtual void eventDraw(Canvas& canvas);
|
||||||
|
|
||||||
|
// draws overlay after child widgets
|
||||||
|
virtual void eventDrawOver(Canvas& canvas);
|
||||||
|
|
||||||
|
virtual void eventUpdateConfiguration(WidgetManager& wm);
|
||||||
|
|
||||||
|
virtual void eventVisible(const Events& events);
|
||||||
|
virtual void eventNotVisible(const Events& events);
|
||||||
|
|
||||||
|
virtual void eventFocusEnter(const Events& events);
|
||||||
|
virtual void eventFocusLeave(const Events& events);
|
||||||
|
|
||||||
|
virtual void eventPressed(const Events& events);
|
||||||
|
virtual void eventReleased(const Events& events);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setEnable(bool enable);
|
||||||
|
void setVisible(bool visible);
|
||||||
|
void setArea(const RectF& area);
|
||||||
|
|
||||||
|
[[nodiscard]] const RectF& getArea() const;
|
||||||
|
[[nodiscard]] bool isFocus() const;
|
||||||
|
[[nodiscard]] bool isPressed() const;
|
||||||
|
[[nodiscard]] bool isReleased() const;
|
||||||
|
[[nodiscard]] bool isHolding() const;
|
||||||
|
|
||||||
|
void clearEvents();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkVisibility(const Events& events, const RectF& parentArea);
|
||||||
|
void checkFocus(const Events& events);
|
||||||
|
void checkClicked(const Events& events);
|
||||||
|
|
||||||
|
public:
|
||||||
|
RectF mArea;
|
||||||
|
RectF mVisibleArea;
|
||||||
|
|
||||||
|
List<Widget*> mChildWidgets;
|
||||||
|
|
||||||
|
bool mVisible = false;
|
||||||
|
bool mEnable = true;
|
||||||
|
bool mHandlesEvents = true;
|
||||||
|
bool mInFocus = false;
|
||||||
|
|
||||||
|
bool mHolding = false;
|
||||||
|
bool mPressed = false;
|
||||||
|
bool mReleased = false;
|
||||||
|
|
||||||
|
|
||||||
|
// docking
|
||||||
|
bool mIsDocked = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
89
.back/WidBack/public/WidgetManager.hpp
Normal file
89
.back/WidBack/public/WidgetManager.hpp
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Animations.hpp"
|
||||||
|
#include "Map.hpp"
|
||||||
|
#include "Rect.hpp"
|
||||||
|
|
||||||
|
#include "InputCodes.hpp"
|
||||||
|
#include "Buffer.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
struct WidgetConfig {
|
||||||
|
|
||||||
|
struct Shortcut {
|
||||||
|
struct Condition {
|
||||||
|
std::string name;
|
||||||
|
std::string state;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string callbackName;
|
||||||
|
|
||||||
|
Shortcut() = default;
|
||||||
|
Shortcut(const InitialierList<Condition>&) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Parameter {
|
||||||
|
enum Type { NONE, VAL, COL };
|
||||||
|
|
||||||
|
halnf value = 0.f;
|
||||||
|
RGBA color = {};
|
||||||
|
Type type = NONE;
|
||||||
|
bool globalReference = false;
|
||||||
|
std::string globalId;
|
||||||
|
|
||||||
|
Parameter() = default;
|
||||||
|
|
||||||
|
explicit Parameter(halnf val) {
|
||||||
|
type = VAL;
|
||||||
|
value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit Parameter(const RGBA& val) {
|
||||||
|
type = COL;
|
||||||
|
color = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit Parameter(const std::string& id, const Type& referenceType) {
|
||||||
|
type = referenceType;
|
||||||
|
globalId = id;
|
||||||
|
globalReference = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<std::string, Parameter> mParameters;
|
||||||
|
Buffer<Shortcut> mShortcuts;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WidgetManager {
|
||||||
|
public:
|
||||||
|
using Parameter = WidgetConfig::Parameter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WidgetManager();
|
||||||
|
~WidgetManager();
|
||||||
|
|
||||||
|
const RGBA& getColor(const std::string& parameterId, const RGBA& defaultValue);
|
||||||
|
const RGBA& getColor(const std::string& parameterId, const char* globalRef);
|
||||||
|
|
||||||
|
halnf getNumber(const std::string& parameterId, halnf defaultValue);
|
||||||
|
halnf getNumber(const std::string& parameterId, const char* globalRef);
|
||||||
|
|
||||||
|
void setActiveId(const std::string& id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
WidgetConfig& getWidgetConfig(const std::string& id);
|
||||||
|
Parameter& getParameter(WidgetConfig& config, const std::string& id, const Parameter& defaultValue);
|
||||||
|
|
||||||
|
void initGlobalParameters();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Map<std::string, WidgetConfig> mConfigurations;
|
||||||
|
WidgetConfig mGlobalConfig;
|
||||||
|
|
||||||
|
RGBA mErrorColor = { 0, 0, 0, 1 };
|
||||||
|
halnf mErrorNumber = 0;
|
||||||
|
|
||||||
|
std::string mActiveId;
|
||||||
|
};
|
||||||
|
}
|
||||||
13
.back/WidBack/public/Widgets.hpp
Normal file
13
.back/WidBack/public/Widgets.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Animations.hpp"
|
||||||
|
#include "ButtonWidget.hpp"
|
||||||
|
#include "LabelWidget.hpp"
|
||||||
|
#include "ScrollableWidget.hpp"
|
||||||
|
#include "TextInputWidget.hpp"
|
||||||
|
#include "SliderWidget.hpp"
|
||||||
|
#include "CollapsableMenu.hpp"
|
||||||
|
#include "FloatingWidget.hpp"
|
||||||
|
#include "FloatingLayoutWidget.hpp"
|
||||||
|
#include "GridLayoutWidget.hpp"
|
||||||
|
#include "WorkspaceWidget.hpp"
|
||||||
19
.back/WidBack/public/WorkspaceWidget.hpp
Normal file
19
.back/WidBack/public/WorkspaceWidget.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Widgets.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
class WorkspaceWidget : public Widget {
|
||||||
|
public:
|
||||||
|
WorkspaceWidget();
|
||||||
|
|
||||||
|
void eventProcess(const Events& events) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DockWidget mDockSpace;
|
||||||
|
FloatingLayoutWidget mFloatingLayer;
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
Vec2F mDefaultFloatSize = { 200, 200 };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
---
|
---
|
||||||
BasedOnStyle: LLVM
|
BasedOnStyle: LLVM
|
||||||
AccessModifierOffset: -2
|
AccessModifierOffset: -2
|
||||||
AlignAfterOpenBracket: Align
|
AlignAfterOpenBracket: BlockIndent
|
||||||
AlignArrayOfStructures: Left
|
AlignArrayOfStructures: None
|
||||||
AlignConsecutiveAssignments:
|
AlignConsecutiveAssignments:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
AcrossEmptyLines: false
|
AcrossEmptyLines: false
|
||||||
AcrossComments: false
|
AcrossComments: false
|
||||||
AlignCompound: false
|
AlignCompound: false
|
||||||
PadOperators: true
|
PadOperators: false
|
||||||
AlignConsecutiveBitFields:
|
AlignConsecutiveBitFields:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
AcrossEmptyLines: false
|
AcrossEmptyLines: false
|
||||||
|
|
@ -22,23 +22,22 @@ AlignConsecutiveDeclarations:
|
||||||
AlignCompound: false
|
AlignCompound: false
|
||||||
PadOperators: false
|
PadOperators: false
|
||||||
AlignConsecutiveMacros:
|
AlignConsecutiveMacros:
|
||||||
Enabled: true
|
Enabled: false
|
||||||
AcrossEmptyLines: false
|
AcrossEmptyLines: false
|
||||||
AcrossComments: false
|
AcrossComments: false
|
||||||
AlignCompound: false
|
AlignCompound: false
|
||||||
PadOperators: false
|
PadOperators: false
|
||||||
AlignEscapedNewlines: Left
|
AlignEscapedNewlines: Left
|
||||||
AlignOperands: Align
|
AlignOperands: Align
|
||||||
AlignTrailingComments:
|
AlignTrailingComments: true
|
||||||
Kind: Always
|
|
||||||
OverEmptyLines: 0
|
|
||||||
AllowAllArgumentsOnNextLine: true
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
AllowAllParametersOfDeclarationOnNextLine: true
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
AllowShortBlocksOnASingleLine: Always
|
AllowShortBlocksOnASingleLine: Never
|
||||||
AllowShortCaseLabelsOnASingleLine: true
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortEnumsOnASingleLine: true
|
AllowShortEnumsOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: All
|
AllowShortFunctionsOnASingleLine: All
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||||
AllowShortLambdasOnASingleLine: All
|
AllowShortLambdasOnASingleLine: All
|
||||||
AllowShortLoopsOnASingleLine: false
|
AllowShortLoopsOnASingleLine: false
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
|
@ -47,13 +46,13 @@ AlwaysBreakBeforeMultilineStrings: false
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
AttributeMacros:
|
AttributeMacros:
|
||||||
- __capability
|
- __capability
|
||||||
BinPackArguments: true
|
BinPackArguments: false
|
||||||
BinPackParameters: true
|
BinPackParameters: false
|
||||||
BitFieldColonSpacing: Both
|
BitFieldColonSpacing: Both
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterCaseLabel: false
|
AfterCaseLabel: true
|
||||||
AfterClass: false
|
AfterClass: true
|
||||||
AfterControlStatement: Never
|
AfterControlStatement: Always
|
||||||
AfterEnum: false
|
AfterEnum: false
|
||||||
AfterFunction: false
|
AfterFunction: false
|
||||||
AfterNamespace: false
|
AfterNamespace: false
|
||||||
|
|
@ -69,29 +68,28 @@ BraceWrapping:
|
||||||
SplitEmptyFunction: true
|
SplitEmptyFunction: true
|
||||||
SplitEmptyRecord: true
|
SplitEmptyRecord: true
|
||||||
SplitEmptyNamespace: true
|
SplitEmptyNamespace: true
|
||||||
BreakAfterAttributes: Never
|
|
||||||
BreakAfterJavaFieldAnnotations: false
|
BreakAfterJavaFieldAnnotations: false
|
||||||
BreakArrays: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
BreakBeforeBinaryOperators: None
|
||||||
BreakBeforeBraces: Attach
|
BreakBeforeBraces: Attach
|
||||||
BreakBeforeConceptDeclarations: Always
|
BreakBeforeConceptDeclarations: Always
|
||||||
BreakBeforeInlineASMColon: OnlyMultiline
|
|
||||||
BreakBeforeTernaryOperators: true
|
BreakBeforeTernaryOperators: true
|
||||||
BreakConstructorInitializers: BeforeColon
|
BreakConstructorInitializers: AfterColon
|
||||||
BreakInheritanceList: BeforeColon
|
BreakInheritanceList: BeforeColon
|
||||||
BreakStringLiterals: true
|
BreakStringLiterals: true
|
||||||
ColumnLimit: 180
|
ColumnLimit: 120
|
||||||
CommentPragmas: "^ IWYU pragma:"
|
CommentPragmas: "^ IWYU pragma:"
|
||||||
CompactNamespaces: false
|
CompactNamespaces: false
|
||||||
ConstructorInitializerIndentWidth: 4
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
ContinuationIndentWidth: 4
|
ConstructorInitializerIndentWidth: 2
|
||||||
Cpp11BracedListStyle: true
|
ContinuationIndentWidth: 2
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DeriveLineEnding: true
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
EmptyLineAfterAccessModifier: Never
|
EmptyLineAfterAccessModifier: Never
|
||||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
ExperimentalAutoDetectBinPacking: false
|
ExperimentalAutoDetectBinPacking: false
|
||||||
FixNamespaceComments: true
|
FixNamespaceComments: false
|
||||||
ForEachMacros:
|
ForEachMacros:
|
||||||
- foreach
|
- foreach
|
||||||
- Q_FOREACH
|
- Q_FOREACH
|
||||||
|
|
@ -117,28 +115,19 @@ IncludeIsMainSourceRegex: ""
|
||||||
IndentAccessModifiers: false
|
IndentAccessModifiers: false
|
||||||
IndentCaseBlocks: true
|
IndentCaseBlocks: true
|
||||||
IndentCaseLabels: true
|
IndentCaseLabels: true
|
||||||
IndentExternBlock: Indent
|
IndentExternBlock: AfterExternBlock
|
||||||
IndentGotoLabels: true
|
IndentGotoLabels: true
|
||||||
IndentPPDirectives: BeforeHash
|
IndentPPDirectives: None
|
||||||
IndentRequiresClause: true
|
IndentRequiresClause: true
|
||||||
IndentWidth: 2
|
IndentWidth: 2
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
InsertBraces: true
|
InsertBraces: false
|
||||||
InsertNewlineAtEOF: true
|
|
||||||
InsertTrailingCommas: None
|
InsertTrailingCommas: None
|
||||||
IntegerLiteralSeparator:
|
|
||||||
Binary: 0
|
|
||||||
BinaryMinDigits: 0
|
|
||||||
Decimal: 0
|
|
||||||
DecimalMinDigits: 0
|
|
||||||
Hex: 0
|
|
||||||
HexMinDigits: 0
|
|
||||||
JavaScriptQuotes: Leave
|
JavaScriptQuotes: Leave
|
||||||
JavaScriptWrapImports: true
|
JavaScriptWrapImports: true
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
LambdaBodyIndentation: Signature
|
LambdaBodyIndentation: Signature
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
LineEnding: DeriveLF
|
|
||||||
MacroBlockBegin: ""
|
MacroBlockBegin: ""
|
||||||
MacroBlockEnd: ""
|
MacroBlockEnd: ""
|
||||||
MaxEmptyLinesToKeep: 1
|
MaxEmptyLinesToKeep: 1
|
||||||
|
|
@ -149,7 +138,7 @@ ObjCBreakBeforeNestedBlockParam: true
|
||||||
ObjCSpaceAfterProperty: false
|
ObjCSpaceAfterProperty: false
|
||||||
ObjCSpaceBeforeProtocolList: true
|
ObjCSpaceBeforeProtocolList: true
|
||||||
PPIndentWidth: -1
|
PPIndentWidth: -1
|
||||||
PackConstructorInitializers: CurrentLine
|
PackConstructorInitializers: Never
|
||||||
PenaltyBreakAssignment: 2
|
PenaltyBreakAssignment: 2
|
||||||
PenaltyBreakBeforeFirstCallParameter: 19
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
PenaltyBreakComment: 300
|
PenaltyBreakComment: 300
|
||||||
|
|
@ -161,25 +150,23 @@ PenaltyExcessCharacter: 1000000
|
||||||
PenaltyIndentedWhitespace: 0
|
PenaltyIndentedWhitespace: 0
|
||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
PointerAlignment: Left
|
PointerAlignment: Left
|
||||||
QualifierAlignment: Custom
|
QualifierAlignment: Leave
|
||||||
ReferenceAlignment: Pointer
|
ReferenceAlignment: Pointer
|
||||||
ReflowComments: true
|
ReflowComments: true
|
||||||
RemoveBracesLLVM: false
|
RemoveBracesLLVM: false
|
||||||
RemoveSemicolon: true
|
|
||||||
RequiresClausePosition: OwnLine
|
RequiresClausePosition: OwnLine
|
||||||
RequiresExpressionIndentation: OuterScope
|
SeparateDefinitionBlocks: Leave
|
||||||
SeparateDefinitionBlocks: Always
|
ShortNamespaceLines: 1
|
||||||
ShortNamespaceLines: 1000
|
SortIncludes: Never
|
||||||
SortIncludes: CaseSensitive
|
|
||||||
SortJavaStaticImport: Before
|
SortJavaStaticImport: Before
|
||||||
SortUsingDeclarations: LexicographicNumeric
|
SortUsingDeclarations: true
|
||||||
SpaceAfterCStyleCast: true
|
SpaceAfterCStyleCast: true
|
||||||
SpaceAfterLogicalNot: false
|
SpaceAfterLogicalNot: false
|
||||||
SpaceAfterTemplateKeyword: true
|
SpaceAfterTemplateKeyword: true
|
||||||
SpaceAroundPointerQualifiers: Default
|
SpaceAroundPointerQualifiers: Default
|
||||||
SpaceBeforeAssignmentOperators: true
|
SpaceBeforeAssignmentOperators: true
|
||||||
SpaceBeforeCaseColon: false
|
SpaceBeforeCaseColon: false
|
||||||
SpaceBeforeCpp11BracedList: true
|
SpaceBeforeCpp11BracedList: false
|
||||||
SpaceBeforeCtorInitializerColon: true
|
SpaceBeforeCtorInitializerColon: true
|
||||||
SpaceBeforeInheritanceColon: true
|
SpaceBeforeInheritanceColon: true
|
||||||
SpaceBeforeParens: ControlStatements
|
SpaceBeforeParens: ControlStatements
|
||||||
|
|
@ -214,15 +201,11 @@ StatementMacros:
|
||||||
- Q_UNUSED
|
- Q_UNUSED
|
||||||
- QT_REQUIRE_VERSION
|
- QT_REQUIRE_VERSION
|
||||||
TabWidth: 2
|
TabWidth: 2
|
||||||
UseTab: Never
|
UseCRLF: false
|
||||||
|
UseTab: ForContinuationAndIndentation
|
||||||
WhitespaceSensitiveMacros:
|
WhitespaceSensitiveMacros:
|
||||||
- BOOST_PP_STRINGIZE
|
|
||||||
- CF_SWIFT_NAME
|
|
||||||
- NS_SWIFT_NAME
|
|
||||||
- PP_STRINGIZE
|
|
||||||
- STRINGIZE
|
- STRINGIZE
|
||||||
QualifierOrder:
|
- PP_STRINGIZE
|
||||||
- inline
|
- BOOST_PP_STRINGIZE
|
||||||
- static
|
- NS_SWIFT_NAME
|
||||||
- const
|
- CF_SWIFT_NAME
|
||||||
- type
|
|
||||||
16
.cproject
Normal file
16
.cproject
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||||
|
<cconfiguration id="org.eclipse.cdt.core.default.config.612128043">
|
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.core.defaultConfigDataProvider" id="org.eclipse.cdt.core.default.config.612128043" moduleId="org.eclipse.cdt.core.settings" name="Configuration">
|
||||||
|
<externalSettings/>
|
||||||
|
<extensions/>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
|
</cconfiguration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.pathentry">
|
||||||
|
<pathentry excluding="**/CMakeFiles/**" kind="out" path="build"/>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||||
|
</cproject>
|
||||||
428
.docs/Designs/Language.drawio
Normal file
428
.docs/Designs/Language.drawio
Normal file
|
|
@ -0,0 +1,428 @@
|
||||||
|
<mxfile host="Electron" modified="2023-10-29T20:02:24.324Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.0.3 Chrome/114.0.5735.289 Electron/25.8.4 Safari/537.36" etag="26yH0Gc3erZ3uKcA6DFE" version="22.0.3" type="device">
|
||||||
|
<diagram name="Page-1" id="8edUMiMEU_fADqxzhr4b">
|
||||||
|
<mxGraphModel dx="1062" dy="-128" grid="0" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="850" pageHeight="1100" background="none" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-158" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-22" target="Knp0EVw5rfMEdcPhjhnq-141" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="User Regular Language Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-22">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="380" y="1237" width="179" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-157" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-53" target="Knp0EVw5rfMEdcPhjhnq-146" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="User Context Free Language Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-53">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="482" y="1610" width="179" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-116" value="Compiler API Rulles To parse Regular grammar Rulles" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;startSize=23;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="175" y="1351" width="384" height="158" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="RE Compiler API Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-124">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-116" vertex="1">
|
||||||
|
<mxGeometry x="24" y="37.5" width="332" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<UserObject label="CF Compiler API Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-125">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-116" vertex="1">
|
||||||
|
<mxGeometry x="24" y="98.5" width="336" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-126" value="CF Parser" style="swimlane;whiteSpace=wrap;html=1;startSize=23;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="2269" y="1405" width="999" height="823" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-13" value="Acceptor" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
|
||||||
|
<mxGeometry x="416" y="171" width="293" height="203" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-34" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-13" source="Knp0EVw5rfMEdcPhjhnq-14" target="Knp0EVw5rfMEdcPhjhnq-19" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-35" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-13" source="Knp0EVw5rfMEdcPhjhnq-14" target="Knp0EVw5rfMEdcPhjhnq-18" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-36" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-13" source="Knp0EVw5rfMEdcPhjhnq-14" target="Knp0EVw5rfMEdcPhjhnq-20" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="Automation" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-14">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-13" vertex="1">
|
||||||
|
<mxGeometry x="92" y="81.5" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-18" value="SymbolStream" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-13" vertex="1">
|
||||||
|
<mxGeometry x="103.5" y="42" width="97" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-19" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-13" vertex="1">
|
||||||
|
<mxGeometry x="131.5" y="159" width="41" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-20" value="Tables" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-13" vertex="1">
|
||||||
|
<mxGeometry x="15" y="98.5" width="53" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-54" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-37" target="Knp0EVw5rfMEdcPhjhnq-13" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-55" value="Get Symbol" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="Knp0EVw5rfMEdcPhjhnq-54" vertex="1" connectable="0">
|
||||||
|
<mxGeometry x="-0.5956" y="-1" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-137" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-37" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="953.4782608695655" y="398.6521739130435" as="targetPoint" />
|
||||||
|
<Array as="points">
|
||||||
|
<mxPoint x="563" y="733" />
|
||||||
|
<mxPoint x="919" y="733" />
|
||||||
|
<mxPoint x="919" y="399" />
|
||||||
|
</Array>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-37" value="Acceptor" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
|
||||||
|
<mxGeometry x="416" y="490" width="293" height="203" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-38" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-37" source="Knp0EVw5rfMEdcPhjhnq-41" target="Knp0EVw5rfMEdcPhjhnq-43" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-39" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-37" source="Knp0EVw5rfMEdcPhjhnq-41" target="Knp0EVw5rfMEdcPhjhnq-42" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-40" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-37" source="Knp0EVw5rfMEdcPhjhnq-41" target="Knp0EVw5rfMEdcPhjhnq-44" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="Automation" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-41">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-37" vertex="1">
|
||||||
|
<mxGeometry x="92" y="81.5" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-42" value="SymbolStream" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-37" vertex="1">
|
||||||
|
<mxGeometry x="103.5" y="42" width="97" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-43" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-37" vertex="1">
|
||||||
|
<mxGeometry x="131.5" y="159" width="41" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-44" value="Tables" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-37" vertex="1">
|
||||||
|
<mxGeometry x="15" y="98.5" width="53" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-59" value="Finate State Automation" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
|
||||||
|
<mxGeometry x="721" y="175.5" width="146" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-60" value="Push Down Automation" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
|
||||||
|
<mxGeometry x="726" y="490" width="143" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-131" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-82" target="Knp0EVw5rfMEdcPhjhnq-37" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-134" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-82" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="24.947368421052943" y="591.5" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-82" value="CFG Compiler" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
|
||||||
|
<mxGeometry x="93" y="448.5" width="281" height="286" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-88" value="CF Comp Rules" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
|
||||||
|
<mxGeometry x="7" y="130" width="103" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-90" value="Tables" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
|
||||||
|
<mxGeometry x="210" y="132.5" width="53" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="LL" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-91">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
|
||||||
|
<mxGeometry x="116" y="51.75" width="83" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<UserObject label="Canonical" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-92">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
|
||||||
|
<mxGeometry x="116" y="119.75" width="83" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<UserObject label="LALR" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-93">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
|
||||||
|
<mxGeometry x="116" y="187.75" width="83" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-132" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-94" target="Knp0EVw5rfMEdcPhjhnq-13" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-133" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-94" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="24.947368421052943" y="272.5" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-94" value="RE Compiler" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;startSize=23;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
|
||||||
|
<mxGeometry x="122" y="228.25" width="260" height="88.5" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-95" value="RE Compiler Rulles" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-94" vertex="1">
|
||||||
|
<mxGeometry x="13" y="33.75" width="123" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-96" value="Tables" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-94" vertex="1">
|
||||||
|
<mxGeometry x="187" y="39.5" width="53" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-154" value="Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
|
||||||
|
<mxGeometry x="21" y="149.5" width="69" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-56" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-13" target="Knp0EVw5rfMEdcPhjhnq-154" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="94" y="166" as="targetPoint" />
|
||||||
|
<Array as="points">
|
||||||
|
<mxPoint x="626" y="104" />
|
||||||
|
<mxPoint x="281" y="104" />
|
||||||
|
<mxPoint x="281" y="166" />
|
||||||
|
</Array>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-57" value="Get Symbol" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="Knp0EVw5rfMEdcPhjhnq-56" vertex="1" connectable="0">
|
||||||
|
<mxGeometry x="-0.0483" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-127" value="Compiler API Rulles To parse Regular grammar Rulles" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;startSize=23;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="285" y="1720" width="385" height="158" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="RE Compiler API Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-128">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-127" vertex="1">
|
||||||
|
<mxGeometry x="24" y="37.5" width="340" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<UserObject label="CF Compiler API Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-129">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-127" vertex="1">
|
||||||
|
<mxGeometry x="24" y="98.5" width="340" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-162" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-130" target="Knp0EVw5rfMEdcPhjhnq-151" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="User Sentence" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-130">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="1063" y="1056" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-138" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="622" y="1273" width="337" height="173" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-139" value="CF AST Rulles for Tokenizer" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-138" vertex="1">
|
||||||
|
<mxGeometry x="19" y="80" width="168" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-140" value="CF AST Rulles for an acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-138" vertex="1">
|
||||||
|
<mxGeometry x="19" y="125" width="180" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-141" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-138" vertex="1">
|
||||||
|
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-142" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-138" vertex="1">
|
||||||
|
<mxGeometry x="265" y="73.5" width="41" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-143" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="714" y="1645" width="337" height="173" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-144" value="CF AST Rulles for Tokenizer" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-143" vertex="1">
|
||||||
|
<mxGeometry x="19" y="80" width="168" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-145" value="CF AST Rulles for an acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-143" vertex="1">
|
||||||
|
<mxGeometry x="19" y="125" width="180" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-146" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-143" vertex="1">
|
||||||
|
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-147" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-143" vertex="1">
|
||||||
|
<mxGeometry x="265" y="73.5" width="41" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-148" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="1391" y="1401" width="337" height="173" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-149" value="RE Compiler API Rulles for FSA" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-148" vertex="1">
|
||||||
|
<mxGeometry x="36" y="79.75" width="189" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-150" value="CF Compiler API Rulles for an PDA acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-148" vertex="1">
|
||||||
|
<mxGeometry x="36" y="124" width="255" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-151" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-148" vertex="1">
|
||||||
|
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-152" value="Sentence AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-148" vertex="1">
|
||||||
|
<mxGeometry x="229" y="35" width="95" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-155" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-129" target="Knp0EVw5rfMEdcPhjhnq-145" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-156" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-128" target="Knp0EVw5rfMEdcPhjhnq-144" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-159" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-124" target="Knp0EVw5rfMEdcPhjhnq-139" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-160" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-125" target="Knp0EVw5rfMEdcPhjhnq-140" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-165" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="B2JnEC1cqt8830IlIT0b-3" target="Knp0EVw5rfMEdcPhjhnq-149" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-166" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="B2JnEC1cqt8830IlIT0b-1" target="Knp0EVw5rfMEdcPhjhnq-150" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Knp0EVw5rfMEdcPhjhnq-167" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-152" target="Knp0EVw5rfMEdcPhjhnq-168" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="1909.9999999999995" y="1483" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="User AST" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-168">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="1977" y="1190" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-2" value="" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="Knp0EVw5rfMEdcPhjhnq-147" target="B2JnEC1cqt8830IlIT0b-1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="1020" y="1732" as="sourcePoint" />
|
||||||
|
<mxPoint x="1408" y="1535" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="AST to CF Compiler API" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-1">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="1117" y="1613" width="197" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-4" value="" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="Knp0EVw5rfMEdcPhjhnq-142" target="B2JnEC1cqt8830IlIT0b-3">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="1032" y="1311" as="sourcePoint" />
|
||||||
|
<mxPoint x="1408" y="1490" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="AST to RE Compiler API" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-3">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="1107" y="1470.5" width="197" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-41" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-42" target="B2JnEC1cqt8830IlIT0b-56">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="Language Grammar <br>(CF RE United Format)" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-42">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="422" y="2209" width="179" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-45" value="Grammar For CF RE United Grammar Format" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;startSize=23;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="253" y="2439" width="384" height="158" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="RE Compiler API Rulles" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-46">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-45">
|
||||||
|
<mxGeometry x="24" y="37.5" width="332" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<UserObject label="CF Compiler API Rulles" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-47">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-45">
|
||||||
|
<mxGeometry x="24" y="98.5" width="336" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-51" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-52" target="B2JnEC1cqt8830IlIT0b-66">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="User Sentence" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-52">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="422" y="2132" width="180" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-53" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="700" y="2361" width="337" height="173" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-54" value="CF AST Rulles for Tokenizer" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-53">
|
||||||
|
<mxGeometry x="19" y="80" width="168" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-55" value="CF AST Rulles for an acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-53">
|
||||||
|
<mxGeometry x="19" y="125" width="180" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-56" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-53">
|
||||||
|
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-57" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-53">
|
||||||
|
<mxGeometry x="265" y="73.5" width="41" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-63" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="1415" y="2271" width="337" height="173" as="geometry">
|
||||||
|
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-64" value="RE Compiler API Rulles for FSA" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-63">
|
||||||
|
<mxGeometry x="36" y="79.75" width="189" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-65" value="CF Compiler API Rulles for an PDA acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-63">
|
||||||
|
<mxGeometry x="36" y="124" width="255" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-66" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-63">
|
||||||
|
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-67" value="Sentence AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-63">
|
||||||
|
<mxGeometry x="229" y="35" width="95" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-70" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-46" target="B2JnEC1cqt8830IlIT0b-54">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-71" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-47" target="B2JnEC1cqt8830IlIT0b-55">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-72" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-79" target="B2JnEC1cqt8830IlIT0b-64">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-73" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-77" target="B2JnEC1cqt8830IlIT0b-65">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-74" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-67" target="B2JnEC1cqt8830IlIT0b-75">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="1933.9999999999995" y="2353" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="User AST" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-75">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="2001" y="2060" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-76" value="" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-57" target="B2JnEC1cqt8830IlIT0b-77">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="1044" y="2601.5" as="sourcePoint" />
|
||||||
|
<mxPoint x="1432" y="2405" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="AST to CF Compiler API" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-77">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="1141" y="2483" width="197" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
<mxCell id="B2JnEC1cqt8830IlIT0b-78" value="" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-57" target="B2JnEC1cqt8830IlIT0b-79">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="1056" y="2181" as="sourcePoint" />
|
||||||
|
<mxPoint x="1432" y="2360" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<UserObject label="AST to RE Compiler API" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-79">
|
||||||
|
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};labelBackgroundColor=none;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="1151" y="2371" width="197" height="46.5" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</UserObject>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
||||||
BIN
.docs/Gallery/Oscript.gif
Normal file
BIN
.docs/Gallery/Oscript.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
.docs/Gallery/RayTracer.png
Normal file
BIN
.docs/Gallery/RayTracer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 416 KiB |
BIN
.docs/Gallery/RayTracerLua.png
Normal file
BIN
.docs/Gallery/RayTracerLua.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
.docs/Gallery/Sketch3D.gif
Normal file
BIN
.docs/Gallery/Sketch3D.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
16
.docs/Gallery/oscript.txt
Normal file
16
.docs/Gallery/oscript.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
method myLogFunction(value) {
|
||||||
|
print value;
|
||||||
|
}
|
||||||
|
|
||||||
|
myLogFunction("hello");
|
||||||
|
|
||||||
|
var i = 10;
|
||||||
|
|
||||||
|
if (i == 10) {
|
||||||
|
while (i > 0) {
|
||||||
|
print i;
|
||||||
|
i = i - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print "still doin' heavy calculations...";
|
||||||
|
}
|
||||||
17
.github/workflows/WindowsPlatform.yml
vendored
Normal file
17
.github/workflows/WindowsPlatform.yml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
name: Windows
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: self-hosted
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
#- name: Build
|
||||||
|
#run: echo hello
|
||||||
62
.github/workflows/cmake-single-platform.yml
vendored
Normal file
62
.github/workflows/cmake-single-platform.yml
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage.
|
||||||
|
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml
|
||||||
|
name: CMake on a single platform
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
|
||||||
|
# You can convert this to a matrix build if you need cross-platform coverage.
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Sutup Dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install python3 python-is-python3
|
||||||
|
sudo apt-get install -y libx11-dev libgl1-mesa-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
|
||||||
|
sudo apt-get install -y clang-15
|
||||||
|
sudo apt-get install -y libasound2-dev libglew-dev
|
||||||
|
sudo apt-get install -y portaudio19-dev
|
||||||
|
sudo apt-get install -y libwayland-dev libxkbcommon-dev
|
||||||
|
|
||||||
|
- name: install OpenImageDenoise
|
||||||
|
run: |
|
||||||
|
sudo snap install ispc
|
||||||
|
sudo apt-get install -y libtbb-dev
|
||||||
|
git clone --recursive https://github.com/RenderKit/oidn.git
|
||||||
|
cd oidn
|
||||||
|
mkdir build; cd build; cmake ..; make -j;
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
- name: Update repository
|
||||||
|
run: |
|
||||||
|
git submodule update --init --recursive
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||||
|
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
# Build your program with the given configuration
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -- -j$(nproc)
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
working-directory: ${{github.workspace}}/build
|
||||||
|
# Execute tests defined by the CMake configuration.
|
||||||
|
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||||
|
run: ctest -C ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
68
.github/workflows/cmake.yml
vendored
68
.github/workflows/cmake.yml
vendored
|
|
@ -18,41 +18,47 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup externals
|
- name: Setup
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
# If your submodules are configured to use SSH instead of HTTPS please uncomment the following line
|
# If your submodules are configured to use SSH instead of HTTPS please uncomment the following line
|
||||||
# git config --global url."https://github.com/".insteadOf "git@github.com:"
|
# git config --global url."https://github.com/".insteadOf "git@github.com:"
|
||||||
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
|
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
|
||||||
git submodule sync --recursive
|
|
||||||
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
|
|
||||||
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install python3 python-is-python3
|
|
||||||
sudo apt-get install -y libx11-dev libgl1-mesa-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
|
|
||||||
|
|
||||||
cd Externals/glew/
|
|
||||||
make extensions
|
|
||||||
|
|
||||||
- name: Set LLVM Toolchain
|
|
||||||
run: |
|
|
||||||
sudo apt-get install -y llvm
|
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 10
|
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 20
|
|
||||||
|
|
||||||
- name: Configure CMake
|
git submodule sync --recursive
|
||||||
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install python3 python-is-python3
|
||||||
|
sudo apt-get install -y libx11-dev libgl1-mesa-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
|
||||||
|
sudo apt-get install -y clang-15
|
||||||
|
sudo apt-get install -y libasound2-dev libglew-dev
|
||||||
|
sudo apt-get install -y portaudio19-dev
|
||||||
|
#cd Externals/glew/
|
||||||
|
#make extensions
|
||||||
|
sudo apt update
|
||||||
|
|
||||||
- name: Build
|
#- name: Set LLVM Toolchain
|
||||||
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
#run: |
|
||||||
|
# sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 10
|
||||||
|
# sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 20
|
||||||
|
|
||||||
- name: Test
|
- name: Configure CMake
|
||||||
working-directory: ${{github.workspace}}/build
|
run: |
|
||||||
# Execute tests defined by the CMake configuration.
|
gcc -v
|
||||||
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
clang++-15 -v
|
||||||
run: ctest -C ${{env.BUILD_TYPE}}
|
CC=clang-15 CXX=clang++-15 cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: CC=clang CXX=clang++ cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -v -j
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
working-directory: ${{github.workspace}}/build
|
||||||
|
# Execute tests defined by the CMake configuration.
|
||||||
|
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||||
|
run: ctest -j -C ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -2,6 +2,11 @@
|
||||||
*tmp*
|
*tmp*
|
||||||
bin
|
bin
|
||||||
build*
|
build*
|
||||||
|
*build*
|
||||||
lib
|
lib
|
||||||
install
|
install
|
||||||
.vscode
|
.vscode
|
||||||
|
out
|
||||||
|
.vs
|
||||||
|
*.bkp
|
||||||
|
*.$*
|
||||||
|
|
|
||||||
37
.gitmodules
vendored
37
.gitmodules
vendored
|
|
@ -1,15 +1,30 @@
|
||||||
[submodule "Externals/asio"]
|
|
||||||
path = Externals/asio
|
|
||||||
url = https://github.com/IlyaShurupov/asio.git
|
|
||||||
[submodule "Externals/glfw"]
|
|
||||||
path = Externals/glfw
|
|
||||||
url = https://github.com/IlyaShurupov/glfw.git
|
|
||||||
[submodule "Externals/imgui"]
|
[submodule "Externals/imgui"]
|
||||||
path = Externals/imgui
|
path = Externals/imgui
|
||||||
url = https://github.com/IlyaShurupov/imgui.git
|
url = https://github.com/elushaX/imgui.git
|
||||||
[submodule "Externals/glew"]
|
[submodule "Externals/lua"]
|
||||||
path = Externals/glew
|
path = Externals/lua
|
||||||
url = https://github.com/IlyaShurupov/glew.git
|
url = https://github.com/elushaX/lua.git
|
||||||
|
[submodule "Externals/unittest-cpp"]
|
||||||
|
path = Externals/unittest-cpp
|
||||||
|
url = https://github.com/elushaX/unittest-cpp.git
|
||||||
|
[submodule "Externals/glfw"]
|
||||||
|
path = Externals/glfw
|
||||||
|
url = https://github.com/elushaX/glfw.git
|
||||||
[submodule "Externals/nanovg"]
|
[submodule "Externals/nanovg"]
|
||||||
path = Externals/nanovg
|
path = Externals/nanovg
|
||||||
url = https://github.com/IlyaShurupov/nanovg.git
|
url = https://github.com/elushaX/nanovg.git
|
||||||
|
[submodule "Externals/lalr"]
|
||||||
|
path = Externals/lalr
|
||||||
|
url = https://github.com/elushaX/lalr.git
|
||||||
|
[submodule "Externals/asio"]
|
||||||
|
path = Externals/asio
|
||||||
|
url = https://github.com/elushaX/asio.git
|
||||||
|
[submodule "Externals/implot"]
|
||||||
|
path = Externals/implot
|
||||||
|
url = https://github.com/epezent/implot.git
|
||||||
|
[submodule "Externals/googletest"]
|
||||||
|
path = Externals/googletest
|
||||||
|
url = https://github.com/google/googletest.git
|
||||||
|
[submodule "Externals/benchmark"]
|
||||||
|
path = Externals/benchmark
|
||||||
|
url = https://github.com/google/benchmark.git
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "rect.h"
|
|
||||||
#include "color.h"
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
|
|
||||||
extern bool gInTransition;
|
|
||||||
|
|
||||||
struct AnimValue {
|
|
||||||
halnf mValPrev = 0;
|
|
||||||
halnf mVal = 0;
|
|
||||||
time_ms mTimeStart = 0;
|
|
||||||
halni mTimeAnim = 250;
|
|
||||||
|
|
||||||
halnf interpolate() const;
|
|
||||||
|
|
||||||
AnimValue();
|
|
||||||
AnimValue(halnf val);
|
|
||||||
|
|
||||||
halnf prev() { return mValPrev; }
|
|
||||||
void set(halnf val);
|
|
||||||
void setNoTransition(halnf);
|
|
||||||
void setAnimTime(halni time);
|
|
||||||
halnf get() const;
|
|
||||||
halnf getTarget() const;
|
|
||||||
bool inTransition() const;
|
|
||||||
explicit operator halnf() const;
|
|
||||||
void operator=(halnf val);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AnimRect : rect<AnimValue> {
|
|
||||||
|
|
||||||
AnimRect() {
|
|
||||||
set({ 0, 0, 0, 0 });
|
|
||||||
setAnimTime(450);
|
|
||||||
}
|
|
||||||
|
|
||||||
rectf get() const;
|
|
||||||
rectf getTarget() const;
|
|
||||||
void setNoTransition(rectf);
|
|
||||||
void set(const rectf&);
|
|
||||||
void setAnimTime(halni time_ms);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AnimColor {
|
|
||||||
AnimRect mColor;
|
|
||||||
rgba get() const;
|
|
||||||
void set(const rgba&);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "stringt.h"
|
|
||||||
#include "fbuffer.h"
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
class Canvas {
|
|
||||||
|
|
||||||
typedef rectf Rect;
|
|
||||||
typedef vec2f Vec2;
|
|
||||||
typedef rgba Col;
|
|
||||||
typedef tp::halnf Val;
|
|
||||||
|
|
||||||
Col mColorPrimary;
|
|
||||||
Col mColorSecondary;
|
|
||||||
|
|
||||||
void* mCtx = NULL;
|
|
||||||
tp::halnf mDpmm = 1;
|
|
||||||
tp::halnf mUIScale = 1;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Rect mClamping;
|
|
||||||
Rect mVieport;
|
|
||||||
|
|
||||||
enum Align : uint4 {
|
|
||||||
LEFT = 1 << 0, // Default, horizontally to left.
|
|
||||||
CENTER = 1 << 1, // horizontally to center.
|
|
||||||
RIGHT = 1 << 2, // horizontally to right.
|
|
||||||
TOP = 1 << 3, // vertically to top.
|
|
||||||
MIDDLE = 1 << 4, // vertically to middle.
|
|
||||||
BOTTOM = 1 << 5, // vertically to bottom.
|
|
||||||
BASELINE = 1 << 6, // Default, vertically to baseline.
|
|
||||||
CENTER_MIDDLE = CENTER | MIDDLE,
|
|
||||||
LEFT_MIDDLE = LEFT | MIDDLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
Canvas();
|
|
||||||
|
|
||||||
Val& convert2pxls(Val&);
|
|
||||||
Rect& convert2pxls(Rect&);
|
|
||||||
Vec2& convert2pxls(Vec2&);
|
|
||||||
Val as2pxls(Val);
|
|
||||||
|
|
||||||
// Canvas Manipulation
|
|
||||||
void beginDraw(Rect viewport, tp::halnf dpmm, tp::halnf uiscale);
|
|
||||||
void clear(Col color = 0);
|
|
||||||
void endDraw();
|
|
||||||
|
|
||||||
void setClamping(Rect rec);
|
|
||||||
void resetViewport();
|
|
||||||
|
|
||||||
// Params control
|
|
||||||
void setCol1(const Col& col);
|
|
||||||
void setCol2(const Col& col);
|
|
||||||
|
|
||||||
// Shapes
|
|
||||||
void rect(Rect rec, halnf rounding = 0, halnf borders = 0);
|
|
||||||
void circle(Vec2 rec, halnf radius, halnf borders = 0);
|
|
||||||
void trig(Vec2 p1, Vec2 p2, Vec2 p3);
|
|
||||||
void line(Vec2 p1, Vec2 p2, halnf thikness = 2);
|
|
||||||
|
|
||||||
// Text
|
|
||||||
void text(const string text, Rect rec, halnf size, Align align = Align::CENTER_MIDDLE);
|
|
||||||
void text(const char* start, const char* end, Rect rec, halnf size, Align align = Align::CENTER_MIDDLE);
|
|
||||||
|
|
||||||
void drawColorwheel(Rect rec, const rgb& col);
|
|
||||||
|
|
||||||
// image
|
|
||||||
struct ImageHandle {
|
|
||||||
halni mId = NULL;
|
|
||||||
void createFromBuff(glw::fbuffer* buff, Canvas* drawer);
|
|
||||||
void free(Canvas* drawer);
|
|
||||||
~ImageHandle();
|
|
||||||
};
|
|
||||||
|
|
||||||
void drawImage(Rect rec, ImageHandle* image, halnf angle = 0.f, halnf alpha = 1.f, halnf rounding = 0.f);
|
|
||||||
|
|
||||||
~Canvas();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
|
|
||||||
#include "window.h"
|
|
||||||
|
|
||||||
namespace ImGui {
|
|
||||||
|
|
||||||
bool SubMenuBegin(const char* desc, int level);
|
|
||||||
void SubMenuEnd(int level);
|
|
||||||
|
|
||||||
void ToolTip(const char* desc);
|
|
||||||
|
|
||||||
struct PopupData {
|
|
||||||
bool opened = false;
|
|
||||||
bool ishovered = false;
|
|
||||||
tp::vec2f p1 = 0;
|
|
||||||
tp::vec2f p2 = 0;
|
|
||||||
operator bool() {
|
|
||||||
return opened;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PopupData HoverPopupBeginButton(const char* id, tp::vec2f butsize = 200, tp::vec2f popupsize = 200);
|
|
||||||
PopupData HoverPopupBegin(const char* id, tp::vec2f size = 200, tp::vec2f pos = -1, int flags = 0);
|
|
||||||
void HoverPopupEnd(PopupData& in);
|
|
||||||
|
|
||||||
void ApplyStyle(tp::halnf dpmm, float font_size_mm = 5, float ui_scale = 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
|
|
||||||
typedef void (DebugUiDrawCallBack)(void* cd);
|
|
||||||
|
|
||||||
struct DebugUI {
|
|
||||||
tp::halnf mDPMM = 1;
|
|
||||||
tp::halnf mFontSizeMM = 3;
|
|
||||||
tp::halnf mUIScale = 1;
|
|
||||||
|
|
||||||
DebugUiDrawCallBack* cb = NULL;
|
|
||||||
void* cd = NULL;
|
|
||||||
|
|
||||||
struct DebugUiInternalContext* mCtx = NULL;
|
|
||||||
|
|
||||||
DebugUI(Window& window, DebugUiDrawCallBack* acb, void* acd);
|
|
||||||
void drawDebugUI(tp::halnf dpmm);
|
|
||||||
~DebugUI();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "rect.h"
|
|
||||||
#include "color.h"
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
class fbuffer {
|
|
||||||
|
|
||||||
uint4 mFrameBufferID = 0; // regroups 0, 1, or more textures, and 0 or 1 depth buffer.
|
|
||||||
uint4 mTextureId = 0; // texture we're going to render to ( colour attachement #0 )
|
|
||||||
uint4 mDepthBufferID = 0;
|
|
||||||
uint4 mDrawBuffers[1];
|
|
||||||
|
|
||||||
vec2f mSize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
rgba mClearCol = 0.f;
|
|
||||||
|
|
||||||
fbuffer(const vec2f& size);
|
|
||||||
fbuffer(const vec2f& size, tp::uint1 samples);
|
|
||||||
|
|
||||||
void beginDraw();
|
|
||||||
void setViewport(const rectf& viewport);
|
|
||||||
void clear();
|
|
||||||
void endDraw();
|
|
||||||
|
|
||||||
uint4 texId() const;
|
|
||||||
uint4 buffId() const;
|
|
||||||
|
|
||||||
const vec2f& getSize() const;
|
|
||||||
uhalni sizeAllocatedMem() const;
|
|
||||||
uhalni sizeUsedMem() const;
|
|
||||||
|
|
||||||
~fbuffer();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
class shader {
|
|
||||||
|
|
||||||
uint4 programm;
|
|
||||||
uint4 VertexShaderID;
|
|
||||||
uint4 FragmentShaderID;
|
|
||||||
uint4 GeometryShaderID;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool compile_shader(const char* ShaderCode, uint4 ShaderID);
|
|
||||||
void load(const char* vert, const char* geom, const char* frag, bool paths);
|
|
||||||
|
|
||||||
shader();
|
|
||||||
|
|
||||||
void vert_bind_source(const char* vert_src);
|
|
||||||
void frag_bind_source(const char* frag_src);
|
|
||||||
void geom_bind_source(const char* geom_src);
|
|
||||||
|
|
||||||
void compile();
|
|
||||||
|
|
||||||
shader(const char* vertid, const char* geomid, const char* fragid, bool paths = true);
|
|
||||||
void bind();
|
|
||||||
uint4 getu(const char* uid);
|
|
||||||
void unbind();
|
|
||||||
~shader();
|
|
||||||
|
|
||||||
alni sizeAllocatedMem();
|
|
||||||
alni sizeUsedMem();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "window.h"
|
|
||||||
#include "canvas.h"
|
|
||||||
#include "animations.h"
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
|
|
||||||
class WindowSimpleInputs {
|
|
||||||
enum class Mouse : uint1 { NONE, PRESSED, HOLD, RELEASED } mMouse;
|
|
||||||
enum class Move : uint1 { NONE, LEFT, RIGHT, UP, DOWN } mMove;
|
|
||||||
public:
|
|
||||||
|
|
||||||
halnf mScaleVal = 0;
|
|
||||||
vec2f mWindowSizeMM;
|
|
||||||
vec2f mCrs;
|
|
||||||
vec2f mCrsPrev;
|
|
||||||
vec2f mCrsmDelta;
|
|
||||||
halnf mPressure = 0.f;
|
|
||||||
|
|
||||||
void update(const glw::Window& window, halnf uiscale);
|
|
||||||
bool Activated();
|
|
||||||
bool Anticipating();
|
|
||||||
bool Selected();
|
|
||||||
bool MoveLeft();
|
|
||||||
bool MoveRight();
|
|
||||||
bool MoveUp();
|
|
||||||
bool MoveDown();
|
|
||||||
bool Drag();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ButtonWidget {
|
|
||||||
rectf mRect = { 0.f, 10.f };
|
|
||||||
rgba mCol = { 0.3f, 0.3f, 0.3f, 1.f };
|
|
||||||
bool mPressed = false;
|
|
||||||
AnimRect mAnimRec;
|
|
||||||
void draw(glw::Canvas& canvas);
|
|
||||||
void proc(glw::WindowSimpleInputs& inputs);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CheckBoxWidget {
|
|
||||||
rectf mRect = { 0.f, 10.f };
|
|
||||||
rgba mCol = { 0.3f, 0.3f, 0.3f, 1.f };
|
|
||||||
rgba mColActive = { 0.5f, 0.5f, 0.5f, 1.f };
|
|
||||||
|
|
||||||
bool mValue = false;
|
|
||||||
AnimRect mAnimRec;
|
|
||||||
AnimColor mAnimCol;
|
|
||||||
|
|
||||||
void draw(glw::Canvas& canvas);
|
|
||||||
void proc(glw::WindowSimpleInputs& inputs);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WindowsHeaderWidget {
|
|
||||||
rectf header_rec = { 10, 10, 50, 10 };
|
|
||||||
rgba col = { 0.13f, 0.13f, 0.13f, 0.9f };
|
|
||||||
rectf grab_rec = 0.f;
|
|
||||||
|
|
||||||
ButtonWidget mExitButton;
|
|
||||||
ButtonWidget mMaxButton;
|
|
||||||
ButtonWidget mMinButton;
|
|
||||||
CheckBoxWidget mPinButton;
|
|
||||||
|
|
||||||
void updRecs();
|
|
||||||
void draw(glw::Canvas& canvas);
|
|
||||||
void proc(glw::Window& window, glw::WindowSimpleInputs& inputs);
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "array2d.h"
|
|
||||||
#include "color.h"
|
|
||||||
#include "vec.h"
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
class texture {
|
|
||||||
uint4 id;
|
|
||||||
public:
|
|
||||||
|
|
||||||
texture();
|
|
||||||
~texture();
|
|
||||||
|
|
||||||
uint4 getid();
|
|
||||||
void update(const Array2D<rgba>& buff);
|
|
||||||
void draw(const uint4& out = 0);
|
|
||||||
|
|
||||||
alni sizeAllocatedMem();
|
|
||||||
alni sizeUsedMem();
|
|
||||||
|
|
||||||
static void init();
|
|
||||||
static void deinit();
|
|
||||||
static void draw_texture(uint4 out, uint4 in);
|
|
||||||
static uint4 get_tex(const char* TexId);
|
|
||||||
static void drawCurcle(vec2f pos, double radius, rgba col);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "vec.h"
|
|
||||||
#include "rect.h"
|
|
||||||
#include "color.h"
|
|
||||||
#include "stringt.h"
|
|
||||||
#include "array.h"
|
|
||||||
#include "map.h"
|
|
||||||
|
|
||||||
#include "keycodes.h"
|
|
||||||
#include "queue.h"
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
|
|
||||||
extern tp::ModuleManifest gModuleGlw;
|
|
||||||
|
|
||||||
namespace glw {
|
|
||||||
|
|
||||||
struct PlatformContext;
|
|
||||||
|
|
||||||
class Window {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct Device {
|
|
||||||
time_ms FrameRate = NULL; // monitor fps
|
|
||||||
vec2f Size; // size of the monitor
|
|
||||||
tp::halnf mDPMM = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Events {
|
|
||||||
tp::Queue<KeyEvent> mKeysQueue;
|
|
||||||
tp::uhalni mRedraw = 2;
|
|
||||||
bool mClose = false;
|
|
||||||
|
|
||||||
vec2f mCursor = 0;
|
|
||||||
halnf mPressure = 1.f;
|
|
||||||
|
|
||||||
vec2f mCursorPrev = 0.f;
|
|
||||||
halnf mPressurePrev = 1.f;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Appearence {
|
|
||||||
vec2f mPos = { 100.f, 100.f }; // global position
|
|
||||||
vec2f mSize = { 300.f, 300.f }; // width and height of window
|
|
||||||
vec2f mSizeMin = { 100.f, 100.f }; // min size possiable
|
|
||||||
vec2f mSizeMax = { 700.f, 700.f }; // max size possiable
|
|
||||||
|
|
||||||
bool mHiden = true;
|
|
||||||
bool mMaximized = false;
|
|
||||||
bool mMinimized = false;
|
|
||||||
bool mTopZ = false;
|
|
||||||
bool mAllDesktops = false;
|
|
||||||
|
|
||||||
rgba mResizeColor = rgba(0.13f, 0.13f, 0.13f, 0.9f);
|
|
||||||
|
|
||||||
rectf mMinMaxBox;
|
|
||||||
|
|
||||||
tp::Array<rectf> mCaptionsAddArea;
|
|
||||||
tp::Array<rectf> mCaptionsRemoveArea;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
PlatformContext* mPlatformCtx = NULL;
|
|
||||||
void platformCallback();
|
|
||||||
void* platform_window() const;
|
|
||||||
|
|
||||||
struct NativeEventListenerCallback {
|
|
||||||
typedef void (call_back_func)(PlatformContext* ctx, void* cd);
|
|
||||||
call_back_func* exec_begin = NULL;
|
|
||||||
call_back_func* exec = NULL;
|
|
||||||
call_back_func* exec_end = NULL;
|
|
||||||
void* cd = NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
tp::HashMap<NativeEventListenerCallback, string> mNativeEventListeners;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
struct Cache {
|
|
||||||
Appearence mAppearencePrev;
|
|
||||||
vec2f mWindowSize = 0;
|
|
||||||
rectf mRectBeforResizing = 0;
|
|
||||||
bool mUserResizing = false;
|
|
||||||
bool mMinMaxHover = false;
|
|
||||||
bool mMouseTracked = false;
|
|
||||||
} mCache;
|
|
||||||
|
|
||||||
void applyAppearance();
|
|
||||||
void initialize();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static Device mDevice;
|
|
||||||
Appearence mAppearence;
|
|
||||||
Events mEvents;
|
|
||||||
|
|
||||||
Window();
|
|
||||||
Window(const Appearence& aAppearence);
|
|
||||||
|
|
||||||
void pollEvents();
|
|
||||||
void beginDraw();
|
|
||||||
void endDraw();
|
|
||||||
|
|
||||||
alni sizeAllocatedMem();
|
|
||||||
alni sizeUsedMem();
|
|
||||||
|
|
||||||
~Window();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "queue.h"
|
|
||||||
|
|
||||||
struct AndroidApi {
|
|
||||||
|
|
||||||
union Event {
|
|
||||||
|
|
||||||
enum Type : tp::uint1 {
|
|
||||||
EV_NONE = 0,
|
|
||||||
} type = EV_NONE;
|
|
||||||
|
|
||||||
struct None {
|
|
||||||
|
|
||||||
} none;
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
tp::Queue<Event> events;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
extern AndroidApi* gAndroidApi;
|
|
||||||
|
|
@ -1,804 +0,0 @@
|
||||||
|
|
||||||
// Copyright (C) 2010 The Android Open Source Project
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// own headers
|
|
||||||
#include "window.h"
|
|
||||||
|
|
||||||
#include "GraphicsLibApi.h"
|
|
||||||
|
|
||||||
// STL
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
// jni
|
|
||||||
//#include <initializer_list>
|
|
||||||
//#include <memory>
|
|
||||||
//#include <cstdlib>
|
|
||||||
//#include <cstring>
|
|
||||||
#include <jni.h>
|
|
||||||
//#include <cerrno>
|
|
||||||
//#include <cassert>
|
|
||||||
|
|
||||||
// opengl
|
|
||||||
#include <EGL/egl.h>
|
|
||||||
#include <GLES3/gl32.h>
|
|
||||||
//#include "GL/glew.h"
|
|
||||||
|
|
||||||
// glue
|
|
||||||
#include <android/sensor.h>
|
|
||||||
#include <android/log.h>
|
|
||||||
#include <android/input.h>
|
|
||||||
#include <../../../android/native_app_glue/android_native_app_glue.h>
|
|
||||||
|
|
||||||
// AcquireASensorManagerInstance
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
|
|
||||||
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
|
|
||||||
|
|
||||||
// application side entry point
|
|
||||||
int main();
|
|
||||||
|
|
||||||
// first function to be called in "main thread"
|
|
||||||
void* main_wrap(void* p);
|
|
||||||
|
|
||||||
// AcquireASensorManagerInstance(void)
|
|
||||||
// Workaround ASensorManager_getInstance() deprecation false alarm
|
|
||||||
// for Android-N and before, when compiling with NDK-r15
|
|
||||||
ASensorManager* AcquireASensorManagerInstance(android_app* app) {
|
|
||||||
|
|
||||||
if (!app)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
typedef ASensorManager* (*PF_GETINSTANCEFORPACKAGE)(const char* name);
|
|
||||||
void* androidHandle = dlopen("libandroid.so", RTLD_NOW);
|
|
||||||
auto getInstanceForPackageFunc = (PF_GETINSTANCEFORPACKAGE)
|
|
||||||
dlsym(androidHandle, "ASensorManager_getInstanceForPackage");
|
|
||||||
if (getInstanceForPackageFunc) {
|
|
||||||
JNIEnv* env = nullptr;
|
|
||||||
app->activity->vm->AttachCurrentThread(&env, nullptr);
|
|
||||||
|
|
||||||
jclass android_content_Context = env->GetObjectClass(app->activity->clazz);
|
|
||||||
jmethodID midGetPackageName = env->GetMethodID(android_content_Context,
|
|
||||||
"getPackageName",
|
|
||||||
"()Ljava/lang/String;");
|
|
||||||
auto packageName = (jstring)env->CallObjectMethod(app->activity->clazz,
|
|
||||||
midGetPackageName);
|
|
||||||
|
|
||||||
const char* nativePackageName = env->GetStringUTFChars(packageName, nullptr);
|
|
||||||
ASensorManager* mgr = getInstanceForPackageFunc(nativePackageName);
|
|
||||||
env->ReleaseStringUTFChars(packageName, nativePackageName);
|
|
||||||
app->activity->vm->DetachCurrentThread();
|
|
||||||
if (mgr) {
|
|
||||||
dlclose(androidHandle);
|
|
||||||
return mgr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef ASensorManager* (*PF_GETINSTANCE)();
|
|
||||||
auto getInstanceFunc = (PF_GETINSTANCE)
|
|
||||||
dlsym(androidHandle, "ASensorManager_getInstance");
|
|
||||||
// by all means at this point, ASensorManager_getInstance should be available
|
|
||||||
assert(getInstanceFunc);
|
|
||||||
dlclose(androidHandle);
|
|
||||||
|
|
||||||
return getInstanceFunc();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GL_APIENTRY MessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
|
|
||||||
DBG_BREAK(true);
|
|
||||||
LOGW("GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, severity, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
char const* gl_error_string(GLenum const err) {
|
|
||||||
switch (err) {
|
|
||||||
case GL_NO_ERROR: return "GL_NO_ERROR";
|
|
||||||
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
|
|
||||||
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
|
|
||||||
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
|
|
||||||
case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW";
|
|
||||||
case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW";
|
|
||||||
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
|
|
||||||
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION";
|
|
||||||
default: return "unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void glerr(GLenum type) {
|
|
||||||
DBG_BREAK(true);
|
|
||||||
const GLchar* message = gl_error_string(type);
|
|
||||||
LOGW("GL CALLBACK: %s type = 0x%x, message = %s\n", (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void glerr(GLenum type);
|
|
||||||
#define AssertGL(x) { x; GLenum __gle = glGetError(); if (__gle != GL_NO_ERROR) glerr(__gle); }
|
|
||||||
|
|
||||||
// --------------------------------- Data --------------------------------------- //
|
|
||||||
|
|
||||||
struct MutexEvent {
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
tp::glw::Window* active_windw;
|
|
||||||
bool parent_thread_has_events = false;
|
|
||||||
bool child_whaiting = false;
|
|
||||||
} mutex_event;
|
|
||||||
|
|
||||||
struct ANativeActivityCtx* android_ctx = NULL;
|
|
||||||
|
|
||||||
tp::glw::Window::Device tp::glw::Window::mDevice;
|
|
||||||
extern const char* g_android_internal_data_path;
|
|
||||||
|
|
||||||
static pthread_t worker_thread;
|
|
||||||
static pthread_mutex_t worker_finished_mutex;
|
|
||||||
static pthread_cond_t worker_finished_cond;
|
|
||||||
static bool worker_finished = false;
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
struct PlatformContext {
|
|
||||||
|
|
||||||
int col = 255;
|
|
||||||
|
|
||||||
EGLint w, h, format;
|
|
||||||
EGLint numConfigs;
|
|
||||||
EGLConfig config = nullptr;
|
|
||||||
EGLSurface surface;
|
|
||||||
EGLContext context;
|
|
||||||
EGLDisplay display = nullptr;
|
|
||||||
|
|
||||||
AInputEvent* chache_event = NULL;
|
|
||||||
|
|
||||||
EGLint majorVersion, minorVersion;
|
|
||||||
|
|
||||||
// Initialize an EGL context for the current display.
|
|
||||||
PlatformContext(ANativeWindow* window) {
|
|
||||||
|
|
||||||
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
||||||
if (EGL_NO_DISPLAY == display) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (eglInitialize(display, &majorVersion, &minorVersion) != EGL_TRUE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Here specify the attributes of the desired configuration.
|
|
||||||
// Below, we select an EGLConfig with at least 8 bits per color component compatible with on-screen windows
|
|
||||||
const EGLint attribs[] = {
|
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, // request OpenGL ES 3.0
|
|
||||||
EGL_BLUE_SIZE, 8,
|
|
||||||
EGL_GREEN_SIZE, 8,
|
|
||||||
EGL_RED_SIZE, 8,
|
|
||||||
EGL_DEPTH_SIZE, GLW_CONTEXT_DEPTH_BITS,
|
|
||||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
// Here, the application chooses the configuration it desires.
|
|
||||||
// find the best match if possible, otherwise use the very first one
|
|
||||||
{
|
|
||||||
if (eglChooseConfig(display, attribs, nullptr, 0, &numConfigs) != EGL_TRUE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<EGLConfig[]> supportedConfigs(new EGLConfig[numConfigs]);
|
|
||||||
assert(supportedConfigs);
|
|
||||||
|
|
||||||
if (eglChooseConfig(display, attribs, supportedConfigs.get(), numConfigs, &numConfigs) != EGL_TRUE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(numConfigs);
|
|
||||||
auto i = 0;
|
|
||||||
for (; i < numConfigs; i++) {
|
|
||||||
auto& cfg = supportedConfigs[i];
|
|
||||||
EGLint r, g, b, d;
|
|
||||||
if (eglGetConfigAttrib(display, cfg, EGL_RED_SIZE, &r) &&
|
|
||||||
eglGetConfigAttrib(display, cfg, EGL_GREEN_SIZE, &g) &&
|
|
||||||
eglGetConfigAttrib(display, cfg, EGL_BLUE_SIZE, &b) &&
|
|
||||||
eglGetConfigAttrib(display, cfg, EGL_DEPTH_SIZE, &d) &&
|
|
||||||
r == 8 && g == 8 && b == 8 && d == GLW_CONTEXT_DEPTH_BITS) {
|
|
||||||
|
|
||||||
config = supportedConfigs[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == numConfigs) {
|
|
||||||
config = supportedConfigs[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config == nullptr) {
|
|
||||||
LOGW("Unable to initialize EGLConfig");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const EGLint egl_context_attributes[] = {
|
|
||||||
EGL_CONTEXT_CLIENT_VERSION, 3,
|
|
||||||
//EGL_CONTEXT_MAJOR_VERSION, 3,
|
|
||||||
//EGL_CONTEXT_MINOR_VERSION, 0,
|
|
||||||
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
|
|
||||||
#ifdef ENV_BUILD_DEBUG
|
|
||||||
//EGL_CONTEXT_OPENGL_DEBUG, EGL_TRUE,
|
|
||||||
#endif
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
// EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
|
|
||||||
// guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
|
|
||||||
// As soon as we picked a EGLConfig, we can safely reconfigure the
|
|
||||||
// ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
|
|
||||||
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
|
|
||||||
surface = eglCreateWindowSurface(display, config, window, nullptr);
|
|
||||||
context = eglCreateContext(display, config, EGL_NO_CONTEXT, egl_context_attributes);
|
|
||||||
|
|
||||||
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
|
|
||||||
LOGW("Unable to eglMakeCurrent");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
eglQuerySurface(display, surface, EGL_WIDTH, &w);
|
|
||||||
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
|
|
||||||
|
|
||||||
// Check openGL on the system
|
|
||||||
auto opengl_info = { GL_VENDOR, GL_RENDERER, GL_VERSION, GL_EXTENSIONS };
|
|
||||||
for (auto name : opengl_info) {
|
|
||||||
auto info = glGetString(name);
|
|
||||||
LOGI("OpenGL Info: %s", info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize GL state.
|
|
||||||
//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
||||||
AssertGL(glEnable(GL_CULL_FACE));
|
|
||||||
//AssertGL(glShadeModel(GL_SMOOTH));
|
|
||||||
AssertGL(glEnable(GL_DEPTH_TEST));
|
|
||||||
AssertGL(glDepthFunc(GL_LESS));
|
|
||||||
|
|
||||||
GLint major = 0;
|
|
||||||
GLint minor = 0;
|
|
||||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
|
||||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
|
||||||
|
|
||||||
glGetIntegerv(GL_DEPTH, &minor);
|
|
||||||
|
|
||||||
AssertGL(glEnable(GL_DEBUG_OUTPUT));
|
|
||||||
AssertGL(glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS));
|
|
||||||
AssertGL(glDebugMessageCallback(MessageCallback, 0));
|
|
||||||
|
|
||||||
tp::glw::Window::mDevice.Size = { w, h };
|
|
||||||
tp::glw::Window::mDevice.FrameRate = 60;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void beginDraw() {
|
|
||||||
if (this->display == nullptr) { return; }
|
|
||||||
|
|
||||||
glViewport(0, 0, tp::glw::Window::mDevice.Size.x, tp::glw::Window::mDevice.Size.y);
|
|
||||||
|
|
||||||
//glClearColor(col / 255.f, col / 255.f, col / 255.f, 1);
|
|
||||||
//glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
//if (col++ > 255) {
|
|
||||||
//col = 0;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
void endDraw() {
|
|
||||||
eglSwapBuffers(display, surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tear down the EGL context currently associated with the display.
|
|
||||||
~PlatformContext() {
|
|
||||||
if (this->display != EGL_NO_DISPLAY) {
|
|
||||||
eglMakeCurrent(this->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
||||||
if (this->context != EGL_NO_CONTEXT) {
|
|
||||||
eglDestroyContext(this->display, this->context);
|
|
||||||
}
|
|
||||||
if (this->surface != EGL_NO_SURFACE) {
|
|
||||||
eglDestroySurface(this->display, this->surface);
|
|
||||||
}
|
|
||||||
eglTerminate(this->display);
|
|
||||||
}
|
|
||||||
|
|
||||||
display = EGL_NO_DISPLAY;
|
|
||||||
context = EGL_NO_CONTEXT;
|
|
||||||
surface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---------------------------------- Parent Thread ------------------------------------ //
|
|
||||||
#ifndef PARENT_THREAD
|
|
||||||
|
|
||||||
// Shared state for our app.
|
|
||||||
struct ANativeActivityCtx {
|
|
||||||
|
|
||||||
// Our saved state data.
|
|
||||||
struct saved_state {
|
|
||||||
float angle;
|
|
||||||
int32_t x;
|
|
||||||
int32_t y;
|
|
||||||
};
|
|
||||||
|
|
||||||
android_app* app;
|
|
||||||
|
|
||||||
ASensorManager* sensorManager;
|
|
||||||
const ASensor* accelerometerSensor;
|
|
||||||
ASensorEventQueue* sensorEventQueue;
|
|
||||||
|
|
||||||
int animating;
|
|
||||||
EGLDisplay display;
|
|
||||||
EGLSurface surface;
|
|
||||||
EGLContext context;
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
saved_state state;
|
|
||||||
|
|
||||||
ANativeActivityCtx(android_app* state) {
|
|
||||||
memset(this, 0, sizeof(*this));
|
|
||||||
|
|
||||||
state->userData = this;
|
|
||||||
state->onAppCmd = engine_handle_cmd;
|
|
||||||
state->onInputEvent = engine_handle_input;
|
|
||||||
|
|
||||||
app = state;
|
|
||||||
|
|
||||||
// Prepare to monitor accelerometer
|
|
||||||
sensorManager = AcquireASensorManagerInstance(state);
|
|
||||||
accelerometerSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
|
|
||||||
sensorEventQueue = ASensorManager_createEventQueue(sensorManager, state->looper, LOOPER_ID_USER, 0, 0);
|
|
||||||
|
|
||||||
// We are starting with a previous saved state; restore from it.
|
|
||||||
if (state->savedState != nullptr) {
|
|
||||||
this->state = *(saved_state*)state->savedState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void proc_events_util() {
|
|
||||||
int ident;
|
|
||||||
int events;
|
|
||||||
struct android_poll_source* source;
|
|
||||||
|
|
||||||
auto window = mutex_event.active_windw;
|
|
||||||
|
|
||||||
if (window) {
|
|
||||||
for (auto proc : window->mNativeEventListeners) {
|
|
||||||
proc->val.exec_begin(window->mPlatformCtx, proc->val.cd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we loop until all events are read
|
|
||||||
while ((ident = ALooper_pollAll(0, nullptr, &events, (void**)&source)) >= 0) {
|
|
||||||
|
|
||||||
// Process this event.
|
|
||||||
if (source != nullptr) {
|
|
||||||
source->process(this->app, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a sensor has data, process it now.
|
|
||||||
if (ident == LOOPER_ID_USER) {
|
|
||||||
if (this->accelerometerSensor != nullptr) {
|
|
||||||
ASensorEvent event;
|
|
||||||
while (ASensorEventQueue_getEvents(this->sensorEventQueue, &event, 1) > 0) {
|
|
||||||
LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x, event.acceleration.y, event.acceleration.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we are exiting.
|
|
||||||
if (this->app->destroyRequested != 0) {
|
|
||||||
DBG_BREAK(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window) {
|
|
||||||
for (auto proc : window->mNativeEventListeners) {
|
|
||||||
proc->val.exec_end(window->mPlatformCtx, proc->val.cd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void proc_events() {
|
|
||||||
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
auto threaded = mutex_event.active_windw;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
|
|
||||||
if (!threaded) {
|
|
||||||
proc_events_util();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read all pending events.
|
|
||||||
int ident;
|
|
||||||
int events;
|
|
||||||
struct android_poll_source* source;
|
|
||||||
|
|
||||||
// check if events exist and if so prepare to proccess them
|
|
||||||
if ((ident = ALooper_pollAll(0, nullptr, &events, (void**)&source)) >= 0) {
|
|
||||||
|
|
||||||
// signal child thread that we need to process those events
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
mutex_event.parent_thread_has_events = true;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
|
|
||||||
// whait until child thread pauses
|
|
||||||
bool whait = true;
|
|
||||||
|
|
||||||
while (whait) {
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
whait = !mutex_event.child_whaiting;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
auto window = mutex_event.active_windw;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
|
|
||||||
proc_events_util();
|
|
||||||
|
|
||||||
// signal to child continue to do its work
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
mutex_event.parent_thread_has_events = false;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the next input event.
|
|
||||||
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
|
|
||||||
auto* engine = (struct ANativeActivityCtx*)app->userData;
|
|
||||||
auto window = mutex_event.active_windw;
|
|
||||||
|
|
||||||
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
|
|
||||||
window->mEvents.mCursorPrev = window->mEvents.mCursor;
|
|
||||||
|
|
||||||
window->mEvents.mCursor.x = AMotionEvent_getX(event, 0);
|
|
||||||
window->mEvents.mCursor.y = AMotionEvent_getY(event, 0);
|
|
||||||
|
|
||||||
window->mEvents.mRedraw = 2;
|
|
||||||
|
|
||||||
int32_t event_action = AMotionEvent_getAction(event);
|
|
||||||
int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
|
||||||
event_action &= AMOTION_EVENT_ACTION_MASK;
|
|
||||||
|
|
||||||
if ((AMotionEvent_getToolType(event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
|
|
||||||
|| (AMotionEvent_getToolType(event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) {
|
|
||||||
|
|
||||||
if (event_action == AMOTION_EVENT_ACTION_DOWN) {
|
|
||||||
window->mEvents.mKeysQueue.push(tp::KeyEvent{ tp::Keycode::MOUSE1, tp::KeyEvent::EventState::PRESSED });
|
|
||||||
}
|
|
||||||
else if (event_action == AMOTION_EVENT_ACTION_UP) {
|
|
||||||
window->mEvents.mKeysQueue.push(tp::KeyEvent{ tp::Keycode::MOUSE1, tp::KeyEvent::EventState::RELEASED });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window) {
|
|
||||||
window->mPlatformCtx->chache_event = event;
|
|
||||||
for (auto proc : window->mNativeEventListeners) {
|
|
||||||
proc->val.exec(window->mPlatformCtx, proc->val.cd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the next main command.
|
|
||||||
static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
|
|
||||||
auto* engine = (struct ANativeActivityCtx*)app->userData;
|
|
||||||
auto window = mutex_event.active_windw;
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
|
|
||||||
// The system has asked us to save our current state. Do so.
|
|
||||||
case APP_CMD_SAVE_STATE: {
|
|
||||||
engine->app->savedState = malloc(sizeof(ANativeActivityCtx::saved_state));
|
|
||||||
*((ANativeActivityCtx::saved_state*)engine->app->savedState) = engine->state;
|
|
||||||
engine->app->savedStateSize = sizeof(ANativeActivityCtx::saved_state);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// The window is being shown, get it ready.
|
|
||||||
case APP_CMD_INIT_WINDOW: {
|
|
||||||
if (engine->app->window != nullptr) {
|
|
||||||
//engine->init_display();
|
|
||||||
//engine->draw_frame();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// The window is being hidden or closed, clean it up.
|
|
||||||
case APP_CMD_TERM_WINDOW: {
|
|
||||||
//engine->term_display();
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// When our app gains focus, we start monitoring the accelerometer.
|
|
||||||
case APP_CMD_GAINED_FOCUS: {
|
|
||||||
if (engine->accelerometerSensor != nullptr) {
|
|
||||||
ASensorEventQueue_enableSensor(engine->sensorEventQueue,
|
|
||||||
engine->accelerometerSensor);
|
|
||||||
// We'd like to get 60 events per second (in us).
|
|
||||||
ASensorEventQueue_setEventRate(engine->sensorEventQueue,
|
|
||||||
engine->accelerometerSensor,
|
|
||||||
(1000L / 60) * 1000);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// When our app loses focus, we stop monitoring the accelerometer.
|
|
||||||
// This is to avoid consuming battery while not being used.
|
|
||||||
case APP_CMD_LOST_FOCUS: {
|
|
||||||
if (engine->accelerometerSensor != nullptr) {
|
|
||||||
ASensorEventQueue_disableSensor(engine->sensorEventQueue,
|
|
||||||
engine->accelerometerSensor);
|
|
||||||
}
|
|
||||||
// Also stop animating.
|
|
||||||
engine->animating = 0;
|
|
||||||
//engine->draw_frame();
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
void unsure_dir_exist(const char* path_to_file) {
|
|
||||||
char* temp_path = strdup(path_to_file);
|
|
||||||
|
|
||||||
for (char* p = temp_path + 1; *p; p++) {
|
|
||||||
if (*p == '/') {
|
|
||||||
*p = '\0';
|
|
||||||
int status = mkdir(temp_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
|
||||||
if (status != 0 && errno != EEXIST) {
|
|
||||||
// handle error
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*p = '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(temp_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
void unpackAsset(AAssetManager* mgr, const char* filename, const std::string& path) {
|
|
||||||
AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
|
|
||||||
if (asset == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
off_t length = AAsset_getLength(asset);
|
|
||||||
char* buffer = new char[length];
|
|
||||||
AAsset_read(asset, buffer, length);
|
|
||||||
|
|
||||||
unsure_dir_exist(path.c_str());
|
|
||||||
FILE* out = fopen(path.c_str(), "w");
|
|
||||||
if (out != NULL) {
|
|
||||||
fwrite(buffer, length, 1, out);
|
|
||||||
fclose(out);
|
|
||||||
}
|
|
||||||
delete[] buffer;
|
|
||||||
AAsset_close(asset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
void unpackDirectory(AAssetManager* mgr, const char* dirname, const std::string& path) {
|
|
||||||
|
|
||||||
AAssetDir* assetDir = AAssetManager_openDir(mgr, dirname);
|
|
||||||
const char* filename = NULL;
|
|
||||||
|
|
||||||
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
|
|
||||||
std::string assetPath = std::string(dirname) + "/" + filename;
|
|
||||||
std::string internalPath = path + "/" + std::string(dirname) + "/" + filename;
|
|
||||||
|
|
||||||
struct stat sb;
|
|
||||||
stat(assetPath.c_str(), &sb);
|
|
||||||
if (S_ISDIR(sb.st_mode)) {
|
|
||||||
unpackDirectory(mgr, assetPath.c_str(), internalPath);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unpackAsset(mgr, assetPath.c_str(), internalPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AAssetDir_close(assetDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
// This is the main entry point of a native application that is using
|
|
||||||
// android_native_app_glue. It runs in its own thread, with its own
|
|
||||||
// event loop for receiving input events and doing other things.
|
|
||||||
void android_main(android_app* state) {
|
|
||||||
|
|
||||||
tp::print_env_info();
|
|
||||||
tp::alloc_init();
|
|
||||||
|
|
||||||
ANativeActivityCtx engine(state);
|
|
||||||
|
|
||||||
unpackDirectory(state->activity->assetManager, "", state->activity->internalDataPath);
|
|
||||||
unpackDirectory(state->activity->assetManager, "rsc", state->activity->internalDataPath);
|
|
||||||
unpackDirectory(state->activity->assetManager, "rsc/fonts", state->activity->internalDataPath);
|
|
||||||
|
|
||||||
android_ctx = &engine;
|
|
||||||
|
|
||||||
bool running = true;
|
|
||||||
while (running) {
|
|
||||||
|
|
||||||
engine.proc_events();
|
|
||||||
|
|
||||||
// whait until our app fully initialized
|
|
||||||
if (!engine.app->window) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// run once
|
|
||||||
static bool main_thread_started = false;
|
|
||||||
if (!main_thread_started) {
|
|
||||||
|
|
||||||
// init types
|
|
||||||
g_android_internal_data_path = state->activity->internalDataPath;
|
|
||||||
|
|
||||||
// create main thread
|
|
||||||
pthread_create(&worker_thread, NULL, main_wrap, NULL);
|
|
||||||
pthread_mutex_init(&worker_finished_mutex, NULL);
|
|
||||||
pthread_cond_init(&worker_finished_cond, NULL);
|
|
||||||
|
|
||||||
main_thread_started = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for exit
|
|
||||||
pthread_mutex_lock(&worker_finished_mutex);
|
|
||||||
running = !worker_finished;
|
|
||||||
pthread_mutex_unlock(&worker_finished_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_join(worker_thread, NULL);
|
|
||||||
|
|
||||||
tp::alloc_uninit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------- Child thread --------------------------------------- //
|
|
||||||
#ifndef CHILD_THREAD
|
|
||||||
|
|
||||||
//#include <android/configuration.h>
|
|
||||||
//#include <android/native_activity.h>
|
|
||||||
|
|
||||||
AInputEvent* androidPlatformContextGetEvent(tp::glw::PlatformContext* ctx) {
|
|
||||||
return ctx->chache_event;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t getDensityDpi(android_app* app) {
|
|
||||||
AConfiguration* config = AConfiguration_new();
|
|
||||||
AConfiguration_fromAssetManager(config, app->activity->assetManager);
|
|
||||||
int32_t density = AConfiguration_getDensity(config);
|
|
||||||
AConfiguration_delete(config);
|
|
||||||
return density;
|
|
||||||
}
|
|
||||||
|
|
||||||
// statics
|
|
||||||
void tp::glw::Window::init() {}
|
|
||||||
void tp::glw::Window::deinit() {}
|
|
||||||
|
|
||||||
void tp::glw::Window::initialize() {
|
|
||||||
mPlatformCtx = new PlatformContext(android_ctx->app->window);
|
|
||||||
applyAppearance();
|
|
||||||
|
|
||||||
|
|
||||||
AConfiguration* config = AConfiguration_new();
|
|
||||||
AConfiguration_fromAssetManager(config, android_ctx->app->activity->assetManager);
|
|
||||||
int32_t density = AConfiguration_getDensity(config);
|
|
||||||
AConfiguration_delete(config);
|
|
||||||
|
|
||||||
mDevice.mDPMM = density / 25.4f;
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::glw::Window::Window() {
|
|
||||||
initialize();
|
|
||||||
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
mutex_event.active_windw = this;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::glw::Window::Window(const Appearence& aAppearence) {
|
|
||||||
mAppearence = aAppearence;
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::glw::Window::~Window() {
|
|
||||||
delete mPlatformCtx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::applyAppearance() {
|
|
||||||
int width = ANativeWindow_getWidth(android_ctx->app->window);
|
|
||||||
int height = ANativeWindow_getHeight(android_ctx->app->window);
|
|
||||||
|
|
||||||
if (width != mAppearence.mSize.x || height != mAppearence.mSize.y) {
|
|
||||||
mEvents.mRedraw = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mAppearence.mPos = mCache.mAppearencePrev.mPos = 0;
|
|
||||||
mAppearence.mSize.x = mCache.mAppearencePrev.mSize.x = tp::glw::Window::mDevice.Size.x = width;
|
|
||||||
mAppearence.mSize.y = mCache.mAppearencePrev.mSize.y = tp::glw::Window::mDevice.Size.y = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::pollEvents() {
|
|
||||||
applyAppearance();
|
|
||||||
|
|
||||||
// check if parent thread has some events to pass
|
|
||||||
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
bool has_event = mutex_event.parent_thread_has_events;
|
|
||||||
mutex_event.child_whaiting = has_event;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
|
|
||||||
while (has_event) {
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
has_event = mutex_event.parent_thread_has_events;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&mutex_event.mutex);
|
|
||||||
mutex_event.child_whaiting = false;
|
|
||||||
pthread_mutex_unlock(&mutex_event.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::platformCallback() {}
|
|
||||||
|
|
||||||
void tp::glw::Window::beginDraw() {
|
|
||||||
mPlatformCtx->beginDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::endDraw() {
|
|
||||||
mPlatformCtx->endDraw();
|
|
||||||
if (mEvents.mRedraw-- < 0) mEvents.mRedraw = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* tp::glw::Window::platform_window() const { return android_ctx->app->window; }
|
|
||||||
|
|
||||||
tp::alni tp::glw::Window::sizeAllocatedMem() { return 0; }
|
|
||||||
|
|
||||||
tp::alni tp::glw::Window::sizeUsedMem() { return 0; }
|
|
||||||
|
|
||||||
|
|
||||||
void* main_wrap(void* p) {
|
|
||||||
|
|
||||||
// exec main
|
|
||||||
main();
|
|
||||||
|
|
||||||
// mark as doen after completion
|
|
||||||
pthread_mutex_lock(&worker_finished_mutex);
|
|
||||||
worker_finished = true;
|
|
||||||
pthread_cond_signal(&worker_finished_cond);
|
|
||||||
pthread_mutex_unlock(&worker_finished_mutex);
|
|
||||||
|
|
||||||
// exit "main thread"
|
|
||||||
pthread_exit(NULL);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,453 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2010 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "android_native_app_glue.h"
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <android/log.h>
|
|
||||||
|
|
||||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
|
|
||||||
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__))
|
|
||||||
|
|
||||||
/* For debug builds, always enable the debug traces in this library */
|
|
||||||
#ifndef NDEBUG
|
|
||||||
# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__))
|
|
||||||
#else
|
|
||||||
# define LOGV(...) ((void)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void free_saved_state(struct android_app* android_app) {
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
if (android_app->savedState != NULL) {
|
|
||||||
free(android_app->savedState);
|
|
||||||
android_app->savedState = NULL;
|
|
||||||
android_app->savedStateSize = 0;
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int8_t android_app_read_cmd(struct android_app* android_app) {
|
|
||||||
int8_t cmd;
|
|
||||||
if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd)) {
|
|
||||||
LOGE("No data on command pipe!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (cmd == APP_CMD_SAVE_STATE) free_saved_state(android_app);
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_cur_config(struct android_app* android_app) {
|
|
||||||
char lang[2], country[2];
|
|
||||||
AConfiguration_getLanguage(android_app->config, lang);
|
|
||||||
AConfiguration_getCountry(android_app->config, country);
|
|
||||||
|
|
||||||
LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
|
|
||||||
"keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
|
|
||||||
"modetype=%d modenight=%d",
|
|
||||||
AConfiguration_getMcc(android_app->config),
|
|
||||||
AConfiguration_getMnc(android_app->config),
|
|
||||||
lang[0], lang[1], country[0], country[1],
|
|
||||||
AConfiguration_getOrientation(android_app->config),
|
|
||||||
AConfiguration_getTouchscreen(android_app->config),
|
|
||||||
AConfiguration_getDensity(android_app->config),
|
|
||||||
AConfiguration_getKeyboard(android_app->config),
|
|
||||||
AConfiguration_getNavigation(android_app->config),
|
|
||||||
AConfiguration_getKeysHidden(android_app->config),
|
|
||||||
AConfiguration_getNavHidden(android_app->config),
|
|
||||||
AConfiguration_getSdkVersion(android_app->config),
|
|
||||||
AConfiguration_getScreenSize(android_app->config),
|
|
||||||
AConfiguration_getScreenLong(android_app->config),
|
|
||||||
AConfiguration_getUiModeType(android_app->config),
|
|
||||||
AConfiguration_getUiModeNight(android_app->config));
|
|
||||||
}
|
|
||||||
|
|
||||||
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
|
|
||||||
switch (cmd) {
|
|
||||||
case APP_CMD_INPUT_CHANGED:
|
|
||||||
LOGV("APP_CMD_INPUT_CHANGED");
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
if (android_app->inputQueue != NULL) {
|
|
||||||
AInputQueue_detachLooper(android_app->inputQueue);
|
|
||||||
}
|
|
||||||
android_app->inputQueue = android_app->pendingInputQueue;
|
|
||||||
if (android_app->inputQueue != NULL) {
|
|
||||||
LOGV("Attaching input queue to looper");
|
|
||||||
AInputQueue_attachLooper(android_app->inputQueue,
|
|
||||||
android_app->looper, LOOPER_ID_INPUT, NULL,
|
|
||||||
&android_app->inputPollSource);
|
|
||||||
}
|
|
||||||
pthread_cond_broadcast(&android_app->cond);
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case APP_CMD_INIT_WINDOW:
|
|
||||||
LOGV("APP_CMD_INIT_WINDOW");
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app->window = android_app->pendingWindow;
|
|
||||||
pthread_cond_broadcast(&android_app->cond);
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case APP_CMD_TERM_WINDOW:
|
|
||||||
LOGV("APP_CMD_TERM_WINDOW");
|
|
||||||
pthread_cond_broadcast(&android_app->cond);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case APP_CMD_RESUME:
|
|
||||||
case APP_CMD_START:
|
|
||||||
case APP_CMD_PAUSE:
|
|
||||||
case APP_CMD_STOP:
|
|
||||||
LOGV("activityState=%d", cmd);
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app->activityState = cmd;
|
|
||||||
pthread_cond_broadcast(&android_app->cond);
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case APP_CMD_CONFIG_CHANGED:
|
|
||||||
LOGV("APP_CMD_CONFIG_CHANGED");
|
|
||||||
AConfiguration_fromAssetManager(android_app->config,
|
|
||||||
android_app->activity->assetManager);
|
|
||||||
print_cur_config(android_app);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case APP_CMD_DESTROY:
|
|
||||||
LOGV("APP_CMD_DESTROY");
|
|
||||||
android_app->destroyRequested = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
|
|
||||||
switch (cmd) {
|
|
||||||
case APP_CMD_TERM_WINDOW:
|
|
||||||
LOGV("APP_CMD_TERM_WINDOW");
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app->window = NULL;
|
|
||||||
pthread_cond_broadcast(&android_app->cond);
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case APP_CMD_SAVE_STATE:
|
|
||||||
LOGV("APP_CMD_SAVE_STATE");
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app->stateSaved = 1;
|
|
||||||
pthread_cond_broadcast(&android_app->cond);
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case APP_CMD_RESUME:
|
|
||||||
free_saved_state(android_app);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void android_app_destroy(struct android_app* android_app) {
|
|
||||||
LOGV("android_app_destroy!");
|
|
||||||
free_saved_state(android_app);
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
if (android_app->inputQueue != NULL) {
|
|
||||||
AInputQueue_detachLooper(android_app->inputQueue);
|
|
||||||
}
|
|
||||||
AConfiguration_delete(android_app->config);
|
|
||||||
android_app->destroyed = 1;
|
|
||||||
pthread_cond_broadcast(&android_app->cond);
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
// Can't touch android_app object after this.
|
|
||||||
}
|
|
||||||
|
|
||||||
void process_input(struct android_app* app, struct android_poll_source* source) {
|
|
||||||
AInputEvent* event = NULL;
|
|
||||||
while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
|
|
||||||
LOGV("New input event: type=%d", AInputEvent_getType(event));
|
|
||||||
if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int32_t handled = 0;
|
|
||||||
if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
|
|
||||||
AInputQueue_finishEvent(app->inputQueue, event, handled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void process_cmd(struct android_app* app, struct android_poll_source* source) {
|
|
||||||
int8_t cmd = android_app_read_cmd(app);
|
|
||||||
android_app_pre_exec_cmd(app, cmd);
|
|
||||||
if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
|
|
||||||
android_app_post_exec_cmd(app, cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* android_app_entry(void* param) {
|
|
||||||
struct android_app* android_app = (struct android_app*)param;
|
|
||||||
|
|
||||||
android_app->config = AConfiguration_new();
|
|
||||||
AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
|
|
||||||
|
|
||||||
print_cur_config(android_app);
|
|
||||||
|
|
||||||
android_app->cmdPollSource.id = LOOPER_ID_MAIN;
|
|
||||||
android_app->cmdPollSource.app = android_app;
|
|
||||||
android_app->cmdPollSource.process = process_cmd;
|
|
||||||
android_app->inputPollSource.id = LOOPER_ID_INPUT;
|
|
||||||
android_app->inputPollSource.app = android_app;
|
|
||||||
android_app->inputPollSource.process = process_input;
|
|
||||||
|
|
||||||
ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
|
||||||
ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
|
|
||||||
&android_app->cmdPollSource);
|
|
||||||
android_app->looper = looper;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app->running = 1;
|
|
||||||
pthread_cond_broadcast(&android_app->cond);
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
|
|
||||||
android_main(android_app);
|
|
||||||
|
|
||||||
android_app_destroy(android_app);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
|
||||||
// Native activity interaction (called from main thread)
|
|
||||||
// --------------------------------------------------------------------
|
|
||||||
|
|
||||||
struct android_app* android_app_create(ANativeActivity* activity,
|
|
||||||
void* savedState, size_t savedStateSize) {
|
|
||||||
struct android_app* android_app = calloc(1, sizeof(struct android_app));
|
|
||||||
android_app->activity = activity;
|
|
||||||
|
|
||||||
pthread_mutex_init(&android_app->mutex, NULL);
|
|
||||||
pthread_cond_init(&android_app->cond, NULL);
|
|
||||||
|
|
||||||
if (savedState != NULL) {
|
|
||||||
android_app->savedState = malloc(savedStateSize);
|
|
||||||
android_app->savedStateSize = savedStateSize;
|
|
||||||
memcpy(android_app->savedState, savedState, savedStateSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
int msgpipe[2];
|
|
||||||
if (pipe(msgpipe)) {
|
|
||||||
LOGE("could not create pipe: %s", strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
android_app->msgread = msgpipe[0];
|
|
||||||
android_app->msgwrite = msgpipe[1];
|
|
||||||
|
|
||||||
pthread_attr_t attr;
|
|
||||||
pthread_attr_init(&attr);
|
|
||||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
||||||
pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
|
|
||||||
|
|
||||||
// Wait for thread to start.
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
while (!android_app->running) {
|
|
||||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
|
|
||||||
return android_app;
|
|
||||||
}
|
|
||||||
|
|
||||||
void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
|
|
||||||
if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
|
|
||||||
LOGE("Failure writing android_app cmd: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app->pendingInputQueue = inputQueue;
|
|
||||||
android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
|
|
||||||
while (android_app->inputQueue != android_app->pendingInputQueue) {
|
|
||||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
if (android_app->pendingWindow != NULL) {
|
|
||||||
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
|
|
||||||
}
|
|
||||||
android_app->pendingWindow = window;
|
|
||||||
if (window != NULL) {
|
|
||||||
android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
|
|
||||||
}
|
|
||||||
while (android_app->window != android_app->pendingWindow) {
|
|
||||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app_write_cmd(android_app, cmd);
|
|
||||||
while (android_app->activityState != cmd) {
|
|
||||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void android_app_free(struct android_app* android_app) {
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app_write_cmd(android_app, APP_CMD_DESTROY);
|
|
||||||
while (!android_app->destroyed) {
|
|
||||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
|
|
||||||
close(android_app->msgread);
|
|
||||||
close(android_app->msgwrite);
|
|
||||||
pthread_cond_destroy(&android_app->cond);
|
|
||||||
pthread_mutex_destroy(&android_app->mutex);
|
|
||||||
free(android_app);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct android_app* ToApp(ANativeActivity* activity) {
|
|
||||||
return (struct android_app*) activity->instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onDestroy(ANativeActivity* activity) {
|
|
||||||
LOGV("Destroy: %p", activity);
|
|
||||||
android_app_free(ToApp(activity));
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStart(ANativeActivity* activity) {
|
|
||||||
LOGV("Start: %p", activity);
|
|
||||||
android_app_set_activity_state(ToApp(activity), APP_CMD_START);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onResume(ANativeActivity* activity) {
|
|
||||||
LOGV("Resume: %p", activity);
|
|
||||||
android_app_set_activity_state(ToApp(activity), APP_CMD_RESUME);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
|
|
||||||
LOGV("SaveInstanceState: %p", activity);
|
|
||||||
|
|
||||||
struct android_app* android_app = ToApp(activity);
|
|
||||||
void* savedState = NULL;
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app->stateSaved = 0;
|
|
||||||
android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
|
|
||||||
while (!android_app->stateSaved) {
|
|
||||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (android_app->savedState != NULL) {
|
|
||||||
savedState = android_app->savedState;
|
|
||||||
*outLen = android_app->savedStateSize;
|
|
||||||
android_app->savedState = NULL;
|
|
||||||
android_app->savedStateSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
|
|
||||||
return savedState;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPause(ANativeActivity* activity) {
|
|
||||||
LOGV("Pause: %p", activity);
|
|
||||||
android_app_set_activity_state(ToApp(activity), APP_CMD_PAUSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStop(ANativeActivity* activity) {
|
|
||||||
LOGV("Stop: %p", activity);
|
|
||||||
android_app_set_activity_state(ToApp(activity), APP_CMD_STOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onConfigurationChanged(ANativeActivity* activity) {
|
|
||||||
LOGV("ConfigurationChanged: %p", activity);
|
|
||||||
android_app_write_cmd(ToApp(activity), APP_CMD_CONFIG_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onContentRectChanged(ANativeActivity* activity, const ARect* r) {
|
|
||||||
LOGV("ContentRectChanged: l=%d,t=%d,r=%d,b=%d", r->left, r->top, r->right, r->bottom);
|
|
||||||
struct android_app* android_app = ToApp(activity);
|
|
||||||
pthread_mutex_lock(&android_app->mutex);
|
|
||||||
android_app->contentRect = *r;
|
|
||||||
pthread_mutex_unlock(&android_app->mutex);
|
|
||||||
android_app_write_cmd(ToApp(activity), APP_CMD_CONTENT_RECT_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onLowMemory(ANativeActivity* activity) {
|
|
||||||
LOGV("LowMemory: %p", activity);
|
|
||||||
android_app_write_cmd(ToApp(activity), APP_CMD_LOW_MEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onWindowFocusChanged(ANativeActivity* activity, int focused) {
|
|
||||||
LOGV("WindowFocusChanged: %p -- %d", activity, focused);
|
|
||||||
android_app_write_cmd(ToApp(activity), focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
|
|
||||||
LOGV("NativeWindowCreated: %p -- %p", activity, window);
|
|
||||||
android_app_set_window(ToApp(activity), window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
|
|
||||||
LOGV("NativeWindowDestroyed: %p -- %p", activity, window);
|
|
||||||
android_app_set_window(ToApp(activity), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window) {
|
|
||||||
LOGV("NativeWindowRedrawNeeded: %p -- %p", activity, window);
|
|
||||||
android_app_write_cmd(ToApp(activity), APP_CMD_WINDOW_REDRAW_NEEDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window) {
|
|
||||||
LOGV("NativeWindowResized: %p -- %p", activity, window);
|
|
||||||
android_app_write_cmd(ToApp(activity), APP_CMD_WINDOW_RESIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
|
|
||||||
LOGV("InputQueueCreated: %p -- %p", activity, queue);
|
|
||||||
android_app_set_input(ToApp(activity), queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
|
|
||||||
LOGV("InputQueueDestroyed: %p -- %p", activity, queue);
|
|
||||||
android_app_set_input(ToApp(activity), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ILOVEU_ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize) {
|
|
||||||
LOGV("Creating: %p", activity);
|
|
||||||
|
|
||||||
activity->callbacks->onConfigurationChanged = onConfigurationChanged;
|
|
||||||
activity->callbacks->onContentRectChanged = onContentRectChanged;
|
|
||||||
activity->callbacks->onDestroy = onDestroy;
|
|
||||||
activity->callbacks->onInputQueueCreated = onInputQueueCreated;
|
|
||||||
activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
|
|
||||||
activity->callbacks->onLowMemory = onLowMemory;
|
|
||||||
activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
|
|
||||||
activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
|
|
||||||
activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;
|
|
||||||
activity->callbacks->onNativeWindowResized = onNativeWindowResized;
|
|
||||||
activity->callbacks->onPause = onPause;
|
|
||||||
activity->callbacks->onResume = onResume;
|
|
||||||
activity->callbacks->onSaveInstanceState = onSaveInstanceState;
|
|
||||||
activity->callbacks->onStart = onStart;
|
|
||||||
activity->callbacks->onStop = onStop;
|
|
||||||
activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
|
|
||||||
|
|
||||||
activity->instance = android_app_create(activity, savedState, savedStateSize);
|
|
||||||
}
|
|
||||||
|
|
@ -1,350 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2010 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <poll.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sched.h>
|
|
||||||
|
|
||||||
#include <android/configuration.h>
|
|
||||||
#include <android/looper.h>
|
|
||||||
#include <android/native_activity.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The native activity interface provided by <android/native_activity.h>
|
|
||||||
* is based on a set of application-provided callbacks that will be called
|
|
||||||
* by the Activity's main thread when certain events occur.
|
|
||||||
*
|
|
||||||
* This means that each one of this callbacks _should_ _not_ block, or they
|
|
||||||
* risk having the system force-close the application. This programming
|
|
||||||
* model is direct, lightweight, but constraining.
|
|
||||||
*
|
|
||||||
* The 'android_native_app_glue' static library is used to provide a different
|
|
||||||
* execution model where the application can implement its own main event
|
|
||||||
* loop in a different thread instead. Here's how it works:
|
|
||||||
*
|
|
||||||
* 1/ The application must provide a function named "android_main()" that
|
|
||||||
* will be called when the activity is created, in a new thread that is
|
|
||||||
* distinct from the activity's main thread.
|
|
||||||
*
|
|
||||||
* 2/ android_main() receives a pointer to a valid "android_app" structure
|
|
||||||
* that contains references to other important objects, e.g. the
|
|
||||||
* ANativeActivity obejct instance the application is running in.
|
|
||||||
*
|
|
||||||
* 3/ the "android_app" object holds an ALooper instance that already
|
|
||||||
* listens to two important things:
|
|
||||||
*
|
|
||||||
* - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX
|
|
||||||
* declarations below.
|
|
||||||
*
|
|
||||||
* - input events coming from the AInputQueue attached to the activity.
|
|
||||||
*
|
|
||||||
* Each of these correspond to an ALooper identifier returned by
|
|
||||||
* ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT,
|
|
||||||
* respectively.
|
|
||||||
*
|
|
||||||
* Your application can use the same ALooper to listen to additional
|
|
||||||
* file-descriptors. They can either be callback based, or with return
|
|
||||||
* identifiers starting with LOOPER_ID_USER.
|
|
||||||
*
|
|
||||||
* 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event,
|
|
||||||
* the returned data will point to an android_poll_source structure. You
|
|
||||||
* can call the process() function on it, and fill in android_app->onAppCmd
|
|
||||||
* and android_app->onInputEvent to be called for your own processing
|
|
||||||
* of the event.
|
|
||||||
*
|
|
||||||
* Alternatively, you can call the low-level functions to read and process
|
|
||||||
* the data directly... look at the process_cmd() and process_input()
|
|
||||||
* implementations in the glue to see how to do this.
|
|
||||||
*
|
|
||||||
* See the sample named "native-activity" that comes with the NDK with a
|
|
||||||
* full usage example. Also look at the JavaDoc of NativeActivity.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct android_app;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data associated with an ALooper fd that will be returned as the "outData"
|
|
||||||
* when that source has data ready.
|
|
||||||
*/
|
|
||||||
struct android_poll_source {
|
|
||||||
// The identifier of this source. May be LOOPER_ID_MAIN or
|
|
||||||
// LOOPER_ID_INPUT.
|
|
||||||
int32_t id;
|
|
||||||
|
|
||||||
// The android_app this ident is associated with.
|
|
||||||
struct android_app* app;
|
|
||||||
|
|
||||||
// Function to call to perform the standard processing of data from
|
|
||||||
// this source.
|
|
||||||
void (*process)(struct android_app* app, struct android_poll_source* source);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the interface for the standard glue code of a threaded
|
|
||||||
* application. In this model, the application's code is running
|
|
||||||
* in its own thread separate from the main thread of the process.
|
|
||||||
* It is not required that this thread be associated with the Java
|
|
||||||
* VM, although it will need to be in order to make JNI calls any
|
|
||||||
* Java objects.
|
|
||||||
*/
|
|
||||||
struct android_app {
|
|
||||||
// The application can place a pointer to its own state object
|
|
||||||
// here if it likes.
|
|
||||||
void* userData;
|
|
||||||
|
|
||||||
// Fill this in with the function to process main app commands (APP_CMD_*)
|
|
||||||
void (*onAppCmd)(struct android_app* app, int32_t cmd);
|
|
||||||
|
|
||||||
// Fill this in with the function to process input events. At this point
|
|
||||||
// the event has already been pre-dispatched, and it will be finished upon
|
|
||||||
// return. Return 1 if you have handled the event, 0 for any default
|
|
||||||
// dispatching.
|
|
||||||
int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
|
|
||||||
|
|
||||||
// The ANativeActivity object instance that this app is running in.
|
|
||||||
ANativeActivity* activity;
|
|
||||||
|
|
||||||
// The current configuration the app is running in.
|
|
||||||
AConfiguration* config;
|
|
||||||
|
|
||||||
// This is the last instance's saved state, as provided at creation time.
|
|
||||||
// It is NULL if there was no state. You can use this as you need; the
|
|
||||||
// memory will remain around until you call android_app_exec_cmd() for
|
|
||||||
// APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
|
|
||||||
// These variables should only be changed when processing a APP_CMD_SAVE_STATE,
|
|
||||||
// at which point they will be initialized to NULL and you can malloc your
|
|
||||||
// state and place the information here. In that case the memory will be
|
|
||||||
// freed for you later.
|
|
||||||
void* savedState;
|
|
||||||
size_t savedStateSize;
|
|
||||||
|
|
||||||
// The ALooper associated with the app's thread.
|
|
||||||
ALooper* looper;
|
|
||||||
|
|
||||||
// When non-NULL, this is the input queue from which the app will
|
|
||||||
// receive user input events.
|
|
||||||
AInputQueue* inputQueue;
|
|
||||||
|
|
||||||
// When non-NULL, this is the window surface that the app can draw in.
|
|
||||||
ANativeWindow* window;
|
|
||||||
|
|
||||||
// Current content rectangle of the window; this is the area where the
|
|
||||||
// window's content should be placed to be seen by the user.
|
|
||||||
ARect contentRect;
|
|
||||||
|
|
||||||
// Current state of the app's activity. May be either APP_CMD_START,
|
|
||||||
// APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
|
|
||||||
int activityState;
|
|
||||||
|
|
||||||
// This is non-zero when the application's NativeActivity is being
|
|
||||||
// destroyed and waiting for the app thread to complete.
|
|
||||||
int destroyRequested;
|
|
||||||
|
|
||||||
// -------------------------------------------------
|
|
||||||
// Below are "private" implementation of the glue code.
|
|
||||||
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
pthread_cond_t cond;
|
|
||||||
|
|
||||||
int msgread;
|
|
||||||
int msgwrite;
|
|
||||||
|
|
||||||
pthread_t thread;
|
|
||||||
|
|
||||||
struct android_poll_source cmdPollSource;
|
|
||||||
struct android_poll_source inputPollSource;
|
|
||||||
|
|
||||||
int running;
|
|
||||||
int stateSaved;
|
|
||||||
int destroyed;
|
|
||||||
int redrawNeeded;
|
|
||||||
AInputQueue* pendingInputQueue;
|
|
||||||
ANativeWindow* pendingWindow;
|
|
||||||
ARect pendingContentRect;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
/**
|
|
||||||
* Looper data ID of commands coming from the app's main thread, which
|
|
||||||
* is returned as an identifier from ALooper_pollOnce(). The data for this
|
|
||||||
* identifier is a pointer to an android_poll_source structure.
|
|
||||||
* These can be retrieved and processed with android_app_read_cmd()
|
|
||||||
* and android_app_exec_cmd().
|
|
||||||
*/
|
|
||||||
LOOPER_ID_MAIN = 1,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looper data ID of events coming from the AInputQueue of the
|
|
||||||
* application's window, which is returned as an identifier from
|
|
||||||
* ALooper_pollOnce(). The data for this identifier is a pointer to an
|
|
||||||
* android_poll_source structure. These can be read via the inputQueue
|
|
||||||
* object of android_app.
|
|
||||||
*/
|
|
||||||
LOOPER_ID_INPUT = 2,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start of user-defined ALooper identifiers.
|
|
||||||
*/
|
|
||||||
LOOPER_ID_USER = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
/**
|
|
||||||
* Command from main thread: the AInputQueue has changed. Upon processing
|
|
||||||
* this command, android_app->inputQueue will be updated to the new queue
|
|
||||||
* (or NULL).
|
|
||||||
*/
|
|
||||||
APP_CMD_INPUT_CHANGED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: a new ANativeWindow is ready for use. Upon
|
|
||||||
* receiving this command, android_app->window will contain the new window
|
|
||||||
* surface.
|
|
||||||
*/
|
|
||||||
APP_CMD_INIT_WINDOW,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the existing ANativeWindow needs to be
|
|
||||||
* terminated. Upon receiving this command, android_app->window still
|
|
||||||
* contains the existing window; after calling android_app_exec_cmd
|
|
||||||
* it will be set to NULL.
|
|
||||||
*/
|
|
||||||
APP_CMD_TERM_WINDOW,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the current ANativeWindow has been resized.
|
|
||||||
* Please redraw with its new size.
|
|
||||||
*/
|
|
||||||
APP_CMD_WINDOW_RESIZED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the system needs that the current ANativeWindow
|
|
||||||
* be redrawn. You should redraw the window before handing this to
|
|
||||||
* android_app_exec_cmd() in order to avoid transient drawing glitches.
|
|
||||||
*/
|
|
||||||
APP_CMD_WINDOW_REDRAW_NEEDED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the content area of the window has changed,
|
|
||||||
* such as from the soft input window being shown or hidden. You can
|
|
||||||
* find the new content rect in android_app::contentRect.
|
|
||||||
*/
|
|
||||||
APP_CMD_CONTENT_RECT_CHANGED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the app's activity window has gained
|
|
||||||
* input focus.
|
|
||||||
*/
|
|
||||||
APP_CMD_GAINED_FOCUS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the app's activity window has lost
|
|
||||||
* input focus.
|
|
||||||
*/
|
|
||||||
APP_CMD_LOST_FOCUS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the current device configuration has changed.
|
|
||||||
*/
|
|
||||||
APP_CMD_CONFIG_CHANGED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the system is running low on memory.
|
|
||||||
* Try to reduce your memory use.
|
|
||||||
*/
|
|
||||||
APP_CMD_LOW_MEMORY,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the app's activity has been started.
|
|
||||||
*/
|
|
||||||
APP_CMD_START,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the app's activity has been resumed.
|
|
||||||
*/
|
|
||||||
APP_CMD_RESUME,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the app should generate a new saved state
|
|
||||||
* for itself, to restore from later if needed. If you have saved state,
|
|
||||||
* allocate it with malloc and place it in android_app.savedState with
|
|
||||||
* the size in android_app.savedStateSize. The will be freed for you
|
|
||||||
* later.
|
|
||||||
*/
|
|
||||||
APP_CMD_SAVE_STATE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the app's activity has been paused.
|
|
||||||
*/
|
|
||||||
APP_CMD_PAUSE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the app's activity has been stopped.
|
|
||||||
*/
|
|
||||||
APP_CMD_STOP,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command from main thread: the app's activity is being destroyed,
|
|
||||||
* and waiting for the app thread to clean up and exit before proceeding.
|
|
||||||
*/
|
|
||||||
APP_CMD_DESTROY,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
|
|
||||||
* app command message.
|
|
||||||
*/
|
|
||||||
int8_t android_app_read_cmd(struct android_app* android_app);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call with the command returned by android_app_read_cmd() to do the
|
|
||||||
* initial pre-processing of the given command. You can perform your own
|
|
||||||
* actions for the command after calling this function.
|
|
||||||
*/
|
|
||||||
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call with the command returned by android_app_read_cmd() to do the
|
|
||||||
* final post-processing of the given command. You must have done your own
|
|
||||||
* actions for the command before calling this function.
|
|
||||||
*/
|
|
||||||
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* No-op function that used to be used to prevent the linker from stripping app
|
|
||||||
* glue code. No longer necessary, since __attribute__((visibility("default")))
|
|
||||||
* does this for us.
|
|
||||||
*/
|
|
||||||
__attribute__((
|
|
||||||
deprecated("Calls to app_dummy are no longer necessary. See "
|
|
||||||
"https://github.com/android-ndk/ndk/issues/381."))) void
|
|
||||||
app_dummy();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the function that application code must implement, representing
|
|
||||||
* the main entry to the app.
|
|
||||||
*/
|
|
||||||
extern void android_main(struct android_app* app);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
|
|
||||||
#include "animations.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
using namespace tp;
|
|
||||||
using namespace glw;
|
|
||||||
|
|
||||||
bool tp::glw::gInTransition = false;
|
|
||||||
|
|
||||||
halnf AnimValue::interpolate() const {
|
|
||||||
if (!mTimeAnim) {
|
|
||||||
return mVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dt = gCurrentTime - mTimeStart;
|
|
||||||
if (dt > mTimeAnim) dt = mTimeAnim;
|
|
||||||
auto t = (halnf)dt / mTimeAnim;
|
|
||||||
t = (halnf)(0.511 + atan((t - 0.36) * 28) / 2.9);
|
|
||||||
t = clamp(t, 0.f, 1.f);
|
|
||||||
auto out = mValPrev + (mVal - mValPrev) * t;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimValue::AnimValue() {}
|
|
||||||
|
|
||||||
void AnimValue::setAnimTime(halni time) {
|
|
||||||
mTimeAnim = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimValue::AnimValue(halnf val) {
|
|
||||||
mVal = val;
|
|
||||||
mValPrev = mVal;
|
|
||||||
mTimeStart = gCurrentTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AnimValue::inTransition() const {
|
|
||||||
auto time_pased = gCurrentTime - mTimeStart >= mTimeAnim;
|
|
||||||
return !time_pased;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimValue::set(halnf val) {
|
|
||||||
if (!inTransition()) {
|
|
||||||
mValPrev = mVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val == mVal) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mValPrev = get();
|
|
||||||
mVal = val;
|
|
||||||
|
|
||||||
if (!inTransition()) {
|
|
||||||
mTimeStart = (halni)gCurrentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
halnf AnimValue::getTarget() const {
|
|
||||||
return mVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimValue::setNoTransition(halnf val) {
|
|
||||||
mValPrev = val;
|
|
||||||
mVal = val;
|
|
||||||
mTimeStart -= mTimeStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
halnf AnimValue::get() const {
|
|
||||||
if (inTransition()) {
|
|
||||||
gInTransition = true;
|
|
||||||
}
|
|
||||||
return interpolate();
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimValue::operator halnf() const {
|
|
||||||
return get();
|
|
||||||
}
|
|
||||||
|
|
||||||
rectf AnimRect::get() const {
|
|
||||||
return { x.get(), y.get() , z.get(), w.get() };
|
|
||||||
}
|
|
||||||
|
|
||||||
rectf AnimRect::getTarget() const {
|
|
||||||
return { x.getTarget(), y.getTarget() , z.getTarget(), w.getTarget() };
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimRect::setNoTransition(rectf rec) {
|
|
||||||
x.setNoTransition(rec.x);
|
|
||||||
y.setNoTransition(rec.y);
|
|
||||||
z.setNoTransition(rec.z);
|
|
||||||
w.setNoTransition(rec.w);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimRect::setAnimTime(const halni time) {
|
|
||||||
x.setAnimTime(time);
|
|
||||||
y.setAnimTime(time);
|
|
||||||
z.setAnimTime(time);
|
|
||||||
w.setAnimTime(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimRect::set(const rectf& in) {
|
|
||||||
x.set(in.x);
|
|
||||||
y.set(in.y);
|
|
||||||
z.set(in.z);
|
|
||||||
w.set(in.w);
|
|
||||||
}
|
|
||||||
|
|
||||||
rgba AnimColor::get() const {
|
|
||||||
auto col = mColor.get();
|
|
||||||
return rgba(col.x, col.y, col.z, col.w);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimColor::set(const rgba& col) {
|
|
||||||
mColor.set(rectf(col.r, col.g, col.b, col.a));
|
|
||||||
}
|
|
||||||
|
|
@ -1,378 +0,0 @@
|
||||||
|
|
||||||
#include "canvas.h"
|
|
||||||
|
|
||||||
#include "GraphicsLibApi.h"
|
|
||||||
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
const char* get_android_abs_path(const char* path, bool second = false);
|
|
||||||
#define NANOVG_GLES3_IMPLEMENTATION // Use GLES3 implementation.
|
|
||||||
#else
|
|
||||||
#define NANOVG_GL3_IMPLEMENTATION // Use GL3 implementation.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "nanovg.h"
|
|
||||||
#include "nanovg_gl.h"
|
|
||||||
#include "nanovg_gl_utils.h"
|
|
||||||
|
|
||||||
using namespace tp;
|
|
||||||
using namespace glw;
|
|
||||||
|
|
||||||
#define NVG ((NVGcontext*) mCtx)
|
|
||||||
|
|
||||||
static const char* getFontPath() {
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
return get_android_abs_path("rsc/fonts/CONSOLAB.TTF");
|
|
||||||
#else
|
|
||||||
return "./rsc/fonts/CONSOLAB.TTF";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Canvas::Canvas() {
|
|
||||||
|
|
||||||
// create context
|
|
||||||
mCtx =
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
nvgCreateGLES3
|
|
||||||
#else
|
|
||||||
nvgCreateGL3
|
|
||||||
#endif
|
|
||||||
(NVG_ANTIALIAS | NVG_STENCIL_STROKES
|
|
||||||
#ifdef ENV_BUILD_DEBUG
|
|
||||||
| NVG_DEBUG
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
mColorPrimary = rgba(0.5f, 0.5f, 0.5f, 0.9f);
|
|
||||||
mColorSecondary = rgba(0.2f, 0.2f, 0.2f, 0.9f);
|
|
||||||
|
|
||||||
nvgCreateFont(NVG, "basic", getFontPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
Canvas::Val& Canvas::convert2pxls(Val& val) {
|
|
||||||
val = val * mDpmm * mUIScale;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
Canvas::Val Canvas::as2pxls(Val val) {
|
|
||||||
return val * mDpmm * mUIScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
Canvas::Rect& Canvas::convert2pxls(Rect& rec) {
|
|
||||||
convert2pxls(rec.x);
|
|
||||||
convert2pxls(rec.y);
|
|
||||||
convert2pxls(rec.z);
|
|
||||||
convert2pxls(rec.w);
|
|
||||||
return rec;
|
|
||||||
}
|
|
||||||
|
|
||||||
Canvas::Vec2& Canvas::convert2pxls(Vec2& vec) {
|
|
||||||
convert2pxls(vec.x);
|
|
||||||
convert2pxls(vec.y);
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::beginDraw(Rect viewport, tp::halnf dpmm, tp::halnf uiscale) {
|
|
||||||
convert2pxls(viewport);
|
|
||||||
nvgBeginFrame(NVG, viewport.size.x, viewport.size.y, 1);
|
|
||||||
|
|
||||||
mVieport = { 0.f, 0.f, viewport.size.x, viewport.size.y };
|
|
||||||
glViewport((GLsizei)mVieport.x, (GLsizei)mVieport.y, (GLsizei)mVieport.size.x, (GLsizei)mVieport.size.y);
|
|
||||||
|
|
||||||
mDpmm = dpmm;
|
|
||||||
mUIScale = tp::clamp(uiscale, 0.03f, 100.f);
|
|
||||||
|
|
||||||
mClamping = mVieport;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::resetViewport() {
|
|
||||||
glViewport((GLsizei)mVieport.x, (GLsizei)mVieport.y, (GLsizei)mVieport.size.x, (GLsizei)mVieport.size.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::clear(Col color) {
|
|
||||||
glClearColor(color.r, color.g, color.b, color.a);
|
|
||||||
//glClearDepth(0.f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::endDraw() {
|
|
||||||
nvgEndFrame(NVG);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::setClamping(Rect rec) {
|
|
||||||
mClamping = rec;
|
|
||||||
convert2pxls(rec);
|
|
||||||
nvgScissor(NVG, rec.x, rec.y, rec.z, rec.w);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::setCol1(const Col& col) {
|
|
||||||
mColorPrimary = col;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::setCol2(const Col& col) {
|
|
||||||
mColorSecondary = col;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::rect(Rect rec, halnf rounding, halnf borders) {
|
|
||||||
convert2pxls(rec);
|
|
||||||
convert2pxls(rounding);
|
|
||||||
convert2pxls(borders);
|
|
||||||
|
|
||||||
if (borders) {
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
|
|
||||||
auto borders_rec = rec;
|
|
||||||
rec.pos += borders;
|
|
||||||
rec.size -= borders * 2;
|
|
||||||
|
|
||||||
if (rounding) {
|
|
||||||
nvgRoundedRect(NVG, borders_rec.x, borders_rec.y, borders_rec.z, borders_rec.w, rounding);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nvgRect(NVG, borders_rec.x, borders_rec.y, borders_rec.z, borders_rec.w);
|
|
||||||
}
|
|
||||||
|
|
||||||
nvgFillColor(NVG, nvgRGBAf(mColorSecondary.r, mColorSecondary.g, mColorSecondary.b, mColorSecondary.a));
|
|
||||||
nvgFill(NVG);
|
|
||||||
}
|
|
||||||
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
|
|
||||||
if (rounding) {
|
|
||||||
nvgRoundedRect(NVG, rec.x, rec.y, rec.z, rec.w, rounding);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nvgRect(NVG, rec.x, rec.y, rec.z, rec.w);
|
|
||||||
}
|
|
||||||
nvgFillColor(NVG, nvgRGBAf(mColorPrimary.r, mColorPrimary.g, mColorPrimary.b, mColorPrimary.a));
|
|
||||||
nvgFill(NVG);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::line(Vec2 p1, Vec2 p2, halnf thikness) {
|
|
||||||
convert2pxls(p1);
|
|
||||||
convert2pxls(p2);
|
|
||||||
convert2pxls(thikness);
|
|
||||||
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
|
|
||||||
nvgMoveTo(NVG, p1.x, p1.y);
|
|
||||||
nvgLineTo(NVG, p2.x, p2.y);
|
|
||||||
|
|
||||||
nvgStrokeColor(NVG, nvgRGBAf(mColorPrimary.r, mColorPrimary.g, mColorPrimary.b, mColorPrimary.a));
|
|
||||||
nvgStrokeWidth(NVG, thikness);
|
|
||||||
nvgStroke(NVG);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::trig(Vec2 p1, Vec2 p2, Vec2 p3) {
|
|
||||||
convert2pxls(p1);
|
|
||||||
convert2pxls(p2);
|
|
||||||
convert2pxls(p3);
|
|
||||||
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
|
|
||||||
nvgMoveTo(NVG, p1.x, p1.y);
|
|
||||||
nvgLineTo(NVG, p2.x, p2.y);
|
|
||||||
nvgLineTo(NVG, p3.x, p3.y);
|
|
||||||
|
|
||||||
nvgFillColor(NVG, nvgRGBAf(mColorPrimary.r, mColorPrimary.g, mColorPrimary.b, mColorPrimary.a));
|
|
||||||
nvgFill(NVG);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::circle(Vec2 rec, halnf radius, halnf borders) {
|
|
||||||
convert2pxls(rec);
|
|
||||||
convert2pxls(radius);
|
|
||||||
convert2pxls(borders);
|
|
||||||
DBG_BREAK(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::text(const char* start, const char* end, Rect rec, halnf size, Align align) {
|
|
||||||
convert2pxls(rec);
|
|
||||||
convert2pxls(size);
|
|
||||||
|
|
||||||
nvgFillColor(NVG, nvgRGBAf(mColorPrimary.r, mColorPrimary.g, mColorPrimary.b, mColorPrimary.a));
|
|
||||||
nvgFontSize(NVG, size);
|
|
||||||
nvgTextAlign(NVG, NVGalign(align));
|
|
||||||
auto y = (align & Align::MIDDLE) ? rec.y + rec.w / 2 : rec.y;
|
|
||||||
auto x = (align & Align::CENTER) ? rec.x + rec.z / 2 : rec.x;
|
|
||||||
nvgText(NVG, x, y, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::text(const string text, Rect rec, halnf size, Align align) {
|
|
||||||
convert2pxls(rec);
|
|
||||||
convert2pxls(size);
|
|
||||||
|
|
||||||
nvgFillColor(NVG, nvgRGBAf(mColorPrimary.r, mColorPrimary.g, mColorPrimary.b, mColorPrimary.a));
|
|
||||||
nvgFontSize(NVG, size);
|
|
||||||
nvgTextAlign(NVG, NVGalign(align));
|
|
||||||
|
|
||||||
//nvgTextBounds(NVG, );
|
|
||||||
|
|
||||||
auto t_mid = rec.y + rec.w / 2;
|
|
||||||
auto t_top = rec.y;
|
|
||||||
auto res = bool(align & Align::MIDDLE);
|
|
||||||
auto y = res ? t_mid : t_top;
|
|
||||||
|
|
||||||
auto x_mid = rec.x + rec.z / 2;
|
|
||||||
auto x_left = rec.x;
|
|
||||||
res = bool(align & Align::CENTER);
|
|
||||||
auto x = res ? x_mid : x_left;
|
|
||||||
|
|
||||||
nvgText(NVG, x, y, text.cstr(), text.cstr() + text.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Canvas::ImageHandle::createFromBuff(glw::fbuffer* buff, Canvas* drawer) {
|
|
||||||
this->~ImageHandle();
|
|
||||||
auto const size = buff->getSize();
|
|
||||||
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
mId = nvglCreateImageFromHandleGLES3((NVGcontext*)drawer->mCtx, buff->texId(), size.x, size.y, 0);
|
|
||||||
#else
|
|
||||||
mId = nvglCreateImageFromHandleGL3((NVGcontext*)drawer->mCtx, buff->texId(), (halni) size.x, (halni) size.y, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::ImageHandle::free(Canvas* drawer) {
|
|
||||||
if (mId && (NVGcontext*)drawer->mCtx) {
|
|
||||||
nvgDeleteImage((NVGcontext*)drawer->mCtx, mId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Canvas::ImageHandle::~ImageHandle() {}
|
|
||||||
|
|
||||||
void Canvas::drawImage(Rect rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding) {
|
|
||||||
convert2pxls(rec);
|
|
||||||
convert2pxls(rounding);
|
|
||||||
|
|
||||||
|
|
||||||
auto imgPaint = nvgImagePattern(NVG, rec.x, rec.y, rec.z, rec.w, angle, image->mId, alpha);
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
nvgRoundedRect(NVG, rec.x, rec.y, rec.z, rec.w, rounding);
|
|
||||||
nvgFillPaint(NVG, imgPaint);
|
|
||||||
nvgFill(NVG);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::drawColorwheel(Rect rec, const rgb& col) {
|
|
||||||
convert2pxls(rec);
|
|
||||||
|
|
||||||
float const x = rec.x;
|
|
||||||
float const y = rec.y;
|
|
||||||
float const w = rec.z;
|
|
||||||
float const h = rec.w;
|
|
||||||
|
|
||||||
hsv hsv = tp::hsv(col);
|
|
||||||
float const hue = hsv.h / (NVG_PI * 2);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
float r0, r1, ax, ay, bx, by, cx, cy, aeps, r;
|
|
||||||
NVGpaint paint;
|
|
||||||
|
|
||||||
nvgSave(NVG);
|
|
||||||
|
|
||||||
cx = x + w * 0.5f;
|
|
||||||
cy = y + h * 0.5f;
|
|
||||||
r1 = (w < h ? w : h) * 0.5f - as2pxls(1.0f);
|
|
||||||
r0 = r1 - as2pxls(3.0f);
|
|
||||||
aeps = 0.5f / r1; // half a pixel arc length in radians (2pi cancels out).
|
|
||||||
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
float a0 = (float)i / 6.0f * NVG_PI * 2.0f - aeps;
|
|
||||||
float a1 = (float)(i + 1.0f) / 6.0f * NVG_PI * 2.0f + aeps;
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
nvgArc(NVG, cx, cy, r0, a0, a1, NVG_CW);
|
|
||||||
nvgArc(NVG, cx, cy, r1, a1, a0, NVG_CCW);
|
|
||||||
nvgClosePath(NVG);
|
|
||||||
ax = cx + cosf(a0) * (r0 + r1) * 0.5f;
|
|
||||||
ay = cy + sinf(a0) * (r0 + r1) * 0.5f;
|
|
||||||
bx = cx + cosf(a1) * (r0 + r1) * 0.5f;
|
|
||||||
by = cy + sinf(a1) * (r0 + r1) * 0.5f;
|
|
||||||
paint = nvgLinearGradient(NVG, ax, ay, bx, by, nvgHSLA(a0 / (NVG_PI * 2), 1.0f, 0.55f, 255), nvgHSLA(a1 / (NVG_PI * 2), 1.0f, 0.55f, 255));
|
|
||||||
nvgFillPaint(NVG, paint);
|
|
||||||
nvgFill(NVG);
|
|
||||||
}
|
|
||||||
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
nvgCircle(NVG, cx, cy, r0 - 0.5f);
|
|
||||||
nvgCircle(NVG, cx, cy, r1 + 0.5f);
|
|
||||||
nvgStrokeColor(NVG, nvgRGBA(0, 0, 0, 64));
|
|
||||||
nvgStrokeWidth(NVG, 1.0f);
|
|
||||||
nvgStroke(NVG);
|
|
||||||
|
|
||||||
// Selector
|
|
||||||
nvgSave(NVG);
|
|
||||||
nvgTranslate(NVG, cx, cy);
|
|
||||||
nvgRotate(NVG, hue * NVG_PI * 2);
|
|
||||||
|
|
||||||
// Marker on
|
|
||||||
nvgStrokeWidth(NVG, 2.0f);
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
nvgRect(NVG, r0 - 1, -3, r1 - r0 + 2, 6);
|
|
||||||
nvgStrokeColor(NVG, nvgRGBA(255, 255, 255, 192));
|
|
||||||
nvgStroke(NVG);
|
|
||||||
|
|
||||||
paint = nvgBoxGradient(NVG, r0 - 3, -5, r1 - r0 + 6, 10, 2, 4, nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
nvgRect(NVG, r0 - 2 - 10, -4 - 10, r1 - r0 + 4 + 20, 8 + 20);
|
|
||||||
nvgRect(NVG, r0 - 2, -4, r1 - r0 + 4, 8);
|
|
||||||
nvgPathWinding(NVG, NVG_HOLE);
|
|
||||||
nvgFillPaint(NVG, paint);
|
|
||||||
nvgFill(NVG);
|
|
||||||
|
|
||||||
// Center triangle
|
|
||||||
r = r0 - 6;
|
|
||||||
ax = cosf(120.0f / 180.0f * NVG_PI) * r;
|
|
||||||
ay = sinf(120.0f / 180.0f * NVG_PI) * r;
|
|
||||||
bx = cosf(-120.0f / 180.0f * NVG_PI) * r;
|
|
||||||
by = sinf(-120.0f / 180.0f * NVG_PI) * r;
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
nvgMoveTo(NVG, r, 0);
|
|
||||||
nvgLineTo(NVG, ax, ay);
|
|
||||||
nvgLineTo(NVG, bx, by);
|
|
||||||
nvgClosePath(NVG);
|
|
||||||
paint = nvgLinearGradient(NVG, r, 0, ax, ay, nvgHSLA(hue, 1.0f, 0.5f, 255), nvgRGBA(255, 255, 255, 255));
|
|
||||||
nvgFillPaint(NVG, paint);
|
|
||||||
nvgFill(NVG);
|
|
||||||
paint = nvgLinearGradient(NVG, (r + ax) * 0.5f, (0 + ay) * 0.5f, bx, by, nvgRGBA(0, 0, 0, 0), nvgRGBA(0, 0, 0, 255));
|
|
||||||
nvgFillPaint(NVG, paint);
|
|
||||||
nvgFill(NVG);
|
|
||||||
nvgStrokeColor(NVG, nvgRGBA(0, 0, 0, 64));
|
|
||||||
nvgStroke(NVG);
|
|
||||||
|
|
||||||
// Select circle on triangle
|
|
||||||
auto inner = as2pxls(3);
|
|
||||||
//auto outter = as2pxls(5);
|
|
||||||
|
|
||||||
float yt = hsv.v * hsv.s;
|
|
||||||
float xt = hsv.v - 0.5f * yt;
|
|
||||||
ay = sinf(120.0f / 180.0f * NVG_PI) * r * (-1.0f + xt * 2.0f);
|
|
||||||
ax = cosf(120.0f / 180.0f * NVG_PI) * r * (1.0f - yt * 3.f);
|
|
||||||
nvgStrokeWidth(NVG, as2pxls(0.6f));
|
|
||||||
nvgBeginPath(NVG);
|
|
||||||
nvgCircle(NVG, ax, ay, inner);
|
|
||||||
nvgStrokeColor(NVG, nvgRGBA(255, 255, 255, 192));
|
|
||||||
nvgStroke(NVG);
|
|
||||||
|
|
||||||
//paint = nvgRadialGradient(NVG, ax, ay, 4, 9, nvgRGBA(0, 0, 0, 64), nvgRGBA(0, 0, 0, 0));
|
|
||||||
//nvgBeginPath(NVG);
|
|
||||||
//nvgRect(NVG, ax - outter, ay - outter, outter * 2, outter * 2);
|
|
||||||
//nvgCircle(NVG, ax, ay, outter);
|
|
||||||
//nvgPathWinding(NVG, NVG_HOLE);
|
|
||||||
//nvgFillPaint(NVG, paint);
|
|
||||||
//nvgFill(NVG);
|
|
||||||
|
|
||||||
nvgRestore(NVG);
|
|
||||||
|
|
||||||
nvgRestore(NVG);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Canvas::~Canvas() {
|
|
||||||
if (NVG) {
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
nvgDeleteGLES3(NVG);
|
|
||||||
#else
|
|
||||||
nvgDeleteGL3(NVG);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
mCtx = NULL;
|
|
||||||
}
|
|
||||||
|
|
@ -1,877 +0,0 @@
|
||||||
|
|
||||||
#include "debugui.h"
|
|
||||||
|
|
||||||
#include "typelist.h"
|
|
||||||
#include "stringt.h"
|
|
||||||
#include "stack.h"
|
|
||||||
#include "npple.h"
|
|
||||||
#include "rect.h"
|
|
||||||
#include "map.h"
|
|
||||||
|
|
||||||
#include "imgui.h"
|
|
||||||
#include "imgui_internal.h"
|
|
||||||
#include "implot.h"
|
|
||||||
|
|
||||||
// -------------- Platform Includes ---------------------- //
|
|
||||||
|
|
||||||
#if defined ENV_OS_WINDOWS
|
|
||||||
#include "backends/imgui_impl_opengl3.h"
|
|
||||||
#include "backends/imgui_impl_win32.h"
|
|
||||||
#include <Windows.h>
|
|
||||||
#elif defined ENV_OS_LINUX
|
|
||||||
#include "backends/imgui_impl_opengl3.h"
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
|
||||||
#elif defined ENV_OS_ANDROID
|
|
||||||
#include "backends/imgui_impl_opengl3.h"
|
|
||||||
#include "backends/imgui_impl_android.h"
|
|
||||||
#include <android/sensor.h>
|
|
||||||
#include <android/log.h>
|
|
||||||
#include <android/input.h>
|
|
||||||
#include <string.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if defined ENV_OS_WINDOWS
|
|
||||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
extern HWND windowsPlatformContextGetNativeWindow(tp::glw::PlatformContext* ctx);
|
|
||||||
extern UINT windowsPlatformContextGetMessage(tp::glw::PlatformContext* ctx);
|
|
||||||
extern WPARAM windowsPlatformContextGetWparam(tp::glw::PlatformContext* ctx);
|
|
||||||
extern LRESULT windowsPlatformContextGetLparam(tp::glw::PlatformContext* ctx);
|
|
||||||
|
|
||||||
#elif defined ENV_OS_LINUX
|
|
||||||
#elif defined ENV_OS_ANDROID
|
|
||||||
extern AInputEvent* androidPlatformContextGetEvent(tp::glw::PlatformContext* ctx);
|
|
||||||
extern const char* get_android_abs_path(const char* path, bool second = false);
|
|
||||||
|
|
||||||
const char* AndroidGetImGuiIniPath() {
|
|
||||||
static char imgui_path[512];
|
|
||||||
auto tmp = get_android_abs_path("imgui.ini");
|
|
||||||
memcpy(imgui_path, tmp, strlen(tmp));
|
|
||||||
return imgui_path;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char* getFontPath() {
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
return get_android_abs_path("rsc/fonts/CONSOLAB.TTF");
|
|
||||||
#else
|
|
||||||
return "./rsc/fonts/CONSOLAB.TTF";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
struct DebugUiInternalContext {
|
|
||||||
|
|
||||||
DebugUiDrawCallBack* cb = NULL;
|
|
||||||
void* cd = NULL;
|
|
||||||
|
|
||||||
ImGuiContext* ui_context = NULL;
|
|
||||||
ImGuiContext* vk_context = NULL;
|
|
||||||
|
|
||||||
bool initialized = false;
|
|
||||||
|
|
||||||
bool ui_first_drawn = false;
|
|
||||||
bool vk_first_drawn = false;
|
|
||||||
|
|
||||||
bool ui_context_want_active = true;
|
|
||||||
bool ui_context_want_active_vk = false;
|
|
||||||
bool vk_context_want_active = false;
|
|
||||||
|
|
||||||
tp::halnf dpmm;
|
|
||||||
tp::halnf font_size_mm;
|
|
||||||
tp::halnf ui_scale;
|
|
||||||
|
|
||||||
struct VKState {
|
|
||||||
|
|
||||||
struct InputButton {
|
|
||||||
char val = '?';
|
|
||||||
char shift_val = '?';
|
|
||||||
tp::halnf width = 1;
|
|
||||||
|
|
||||||
void (*action)(InputButton* button, VKState* state) = [](InputButton* button, VKState* state) {
|
|
||||||
if (state->mShifted) {
|
|
||||||
ImGui::GetIO().AddInputCharacter(button->shift_val);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::GetIO().AddInputCharacter(button->val);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* display_name = NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Config {
|
|
||||||
InputButton** rows = NULL;
|
|
||||||
tp::halni nrows = NULL;
|
|
||||||
tp::halnf* rows_widths = NULL;
|
|
||||||
tp::halnf* rows_sizes = NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool mShifted = false;
|
|
||||||
|
|
||||||
static const tp::uhalni mNConfigs = 2;
|
|
||||||
Config mConfigs[mNConfigs];
|
|
||||||
tp::uhalni mActiveConfigIdx = 0;
|
|
||||||
|
|
||||||
InputButton mCommonRow[7];
|
|
||||||
//bool mActive = false;
|
|
||||||
|
|
||||||
VKState() {
|
|
||||||
mCommonRow[0] = { '^', '^', 1 , [](InputButton* button, VKState* state) { state->mShifted = !state->mShifted; } };
|
|
||||||
|
|
||||||
mCommonRow[1] = { ' ', ' ', 1,
|
|
||||||
[](InputButton* button, VKState* state) {
|
|
||||||
state->mActiveConfigIdx++;
|
|
||||||
if (state->mActiveConfigIdx == state->mNConfigs) {
|
|
||||||
state->mActiveConfigIdx = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"..."
|
|
||||||
};
|
|
||||||
|
|
||||||
mCommonRow[2] = { ' ', ' ', 2 };
|
|
||||||
|
|
||||||
mCommonRow[3] = { '<', '<', 2, [](InputButton* button, VKState* state) {
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_Backspace, true);
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_Backspace, false);
|
|
||||||
} };
|
|
||||||
|
|
||||||
mCommonRow[4] = { '.', '.', 1 };
|
|
||||||
mCommonRow[5] = { '@', '@', 1 };
|
|
||||||
|
|
||||||
mCommonRow[6] = { ' ', ' ', 2, [](InputButton* button, VKState* state) {
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_Enter, true);
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_Enter, false);
|
|
||||||
}, "Entrer" };
|
|
||||||
|
|
||||||
setupMainConfig(mConfigs[0]);
|
|
||||||
setupAdditionalConfig(mConfigs[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupMainConfig(Config& config) {
|
|
||||||
|
|
||||||
static InputButton row1[] = {
|
|
||||||
{'1', '!'},
|
|
||||||
{'2', '@'},
|
|
||||||
{'3', '#'},
|
|
||||||
{'4', '$'},
|
|
||||||
{'5', '%'},
|
|
||||||
{'6', '^'},
|
|
||||||
{'7', '&'},
|
|
||||||
{'8', '*'},
|
|
||||||
{'9', '('},
|
|
||||||
{'0', ')'},
|
|
||||||
};
|
|
||||||
|
|
||||||
static InputButton row2[] = {
|
|
||||||
{'q', 'Q'},
|
|
||||||
{'w', 'W'},
|
|
||||||
{'e', 'E'},
|
|
||||||
{'r', 'R'},
|
|
||||||
{'t', 'T'},
|
|
||||||
{'y', 'Y'},
|
|
||||||
{'u', 'U'},
|
|
||||||
{'i', 'I'},
|
|
||||||
{'o', 'O'},
|
|
||||||
{'p', 'P'},
|
|
||||||
};
|
|
||||||
|
|
||||||
static InputButton row3[] = {
|
|
||||||
{'a', 'A'},
|
|
||||||
{'s', 'S'},
|
|
||||||
{'d', 'D'},
|
|
||||||
{'f', 'F'},
|
|
||||||
{'g', 'G'},
|
|
||||||
{'h', 'H'},
|
|
||||||
{'j', 'J'},
|
|
||||||
{'k', 'K'},
|
|
||||||
{'l', 'L'},
|
|
||||||
};
|
|
||||||
|
|
||||||
static InputButton row4[] = {
|
|
||||||
{'z', 'Z'},
|
|
||||||
{'x', 'X'},
|
|
||||||
{'c', 'C'},
|
|
||||||
{'v', 'V'},
|
|
||||||
{'b', 'B'},
|
|
||||||
{'n', 'N'},
|
|
||||||
{'m', 'M'},
|
|
||||||
};
|
|
||||||
|
|
||||||
static InputButton* rows[] = {
|
|
||||||
row1,
|
|
||||||
row2,
|
|
||||||
row3,
|
|
||||||
row4,
|
|
||||||
mCommonRow,
|
|
||||||
};
|
|
||||||
|
|
||||||
static tp::halnf rows_sizes[IM_ARRAYSIZE(rows)] = {
|
|
||||||
IM_ARRAYSIZE(row1),
|
|
||||||
IM_ARRAYSIZE(row2),
|
|
||||||
IM_ARRAYSIZE(row3),
|
|
||||||
IM_ARRAYSIZE(row4),
|
|
||||||
IM_ARRAYSIZE(mCommonRow),
|
|
||||||
};
|
|
||||||
|
|
||||||
static tp::halnf rows_widths[IM_ARRAYSIZE(rows)];
|
|
||||||
for (auto row = 0; row < IM_ARRAYSIZE(rows); row++) {
|
|
||||||
for (auto butt = 0; butt < rows_sizes[row]; butt++) {
|
|
||||||
rows_widths[row] += rows[row][butt].width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config = {
|
|
||||||
rows,
|
|
||||||
IM_ARRAYSIZE(rows),
|
|
||||||
rows_widths,
|
|
||||||
rows_sizes,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupAdditionalConfig(Config& config) {
|
|
||||||
static InputButton row1[] = {
|
|
||||||
{'~', '~'},
|
|
||||||
{'`', '`'},
|
|
||||||
{'_', '_'},
|
|
||||||
{'|', '|'},
|
|
||||||
{'\\', '\\'},
|
|
||||||
{'/', '/'},
|
|
||||||
{'"', '"'},
|
|
||||||
{'\'', '\''},
|
|
||||||
};
|
|
||||||
|
|
||||||
static InputButton row2[] = {
|
|
||||||
{';', ';'},
|
|
||||||
{':', ':'},
|
|
||||||
{'?', '?'},
|
|
||||||
{',', ','},
|
|
||||||
{'[', '['},
|
|
||||||
{']', ']'},
|
|
||||||
{'{', '{'},
|
|
||||||
{'}', '}'},
|
|
||||||
{'(', '('},
|
|
||||||
{')', ')'},
|
|
||||||
};
|
|
||||||
|
|
||||||
static InputButton row3[] = {
|
|
||||||
{'-', '-'},
|
|
||||||
{'=', '='},
|
|
||||||
{'*', '*'},
|
|
||||||
{'+', '+'},
|
|
||||||
{'<', '<'},
|
|
||||||
{'>', '>'},
|
|
||||||
};
|
|
||||||
|
|
||||||
static InputButton row4[] = {
|
|
||||||
{' ', ' ', 1, [](InputButton* butt, VKState* state) {
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_UpArrow, true);
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_UpArrow, false);
|
|
||||||
}, "up" },
|
|
||||||
{' ', ' ', 1, [](InputButton* butt, VKState* state) {
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_DownArrow, true);
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_DownArrow, false);
|
|
||||||
}, "down"},
|
|
||||||
{' ', ' ', 1, [](InputButton* butt, VKState* state) {
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_LeftArrow, true);
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_LeftArrow, false);
|
|
||||||
}, "left"},
|
|
||||||
{' ', ' ', 1, [](InputButton* butt, VKState* state) {
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_RightArrow, true);
|
|
||||||
ImGui::GetIO().AddKeyEvent(ImGuiKey_RightArrow, false);
|
|
||||||
}, "right"},
|
|
||||||
};
|
|
||||||
|
|
||||||
static InputButton* rows[] = {
|
|
||||||
row1,
|
|
||||||
row2,
|
|
||||||
row3,
|
|
||||||
row4,
|
|
||||||
mCommonRow,
|
|
||||||
};
|
|
||||||
|
|
||||||
static tp::halnf rows_sizes[IM_ARRAYSIZE(rows)] = {
|
|
||||||
IM_ARRAYSIZE(row1),
|
|
||||||
IM_ARRAYSIZE(row2),
|
|
||||||
IM_ARRAYSIZE(row3),
|
|
||||||
IM_ARRAYSIZE(row4),
|
|
||||||
IM_ARRAYSIZE(mCommonRow),
|
|
||||||
};
|
|
||||||
|
|
||||||
static tp::halnf rows_widths[IM_ARRAYSIZE(rows)];
|
|
||||||
for (auto row = 0; row < IM_ARRAYSIZE(rows); row++) {
|
|
||||||
for (auto butt = 0; butt < rows_sizes[row]; butt++) {
|
|
||||||
rows_widths[row] += rows[row][butt].width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config = {
|
|
||||||
rows,
|
|
||||||
IM_ARRAYSIZE(rows),
|
|
||||||
rows_widths,
|
|
||||||
rows_sizes,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
} mVKState;
|
|
||||||
|
|
||||||
DebugUiInternalContext(Window& window, DebugUiDrawCallBack* acb, void* acd) {
|
|
||||||
|
|
||||||
cb = acb;
|
|
||||||
cd = acd;
|
|
||||||
|
|
||||||
ui_context = ImGui::CreateContext();
|
|
||||||
ImGui::SetCurrentContext(ui_context);
|
|
||||||
ImGuiContextInit(window);
|
|
||||||
|
|
||||||
vk_context = ImGui::CreateContext();
|
|
||||||
ImGui::SetCurrentContext(vk_context);
|
|
||||||
ImGuiContextInit(window);
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawDebugUI(tp::halnf a_dpmm, tp::halnf a_font_size_mm, tp::halnf a_ui_scale) {
|
|
||||||
dpmm = a_dpmm;
|
|
||||||
font_size_mm = a_font_size_mm;
|
|
||||||
ui_scale = a_ui_scale;
|
|
||||||
|
|
||||||
if (!initialized) return;
|
|
||||||
|
|
||||||
ImGui::SetCurrentContext(ui_context);
|
|
||||||
ImGui::ApplyStyle(dpmm, font_size_mm, ui_scale);
|
|
||||||
ImGuiContextBeginFrame();
|
|
||||||
cb(cd);
|
|
||||||
ImGuiContextEndFrame();
|
|
||||||
ImGui::SetCurrentContext(NULL);
|
|
||||||
ui_first_drawn = true;
|
|
||||||
|
|
||||||
if (ui_context_want_active_vk || vk_context_want_active) {
|
|
||||||
ImGui::SetCurrentContext(vk_context);
|
|
||||||
ImGui::ApplyStyle(dpmm, font_size_mm, ui_scale);
|
|
||||||
ImGuiContextBeginFrame();
|
|
||||||
VirtualKeyboard(dpmm, font_size_mm, ui_scale);
|
|
||||||
ImGuiContextEndFrame();
|
|
||||||
ImGui::SetCurrentContext(NULL);
|
|
||||||
|
|
||||||
vk_first_drawn = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~DebugUiInternalContext() {
|
|
||||||
if (!initialized) return;
|
|
||||||
|
|
||||||
ImGui::SetCurrentContext(ui_context);
|
|
||||||
ImGuiContextDeinit();
|
|
||||||
ImGui::DestroyContext(ui_context);
|
|
||||||
|
|
||||||
ImGui::SetCurrentContext(vk_context);
|
|
||||||
ImGuiContextDeinit();
|
|
||||||
ImGui::DestroyContext(vk_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void ImGuiContextInit(Window& window) {
|
|
||||||
#if defined ENV_OS_WINDOWS
|
|
||||||
ImGui_ImplOpenGL3_Init();
|
|
||||||
ImGui_ImplWin32_Init(window.platform_window());
|
|
||||||
window.mNativeEventListeners.put("imgui", {
|
|
||||||
nativeWindowEventListenerWrapBegin,
|
|
||||||
nativeWindowEventListenerWrap,
|
|
||||||
nativeWindowEventListenerWrapEnd,
|
|
||||||
this
|
|
||||||
});
|
|
||||||
#elif defined ENV_OS_LINUX
|
|
||||||
ImGui_ImplOpenGL3_Init();
|
|
||||||
ImGui_ImplGlfw_InitForOpenGL((GLFWwindow*)window.platform_window(), true);
|
|
||||||
#elif defined ENV_OS_ANDROID
|
|
||||||
ImGui_ImplOpenGL3_Init("#version 300 es");
|
|
||||||
ImGui_ImplAndroid_Init((ANativeWindow*)window.platform_window());
|
|
||||||
ImGui::GetIO().IniFilename = AndroidGetImGuiIniPath();
|
|
||||||
window.mNativeEventListeners.put("imgui", {
|
|
||||||
nativeWindowEventListenerWrapBegin,
|
|
||||||
nativeWindowEventListenerWrap,
|
|
||||||
nativeWindowEventListenerWrapEnd,
|
|
||||||
this
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiContextBeginFrame() {
|
|
||||||
#if defined ENV_OS_WINDOWS
|
|
||||||
ImGui_ImplWin32_NewFrame();
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
|
||||||
#elif defined ENV_OS_LINUX
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
|
||||||
ImGui_ImplGlfw_NewFrame();
|
|
||||||
#elif defined ENV_OS_ANDROID
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
|
||||||
ImGui_ImplAndroid_NewFrame();
|
|
||||||
#endif
|
|
||||||
ImGui::NewFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiContextEndFrame() {
|
|
||||||
ImGui::Render();
|
|
||||||
|
|
||||||
#if defined ENV_OS_WINDOWS
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
||||||
#elif defined ENV_OS_LINUX
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
||||||
#elif defined ENV_OS_ANDROID
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiContextDeinit() {
|
|
||||||
#if defined ENV_OS_WINDOWS
|
|
||||||
ImGui_ImplWin32_Shutdown();
|
|
||||||
#elif defined ENV_OS_LINUX
|
|
||||||
ImGui_ImplGlfw_Shutdown();
|
|
||||||
#elif defined ENV_OS_ANDROID
|
|
||||||
ImGui_ImplAndroid_Shutdown();
|
|
||||||
#endif
|
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
void nativeWindowEventListenerPlatform(tp::glw::PlatformContext* ctx) {
|
|
||||||
#if defined ENV_OS_WINDOWS
|
|
||||||
auto native_window = windowsPlatformContextGetNativeWindow(ctx);
|
|
||||||
auto message = windowsPlatformContextGetMessage(ctx);
|
|
||||||
auto w_param = windowsPlatformContextGetWparam(ctx);
|
|
||||||
auto l_param = windowsPlatformContextGetLparam(ctx);
|
|
||||||
// IMGUI : needs to be commented out
|
|
||||||
//if (bd->MouseButtonsDown == 0 && ::GetCapture() == nullptr)
|
|
||||||
// ::SetCapture(hwnd);
|
|
||||||
ImGui_ImplWin32_WndProcHandler(native_window, message, w_param, l_param);
|
|
||||||
#elif defined ENV_OS_LINUX
|
|
||||||
#elif defined ENV_OS_ANDROID
|
|
||||||
|
|
||||||
auto aev = androidPlatformContextGetEvent(ctx);
|
|
||||||
|
|
||||||
int32_t event_type = AInputEvent_getType(aev);
|
|
||||||
|
|
||||||
ImGui_ImplAndroid_HandleInputEvent(aev);
|
|
||||||
|
|
||||||
auto& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
if (event_type == AINPUT_EVENT_TYPE_MOTION); {
|
|
||||||
int32_t event_action = AMotionEvent_getAction(aev);
|
|
||||||
int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
|
||||||
event_action &= AMOTION_EVENT_ACTION_MASK;
|
|
||||||
|
|
||||||
if ((AMotionEvent_getToolType(aev, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
|
|
||||||
|| (AMotionEvent_getToolType(aev, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) {
|
|
||||||
|
|
||||||
if (event_action == AMOTION_EVENT_ACTION_DOWN) {
|
|
||||||
io.AddMousePosEvent(AMotionEvent_getX(aev, event_pointer_index), AMotionEvent_getY(aev, event_pointer_index));
|
|
||||||
}
|
|
||||||
else if (event_action == AMOTION_EVENT_ACTION_UP) {
|
|
||||||
io.AddMousePosEvent(AMotionEvent_getX(aev, event_pointer_index), AMotionEvent_getY(aev, event_pointer_index));
|
|
||||||
if (!ui_context_want_active_vk || vk_context_want_active) {
|
|
||||||
io.AddMousePosEvent(-1, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void nativeWindowEventListenerBegin(tp::glw::PlatformContext* ctx) {
|
|
||||||
vk_context_want_active = vk_context->IO.WantCaptureMouse || vk_context->IO.WantSetMousePos;
|
|
||||||
|
|
||||||
ui_context_want_active_vk = ui_context->IO.WantTextInput;
|
|
||||||
ui_context_want_active = ui_context->IO.WantCaptureKeyboard || ui_context->IO.WantCaptureMouse || ui_context->IO.WantSetMousePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nativeWindowEventListener(tp::glw::PlatformContext* ctx) {
|
|
||||||
|
|
||||||
// proc vk
|
|
||||||
if ((ui_context_want_active_vk || vk_context_want_active) && vk_first_drawn) {
|
|
||||||
ImGui::SetCurrentContext(vk_context);
|
|
||||||
nativeWindowEventListenerPlatform(ctx);
|
|
||||||
|
|
||||||
while (vk_context->InputEventsQueue.Size) {
|
|
||||||
ImGui::ApplyStyle(dpmm, font_size_mm, ui_scale);
|
|
||||||
ImGui::NewFrame();
|
|
||||||
VirtualKeyboard(dpmm, font_size_mm, ui_scale);
|
|
||||||
ImGui::Render();
|
|
||||||
|
|
||||||
vk_context_want_active |= vk_context->IO.WantCaptureMouse || vk_context->IO.WantSetMousePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
vk_context_want_active |= vk_context->IO.WantCaptureMouse || vk_context->IO.WantSetMousePos;
|
|
||||||
|
|
||||||
ImGui::SetCurrentContext(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// proc ui
|
|
||||||
if (!vk_context_want_active && ui_first_drawn) {
|
|
||||||
ImGui::SetCurrentContext(ui_context);
|
|
||||||
nativeWindowEventListenerPlatform(ctx);
|
|
||||||
|
|
||||||
while (ui_context->InputEventsQueue.Size) {
|
|
||||||
ImGui::ApplyStyle(dpmm, font_size_mm, ui_scale);
|
|
||||||
ImGui::NewFrame();
|
|
||||||
cb(cd);
|
|
||||||
ImGui::Render();
|
|
||||||
|
|
||||||
ui_context_want_active_vk |= ui_context->IO.WantTextInput;
|
|
||||||
ui_context_want_active |= ui_context->IO.WantCaptureKeyboard || ui_context->IO.WantCaptureMouse || ui_context->IO.WantSetMousePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetCurrentContext(NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nativeWindowEventListenerEnd(tp::glw::PlatformContext* ctx) {}
|
|
||||||
|
|
||||||
static void nativeWindowEventListenerWrapBegin(tp::glw::PlatformContext* ctx, void* cd) { ((DebugUiInternalContext*)cd)->nativeWindowEventListenerBegin(ctx); }
|
|
||||||
static void nativeWindowEventListenerWrap(tp::glw::PlatformContext* ctx, void* cd) { ((DebugUiInternalContext*)cd)->nativeWindowEventListener(ctx); }
|
|
||||||
static void nativeWindowEventListenerWrapEnd(tp::glw::PlatformContext* ctx, void* cd) { ((DebugUiInternalContext*)cd)->nativeWindowEventListenerEnd(ctx); }
|
|
||||||
|
|
||||||
void VirtualKeyboard(tp::halnf dpmm, tp::halnf font_size_mm, tp::halnf ui_scale) {
|
|
||||||
auto& config = mVKState.mConfigs[mVKState.mActiveConfigIdx];
|
|
||||||
|
|
||||||
ImGuiID dockspace_id = ImGui::DockSpaceOverViewport(0, ImGuiDockNodeFlags_PassthruCentralNode);
|
|
||||||
|
|
||||||
ImGuiDockNode* node = ImGui::DockContextFindNodeByID(ImGui::GetCurrentContext(), dockspace_id);
|
|
||||||
|
|
||||||
if (!node->IsSplitNode()) {
|
|
||||||
node->MergedFlags |= ImGuiDockNodeFlags_HiddenTabBar;
|
|
||||||
ImGuiID dock_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Down, 0.33f, nullptr, &dockspace_id);
|
|
||||||
ImGui::DockBuilderDockWindow("VK", dock_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0.f, 0.f });
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.f);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, { 50 * dpmm, 30 * dpmm });
|
|
||||||
ImGui::Begin("VK");
|
|
||||||
ImGui::PopStyleVar(3);
|
|
||||||
|
|
||||||
auto pos = ImGui::GetCursorPos();
|
|
||||||
|
|
||||||
auto width = ImGui::GetWindowWidth();
|
|
||||||
auto height = ImGui::GetWindowHeight() - pos.y;
|
|
||||||
//auto scale = dpmm * ui_scale;
|
|
||||||
auto padding = dpmm * 2 * ui_scale;
|
|
||||||
auto button_sizey = (tp::halnf)(height - (config.nrows + 1) * padding) / config.nrows;
|
|
||||||
|
|
||||||
tp::vec2f crs = { pos.x + padding, pos.y + padding };
|
|
||||||
|
|
||||||
for (auto row = 0; row < config.nrows; row++) {
|
|
||||||
tp::halnf butt_scalex = (width - (config.rows_sizes[row] + 1) * padding) / config.rows_widths[row];
|
|
||||||
|
|
||||||
crs.x = pos.x + padding;
|
|
||||||
|
|
||||||
for (auto butt = 0; butt < config.rows_sizes[row]; butt++) {
|
|
||||||
auto& button = config.rows[row][butt];
|
|
||||||
|
|
||||||
ImGui::SetCursorPos({ crs.x, crs.y });
|
|
||||||
|
|
||||||
char name[2] = { mVKState.mShifted ? button.shift_val : button.val, 0 };
|
|
||||||
|
|
||||||
ImGui::PushID(&button);
|
|
||||||
if (!ImGui::Button(button.display_name ? button.display_name: name, { butt_scalex * button.width, button_sizey })) {
|
|
||||||
crs.x += butt_scalex * button.width + padding;
|
|
||||||
ImGui::PopID();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetCurrentContext(ui_context);
|
|
||||||
button.action(&button, &mVKState);
|
|
||||||
ImGui::SetCurrentContext(vk_context);
|
|
||||||
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
|
||||||
|
|
||||||
crs.y += button_sizey + padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::glw::DebugUI::DebugUI(Window& window, DebugUiDrawCallBack* acb, void* acd) {
|
|
||||||
mDPMM = window.mDevice.mDPMM;
|
|
||||||
|
|
||||||
// map device size to font and ui size
|
|
||||||
{
|
|
||||||
auto device_max = 600.f;
|
|
||||||
auto device_min = 50.f;
|
|
||||||
auto device = tp::clamp(window.mDevice.Size.x / mDPMM, device_min, device_max);
|
|
||||||
auto device_factor = (device - device_min) / (device_max - device_min);
|
|
||||||
|
|
||||||
auto font_min = 2.f;
|
|
||||||
auto font_max = 3.5f;
|
|
||||||
mFontSizeMM = (font_max - font_min) * device_factor + font_min;
|
|
||||||
|
|
||||||
auto ui_max = 1.f;
|
|
||||||
auto ui_min = 0.45f;
|
|
||||||
mUIScale = (ui_max - ui_min) * device_factor + ui_min;
|
|
||||||
}
|
|
||||||
|
|
||||||
mCtx = new DebugUiInternalContext(window, acb, acd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::DebugUI::drawDebugUI(tp::halnf dpmm) {
|
|
||||||
mDPMM = dpmm;
|
|
||||||
mCtx->drawDebugUI(mDPMM, mFontSizeMM, mUIScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::glw::DebugUI::~DebugUI() {
|
|
||||||
delete mCtx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------ //
|
|
||||||
|
|
||||||
static const int sWindowFrameFlags = (ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoDecoration);
|
|
||||||
|
|
||||||
bool ImGui::SubMenuBegin(const char* desc, int level) {
|
|
||||||
if (level == 1) {
|
|
||||||
ImGui::Separator();
|
|
||||||
}
|
|
||||||
if (ImGui::TreeNode(desc)) {
|
|
||||||
GImGui->Style.IndentSpacing = 6;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui::SubMenuEnd(int level) {
|
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui::ToolTip(const char* desc) {
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::TextDisabled("*");
|
|
||||||
if (ImGui::IsItemHovered()) {
|
|
||||||
ImGui::BeginTooltip();
|
|
||||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
|
||||||
ImGui::TextUnformatted(desc);
|
|
||||||
ImGui::PopTextWrapPos();
|
|
||||||
ImGui::EndTooltip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopupData ImGui::HoverPopupBeginButton(const char* id, tp::vec2f butsize, tp::vec2f popupsize) {
|
|
||||||
ImVec2 curs = ImGui::GetCursorScreenPos();
|
|
||||||
tp::vec2f popup_pos = tp::vec2f(curs.x + butsize.x / 2.f - popupsize.x / 2.f, (curs.y + butsize.y + 7));
|
|
||||||
ImGui::Button(id, ImVec2(butsize.x, butsize.y)); ImGui::SameLine();
|
|
||||||
return HoverPopupBegin(id, popupsize, popup_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopupData ImGui::HoverPopupBegin(const char* str_id, tp::vec2f size, tp::vec2f pos_p, ImGuiPopupFlags popup_flags) {
|
|
||||||
ImGui::PopupData out;
|
|
||||||
out.ishovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
|
|
||||||
|
|
||||||
if (out.ishovered) {
|
|
||||||
ImVec2 pos;
|
|
||||||
|
|
||||||
if (pos_p == tp::vec2f(-1)) {
|
|
||||||
pos = GImGui->CurrentWindow->DC.CursorPos;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pos.x = pos_p.x;
|
|
||||||
pos.y = pos_p.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetNextWindowPos(pos);
|
|
||||||
out.p1 = { pos.x, pos.y };
|
|
||||||
|
|
||||||
ImGui::OpenPopup(str_id);
|
|
||||||
|
|
||||||
out.p2 = out.p1;
|
|
||||||
out.p2.x += ImGui::GetWindowWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BeginPopup(str_id, ImGuiWindowFlags_NoMove)) {
|
|
||||||
out.opened = true;
|
|
||||||
|
|
||||||
auto pos = GetWindowPos();
|
|
||||||
out.p1 = { pos.x, pos.y };
|
|
||||||
out.p2 = out.p1;
|
|
||||||
out.p2.x += ImGui::GetWindowWidth();
|
|
||||||
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui::HoverPopupEnd(ImGui::PopupData& in) {
|
|
||||||
|
|
||||||
if (!in.opened) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
in.ishovered |= IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ChildWindows);
|
|
||||||
|
|
||||||
tp::vec2f mousepos = { ImGui::GetMousePos().x, ImGui::GetMousePos().y };
|
|
||||||
tp::halnf tollerance = 10;
|
|
||||||
tp::rectf tollerace_rect = tp::rectf(tp::vec2f(in.p1.x, in.p1.y - tollerance), tp::vec2f(in.p2.x - in.p1.x, tollerance * 2.f));
|
|
||||||
bool is_tollerance = tollerace_rect.inside(mousepos);
|
|
||||||
|
|
||||||
if (!(in.ishovered || is_tollerance)) {
|
|
||||||
CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
#define VAL(val) (val * dpmm / 3 * ui_scale)
|
|
||||||
#define VEC(x, y) ImVec2(x * dpmm / 3, y * dpmm / 3 * ui_scale)
|
|
||||||
|
|
||||||
void ImGui::ApplyStyle(tp::halnf dpmm, float font_size_mm, float ui_scale) {
|
|
||||||
|
|
||||||
ImGuiStyle* style = &ImGui::GetStyle();
|
|
||||||
auto& io = ImGui::GetIO();
|
|
||||||
bool first_init = io.Fonts->Fonts.Size == 0;
|
|
||||||
auto font_path = getFontPath();
|
|
||||||
|
|
||||||
// supports PDMM from 0.3 to 10
|
|
||||||
const float min_dpmm = 0.3f;
|
|
||||||
const float max_dpmm = 20.f;
|
|
||||||
dpmm = tp::clamp(dpmm, min_dpmm, max_dpmm);
|
|
||||||
|
|
||||||
// calc font
|
|
||||||
const float font_size_mm_max = 10;
|
|
||||||
const float font_size_pixels_min = 9;
|
|
||||||
float font_size_mm_min = font_size_pixels_min / dpmm;
|
|
||||||
const int font_quality_steps = 3;
|
|
||||||
font_size_mm = tp::clamp(font_size_mm, font_size_mm_min, font_size_mm_max);
|
|
||||||
|
|
||||||
float font_sizes[font_quality_steps];
|
|
||||||
for (auto i = 0; i < font_quality_steps; i++) {
|
|
||||||
auto mm = font_size_mm_min + (font_size_mm_max - font_size_mm_min) * tp::pow(((tp::halnf) (i + 1) / font_quality_steps), 3);
|
|
||||||
font_sizes[i] = dpmm * mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_init) {
|
|
||||||
for (auto i = 0; i < font_quality_steps; i++) {
|
|
||||||
io.Fonts->AddFontFromFileTTF(font_path, font_sizes[i] * 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// select fonts
|
|
||||||
auto const pixels_required = dpmm * font_size_mm;
|
|
||||||
auto idx = -1;
|
|
||||||
for (auto i = 0; i < font_quality_steps; i++) {
|
|
||||||
idx = i;
|
|
||||||
if (pixels_required <= font_sizes[i]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DBG_BREAK(idx == -1);
|
|
||||||
io.FontDefault = io.Fonts->Fonts[idx];
|
|
||||||
io.FontGlobalScale = font_size_mm / (font_size_mm_min + ((font_size_mm_max - font_size_mm_min) / font_quality_steps) * (idx + 1));
|
|
||||||
io.FontGlobalScale = pixels_required / font_sizes[idx];
|
|
||||||
|
|
||||||
auto rounding = VAL(5);
|
|
||||||
auto pudding = VEC(7, 7);
|
|
||||||
|
|
||||||
style->WindowPadding = pudding;
|
|
||||||
style->WindowRounding = rounding;
|
|
||||||
//style->WindowMinSize = VEC(11, 11);
|
|
||||||
style->ChildRounding = rounding;
|
|
||||||
style->PopupRounding = rounding;
|
|
||||||
style->FramePadding = pudding;
|
|
||||||
style->FrameRounding = rounding;
|
|
||||||
style->ItemSpacing = VEC(4, 11);
|
|
||||||
style->ItemInnerSpacing = VEC(9, 4);
|
|
||||||
style->CellPadding = pudding;
|
|
||||||
style->TouchExtraPadding = pudding;
|
|
||||||
style->IndentSpacing = VAL(25);
|
|
||||||
style->ColumnsMinSpacing = VAL(5);
|
|
||||||
style->ScrollbarSize = VAL(16);
|
|
||||||
style->ScrollbarRounding = rounding;
|
|
||||||
style->GrabMinSize = VAL(2);
|
|
||||||
style->GrabRounding = rounding;
|
|
||||||
style->LogSliderDeadzone = VAL(2);
|
|
||||||
style->TabRounding = rounding;
|
|
||||||
style->TabMinWidthForCloseButton = VAL(5);
|
|
||||||
style->DisplayWindowPadding = pudding;
|
|
||||||
style->DisplaySafeAreaPadding = pudding;
|
|
||||||
style->MouseCursorScale = VAL(5);
|
|
||||||
|
|
||||||
style->FrameBorderSize = VAL(0);
|
|
||||||
style->WindowBorderSize = VAL(1.5f);
|
|
||||||
style->ChildBorderSize = VAL(2);
|
|
||||||
|
|
||||||
style->WindowTitleAlign = VEC(0.5f, 0.6f);
|
|
||||||
style->WindowMenuButtonPosition = ImGuiDir_Right;
|
|
||||||
|
|
||||||
if (!first_init)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ImVec4* colors = ImGui::GetStyle().Colors;
|
|
||||||
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_TextDisabled] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
|
|
||||||
colors[ImGuiCol_WindowBg] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
|
||||||
colors[ImGuiCol_ChildBg] = ImVec4(0.09f, 0.09f, 0.10f, 1.00f);
|
|
||||||
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.10f, 1.00f);
|
|
||||||
colors[ImGuiCol_Border] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f);
|
|
||||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
||||||
colors[ImGuiCol_FrameBg] = ImVec4(0.14f, 0.14f, 0.17f, 1.00f);
|
|
||||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.27f, 0.27f, 0.33f, 1.00f);
|
|
||||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0.43f, 0.43f, 0.53f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBg] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBgActive] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
|
||||||
colors[ImGuiCol_MenuBarBg] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.09f, 0.09f, 0.10f, 0.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.15f, 0.15f, 0.19f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.21f, 0.20f, 0.25f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.30f, 0.29f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.48f, 0.50f, 1.00f);
|
|
||||||
colors[ImGuiCol_SliderGrab] = ImVec4(0.53f, 0.57f, 0.64f, 1.00f);
|
|
||||||
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.69f, 0.74f, 0.83f, 1.00f);
|
|
||||||
colors[ImGuiCol_Button] = ImVec4(0.14f, 0.14f, 0.17f, 1.00f);
|
|
||||||
colors[ImGuiCol_ButtonHovered] = ImVec4(0.27f, 0.27f, 0.33f, 1.00f);
|
|
||||||
colors[ImGuiCol_ButtonActive] = ImVec4(0.43f, 0.43f, 0.53f, 1.00f);
|
|
||||||
colors[ImGuiCol_Header] = ImVec4(0.14f, 0.14f, 0.17f, 1.00f);
|
|
||||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.27f, 0.27f, 0.33f, 1.00f);
|
|
||||||
colors[ImGuiCol_HeaderActive] = ImVec4(0.33f, 0.33f, 0.40f, 1.00f);
|
|
||||||
colors[ImGuiCol_Separator] = ImVec4(0.37f, 0.37f, 0.40f, 1.00f);
|
|
||||||
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.33f, 0.35f, 0.38f, 1.00f);
|
|
||||||
colors[ImGuiCol_SeparatorActive] = ImVec4(0.37f, 0.39f, 0.42f, 1.00f);
|
|
||||||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.16f, 0.17f, 0.19f, 1.00f);
|
|
||||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.33f, 0.35f, 0.38f, 1.00f);
|
|
||||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.28f, 0.34f, 0.42f, 1.00f);
|
|
||||||
colors[ImGuiCol_Tab] = ImVec4(0.14f, 0.14f, 0.17f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabHovered] = ImVec4(0.23f, 0.23f, 0.28f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabActive] = ImVec4(0.23f, 0.23f, 0.28f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.43f, 0.45f, 0.48f, 1.00f);
|
|
||||||
colors[ImGuiCol_DockingPreview] = ImVec4(0.81f, 0.81f, 0.81f, 0.18f);
|
|
||||||
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.33f, 0.35f, 0.38f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.49f, 0.51f, 0.54f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.13f, 0.13f, 0.20f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.23f, 0.20f, 0.20f, 0.00f);
|
|
||||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
|
|
||||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
|
||||||
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
|
||||||
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
|
||||||
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
|
||||||
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.38f, 0.22f, 0.22f, 0.20f);
|
|
||||||
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.10f, 1.00f);
|
|
||||||
colors[ImGuiCol_DockingPreview] = ImVec4(0.64f, 0.75f, 0.83f, 0.18f);
|
|
||||||
colors[ImGuiCol_TabHovered] = ImVec4(0.39f, 0.39f, 0.47f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabActive] = ImVec4(0.27f, 0.27f, 0.33f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.14f, 0.14f, 0.17f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.24f, 0.24f, 0.29f, 1.00f);
|
|
||||||
colors[ImGuiCol_Border] = ImVec4(0.65f, 0.65f, 0.65f, 0.70f);
|
|
||||||
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
|
||||||
}
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
|
|
||||||
#include "fbuffer.h"
|
|
||||||
|
|
||||||
#include "GraphicsLibApi.h"
|
|
||||||
|
|
||||||
void glerr(GLenum type);
|
|
||||||
#define AssertGL(x) { x; GLenum __gle = glGetError(); if (__gle != GL_NO_ERROR) glerr(__gle); }
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
|
|
||||||
using namespace glw;
|
|
||||||
|
|
||||||
fbuffer::fbuffer(const vec2f& size) : mSize(size) {
|
|
||||||
mDrawBuffers[0] = {GL_COLOR_ATTACHMENT0};
|
|
||||||
|
|
||||||
// --------- texture ---------
|
|
||||||
AssertGL(glGenTextures(1, &mTextureId));
|
|
||||||
AssertGL(glBindTexture(GL_TEXTURE_2D, mTextureId));
|
|
||||||
// Give an empty image to OpenGL ( the last "0" )
|
|
||||||
AssertGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
|
|
||||||
// Poor filtering. Needed
|
|
||||||
AssertGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
|
||||||
AssertGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
|
||||||
|
|
||||||
// --------- depth ---------
|
|
||||||
AssertGL(glGenRenderbuffers(1, &mDepthBufferID));
|
|
||||||
AssertGL(glBindRenderbuffer(GL_RENDERBUFFER, mDepthBufferID));
|
|
||||||
AssertGL(glRenderbufferStorage(GL_RENDERBUFFER, GLW_CONTEXT_DEPTH_COMPONENT, (GLsizei)size.x, (GLsizei)size.y));
|
|
||||||
|
|
||||||
// ------------ framebuffer ------------
|
|
||||||
AssertGL(glGenFramebuffers(1, &mFrameBufferID));
|
|
||||||
AssertGL(glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferID));
|
|
||||||
AssertGL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBufferID));
|
|
||||||
// Set "renderedTexture" as our colour attachement #0
|
|
||||||
AssertGL(glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextureId, 0));
|
|
||||||
// Set the list of draw buffers.
|
|
||||||
AssertGL(glDrawBuffers(1, mDrawBuffers)); // "1" is the size of DrawBuffers
|
|
||||||
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fbuffer::fbuffer(const vec2f& size, tp::uint1 samples) : mSize(size) {
|
|
||||||
mDrawBuffers[0] = { GL_COLOR_ATTACHMENT0 };
|
|
||||||
|
|
||||||
// ------- texture ---------
|
|
||||||
AssertGL(glGenTextures(1, &mTextureId));
|
|
||||||
AssertGL(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextureId));
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
AssertGL(glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, GL_TRUE));
|
|
||||||
#else
|
|
||||||
AssertGL(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, GL_TRUE));
|
|
||||||
#endif
|
|
||||||
// !?
|
|
||||||
//AssertGL(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
|
||||||
//AssertGL(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
|
||||||
|
|
||||||
// ------- depth -------
|
|
||||||
AssertGL(glGenRenderbuffers(1, &mDepthBufferID));
|
|
||||||
AssertGL(glBindRenderbuffer(GL_RENDERBUFFER, mDepthBufferID));
|
|
||||||
AssertGL(glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GLW_CONTEXT_DEPTH_COMPONENT, (GLsizei)size.x, (GLsizei)size.y));
|
|
||||||
|
|
||||||
// ------- fbuff -------
|
|
||||||
AssertGL(glGenFramebuffers(1, &mFrameBufferID));
|
|
||||||
AssertGL(glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferID));
|
|
||||||
AssertGL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, mTextureId, 0));
|
|
||||||
AssertGL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBufferID));
|
|
||||||
AssertGL(glDrawBuffers(1, mDrawBuffers));
|
|
||||||
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::uint4 fbuffer::buffId() const {
|
|
||||||
return mFrameBufferID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fbuffer::beginDraw() {
|
|
||||||
AssertGL(glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferID));
|
|
||||||
setViewport({ 0.f, 0.f, mSize.x, mSize.y });
|
|
||||||
}
|
|
||||||
|
|
||||||
void fbuffer::setViewport(const rectf& viewport) {
|
|
||||||
AssertGL(glViewport((GLsizei)viewport.x, (GLsizei)viewport.y, (GLsizei)viewport.z, (GLsizei)viewport.w));
|
|
||||||
}
|
|
||||||
|
|
||||||
void fbuffer::clear() {
|
|
||||||
AssertGL(glClearColor(mClearCol.r, mClearCol.g, mClearCol.b, mClearCol.a));
|
|
||||||
AssertGL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
|
||||||
}
|
|
||||||
|
|
||||||
void fbuffer::endDraw() {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
glClearColor(0, 0, 0, 0);
|
|
||||||
glUseProgram(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fbuffer::~fbuffer() {
|
|
||||||
glDeleteFramebuffers(1, &mFrameBufferID);
|
|
||||||
glDeleteTextures(1, &mTextureId);
|
|
||||||
glDeleteRenderbuffers(1, &mDepthBufferID);
|
|
||||||
}
|
|
||||||
|
|
||||||
uhalni glw::fbuffer::sizeAllocatedMem() const {
|
|
||||||
return uhalni(sizeof(GLenum) * 4 + mSize.sizeAllocatedMem() + (sizeof(mClearCol) + 1) * (alni) mSize.x * (alni) mSize.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
uhalni glw::fbuffer::sizeUsedMem() const {
|
|
||||||
return sizeAllocatedMem();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint4 glw::fbuffer::texId() const {
|
|
||||||
return mTextureId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const vec2f& fbuffer::getSize() const { return mSize; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@ -1,282 +0,0 @@
|
||||||
|
|
||||||
#include "window.h"
|
|
||||||
|
|
||||||
#include "GL/glew.h"
|
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
tp::glw::Window::Device tp::glw::Window::mDevice;
|
|
||||||
|
|
||||||
static void glfw_error_callback(int error, const char* description) {
|
|
||||||
std::cout << stderr << "Glfw Error" << error << " " << description << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::init() {
|
|
||||||
tp::glw::Window::mDevice.Size;
|
|
||||||
tp::glw::Window::mDevice.FrameRate;
|
|
||||||
|
|
||||||
// Setup window
|
|
||||||
|
|
||||||
setenv("DISPLAY", ":0.0", 0); // does overwrite
|
|
||||||
|
|
||||||
glfwSetErrorCallback(glfw_error_callback);
|
|
||||||
RelAssert(glfwInit());
|
|
||||||
|
|
||||||
|
|
||||||
// GL 3.0 + GLSL 130
|
|
||||||
const char* glsl_version = "#version 130";
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only
|
|
||||||
|
|
||||||
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
|
|
||||||
|
|
||||||
GLFWmonitor* primary = glfwGetPrimaryMonitor();
|
|
||||||
auto mode = glfwGetVideoMode(primary);
|
|
||||||
|
|
||||||
tp::glw::Window::mDevice.Size = { mode->width, mode->height };
|
|
||||||
tp::glw::Window::mDevice.FrameRate = mode->refreshRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAP_EV(SYSKEY, code) case SYSKEY: { self->mEvents.mKeysQueue.push(tp::KeyEvent{ code, state }); break; }
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
namespace glw {
|
|
||||||
struct PlatformContext {
|
|
||||||
|
|
||||||
GLFWwindow* window;
|
|
||||||
tp::glw::Window* window_ctx = NULL;
|
|
||||||
|
|
||||||
PlatformContext(tp::glw::Window* a_window_ctx) {
|
|
||||||
|
|
||||||
window_ctx = a_window_ctx;
|
|
||||||
|
|
||||||
// Create window with graphics context
|
|
||||||
window = glfwCreateWindow(300, 300, " ", NULL, NULL);
|
|
||||||
RelAssert(window);
|
|
||||||
|
|
||||||
glfwMakeContextCurrent(window);
|
|
||||||
|
|
||||||
GLenum err = glewInit();
|
|
||||||
if (GLEW_OK != err)
|
|
||||||
{
|
|
||||||
std::cout << stderr << "Error:" << glewGetErrorString(err);
|
|
||||||
RelAssert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwSwapInterval(1); // Enable vsync
|
|
||||||
|
|
||||||
glfwSetWindowUserPointer(window, window_ctx);
|
|
||||||
|
|
||||||
glfwSetKeyCallback(window, key_callback);
|
|
||||||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
|
||||||
glfwSetScrollCallback(window, scroll_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyAppearance(tp::glw::Window::Appearence& appear, tp::glw::Window::Appearence& prev, tp::glw::Window* win_ctx) {
|
|
||||||
|
|
||||||
if (!(appear.mSize == prev.mSize)) {
|
|
||||||
glfwSetWindowSize(window, appear.mSize.x, appear.mSize.y);
|
|
||||||
prev.mSize = appear.mSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(appear.mPos == prev.mPos)) {
|
|
||||||
//glfwSetWindowPos(window, appear.mPos.x, appear.mPos.y);
|
|
||||||
|
|
||||||
win_ctx->mEvents.mCursor -= appear.mPos - prev.mPos;
|
|
||||||
//win_ctx->mEvents.mCursorPrev -= appear.mPos - prev.mPos;
|
|
||||||
prev.mPos = appear.mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(appear.mSizeMax == prev.mSizeMax && appear.mSizeMin == prev.mSizeMin)) {
|
|
||||||
glfwSetWindowSizeLimits(window, appear.mSizeMin.x, appear.mSizeMin.y, appear.mSizeMax.x, appear.mSizeMax.y);
|
|
||||||
prev.mSizeMax = appear.mSizeMax;
|
|
||||||
prev.mSizeMin = appear.mSizeMin;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(appear.mMaximized == prev.mMaximized)) {
|
|
||||||
DBG_BREAK(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(appear.mMinimized == prev.mMinimized)) {
|
|
||||||
DBG_BREAK(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int width, height;
|
|
||||||
glfwGetWindowSize(window, &width, &height);
|
|
||||||
appear.mSize = { width, height };
|
|
||||||
prev.mSize = appear.mSize;
|
|
||||||
|
|
||||||
glfwGetWindowPos(window, &width, &height);
|
|
||||||
appear.mPos = { width, height };
|
|
||||||
prev.mPos = appear.mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void beginDraw() {
|
|
||||||
//int display_w, display_h;
|
|
||||||
//glfwGetFramebufferSize(window, &display_w, &display_h);
|
|
||||||
//glViewport(0, 0, display_w, display_h);
|
|
||||||
//glClearColor(0, 0, 0, 0);
|
|
||||||
//glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void endDraw() {
|
|
||||||
glfwSwapBuffers(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pollEvents() {
|
|
||||||
|
|
||||||
glfwPollEvents();
|
|
||||||
|
|
||||||
double xpos, ypos;
|
|
||||||
glfwGetCursorPos(window, &xpos, &ypos);
|
|
||||||
|
|
||||||
window_ctx->mEvents.mCursorPrev = window_ctx->mEvents.mCursor;
|
|
||||||
window_ctx->mEvents.mCursor = { xpos, ypos };
|
|
||||||
}
|
|
||||||
|
|
||||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
|
||||||
auto self = (tp::glw::Window*) glfwGetWindowUserPointer(window);
|
|
||||||
|
|
||||||
if (action != GLFW_PRESS && action != GLFW_RELEASE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto state = (action == GLFW_RELEASE) ? tp::KeyEvent::EventState::RELEASED : tp::KeyEvent::EventState::PRESSED;
|
|
||||||
|
|
||||||
//* VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39)
|
|
||||||
if (key >= GLFW_KEY_0 && key <= GLFW_KEY_9) {
|
|
||||||
self->mEvents.mKeysQueue.push(tp::KeyEvent{ tp::Keycode(key), state });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//* VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A)
|
|
||||||
else if (key >= GLFW_KEY_A && key <= GLFW_KEY_Z) {
|
|
||||||
self->mEvents.mKeysQueue.push(tp::KeyEvent{ tp::Keycode(key), state });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
MAP_EV(GLFW_KEY_LEFT_SHIFT, tp::Keycode::LEFT_SHIFT);
|
|
||||||
MAP_EV(GLFW_KEY_LEFT, tp::Keycode::LEFT);
|
|
||||||
MAP_EV(GLFW_KEY_RIGHT, tp::Keycode::RIGHT);
|
|
||||||
MAP_EV(GLFW_KEY_UP, tp::Keycode::UP);
|
|
||||||
MAP_EV(GLFW_KEY_DOWN, tp::Keycode::DOWN);
|
|
||||||
MAP_EV(GLFW_KEY_BACKSPACE, tp::Keycode::BACKSPACE);
|
|
||||||
MAP_EV(GLFW_KEY_LEFT_CONTROL, tp::Keycode::LEFT_CONTROL);
|
|
||||||
MAP_EV(GLFW_KEY_MENU, tp::Keycode::LEFT_ALT);
|
|
||||||
MAP_EV(GLFW_KEY_ENTER, tp::Keycode::ENTER);
|
|
||||||
MAP_EV(GLFW_KEY_SPACE, tp::Keycode::SPACE);
|
|
||||||
MAP_EV(GLFW_KEY_COMMA, tp::Keycode::COMMA);
|
|
||||||
MAP_EV(GLFW_KEY_PERIOD, tp::Keycode::PERIOD);
|
|
||||||
MAP_EV(GLFW_KEY_TAB, tp::Keycode::TAB);
|
|
||||||
MAP_EV(GLFW_KEY_EQUAL, tp::Keycode::EQUAL);
|
|
||||||
MAP_EV(GLFW_KEY_MINUS, tp::Keycode::MINUS);
|
|
||||||
MAP_EV(GLFW_KEY_3, tp::Keycode::TILDA);
|
|
||||||
MAP_EV(GLFW_KEY_4, tp::Keycode::BRA);
|
|
||||||
MAP_EV(GLFW_KEY_5, tp::Keycode::SLASH);
|
|
||||||
MAP_EV(GLFW_KEY_6, tp::Keycode::KET);
|
|
||||||
MAP_EV(GLFW_KEY_1, tp::Keycode::DOUBLE_DOT);
|
|
||||||
MAP_EV(GLFW_KEY_7, tp::Keycode::QUOTES);
|
|
||||||
MAP_EV(GLFW_KEY_2, tp::Keycode::INV_SLASH);
|
|
||||||
MAP_EV(GLFW_KEY_ESCAPE, tp::Keycode::ESCAPE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
|
|
||||||
auto self = (tp::glw::Window*)glfwGetWindowUserPointer(window);
|
|
||||||
|
|
||||||
if (action != GLFW_PRESS && action != GLFW_RELEASE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto state = (action == GLFW_RELEASE) ? tp::KeyEvent::EventState::RELEASED : tp::KeyEvent::EventState::PRESSED;
|
|
||||||
|
|
||||||
|
|
||||||
switch (button) {
|
|
||||||
case GLFW_MOUSE_BUTTON_RIGHT: {
|
|
||||||
self->mEvents.mKeysQueue.push(tp::KeyEvent{ tp::Keycode::MOUSE2, state });
|
|
||||||
} break;
|
|
||||||
case GLFW_MOUSE_BUTTON_LEFT: {
|
|
||||||
self->mEvents.mKeysQueue.push(tp::KeyEvent{ tp::Keycode::MOUSE1, state });
|
|
||||||
} break;
|
|
||||||
case GLFW_MOUSE_BUTTON_MIDDLE: {
|
|
||||||
self->mEvents.mKeysQueue.push(tp::KeyEvent{ tp::Keycode::MOUSE3, state });
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
|
|
||||||
}
|
|
||||||
|
|
||||||
~PlatformContext() {
|
|
||||||
glfwDestroyWindow(window);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void tp::glw::Window::deinit() {}
|
|
||||||
|
|
||||||
tp::glw::Window::Window() {
|
|
||||||
initialize();
|
|
||||||
|
|
||||||
mAppearence.mSize = tp::glw::Window::mDevice.Size / 1.5f;
|
|
||||||
mAppearence.mPos = (tp::glw::Window::mDevice.Size - mAppearence.mSize) / 2.f;
|
|
||||||
mAppearence.mSizeMax = tp::glw::Window::mDevice.Size;
|
|
||||||
|
|
||||||
applyAppearance();
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::glw::Window::Window(const Appearence& aAppearence) {
|
|
||||||
mAppearence = aAppearence;
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::initialize() {
|
|
||||||
mPlatformCtx = new PlatformContext(this);
|
|
||||||
applyAppearance();
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::applyAppearance() {
|
|
||||||
mPlatformCtx->applyAppearance(mAppearence, this->mCache.mAppearencePrev, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::pollEvents() {
|
|
||||||
applyAppearance();
|
|
||||||
mPlatformCtx->pollEvents();
|
|
||||||
|
|
||||||
mEvents.mRedraw |= (mEvents.mCursorPrev - mEvents.mCursor) != 0;
|
|
||||||
mEvents.mRedraw |= mEvents.mKeysQueue.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::platformCallback() {}
|
|
||||||
|
|
||||||
void tp::glw::Window::beginDraw() {
|
|
||||||
mPlatformCtx->beginDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void tp::glw::Window::endDraw() {
|
|
||||||
mPlatformCtx->endDraw();
|
|
||||||
if (mEvents.mRedraw-- < 0) mEvents.mRedraw = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* tp::glw::Window::platform_window() const {
|
|
||||||
return mPlatformCtx->window;
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::alni tp::glw::Window::sizeAllocatedMem() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::alni tp::glw::Window::sizeUsedMem() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tp::glw::Window::~Window() {
|
|
||||||
delete mPlatformCtx;
|
|
||||||
}
|
|
||||||
|
|
@ -1,170 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
#include "stringt.h"
|
|
||||||
|
|
||||||
#include "array.h"
|
|
||||||
|
|
||||||
#include "array.h"
|
|
||||||
#include "filesystem.h"
|
|
||||||
#include "shader.h"
|
|
||||||
|
|
||||||
#include "new.h"
|
|
||||||
|
|
||||||
#include "GraphicsLibApi.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
|
|
||||||
using namespace glw;
|
|
||||||
|
|
||||||
//string shader_path = "../rsc/shaders/";
|
|
||||||
|
|
||||||
shader::shader() {
|
|
||||||
programm = 0;
|
|
||||||
VertexShaderID = 0;
|
|
||||||
FragmentShaderID = 0;
|
|
||||||
GeometryShaderID = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void shader::vert_bind_source(const char* vert_src) {
|
|
||||||
VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
|
||||||
compile_shader(vert_src, VertexShaderID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shader::frag_bind_source(const char* frag_src) {
|
|
||||||
FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
compile_shader(frag_src, FragmentShaderID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shader::geom_bind_source(const char* geom_src) {
|
|
||||||
GeometryShaderID = glCreateShader(GL_GEOMETRY_SHADER);
|
|
||||||
compile_shader(geom_src, GeometryShaderID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shader::compile() {
|
|
||||||
GLint Result = GL_FALSE;
|
|
||||||
int InfoLogLength;
|
|
||||||
|
|
||||||
programm = glCreateProgram();
|
|
||||||
glAttachShader(programm, VertexShaderID);
|
|
||||||
if (GeometryShaderID) glAttachShader(programm, GeometryShaderID);
|
|
||||||
glAttachShader(programm, FragmentShaderID);
|
|
||||||
glLinkProgram(programm);
|
|
||||||
|
|
||||||
// Check the program
|
|
||||||
glGetProgramiv(programm, GL_LINK_STATUS, &Result);
|
|
||||||
glGetProgramiv(programm, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
|
||||||
|
|
||||||
if (InfoLogLength > 0) {
|
|
||||||
Array<char> ProgramErrorMessage(InfoLogLength + 1);
|
|
||||||
glGetProgramInfoLog(programm, InfoLogLength, NULL, &ProgramErrorMessage[0]);
|
|
||||||
printf("%s\n", &ProgramErrorMessage[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
glDetachShader(programm, VertexShaderID);
|
|
||||||
glDetachShader(programm, FragmentShaderID);
|
|
||||||
if (GeometryShaderID) glDetachShader(programm, GeometryShaderID);
|
|
||||||
|
|
||||||
glDeleteShader(VertexShaderID);
|
|
||||||
glDeleteShader(FragmentShaderID);
|
|
||||||
if (GeometryShaderID) glDeleteShader(GeometryShaderID);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool shader::compile_shader(const char* ShaderCode, uint4 ShaderID) {
|
|
||||||
GLint Result = GL_FALSE;
|
|
||||||
int InfoLogLength;
|
|
||||||
|
|
||||||
char const* SourcePointer = ShaderCode;
|
|
||||||
glShaderSource(ShaderID, 1, &SourcePointer, NULL);
|
|
||||||
glCompileShader(ShaderID);
|
|
||||||
|
|
||||||
// Check Shader
|
|
||||||
glGetShaderiv(ShaderID, GL_COMPILE_STATUS, &Result);
|
|
||||||
glGetShaderiv(ShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
|
||||||
|
|
||||||
if (InfoLogLength > 0) {
|
|
||||||
Array<char> VertexShaderErrorMessage(InfoLogLength + 1);
|
|
||||||
glGetShaderInfoLog(ShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
|
|
||||||
printf("%s\n", &VertexShaderErrorMessage[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void shader::load(const char* pvert, const char* pgeom, const char* pfrag, bool paths) {
|
|
||||||
|
|
||||||
// Create the shaders
|
|
||||||
VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
|
||||||
FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
if (pgeom) GeometryShaderID = glCreateShader(GL_GEOMETRY_SHADER);
|
|
||||||
else GeometryShaderID = 0;
|
|
||||||
|
|
||||||
GLint Result = GL_FALSE;
|
|
||||||
int InfoLogLength = 0;
|
|
||||||
|
|
||||||
if (paths) {
|
|
||||||
string vert = sfmt("%c.vert", pvert);
|
|
||||||
string geom = pgeom ? sfmt("%c.geom", pgeom) : " ";
|
|
||||||
string frag = sfmt("%c.frag", pfrag);
|
|
||||||
|
|
||||||
tp::string content;
|
|
||||||
|
|
||||||
printf("Compiling shader : %s\n", vert.cstr());
|
|
||||||
if (content.loadFile(vert)) {
|
|
||||||
compile_shader(content.cstr(), VertexShaderID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GeometryShaderID) {
|
|
||||||
printf("Compiling shader : %s\n", geom.cstr());
|
|
||||||
if (content.loadFile(geom)) {
|
|
||||||
compile_shader(content.cstr(), GeometryShaderID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Compiling shader : %s\n", frag.cstr());
|
|
||||||
if (content.loadFile(frag)) {
|
|
||||||
compile_shader(content.cstr(), FragmentShaderID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
compile_shader(pvert, VertexShaderID);
|
|
||||||
if (GeometryShaderID) {
|
|
||||||
compile_shader(pgeom, GeometryShaderID);
|
|
||||||
}
|
|
||||||
compile_shader(pfrag, FragmentShaderID);
|
|
||||||
}
|
|
||||||
|
|
||||||
compile();
|
|
||||||
}
|
|
||||||
|
|
||||||
shader::shader(const char* vert, const char* geom, const char* frag, bool paths) {
|
|
||||||
load(vert, geom, frag, paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shader::bind() {
|
|
||||||
glUseProgram(programm);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint glw::shader::getu(const char* uid) {
|
|
||||||
return glGetUniformLocation(programm, uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shader::unbind() {
|
|
||||||
glUseProgram(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
shader::~shader() {
|
|
||||||
glDeleteProgram(programm);
|
|
||||||
}
|
|
||||||
|
|
||||||
alni glw::shader::sizeAllocatedMem() {
|
|
||||||
return sizeof(GLuint) * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
alni glw::shader::sizeUsedMem() {
|
|
||||||
return sizeof(GLuint) * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@ -1,164 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "simplegui.h"
|
|
||||||
|
|
||||||
using namespace tp;
|
|
||||||
using namespace glw;
|
|
||||||
|
|
||||||
void WindowSimpleInputs::update(const glw::Window& window, halnf uiscale) {
|
|
||||||
mScaleVal = (window.mDevice.mDPMM * uiscale);
|
|
||||||
mWindowSizeMM = window.mAppearence.mSize / mScaleVal;
|
|
||||||
mCrs = window.mEvents.mCursor / mScaleVal;
|
|
||||||
mCrsPrev = window.mEvents.mCursorPrev / mScaleVal;
|
|
||||||
mCrsmDelta = mCrs - mCrsPrev;
|
|
||||||
|
|
||||||
if (mMouse == Mouse::PRESSED) {
|
|
||||||
mMouse = Mouse::HOLD;
|
|
||||||
}
|
|
||||||
else if (mMouse == Mouse::RELEASED) {
|
|
||||||
mMouse = Mouse::NONE;
|
|
||||||
}
|
|
||||||
mMove = Move::NONE;
|
|
||||||
|
|
||||||
for (auto event : window.mEvents.mKeysQueue) {
|
|
||||||
bool press = event.data().event_state == KeyEvent::EventState::PRESSED;
|
|
||||||
if (press) {
|
|
||||||
switch (event.data().code) {
|
|
||||||
case Keycode::UP: mMove = Move::UP; break;
|
|
||||||
case Keycode::DOWN: mMove = Move::DOWN; break;
|
|
||||||
case Keycode::LEFT: mMove = Move::LEFT; break;
|
|
||||||
case Keycode::RIGHT: mMove = Move::RIGHT; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (event.data().code == Keycode::MOUSE1) {
|
|
||||||
if (press) {
|
|
||||||
mMouse = Mouse::PRESSED;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mMouse = Mouse::RELEASED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WindowSimpleInputs::Activated() { return mMouse == Mouse::PRESSED; }
|
|
||||||
bool WindowSimpleInputs::Anticipating() { return mMouse == Mouse::HOLD; }
|
|
||||||
bool WindowSimpleInputs::Selected() { return mMouse == Mouse::RELEASED; }
|
|
||||||
bool WindowSimpleInputs::MoveLeft() { return mMove == Move::LEFT; }
|
|
||||||
bool WindowSimpleInputs::MoveRight() { return mMove == Move::RIGHT; }
|
|
||||||
bool WindowSimpleInputs::MoveUp() { return mMove == Move::UP; }
|
|
||||||
bool WindowSimpleInputs::MoveDown() { return mMove == Move::DOWN; }
|
|
||||||
bool WindowSimpleInputs::Drag() { return mCrsmDelta != 0; }
|
|
||||||
|
|
||||||
void ButtonWidget::draw(glw::Canvas& canvas) {
|
|
||||||
canvas.setCol1(mCol);
|
|
||||||
canvas.rect(mAnimRec.get(), 1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ButtonWidget::proc(glw::WindowSimpleInputs& inputs) {
|
|
||||||
auto rec = mAnimRec.get();
|
|
||||||
mPressed = false;
|
|
||||||
|
|
||||||
mAnimRec.setAnimTime(100);
|
|
||||||
|
|
||||||
if (rec.inside(inputs.mCrs)) {
|
|
||||||
if (inputs.Anticipating()) {
|
|
||||||
auto new_rec = mRect;
|
|
||||||
new_rec.scale_from_center(0.3f, true);
|
|
||||||
mAnimRec.setNoTransition(new_rec);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mAnimRec.set(mRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputs.Selected()) {
|
|
||||||
mPressed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto new_rec = mRect;
|
|
||||||
new_rec.scale_from_center(0.3f, true);
|
|
||||||
mAnimRec.set(new_rec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckBoxWidget::draw(glw::Canvas& canvas) {
|
|
||||||
canvas.setCol1(mAnimCol.get());
|
|
||||||
canvas.rect(mAnimRec.get(), 1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckBoxWidget::proc(glw::WindowSimpleInputs& inputs) {
|
|
||||||
auto rec = mAnimRec.get();
|
|
||||||
|
|
||||||
mAnimRec.setAnimTime(100);
|
|
||||||
|
|
||||||
if (rec.inside(inputs.mCrs)) {
|
|
||||||
if (inputs.Anticipating()) {
|
|
||||||
auto new_rec = mRect;
|
|
||||||
new_rec.scale_from_center(0.3f, true);
|
|
||||||
mAnimRec.setNoTransition(new_rec);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mAnimRec.set(mRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputs.Selected()) {
|
|
||||||
mValue = !mValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto new_rec = mRect;
|
|
||||||
new_rec.scale_from_center(0.3f, true);
|
|
||||||
mAnimRec.set(new_rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mValue) {
|
|
||||||
mAnimCol.set(mColActive);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mAnimCol.set(mCol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowsHeaderWidget::updRecs() {
|
|
||||||
auto padding = 0.7f;
|
|
||||||
auto butt_size = header_rec.w - padding * 2.f;
|
|
||||||
grab_rec = { header_rec.pos, { header_rec.z - header_rec.w * 4, header_rec.w } };
|
|
||||||
mPinButton.mRect = { { grab_rec.pos.x + grab_rec.size.x + padding, grab_rec.y + padding }, butt_size };
|
|
||||||
mMinButton.mRect = { { mPinButton.mRect.pos.x + mPinButton.mRect.size.x + padding * 2, mPinButton.mRect.y }, butt_size };
|
|
||||||
mMaxButton.mRect = { { mMinButton.mRect.pos.x + mMinButton.mRect.size.x + padding * 2, mPinButton.mRect.y }, butt_size };
|
|
||||||
mExitButton.mRect = { { mMaxButton.mRect.pos.x + mMaxButton.mRect.size.x + padding * 2, mPinButton.mRect.y }, butt_size };
|
|
||||||
|
|
||||||
mPinButton.mCol = { 0.3f, 0.3f, 0.3f, 0.9f};
|
|
||||||
mMinButton.mCol = { 0.3f, 0.3f, 0.8f, 0.9f };
|
|
||||||
mMaxButton.mCol = { 0.3f, 0.8f, 0.3f, 0.9f };
|
|
||||||
mExitButton.mCol = { 0.8f, 0.3f, 0.3f, 0.9f };
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowsHeaderWidget::draw(glw::Canvas& canvas) {
|
|
||||||
updRecs();
|
|
||||||
canvas.setCol1(col);
|
|
||||||
canvas.rect(header_rec, 1.f);
|
|
||||||
canvas.setCol1(1.f);
|
|
||||||
canvas.text("MemLeaks", grab_rec, 4.f);
|
|
||||||
|
|
||||||
mExitButton.draw(canvas);
|
|
||||||
mMaxButton.draw(canvas);
|
|
||||||
mMinButton.draw(canvas);
|
|
||||||
mPinButton.draw(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowsHeaderWidget::proc(glw::Window& window, glw::WindowSimpleInputs& inputs) {
|
|
||||||
get_time();
|
|
||||||
|
|
||||||
mExitButton.proc(inputs);
|
|
||||||
mMaxButton.proc(inputs);
|
|
||||||
mMinButton.proc(inputs);
|
|
||||||
mPinButton.proc(inputs);
|
|
||||||
|
|
||||||
window.mAppearence.mMinMaxBox = mMaxButton.mRect * inputs.mScaleVal;
|
|
||||||
window.mAppearence.mCaptionsAddArea = { grab_rec * inputs.mScaleVal };
|
|
||||||
window.mAppearence.mMinimized = mMinButton.mPressed;
|
|
||||||
window.mEvents.mClose = mExitButton.mPressed;
|
|
||||||
window.mAppearence.mTopZ = mPinButton.mValue;
|
|
||||||
}
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
||||||
|
|
||||||
#include "texture.h"
|
|
||||||
|
|
||||||
#include "map.h"
|
|
||||||
|
|
||||||
#include "stringt.h"
|
|
||||||
|
|
||||||
#include "shader.h"
|
|
||||||
|
|
||||||
#include "GraphicsLibApi.h"
|
|
||||||
|
|
||||||
const char* texture_vertex =
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
"#version 300 es\n"
|
|
||||||
"precision mediump float;\n"
|
|
||||||
#else
|
|
||||||
"#version 330 core\n"
|
|
||||||
#endif
|
|
||||||
"layout(location = 0) in vec3 vPos;\n"
|
|
||||||
"out vec2 UV;\n"
|
|
||||||
"void main() {\n"
|
|
||||||
" gl_Position = vec4(vPos, 1);\n"
|
|
||||||
" UV = (vPos.xy + vec2(1, 1)) / 2.0;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
const char* texture_fragment =
|
|
||||||
#ifdef ENV_OS_ANDROID
|
|
||||||
"#version 300 es\n"
|
|
||||||
"precision mediump float;\n"
|
|
||||||
#else
|
|
||||||
"#version 330 core\n"
|
|
||||||
#endif
|
|
||||||
"in vec2 UV;\n"
|
|
||||||
"out vec4 color;\n"
|
|
||||||
"uniform sampler2D renderedTexture;\n"
|
|
||||||
"uniform float time;\n"
|
|
||||||
"void main() {\n"
|
|
||||||
" vec4 texColor = texture(renderedTexture, UV);\n"
|
|
||||||
" if (texColor.a < 0.2)\n"
|
|
||||||
" discard;\n"
|
|
||||||
" color = texColor;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
namespace tp {
|
|
||||||
|
|
||||||
using namespace glw;
|
|
||||||
|
|
||||||
GLuint texture::getid() { return id; }
|
|
||||||
|
|
||||||
texture::texture() {
|
|
||||||
glGenTextures(1, &id);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, id);
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture::~texture() { glDeleteTextures(1, &id); }
|
|
||||||
|
|
||||||
alni texture::sizeAllocatedMem() {
|
|
||||||
return sizeof(GLuint);
|
|
||||||
}
|
|
||||||
|
|
||||||
alni texture::sizeUsedMem() {
|
|
||||||
return sizeof(GLuint);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void texture::update(const Array2D<rgba>& buff) {
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)buff.size().x, (GLsizei)buff.size().y, 0, GL_RGBA, GL_FLOAT, buff.buff());
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture::draw(const GLuint& out) {
|
|
||||||
draw_texture(out, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct texture_drawer_data {
|
|
||||||
|
|
||||||
HashMap<GLuint, string> textures;
|
|
||||||
|
|
||||||
GLuint quad_VertexArrayID;
|
|
||||||
GLuint quad_vertexbuffer;
|
|
||||||
GLuint texID;
|
|
||||||
glw::shader shader;
|
|
||||||
|
|
||||||
const GLfloat g_quad_vertex_buffer_data[18] = {
|
|
||||||
-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f,
|
|
||||||
-1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f,
|
|
||||||
};
|
|
||||||
|
|
||||||
texture_drawer_data() : shader(texture_vertex, NULL, texture_fragment, false) {
|
|
||||||
// The fullscreen quad's FBO
|
|
||||||
glGenVertexArrays(1, &quad_VertexArrayID);
|
|
||||||
glBindVertexArray(quad_VertexArrayID);
|
|
||||||
|
|
||||||
glGenBuffers(1, &quad_vertexbuffer);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data),
|
|
||||||
g_quad_vertex_buffer_data, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
texID = shader.getu("renderedTexture");
|
|
||||||
}
|
|
||||||
|
|
||||||
~texture_drawer_data() {
|
|
||||||
glDeleteBuffers(1, &quad_vertexbuffer);
|
|
||||||
glDeleteVertexArrays(1, &quad_VertexArrayID);
|
|
||||||
|
|
||||||
for (auto tex : textures) {
|
|
||||||
glDeleteTextures(1, &tex->val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
texture_drawer_data* texdd = NULL;
|
|
||||||
|
|
||||||
void texture::init() {
|
|
||||||
if (!texdd) texdd = new texture_drawer_data();
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture::deinit() {
|
|
||||||
if (texdd) delete texdd;
|
|
||||||
texdd = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture::draw_texture(uint4 out, uint4 in) {
|
|
||||||
assert(in);
|
|
||||||
|
|
||||||
// Render to the screen
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, out);
|
|
||||||
|
|
||||||
// Use our shader
|
|
||||||
texdd->shader.bind();
|
|
||||||
|
|
||||||
// Bind our texture in Texture Unit 0
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, in);
|
|
||||||
// Set our "renderedTexture" sampler to use Texture Unit 0
|
|
||||||
glUniform1i(texdd->texID, 0);
|
|
||||||
|
|
||||||
// glUniformMatrix4fv(texdd->rect_mat, 1, GL_FALSE, &tmat[0][0]);
|
|
||||||
|
|
||||||
// 1rst attribute buffer : vertices
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, texdd->quad_vertexbuffer);
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
|
|
||||||
|
|
||||||
// Draw the triangles. 2*3 indices starting at 0 -> 2 triangles
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
||||||
|
|
||||||
glDisableVertexAttribArray(0);
|
|
||||||
|
|
||||||
texdd->shader.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint load_texture(string name) {
|
|
||||||
GLuint tex_2d = 0;
|
|
||||||
RelAssert(0 && "incomplete compilation - no SOIL support added");
|
|
||||||
|
|
||||||
if (0) {
|
|
||||||
//auto document = lunasvg::Document::loadFromFile("tiger.svg");
|
|
||||||
//auto bitmap = document->renderToBitmap();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/*
|
|
||||||
tex_2d = SOIL_load_OGL_texture(
|
|
||||||
name.cstr(), SOIL_LOAD_RGBA, SOIL_CREATE_NEW_ID,
|
|
||||||
SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB |
|
|
||||||
SOIL_FLAG_COMPRESS_TO_DXT);
|
|
||||||
|
|
||||||
if (0 == tex_2d) {
|
|
||||||
printf("SOIL loading error: '%s'\n", SOIL_last_result());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
return tex_2d;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint texture::get_tex(const char* TexId) {
|
|
||||||
GLuint out = 0;
|
|
||||||
alni idx = texdd->textures.presents(TexId);
|
|
||||||
if (idx != -1) {
|
|
||||||
out = texdd->textures.get(TexId);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out = load_texture(TexId);
|
|
||||||
texdd->textures.put(TexId, out);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture::drawCurcle(vec2f pos, double radius, rgba col) {
|
|
||||||
#ifndef ENV_OS_ANDROID
|
|
||||||
static alni precision = 40;
|
|
||||||
|
|
||||||
glColor4f(col.r, col.g, col.b, col.a);
|
|
||||||
|
|
||||||
double twicePi = 2.0 * 3.142;
|
|
||||||
|
|
||||||
glBegin(GL_TRIANGLE_FAN); // BEGIN CIRCLE
|
|
||||||
glVertex2f(pos.x, pos.y); // center of circle
|
|
||||||
|
|
||||||
for (alni i = 0; i <= precision; i++) {
|
|
||||||
glVertex2f((GLfloat)(pos.x + (radius * cos(i * twicePi / precision))),
|
|
||||||
(GLfloat)(pos.y + (radius * sin(i * twicePi / precision))));
|
|
||||||
}
|
|
||||||
glEnd(); // END
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -1,107 +0,0 @@
|
||||||
|
|
||||||
#include "SimpleGui.h"
|
|
||||||
#include "debugui.h"
|
|
||||||
#include "texture.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "imgui.h"
|
|
||||||
|
|
||||||
struct CollorWheelWidget {
|
|
||||||
tp::rgba col = { 0.3f, 0.3f, 0.3f, 0.9f };
|
|
||||||
tp::rectf rec = { 10, 30, 40, 40 };
|
|
||||||
|
|
||||||
void draw(tp::glw::Canvas& canvas) {
|
|
||||||
canvas.setCol1(col);
|
|
||||||
canvas.rect(rec, 3.f);
|
|
||||||
canvas.drawColorwheel(rec, col.rgbs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Test {
|
|
||||||
|
|
||||||
tp::glw::Window window;
|
|
||||||
tp::glw::DebugUI ui;
|
|
||||||
tp::glw::Canvas canvas;
|
|
||||||
tp::glw::WindowsHeaderWidget header;
|
|
||||||
tp::glw::WindowSimpleInputs inputs;
|
|
||||||
tp::halnf mHeaderHeight = 6.5f;
|
|
||||||
|
|
||||||
CollorWheelWidget colorwheel;
|
|
||||||
tp::halnf uiscale = 1.f;
|
|
||||||
tp::Timer time;
|
|
||||||
tp::halni frames = 0;
|
|
||||||
tp::halni fps = 0;
|
|
||||||
|
|
||||||
Test() : window(), ui(window, debuguiCallBack, this), time(1000) {
|
|
||||||
tp::glw::texture::init();
|
|
||||||
canvas.setCol1({ 0.5f, 0.5f, 0.5f, 0.5f });
|
|
||||||
window.mAppearence.mHiden = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void proc() {
|
|
||||||
window.pollEvents();
|
|
||||||
inputs.update(window, uiscale);
|
|
||||||
|
|
||||||
header.header_rec = { (inputs.mWindowSizeMM.x - 60.f) / 2.f, 3.f, 60.f, mHeaderHeight };
|
|
||||||
header.proc(window, inputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw() {
|
|
||||||
// window frame
|
|
||||||
window.beginDraw(); {
|
|
||||||
// canvas draw
|
|
||||||
canvas.beginDraw({ { 0, 0 }, inputs.mWindowSizeMM }, window.mDevice.mDPMM, uiscale); {
|
|
||||||
canvas.clear();
|
|
||||||
header.draw(canvas);
|
|
||||||
colorwheel.draw(canvas);
|
|
||||||
} canvas.endDraw();
|
|
||||||
// debug draw
|
|
||||||
ui.drawDebugUI(window.mDevice.mDPMM);
|
|
||||||
} window.endDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() {
|
|
||||||
while (!window.mEvents.mClose) {
|
|
||||||
proc();
|
|
||||||
if (window.mEvents.mRedraw || tp::glw::gInTransition) {
|
|
||||||
draw();
|
|
||||||
}
|
|
||||||
if (time.isTimeout()) {
|
|
||||||
fps = frames;
|
|
||||||
frames = 0;
|
|
||||||
time.reset();
|
|
||||||
}
|
|
||||||
frames++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void debugui() {
|
|
||||||
static char buff[100];
|
|
||||||
ImGui::DragFloat("UI SCale", &uiscale, 0.02);
|
|
||||||
ImGui::Text("Fps: %i", fps);
|
|
||||||
ImGui::InputText("Fps: %i", buff, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void debuguiCallBack(void* self) {
|
|
||||||
((Test*)self)->debugui();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Test() {
|
|
||||||
tp::glw::texture::deinit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CROSSPLATFORM_MAIN
|
|
||||||
int main() {
|
|
||||||
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleGlw, NULL };
|
|
||||||
tp::ModuleManifest TestModule("Test", NULL, NULL, ModuleDependencies);
|
|
||||||
if (!TestModule.initialize()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Test test;
|
|
||||||
test.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
TestModule.deinitialize();
|
|
||||||
}
|
|
||||||
20
.project
Normal file
20
.project
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>Modules</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.core.cBuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.cmake.core.cmakeNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
|
|
@ -3,20 +3,18 @@ cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
project(Tokenizer)
|
project(Language)
|
||||||
|
|
||||||
### ---------------------- Static Library --------------------- ###
|
### ---------------------- Static Library --------------------- ###
|
||||||
file(GLOB SOURCES "./private/*.cpp")
|
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
|
||||||
file(GLOB HEADERS "./public/*.hpp")
|
file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp")
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
target_include_directories(${PROJECT_NAME} PUBLIC public/)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Strings)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Strings)
|
||||||
|
|
||||||
### -------------------------- Tests -------------------------- ###
|
### -------------------------- Tests -------------------------- ###
|
||||||
enable_testing()
|
enable_testing()
|
||||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
||||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils)
|
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
|
||||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
||||||
|
|
||||||
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib)
|
|
||||||
36
.wip/Language/private/Grammar.cpp
Normal file
36
.wip/Language/private/Grammar.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
#include "Grammar.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
ContextFreeGrammar::Arg::Arg(const String& id, bool terminal, bool epsilon) {
|
||||||
|
mId = id;
|
||||||
|
mIsTerminal = terminal;
|
||||||
|
mIsEpsilon = epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
const String& ContextFreeGrammar::Arg::getId() const { return mId; }
|
||||||
|
|
||||||
|
bool ContextFreeGrammar::Arg::operator==(const Arg& in) const {
|
||||||
|
return (mId == in.mId) && (mIsEpsilon == in.mIsEpsilon) && (mIsTerminal == in.mIsTerminal);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextFreeGrammar::Rule::Rule(const String& id, const InitialierList<Arg>& args) {
|
||||||
|
mId = id;
|
||||||
|
mArgs = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContextFreeGrammar::Rule::operator==(const Rule& in) const { return (mId == in.mId) && (mArgs == in.mArgs); }
|
||||||
|
|
||||||
|
bool ContextFreeGrammar::Rule::isProductive() const {
|
||||||
|
for (auto arg : mArgs) {
|
||||||
|
if (arg->getId() == mId) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextFreeGrammar::addRule(const Rule& rule) { mRules.append(rule); }
|
||||||
|
|
||||||
|
void ContextFreeGrammar::addRule(const String& id, const InitialierList<Arg>& args) { addRule(Rule(id, args)); }
|
||||||
|
|
||||||
|
void ContextFreeGrammar::setStart(const String& startRule) { mStartTerminal = startRule; }
|
||||||
8
.wip/Language/private/LanguageCommon.cpp
Normal file
8
.wip/Language/private/LanguageCommon.cpp
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
#include "LanguageCommon.hpp"
|
||||||
|
#include "Strings.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
static ModuleManifest* sModuleDependencies[] = { &gModuleStrings, nullptr };
|
||||||
|
ModuleManifest tp::gModuleLanguage = ModuleManifest("Language", nullptr, nullptr, sModuleDependencies);
|
||||||
249
.wip/Language/public/Automata.hpp
Normal file
249
.wip/Language/public/Automata.hpp
Normal file
|
|
@ -0,0 +1,249 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Utils.hpp"
|
||||||
|
#include "List.hpp"
|
||||||
|
#include "Map.hpp"
|
||||||
|
#include "Tree.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
// Non-Deterministic Finite-State Automata
|
||||||
|
template <typename tAlphabetType, typename tStateType>
|
||||||
|
class FiniteStateAutomation {
|
||||||
|
public:
|
||||||
|
struct State;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Transition {
|
||||||
|
friend FiniteStateAutomation;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Type { ANY, EPSILON, SYMBOL };
|
||||||
|
|
||||||
|
public:
|
||||||
|
Transition(Type type, State* state, tAlphabetType symbol = tAlphabetType()) {
|
||||||
|
mState = state;
|
||||||
|
mType = type;
|
||||||
|
mSymbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isTransition(const tAlphabetType& symbol) const {
|
||||||
|
return (mType == ANY || mType == EPSILON) || (mSymbol == symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool doesConsumes(const tAlphabetType& symbol) const {
|
||||||
|
return (mType == ANY || (mType == SYMBOL && mSymbol == symbol));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isEpsilon() const { return mType == EPSILON; }
|
||||||
|
|
||||||
|
const State* getState() const { return mState; }
|
||||||
|
const tAlphabetType& getSymbol() const { return mSymbol; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
State* mState = nullptr;
|
||||||
|
Type mType;
|
||||||
|
tAlphabetType mSymbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
class State {
|
||||||
|
friend FiniteStateAutomation;
|
||||||
|
|
||||||
|
public:
|
||||||
|
State() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setValue(const tStateType& stateValue) { mStateVal = stateValue; }
|
||||||
|
void setAcceptance(bool isAccepting) { mIsAccepting = isAccepting; }
|
||||||
|
[[nodiscard]] bool isAccepting() const { return mIsAccepting; }
|
||||||
|
const tStateType& getStateVal() const { return mStateVal; }
|
||||||
|
[[nodiscard]] const Buffer<Transition>* getTransitions() const { return &mTransitions; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Buffer<Transition> mTransitions{};
|
||||||
|
tStateType mStateVal = tStateType();
|
||||||
|
bool mIsAccepting = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
List<State> mStates;
|
||||||
|
State* mStartState = nullptr;
|
||||||
|
Range<ualni> mAlphabetRange = { ENV_UALNI_MAX, ENV_UALNI_MIN };
|
||||||
|
|
||||||
|
public:
|
||||||
|
FiniteStateAutomation() = default;
|
||||||
|
|
||||||
|
State* addState(const tStateType& state, bool accepting) {
|
||||||
|
auto node = mStates.newNode();
|
||||||
|
node->data.mIsAccepting = accepting;
|
||||||
|
node->data.mStateVal = state;
|
||||||
|
mStates.pushBack(node);
|
||||||
|
return &node->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTransition(State* from, State* to, const tAlphabetType& symbol) {
|
||||||
|
from->mTransitions.append(Transition(Transition::SYMBOL, to, symbol));
|
||||||
|
if (mAlphabetRange.mBegin < ualni(symbol)) mAlphabetRange.mBegin = ualni(symbol);
|
||||||
|
if (mAlphabetRange.mEnd > ualni(symbol)) mAlphabetRange.mEnd = ualni(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addEpsilonTransition(State* from, State* to) { from->mTransitions.append(Transition(Transition::SYMBOL, to)); }
|
||||||
|
|
||||||
|
void addAnyTransition(State* from, State* to) { from->mTransitions.append(Transition(Transition::ANY, to)); }
|
||||||
|
|
||||||
|
void setStartState(State* start) { mStartState = start; }
|
||||||
|
|
||||||
|
[[nodiscard]] State* getStartState() const { return mStartState; }
|
||||||
|
|
||||||
|
[[nodiscard]] bool isValid() const {
|
||||||
|
if (!mStartState) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ualni numStates() const { return mStates.length(); }
|
||||||
|
|
||||||
|
[[nodiscard]] const List<State>* getStates() const { return &mStates; }
|
||||||
|
|
||||||
|
[[nodiscard]] Range<ualni> getAlphabetRange() const { return mAlphabetRange; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef AvlTree<AvlNumericKey<State*>, bool> StatesSet;
|
||||||
|
|
||||||
|
// Expands initial set with states that are reachable from initial set with no input consumption (E-transitions)
|
||||||
|
static void expandSet(StatesSet& set) {
|
||||||
|
List<State*> workingSet;
|
||||||
|
|
||||||
|
set.forEach([&](AvlNumericKey<State*>& key, bool) { workingSet.pushBack(key.val); });
|
||||||
|
|
||||||
|
while (workingSet.length()) {
|
||||||
|
auto first = workingSet.first()->data;
|
||||||
|
set.insert(first, {});
|
||||||
|
|
||||||
|
for (auto transition : first->mTransitions) {
|
||||||
|
if (!transition->isEpsilon()) continue;
|
||||||
|
if (set.find(transition->mState)) continue;
|
||||||
|
workingSet.pushBack(transition->mState);
|
||||||
|
}
|
||||||
|
|
||||||
|
workingSet.popFront();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// States that are reachable from initial set with symbol transition
|
||||||
|
static void findMoveSet(StatesSet& from, StatesSet& moveSet, tAlphabetType symbol) {
|
||||||
|
from.forEach([&](AvlNumericKey<State*>& key, bool) {
|
||||||
|
for (auto transition : key.val->mTransitions) {
|
||||||
|
if (transition->isEpsilon()) continue;
|
||||||
|
if (!transition->isTransition(symbol)) continue;
|
||||||
|
if (moveSet.find(transition->mState)) continue;
|
||||||
|
moveSet.insert(transition->mState, {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool makeDeterministic() {
|
||||||
|
if (!isValid()) return false;
|
||||||
|
|
||||||
|
struct GroupKey {
|
||||||
|
const StatesSet* group;
|
||||||
|
static ualni hash(GroupKey key) { return 0; }
|
||||||
|
bool operator==(const GroupKey& key) const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GroupInfo {
|
||||||
|
StatesSet* group = nullptr;
|
||||||
|
AvlTree<AvlNumericKey<StatesSet*>, tAlphabetType> transitions;
|
||||||
|
State* newState = nullptr;
|
||||||
|
bool accepting = false;
|
||||||
|
tStateType stateVal = tStateType();
|
||||||
|
};
|
||||||
|
|
||||||
|
Buffer<StatesSet> groups = { {} };
|
||||||
|
Map<GroupKey, GroupInfo, DefaultAllocator, GroupKey::hash> groupInfos;
|
||||||
|
|
||||||
|
groups.first().insert(getStartState(), false);
|
||||||
|
|
||||||
|
expandSet(groups.first());
|
||||||
|
|
||||||
|
groupInfos.put({ &groups.first() }, { &groups.first() });
|
||||||
|
|
||||||
|
// 1) find new states
|
||||||
|
List<StatesSet*> workingSet;
|
||||||
|
workingSet.pushBack(&groups.first());
|
||||||
|
|
||||||
|
while (workingSet.length()) {
|
||||||
|
StatesSet* group = workingSet.first()->data;
|
||||||
|
GroupInfo* info = &groupInfos.get({ group });
|
||||||
|
|
||||||
|
for (auto symbol : getAlphabetRange()) {
|
||||||
|
|
||||||
|
// calculate new possible state
|
||||||
|
StatesSet potentialGroup;
|
||||||
|
|
||||||
|
findMoveSet(*group, potentialGroup, tAlphabetType(symbol));
|
||||||
|
expandSet(potentialGroup);
|
||||||
|
|
||||||
|
if (!potentialGroup.size()) continue;
|
||||||
|
|
||||||
|
// find existing or create group
|
||||||
|
StatesSet* targetGroup = nullptr;
|
||||||
|
auto iter = groupInfos.presents({ &potentialGroup });
|
||||||
|
if (iter) {
|
||||||
|
targetGroup = groupInfos.getSlotVal(iter).group;
|
||||||
|
} else {
|
||||||
|
targetGroup = &groups.append(potentialGroup);
|
||||||
|
groupInfos.put({ targetGroup }, { targetGroup });
|
||||||
|
workingSet.pushBack(targetGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert transition is added
|
||||||
|
info->transitions.insert(targetGroup, tAlphabetType(symbol));
|
||||||
|
}
|
||||||
|
|
||||||
|
workingSet.popFront();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) find new states termination values
|
||||||
|
for (auto group : groupInfos) {
|
||||||
|
GroupInfo* info = &group->val;
|
||||||
|
ualni accepting = 0;
|
||||||
|
|
||||||
|
info->group->forEach([&](AvlNumericKey<State*>& key, bool) {
|
||||||
|
if (key.val->mIsAccepting) {
|
||||||
|
accepting++;
|
||||||
|
info->accepting = true;
|
||||||
|
info->stateVal = key.val->mStateVal;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!accepting) {
|
||||||
|
info->accepting = false;
|
||||||
|
info->stateVal = info->group->head()->key.val->mStateVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) transfer
|
||||||
|
mStates.removeAll();
|
||||||
|
|
||||||
|
// create states
|
||||||
|
for (auto group : groupInfos) {
|
||||||
|
group->val.newState = addState(group->val.stateVal, group->val.accepting);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create transitions
|
||||||
|
for (auto group : groupInfos) {
|
||||||
|
auto functor = [&](AvlNumericKey<StatesSet*> targetGroupKey, tAlphabetType symbol) {
|
||||||
|
GroupInfo* targetGroup = &groupInfos.get({ (StatesSet*) targetGroupKey.val });
|
||||||
|
addTransition(group->val.newState, targetGroup->newState, symbol);
|
||||||
|
};
|
||||||
|
group->val.transitions.forEach(functor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
137
.wip/Language/public/ContextFreeAutomata.hpp
Normal file
137
.wip/Language/public/ContextFreeAutomata.hpp
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Strings.hpp"
|
||||||
|
#include "Automata.hpp"
|
||||||
|
#include "Buffer2D.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
template <typename tAlphabetType, typename tStateType>
|
||||||
|
class ContextFreeAutomata {
|
||||||
|
|
||||||
|
struct Action {
|
||||||
|
enum Type { SHIFT, REDUCE, TRAP } type = TRAP;
|
||||||
|
ualni num = 0; // state to shift (shift action) or pop count (reduce action)
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct StackItem {
|
||||||
|
ualni state = 0;
|
||||||
|
tAlphabetType symbol;
|
||||||
|
Buffer<StackItem*> leafs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AcceptResult {
|
||||||
|
bool accepted = false;
|
||||||
|
ualni advancedIdx = 0;
|
||||||
|
const StackItem* ast = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
ContextFreeAutomata() = default;
|
||||||
|
|
||||||
|
AcceptResult accept(const tAlphabetType* stream, ualni size) {
|
||||||
|
mCurrentState = mStartState;
|
||||||
|
mStack.append(&mItems.append({ mCurrentState, {}, {} }));
|
||||||
|
|
||||||
|
ualni advancedIdx = 0;
|
||||||
|
while (advancedIdx < size) {
|
||||||
|
const tAlphabetType& symbol = *(stream + advancedIdx);
|
||||||
|
|
||||||
|
if (!(symbol >= mRange.mBegin && symbol < mRange.mEnd)) {
|
||||||
|
return { false, advancedIdx, nullptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
const Action& action = mTable.get({ ualni(symbol - mRange.mBegin), mCurrentState });
|
||||||
|
|
||||||
|
if (action.type == Action::TRAP) {
|
||||||
|
return { false, advancedIdx, nullptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type == Action::SHIFT) {
|
||||||
|
mStack.last()->symbol = symbol;
|
||||||
|
mStack.append(&mItems.append({ mCurrentState, {}, {} }));
|
||||||
|
mCurrentState = action.num;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTable.get({ 0, mCurrentState }).type == Action::REDUCE) {
|
||||||
|
StackItem* newItem = &mItems.append(StackItem{});
|
||||||
|
for (auto iter : Range<ualni>(action.num)) {
|
||||||
|
newItem->leafs.append(mStack.last());
|
||||||
|
mCurrentState = mStack.last()->state;
|
||||||
|
mStack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mStack.size()) {
|
||||||
|
if (advancedIdx == size) {
|
||||||
|
return { true, advancedIdx, newItem };
|
||||||
|
} else {
|
||||||
|
return { false, advancedIdx, {} };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mStack.append(&mItems.append({ mCurrentState, {}, {} }));
|
||||||
|
}
|
||||||
|
|
||||||
|
advancedIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { false, advancedIdx, nullptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef FiniteStateAutomation<tAlphabetType, tStateType> Automata;
|
||||||
|
typedef Automata::State AutomataState;
|
||||||
|
|
||||||
|
void construct(const Automata& automata) {
|
||||||
|
mRange = automata.getAlphabetRange();
|
||||||
|
|
||||||
|
const ualni numStates = automata.numStates();
|
||||||
|
const ualni numSymbols = mRange.idxDiff();
|
||||||
|
|
||||||
|
mTable.reserve({ numSymbols, numStates });
|
||||||
|
mTable.assign(Action{ Action::TRAP, 0 });
|
||||||
|
|
||||||
|
Map<const AutomataState*, ualni> states;
|
||||||
|
ualni stateIndex = 0;
|
||||||
|
for (auto state : *automata.getStates()) {
|
||||||
|
states.put(&state.data(), { stateIndex });
|
||||||
|
stateIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
stateIndex = 0;
|
||||||
|
for (auto state : *automata.getStates()) {
|
||||||
|
if (&state.data() == automata.getStartState()) {
|
||||||
|
mStartState = stateIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->isAccepting()) {
|
||||||
|
ASSERT(state->getTransitions()->size() == 0)
|
||||||
|
for (auto symbolIndex : Range<ualni>(numSymbols)) {
|
||||||
|
mTable.set({ stateIndex, symbolIndex }, { Action::REDUCE, state->getStateVal().numArgs() });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto transition : *state->getTransitions()) {
|
||||||
|
ualni symbolIndex = ualni(transition->getSymbol()) - mRange.mBegin;
|
||||||
|
ualni targetStateIndex = states.get(transition->getState());
|
||||||
|
mTable.set({ stateIndex, symbolIndex }, { Action::SHIFT, targetStateIndex });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stateIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Buffer2D<Action> mTable;
|
||||||
|
|
||||||
|
Buffer<StackItem> mItems;
|
||||||
|
Buffer<StackItem*> mStack;
|
||||||
|
|
||||||
|
ualni mStartState = 0;
|
||||||
|
ualni mCurrentState = 0;
|
||||||
|
|
||||||
|
Range<ualni> mRange;
|
||||||
|
};
|
||||||
|
}
|
||||||
181
.wip/Language/public/ContextFreeCompiler.hpp
Normal file
181
.wip/Language/public/ContextFreeCompiler.hpp
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Automata.hpp"
|
||||||
|
#include "Grammar.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class ContextFreeCompiler {
|
||||||
|
public:
|
||||||
|
struct SymbolVal {
|
||||||
|
SymbolVal() = default;
|
||||||
|
|
||||||
|
SymbolVal(ualni aId, ualni aStart, ualni aLen) {
|
||||||
|
id = aId;
|
||||||
|
start = aStart;
|
||||||
|
len = aLen;
|
||||||
|
};
|
||||||
|
|
||||||
|
SymbolVal(ualni val) { id = val; }
|
||||||
|
|
||||||
|
operator ualni() const { return id; }
|
||||||
|
|
||||||
|
bool operator==(const SymbolVal& in) const { return in.id == id; }
|
||||||
|
SymbolVal& operator=(const SymbolVal& in) = default;
|
||||||
|
|
||||||
|
ualni id = 0;
|
||||||
|
ualni start = 0;
|
||||||
|
ualni len = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Item {
|
||||||
|
const ContextFreeGrammar::Rule* mRule = nullptr;
|
||||||
|
ualni mAdvanceIdx = 0;
|
||||||
|
ualni numArgs() const { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Symbol {
|
||||||
|
String mId;
|
||||||
|
bool mIsTerminal = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct NonTerminal {
|
||||||
|
Buffer<ContextFreeGrammar::Rule*> rules;
|
||||||
|
Map<String, NonTerminal*> references;
|
||||||
|
Map<String, NonTerminal*> referencing;
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] bool isProductive() const {
|
||||||
|
for (auto rule : rules) {
|
||||||
|
if (rule->isProductive()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isLooped(Map<String, ualni>& processed, const String& id) const {
|
||||||
|
for (auto ref : referencing) {
|
||||||
|
if (processed.presents(ref->key)) return true;
|
||||||
|
}
|
||||||
|
processed.put(id, {});
|
||||||
|
for (auto ref : referencing) {
|
||||||
|
if (ref->val->isLooped(processed, ref->key)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool compile(const ContextFreeGrammar& grammar, FiniteStateAutomation<SymbolVal, Item>& automata) {
|
||||||
|
if (!init(grammar)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const Buffer<Symbol>* getSymbols() const { return &mSymbols; }
|
||||||
|
[[nodiscard]] SymbolVal getSymbolId(const String& name) const { return mSymbolLookup.get(name); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool init(const ContextFreeGrammar& grammar) {
|
||||||
|
|
||||||
|
if (!grammar.getRules()->size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto rule : *grammar.getRules()) {
|
||||||
|
if (!rule->getArgs()->size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findNonTerminals(grammar);
|
||||||
|
|
||||||
|
for (auto nonTerminal : mNonTerminals) {
|
||||||
|
for (auto rule : nonTerminal->val.rules) {
|
||||||
|
for (auto arg : *rule->getArgs()) {
|
||||||
|
if (arg->isTerminal() || arg->isEpsilon()) continue;
|
||||||
|
|
||||||
|
if (!mNonTerminals.presents(arg->getId())) {
|
||||||
|
printf("Referenced non-terminal '%s' is not defined\n", arg->getId().read());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findAllReferences(grammar);
|
||||||
|
|
||||||
|
for (auto nonTerminal : mNonTerminals) {
|
||||||
|
if (!nonTerminal->val.references.size() && nonTerminal->key != grammar.getStartTerminal()) {
|
||||||
|
printf("Non-terminal '%s' is defined but not used\n", nonTerminal->key.read());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto nonTerminal : mNonTerminals) {
|
||||||
|
if (!nonTerminal->val.isProductive()) {
|
||||||
|
printf("Non-terminal '%s' is not productive\n", nonTerminal->val.rules.first()->getId().read());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, ualni> processed;
|
||||||
|
if (mNonTerminals.get(grammar.getStartTerminal()).isLooped(processed, grammar.getStartTerminal())) {
|
||||||
|
printf("Note that grammar is looped.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
initSymbols(grammar);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void findNonTerminals(const ContextFreeGrammar& grammar) {
|
||||||
|
for (auto rule : *grammar.getRules()) {
|
||||||
|
if (!mNonTerminals.presents(rule->getId())) {
|
||||||
|
mNonTerminals.put(rule->getId(), {});
|
||||||
|
}
|
||||||
|
auto nonTerminal = &mNonTerminals.get(rule->getId());
|
||||||
|
nonTerminal->rules.append(&rule.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void findAllReferences(const ContextFreeGrammar& grammar) {
|
||||||
|
for (auto nonTerminal : mNonTerminals) {
|
||||||
|
for (auto rule : nonTerminal->val.rules) {
|
||||||
|
for (auto arg : *rule->getArgs()) {
|
||||||
|
if (arg->isTerminal() || arg->isEpsilon()) continue;
|
||||||
|
|
||||||
|
NonTerminal* reference = &mNonTerminals.get(arg->getId());
|
||||||
|
nonTerminal->val.referencing.put(arg->getId(), reference);
|
||||||
|
reference->references.put(nonTerminal->key, &nonTerminal->val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initSymbols(const ContextFreeGrammar& grammar) {
|
||||||
|
for (auto nonTerminal : mNonTerminals) {
|
||||||
|
mSymbols.append({ nonTerminal->key, false });
|
||||||
|
mSymbolLookup.put(nonTerminal->key, SymbolVal(mSymbols.size() - 1));
|
||||||
|
|
||||||
|
for (auto rule : nonTerminal->val.rules) {
|
||||||
|
for (auto arg : *rule->getArgs()) {
|
||||||
|
if (arg->isEpsilon() || arg->isTerminal()) continue;
|
||||||
|
if (mTerminals.presents(arg->getId())) continue;
|
||||||
|
mTerminals.put(arg->getId(), {});
|
||||||
|
|
||||||
|
mSymbols.append({ nonTerminal->key, true });
|
||||||
|
mSymbolLookup.put(nonTerminal->key, SymbolVal(mSymbols.size() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Map<String, NonTerminal> mNonTerminals;
|
||||||
|
Map<String, bool> mTerminals;
|
||||||
|
Buffer<Symbol> mSymbols;
|
||||||
|
Map<String, SymbolVal> mSymbolLookup;
|
||||||
|
};
|
||||||
|
}
|
||||||
224
.wip/Language/public/Grammar.hpp
Normal file
224
.wip/Language/public/Grammar.hpp
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Buffer.hpp"
|
||||||
|
#include "LanguageCommon.hpp"
|
||||||
|
#include "Map.hpp"
|
||||||
|
#include "Strings.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class ContextFreeGrammar {
|
||||||
|
public:
|
||||||
|
struct Arg {
|
||||||
|
friend class Rule;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Arg() = default;
|
||||||
|
explicit Arg(const String& id, bool terminal = true, bool epsilon = false);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool operator==(const Arg& in) const;
|
||||||
|
[[nodiscard]] const String& getId() const;
|
||||||
|
[[nodiscard]] bool isTerminal() const { return mIsTerminal; }
|
||||||
|
[[nodiscard]] bool isEpsilon() const { return mIsEpsilon; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
String mId;
|
||||||
|
bool mIsTerminal = false;
|
||||||
|
bool mIsEpsilon = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Rule {
|
||||||
|
public:
|
||||||
|
Rule() = default;
|
||||||
|
Rule(const String& id, const InitialierList<Arg>& args);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool operator==(const Rule& in) const;
|
||||||
|
[[nodiscard]] bool isProductive() const;
|
||||||
|
[[nodiscard]] const String& getId() const { return mId; }
|
||||||
|
[[nodiscard]] const Buffer<Arg>* getArgs() const { return &mArgs; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
String mId;
|
||||||
|
Buffer<Arg> mArgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
ContextFreeGrammar() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void addRule(const Rule& rule);
|
||||||
|
void addRule(const String& id, const InitialierList<Arg>& args);
|
||||||
|
void setStart(const String& startRule);
|
||||||
|
[[nodiscard]] const Buffer<Rule>* getRules() const { return &mRules; }
|
||||||
|
[[nodiscard]] const String& getStartTerminal() const { return mStartTerminal; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buffer<Rule> mRules;
|
||||||
|
String mStartTerminal;
|
||||||
|
bool mIsLooped = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tAlphabetType, typename tTokType>
|
||||||
|
class RegularGrammar {
|
||||||
|
public:
|
||||||
|
struct Node {
|
||||||
|
enum Type {
|
||||||
|
NONE,
|
||||||
|
ANY,
|
||||||
|
OR,
|
||||||
|
IF,
|
||||||
|
CLASS,
|
||||||
|
COMPOUND,
|
||||||
|
REPEAT,
|
||||||
|
VAL,
|
||||||
|
} mType = NONE;
|
||||||
|
|
||||||
|
explicit Node(Type type) :
|
||||||
|
mType(type) {}
|
||||||
|
|
||||||
|
virtual ~Node() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ValueNode : public Node {
|
||||||
|
public:
|
||||||
|
explicit ValueNode(tAlphabetType val) :
|
||||||
|
mVal(val),
|
||||||
|
Node(Node::VAL) {}
|
||||||
|
|
||||||
|
~ValueNode() override = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
tAlphabetType mVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompoundNode : public Node {
|
||||||
|
public:
|
||||||
|
CompoundNode() :
|
||||||
|
Node(Node::COMPOUND) {}
|
||||||
|
|
||||||
|
CompoundNode(const InitialierList<const Node*>& nodes) :
|
||||||
|
Node(Node::COMPOUND) {
|
||||||
|
mSequence = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
~CompoundNode() override {
|
||||||
|
for (auto iter : mSequence) {
|
||||||
|
delete iter.data();
|
||||||
|
}
|
||||||
|
mSequence.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buffer<const Node*> mSequence;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlternationNode : public Node {
|
||||||
|
public:
|
||||||
|
AlternationNode() :
|
||||||
|
Node(Node::OR) {}
|
||||||
|
|
||||||
|
AlternationNode(const Node* a, const Node* b) :
|
||||||
|
Node(Node::OR) {
|
||||||
|
mFirst = a;
|
||||||
|
mSecond = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
~AlternationNode() override {
|
||||||
|
delete mFirst;
|
||||||
|
delete mSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Node* mFirst = nullptr;
|
||||||
|
const Node* mSecond = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IfNode : public Node {
|
||||||
|
public:
|
||||||
|
IfNode() :
|
||||||
|
Node(Node::IF) {}
|
||||||
|
|
||||||
|
explicit IfNode(const Node* a) :
|
||||||
|
Node(Node::IF) {
|
||||||
|
mNode = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
~IfNode() override { delete mNode; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Node* mNode = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnyNode : public Node {
|
||||||
|
public:
|
||||||
|
AnyNode() :
|
||||||
|
Node(Node::ANY) {}
|
||||||
|
|
||||||
|
~AnyNode() override = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RepetitionNode : public Node {
|
||||||
|
public:
|
||||||
|
RepetitionNode() :
|
||||||
|
Node(Node::REPEAT) {}
|
||||||
|
|
||||||
|
explicit RepetitionNode(const Node* rep, bool plus = false) :
|
||||||
|
Node(Node::REPEAT) {
|
||||||
|
mNode = rep;
|
||||||
|
mPlus = plus;
|
||||||
|
}
|
||||||
|
|
||||||
|
~RepetitionNode() override { delete mNode; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Node* mNode = nullptr;
|
||||||
|
bool mPlus = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClassNode : public Node {
|
||||||
|
public:
|
||||||
|
ClassNode() :
|
||||||
|
Node(Node::CLASS) {}
|
||||||
|
|
||||||
|
explicit ClassNode(const Buffer<Range<tAlphabetType>>& ranges, bool exclude = false) :
|
||||||
|
Node(Node::CLASS) {
|
||||||
|
mExclude = exclude;
|
||||||
|
mRanges = ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ClassNode() override { mRanges.removeAll(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buffer<Range<tAlphabetType>> mRanges;
|
||||||
|
bool mExclude = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
RegularGrammar() = default;
|
||||||
|
|
||||||
|
~RegularGrammar() {
|
||||||
|
for (auto rule : mRules) {
|
||||||
|
delete rule->t1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRule(const Node* node, tTokType id) { mRules.append({ node, id }); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Node* seq(const InitialierList<const Node*>& nodes) { return new CompoundNode(nodes); }
|
||||||
|
const Node* val(tAlphabetType in) { return new ValueNode(in); }
|
||||||
|
const Node* alt(const Node* a, const Node* b) { return new AlternationNode(a, b); }
|
||||||
|
const Node* may(const Node* a) { return new IfNode(a); }
|
||||||
|
const Node* any() { return new AnyNode(); }
|
||||||
|
const Node* rep(const Node* rep, bool plus = false) { return new RepetitionNode(rep, plus); }
|
||||||
|
const Node* ranges(const Buffer<Range<tAlphabetType>>& ranges, bool exclude = false) {
|
||||||
|
return new ClassNode(ranges, exclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buffer<Pair<const Node*, tTokType>> mRules;
|
||||||
|
};
|
||||||
|
}
|
||||||
7
.wip/Language/public/LanguageCommon.hpp
Normal file
7
.wip/Language/public/LanguageCommon.hpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Module.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
extern ModuleManifest gModuleLanguage;
|
||||||
|
}
|
||||||
107
.wip/Language/public/Parser.hpp
Normal file
107
.wip/Language/public/Parser.hpp
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RegularCompiler.hpp"
|
||||||
|
#include "RegularAutomata.hpp"
|
||||||
|
|
||||||
|
#include "ContextFreeCompiler.hpp"
|
||||||
|
#include "ContextFreeAutomata.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
template <typename tAlphabetType, typename tTokenType, tTokenType tInTransition, ualni MinSymbol, ualni MaxSymbol>
|
||||||
|
class Parser {
|
||||||
|
|
||||||
|
typedef RegularGrammar<tAlphabetType, tTokenType> RegularGrammar;
|
||||||
|
typedef RegularCompiler<tAlphabetType, tTokenType, tInTransition, MinSymbol, MaxSymbol> RegularCompiler;
|
||||||
|
typedef FiniteStateAutomation<tAlphabetType, tTokenType> RegularGraph;
|
||||||
|
typedef RegularAutomata<tAlphabetType, tTokenType> RegularAutomata;
|
||||||
|
|
||||||
|
// ContextFreeGrammar;
|
||||||
|
// ContextFreeCompiler;
|
||||||
|
typedef FiniteStateAutomation<ContextFreeCompiler::SymbolVal, ContextFreeCompiler::Item> ContextFreeGraph;
|
||||||
|
typedef ContextFreeAutomata<ContextFreeCompiler::SymbolVal, ContextFreeCompiler::Item> ContextFreeAutomata;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct ParseResult {
|
||||||
|
bool accepted = false;
|
||||||
|
const ContextFreeAutomata::StackItem* ast = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Parser() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool compileTables(
|
||||||
|
const ContextFreeGrammar& cfGrammar,
|
||||||
|
const RegularGrammar& reGrammar,
|
||||||
|
const Map<String, tTokenType>& contextFreeToRegular
|
||||||
|
) {
|
||||||
|
// Compile Regular Grammar
|
||||||
|
{
|
||||||
|
RegularGraph graph;
|
||||||
|
RegularCompiler compiler;
|
||||||
|
compiler.compile(graph, reGrammar);
|
||||||
|
graph.makeDeterministic();
|
||||||
|
mRegularAutomata.construct(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile context free grammar
|
||||||
|
{
|
||||||
|
ContextFreeGraph graph;
|
||||||
|
ContextFreeCompiler compiler;
|
||||||
|
compiler.compile(cfGrammar, graph);
|
||||||
|
graph.makeDeterministic();
|
||||||
|
mContextFreeAutomata.construct(graph);
|
||||||
|
|
||||||
|
// make glue
|
||||||
|
for (auto symbol : *compiler.getSymbols()) {
|
||||||
|
auto symbolId = compiler.getSymbolId(symbol->mId);
|
||||||
|
if (symbol->mIsTerminal) {
|
||||||
|
auto iter = contextFreeToRegular.presents(symbol->mId);
|
||||||
|
if (!iter) return false;
|
||||||
|
mGrammarGlue.put(contextFreeToRegular.getSlotVal(iter), symbolId);
|
||||||
|
} else {
|
||||||
|
mAstNames.put(symbolId, symbol->mId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseResult parse(const tAlphabetType* sentence, ualni sentenceLength) {
|
||||||
|
// get tokens stream
|
||||||
|
Buffer<ContextFreeCompiler::SymbolVal> tokens;
|
||||||
|
|
||||||
|
const tAlphabetType* sentenceIter = sentence;
|
||||||
|
ualni lengthIter = sentenceLength;
|
||||||
|
|
||||||
|
while (lengthIter) {
|
||||||
|
auto result = mRegularAutomata.accept(sentenceIter, lengthIter);
|
||||||
|
|
||||||
|
if (!result.accepted) {
|
||||||
|
return { false, nullptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.append(ContextFreeCompiler::SymbolVal(
|
||||||
|
mGrammarGlue.get(result.state), ualni(sentenceIter - sentence), result.advancedIdx
|
||||||
|
));
|
||||||
|
|
||||||
|
sentenceIter += result.advancedIdx;
|
||||||
|
lengthIter -= result.advancedIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextFreeAutomata::AcceptResult result = mContextFreeAutomata.accept(tokens.getBuff(), tokens.size());
|
||||||
|
return { result.accepted, result.ast };
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// save load compiled tables
|
||||||
|
RegularAutomata mRegularAutomata;
|
||||||
|
ContextFreeAutomata mContextFreeAutomata;
|
||||||
|
|
||||||
|
Map<tTokenType, ContextFreeCompiler::SymbolVal> mGrammarGlue;
|
||||||
|
Map<ContextFreeCompiler::SymbolVal, String> mAstNames;
|
||||||
|
};
|
||||||
|
}
|
||||||
101
.wip/Language/public/RegularAutomata.hpp
Normal file
101
.wip/Language/public/RegularAutomata.hpp
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Strings.hpp"
|
||||||
|
#include "Automata.hpp"
|
||||||
|
#include "Buffer2D.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
template <typename tAlphabetType, typename tStateType>
|
||||||
|
class RegularAutomata {
|
||||||
|
public:
|
||||||
|
struct AcceptResult {
|
||||||
|
bool accepted = false;
|
||||||
|
ualni advancedIdx = 0;
|
||||||
|
tStateType state = tStateType();
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
RegularAutomata() = default;
|
||||||
|
|
||||||
|
AcceptResult accept(const tAlphabetType* stream, ualni size) {
|
||||||
|
mCurrentState = mStartState;
|
||||||
|
|
||||||
|
ualni advancedIdx = 0;
|
||||||
|
|
||||||
|
while (advancedIdx < size) {
|
||||||
|
const tAlphabetType& symbol = *(stream + advancedIdx);
|
||||||
|
|
||||||
|
if (!(symbol >= mSymbolRange.mBegin && symbol < mSymbolRange.mEnd)) {
|
||||||
|
return { false, advancedIdx, {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentState = mTable.get({ (ualni) (symbol - mSymbolRange.mBegin), mCurrentState });
|
||||||
|
|
||||||
|
if (mCurrentState == mStates.size()) {
|
||||||
|
return { false, advancedIdx, {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mStates[mCurrentState].first) {
|
||||||
|
return { true, advancedIdx, mStates[mCurrentState].second };
|
||||||
|
}
|
||||||
|
|
||||||
|
advancedIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { false, advancedIdx, {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void construct(const FiniteStateAutomation<tAlphabetType, tStateType>& automata) {
|
||||||
|
const auto range = automata.getAlphabetRange();
|
||||||
|
mSymbolRange = { tAlphabetType(range.mBegin), tAlphabetType(range.mEnd) };
|
||||||
|
|
||||||
|
auto range_len = ualni(mSymbolRange.mEnd - mSymbolRange.mBegin);
|
||||||
|
auto sizeX = range_len ? range_len : 1;
|
||||||
|
auto sizeY = (ualni) (automata.numStates());
|
||||||
|
|
||||||
|
mTable.reserve({ sizeX, sizeY });
|
||||||
|
mTable.assign(automata.numStates());
|
||||||
|
mStates.reserve(sizeY);
|
||||||
|
|
||||||
|
ualni idx = 0;
|
||||||
|
for (auto state : *automata.getStates()) {
|
||||||
|
mStates[idx] = { state->isAccepting(), state->getStateVal() };
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
for (auto state : *automata.getStates()) {
|
||||||
|
if (&state.data() == automata.getStartState()) {
|
||||||
|
mStartState = mCurrentState = idx;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ualni stateIdx = 0;
|
||||||
|
for (auto state : *automata.getStates()) {
|
||||||
|
for (auto transition : *state->getTransitions()) {
|
||||||
|
ualni stateIdx2 = 0;
|
||||||
|
for (auto state2 : *automata.getStates()) {
|
||||||
|
if (transition->getState() == &state2.data()) break;
|
||||||
|
stateIdx2++;
|
||||||
|
}
|
||||||
|
auto const code = transition->getSymbol();
|
||||||
|
mTable.set({ (ualni) (code - mSymbolRange.mBegin), (ualni) stateIdx }, stateIdx2);
|
||||||
|
}
|
||||||
|
stateIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Buffer2D<ualni> mTable;
|
||||||
|
Buffer<Pair<bool, tStateType>> mStates;
|
||||||
|
|
||||||
|
ualni mCurrentState = 0;
|
||||||
|
ualni mStartState = 0;
|
||||||
|
|
||||||
|
Range<tAlphabetType> mSymbolRange = { 0, 0 };
|
||||||
|
};
|
||||||
|
}
|
||||||
208
.wip/Language/public/RegularCompiler.hpp
Normal file
208
.wip/Language/public/RegularCompiler.hpp
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Grammar.hpp"
|
||||||
|
#include "Automata.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
template <typename tAlphabetType, typename tStateType, tStateType tInTransition, ualni tMinSymbol, ualni tMaxSymbol>
|
||||||
|
class RegularCompiler {
|
||||||
|
|
||||||
|
typedef FiniteStateAutomation<tAlphabetType, tStateType> Graph;
|
||||||
|
typedef typename Graph::State Vertex;
|
||||||
|
typedef RegularGrammar<tAlphabetType, tStateType> Grammar;
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
Vertex* left = nullptr;
|
||||||
|
Vertex* right = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Graph* mGraph = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct CompileError {
|
||||||
|
uhalni mRuleIndex = 0;
|
||||||
|
tStateType mRuleState;
|
||||||
|
const char* description = nullptr;
|
||||||
|
[[nodiscard]] bool isError() const { return description; }
|
||||||
|
};
|
||||||
|
|
||||||
|
CompileError mError;
|
||||||
|
|
||||||
|
void compile(Graph& graph, const tAlphabetType* regex, tStateType state) {
|
||||||
|
mGraph = &graph;
|
||||||
|
compileUtil(regex, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile(Graph& aGraph, const Grammar& grammar) {
|
||||||
|
mGraph = &aGraph;
|
||||||
|
|
||||||
|
auto left = addVertex();
|
||||||
|
auto right = addVertex();
|
||||||
|
|
||||||
|
halni idx = 0;
|
||||||
|
for (auto rule : grammar.mRules) {
|
||||||
|
|
||||||
|
auto node = compileUtil(rule.data().first, rule.data().second);
|
||||||
|
|
||||||
|
if (!(node.left && node.right)) {
|
||||||
|
mError.mRuleIndex = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transitionAny(left, node.left);
|
||||||
|
transitionAny(node.right, right);
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGraph->setStartState(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Node compileUtil(const Grammar::Node* astNode, tStateType state) {
|
||||||
|
|
||||||
|
auto node = compileNode(astNode, nullptr, nullptr);
|
||||||
|
|
||||||
|
node.right->setValue(state);
|
||||||
|
node.right->setAcceptance(true);
|
||||||
|
|
||||||
|
mGraph->setStartState(node.left);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node compileVal(Grammar::ValueNode* val, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
|
||||||
|
auto left = aLeft ? aLeft : addVertex();
|
||||||
|
auto right = aRight ? aRight : addVertex();
|
||||||
|
transitionVal(left, right, val->mVal);
|
||||||
|
return { left, right };
|
||||||
|
}
|
||||||
|
|
||||||
|
Node compileAlternation(const Grammar::AlternationNode* alt, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
|
||||||
|
auto first_node = compileNode(alt->mFirst, aLeft, aRight);
|
||||||
|
auto second_node = compileNode(alt->mSecond);
|
||||||
|
transitionAny(first_node.left, second_node.left);
|
||||||
|
transitionAny(second_node.right, first_node.right);
|
||||||
|
return first_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node compileAny(const Grammar::AnyNode*, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
|
||||||
|
auto left = aLeft ? aLeft : addVertex();
|
||||||
|
auto right = aRight ? aRight : addVertex();
|
||||||
|
transitionAny(left, right, true);
|
||||||
|
return { left, right };
|
||||||
|
}
|
||||||
|
|
||||||
|
Node compileRepeat(const Grammar::RepetitionNode* repeat, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
|
||||||
|
if (repeat->mPlus) {
|
||||||
|
auto middle = addVertex();
|
||||||
|
|
||||||
|
auto left_node = compileNode(repeat->mNode, aLeft, middle);
|
||||||
|
|
||||||
|
auto right_node = compileNode(repeat->mNode, middle, aRight);
|
||||||
|
transitionAny(right_node.right, right_node.left);
|
||||||
|
transitionAny(right_node.left, right_node.right);
|
||||||
|
|
||||||
|
return { left_node.left, right_node.right };
|
||||||
|
} else {
|
||||||
|
auto node = compileNode(repeat->mNode, aLeft, aRight);
|
||||||
|
transitionAny(node.right, node.left);
|
||||||
|
transitionAny(node.left, node.right);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Node compileIf(const Grammar::IfNode* ifNode, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
|
||||||
|
auto node = compileNode(ifNode->mNode, aLeft, aRight);
|
||||||
|
transitionAny(node.left, node.right);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node compileClass(const Grammar::ClassNode* node, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
|
||||||
|
auto left = aLeft ? aLeft : addVertex();
|
||||||
|
auto right = aRight ? aRight : addVertex();
|
||||||
|
|
||||||
|
if (node->mRanges.size() == 1) {
|
||||||
|
auto const& range = node->mRanges.first();
|
||||||
|
transitionRange(left, right, { ualni(range.mBegin), ualni(range.mEnd) }, node->mExclude);
|
||||||
|
return { left, right };
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto range : node->mRanges) {
|
||||||
|
auto middle = addVertex();
|
||||||
|
transitionRange(left, middle, { ualni(range->mBegin), ualni(range->mEnd) }, node->mExclude);
|
||||||
|
transitionAny(middle, right);
|
||||||
|
}
|
||||||
|
return { left, right };
|
||||||
|
}
|
||||||
|
|
||||||
|
Node compileCompound(const Grammar::CompoundNode* compound, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
|
||||||
|
Vertex* left = nullptr;
|
||||||
|
Vertex* rigth = nullptr;
|
||||||
|
|
||||||
|
ualni idx = 0;
|
||||||
|
for (auto child : compound->mSequence) {
|
||||||
|
auto pass_left = idx == 0 ? aLeft : rigth;
|
||||||
|
auto pass_right = idx == compound->mSequence.size() - 1 ? aRight : nullptr;
|
||||||
|
auto node = compileNode(child.data(), pass_left, pass_right);
|
||||||
|
if (!left) left = node.left;
|
||||||
|
rigth = node.right;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { left, rigth };
|
||||||
|
}
|
||||||
|
|
||||||
|
Node compileNode(const Grammar::Node* node, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
|
||||||
|
switch (node->mType) {
|
||||||
|
case Grammar::Node::CLASS: return compileClass((typename Grammar::ClassNode*) node, aLeft, aRight);
|
||||||
|
case Grammar::Node::COMPOUND: return compileCompound((typename Grammar::CompoundNode*) node, aLeft, aRight);
|
||||||
|
case Grammar::Node::IF: return compileIf((typename Grammar::IfNode*) node, aLeft, aRight);
|
||||||
|
case Grammar::Node::REPEAT: return compileRepeat((typename Grammar::RepetitionNode*) node, aLeft, aRight);
|
||||||
|
case Grammar::Node::ANY: return compileAny((typename Grammar::AnyNode*) node, aLeft, aRight);
|
||||||
|
case Grammar::Node::OR: return compileAlternation((typename Grammar::AlternationNode*) node, aLeft, aRight);
|
||||||
|
case Grammar::Node::VAL: return compileVal((typename Grammar::ValueNode*) node, aLeft, aRight);
|
||||||
|
case Grammar::Node::NONE: break;
|
||||||
|
}
|
||||||
|
ASSERT(0)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void transitionAny(Vertex* from, Vertex* to, bool consumes = false) {
|
||||||
|
for (auto symbol : Range<ualni>(tMinSymbol, tMaxSymbol)) {
|
||||||
|
transitionVal(from, to, symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void transitionVal(Vertex* from, Vertex* to, tAlphabetType val) { mGraph->addTransition(from, to, val); }
|
||||||
|
|
||||||
|
void transitionRange(Vertex* from, Vertex* to, Range<ualni> range, bool exclude) {
|
||||||
|
if (exclude) {
|
||||||
|
Range<ualni> first = { tMinSymbol, range.mBegin - 1 };
|
||||||
|
Range<ualni> second = { range.mEnd + 1, tMaxSymbol };
|
||||||
|
|
||||||
|
if (first.valid()) {
|
||||||
|
for (auto symbol : first) {
|
||||||
|
transitionVal(from, to, symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (second.valid()) {
|
||||||
|
for (auto symbol : second) {
|
||||||
|
transitionVal(from, to, symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (auto symbol : range) {
|
||||||
|
transitionVal(from, to, symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex* addVertex() { return mGraph->addState(tInTransition, false); }
|
||||||
|
};
|
||||||
|
}
|
||||||
69
.wip/Language/public/SimpleParser.hpp
Normal file
69
.wip/Language/public/SimpleParser.hpp
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Parser.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
// Gives ability to express grammar in the Unified Format as sentence
|
||||||
|
template <typename tAlphabetType>
|
||||||
|
class SimpleParser {
|
||||||
|
enum UGTokens : alni { InTransition = -1, TestSeq };
|
||||||
|
|
||||||
|
typedef Parser<tAlphabetType, UGTokens, InTransition, 0, 127> UGParser;
|
||||||
|
typedef Parser<tAlphabetType, alni, -1, 0, 127> UserParser;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SimpleParser() {
|
||||||
|
// Grammar for unified grammar format sentence that tables compiled from
|
||||||
|
|
||||||
|
// Define Context-Free grammar
|
||||||
|
ContextFreeGrammar contextFreeGrammar;
|
||||||
|
{
|
||||||
|
// use existing CF grammar interface
|
||||||
|
contextFreeGrammar.addRule("a", { ContextFreeGrammar::Arg("") });
|
||||||
|
contextFreeGrammar.setStart("a");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define Regular grammar
|
||||||
|
RegularGrammar<tAlphabetType, UGTokens> regularGrammar;
|
||||||
|
{
|
||||||
|
// this is basically ast from existing tokenizer
|
||||||
|
regularGrammar.addRule(regularGrammar.seq({ regularGrammar.val('a'), regularGrammar.val('b') }), TestSeq);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, UGTokens> terminalsMap;
|
||||||
|
terminalsMap.put("TestSeq", TestSeq);
|
||||||
|
|
||||||
|
mUnifiedGrammarParser.compileTables(contextFreeGrammar, regularGrammar, terminalsMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void compileTables(const tAlphabetType* grammar, ualni grammarLength) {
|
||||||
|
mUnifiedGrammarParser.parse(grammar, grammarLength);
|
||||||
|
|
||||||
|
// compile each ast into RegularGrammar and ContextFree Grammar api instructions
|
||||||
|
ContextFreeGrammar userContextFreeGrammar;
|
||||||
|
RegularGrammar<tAlphabetType, alni> userRegularGrammar;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
// split ast into RE and CF part
|
||||||
|
// generate and execute grammar api commands
|
||||||
|
// use existing tokenizer code to create RE transition matrix
|
||||||
|
// ...
|
||||||
|
// compile tables from user grammar
|
||||||
|
|
||||||
|
Map<String, alni> terminalsMap;
|
||||||
|
terminalsMap.put("TestSeq", 0);
|
||||||
|
|
||||||
|
mUserParser.compileTables(userContextFreeGrammar, userRegularGrammar, terminalsMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserParser::ParseResult parse(const tAlphabetType* grammar, ualni grammarLength) {
|
||||||
|
return mUserParser.parse(grammar, grammarLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UGParser mUnifiedGrammarParser;
|
||||||
|
UserParser mUserParser;
|
||||||
|
};
|
||||||
|
}
|
||||||
43
.wip/Language/tests/Test.hpp
Normal file
43
.wip/Language/tests/Test.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// #include "SimpleParser.hpp"
|
||||||
|
|
||||||
|
const char* gGrammar = R"(
|
||||||
|
# Grammar in the CF-RE United Format (Defined by language module)
|
||||||
|
|
||||||
|
Rules : {
|
||||||
|
ScopeList : ScopeList Scope | Scope ;
|
||||||
|
Scope : \ScopeBegin StatementList \ScopeEnd;
|
||||||
|
StatementList : StatementList Statement \StatementEnd;
|
||||||
|
StatementList : Statement \StatementEnd;
|
||||||
|
Statement : \StatementBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
Terminals : {
|
||||||
|
Space : " " | "\t" | "\n" | "\r";
|
||||||
|
ScopeBegin : "{";
|
||||||
|
ScopeEnd : "}";
|
||||||
|
StatementEnd : ";";
|
||||||
|
StatementBody : "a" | "b";
|
||||||
|
}
|
||||||
|
|
||||||
|
Start : Scope;
|
||||||
|
Ignore : Space;
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char* gSentence = R"(
|
||||||
|
{}
|
||||||
|
|
||||||
|
{ }
|
||||||
|
|
||||||
|
{
|
||||||
|
a;
|
||||||
|
a ; a ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
a;
|
||||||
|
a;
|
||||||
|
}
|
||||||
|
)";
|
||||||
45
.wip/Language/tests/Tests.cpp
Normal file
45
.wip/Language/tests/Tests.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
#include "Test.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void testAutomation() {
|
||||||
|
|
||||||
|
FiniteStateAutomation<char, int> automata;
|
||||||
|
|
||||||
|
auto start = automata.addState(0, false);
|
||||||
|
auto end = automata.addState(1, true);
|
||||||
|
|
||||||
|
automata.addTransition(start, end, 'a');
|
||||||
|
|
||||||
|
automata.setStartState(start);
|
||||||
|
|
||||||
|
automata.makeDeterministic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
auto parser = SimpleParser<int1>();
|
||||||
|
|
||||||
|
parser.compileTables(gGrammar, String::Logic::calcLength(gGrammar));
|
||||||
|
auto result = parser.parse(gSentence, String::Logic::calcLength(gSentence));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
tp::ModuleManifest* deps[] = { &tp::gModuleLanguage, nullptr };
|
||||||
|
tp::ModuleManifest testModule("Test", nullptr, nullptr, deps);
|
||||||
|
|
||||||
|
if (!testModule.initialize()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
testAutomation();
|
||||||
|
test();
|
||||||
|
|
||||||
|
testModule.deinitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main() { return 0; }
|
||||||
24
3DEditor/CMakeLists.txt
Normal file
24
3DEditor/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
project(3DEditor)
|
||||||
|
|
||||||
|
### ---------------------- Externals --------------------- ###
|
||||||
|
set(BINDINGS_INCLUDE ../Externals/glfw/include ../Externals)
|
||||||
|
set(BINDINGS_LIBS glfw Imgui OpenImageDenoise)
|
||||||
|
|
||||||
|
### ---------------------- Static Library --------------------- ###
|
||||||
|
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
|
||||||
|
file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp")
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ${BINDINGS_INCLUDE} ./ext/)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC Widgets RasterRender RayTracer)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE ${BINDINGS_LIBS})
|
||||||
|
|
||||||
|
### -------------------------- Applications -------------------------- ###
|
||||||
|
file(GLOB APP_SOURCES "./applications/*.cpp")
|
||||||
|
add_executable(3DEditorApp ${APP_SOURCES})
|
||||||
|
target_link_libraries(3DEditorApp ${PROJECT_NAME})
|
||||||
|
|
||||||
|
file(COPY "../RasterRender/rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
|
||||||
|
file(COPY "../Graphics/rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
|
||||||
|
file(COPY "../3DScene/rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
|
||||||
31
3DEditor/applications/Entry.cpp
Normal file
31
3DEditor/applications/Entry.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
|
||||||
|
#include "WidgetApplication.hpp"
|
||||||
|
#include "RootWidget.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
class EditorGUI : public WidgetApplication {
|
||||||
|
public:
|
||||||
|
EditorGUI() {
|
||||||
|
auto canvas = this->mGraphics->getCanvas();
|
||||||
|
mGui = new EditorWidget(canvas, &mEditor);
|
||||||
|
|
||||||
|
mEditor.loadDefaults();
|
||||||
|
|
||||||
|
setRoot(mGui);
|
||||||
|
// mScene.mCamera.lookAtPoint({ 0, 0, 0 }, { 3, 3, 2 }, { 0, 0, 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
~EditorGUI() override { delete mGui; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Editor mEditor;
|
||||||
|
EditorWidget* mGui;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
EditorGUI gui;
|
||||||
|
gui.run();
|
||||||
|
}
|
||||||
40
3DEditor/private/Denoise.cpp
Normal file
40
3DEditor/private/Denoise.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
#include "Editor.hpp"
|
||||||
|
|
||||||
|
#include "OpenImageDenoise/oidn.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void Editor::denoise() {
|
||||||
|
auto& out = mPathTracerBuffers;
|
||||||
|
|
||||||
|
// Initialize OIDN device
|
||||||
|
oidn::DeviceRef device = oidn::newDevice(oidn::DeviceType::CPU);
|
||||||
|
device.commit();
|
||||||
|
|
||||||
|
// Define buffer size
|
||||||
|
const int channels = 4; // ARGB
|
||||||
|
const auto size = out.color.size();
|
||||||
|
// Create the denoising filter
|
||||||
|
oidn::FilterRef filter = device.newFilter("RT"); // Use the 'RT' filter for path tracing
|
||||||
|
|
||||||
|
// Set the input and output buffer (same buffer for in-place denoising)
|
||||||
|
filter.setImage("color", out.color.getBuff(), oidn::Format::Float3, size.x, size.y, 0, sizeof(float) * channels); // ARGB
|
||||||
|
filter.setImage("output", out.color.getBuff(), oidn::Format::Float3, size.x, size.y, 0, sizeof(float) * channels); // ARGB
|
||||||
|
|
||||||
|
// Set additional parameters if needed
|
||||||
|
filter.set("hdr", false); // Assuming the input image is not HDR
|
||||||
|
|
||||||
|
// Commit the filter
|
||||||
|
filter.commit();
|
||||||
|
|
||||||
|
// Execute the filter
|
||||||
|
filter.execute();
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
const char* errorMessage;
|
||||||
|
if (device.getError(errorMessage) != oidn::Error::None) {
|
||||||
|
std::cerr << "Error: " << errorMessage << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
140
3DEditor/private/Editor.cpp
Normal file
140
3DEditor/private/Editor.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
|
||||||
|
#include "Editor.hpp"
|
||||||
|
|
||||||
|
#include "GraphicsApi.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
Editor::Editor() {
|
||||||
|
|
||||||
|
{ // create path tracer gpu texture
|
||||||
|
glGenTextures(1, &mPathRenderTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mPathRenderTexture);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
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_RGBA32F, 100, 100, 0, GL_RGBA, GL_FLOAT, nullptr);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::renderViewport() {
|
||||||
|
switch (mRenderType) {
|
||||||
|
case RenderType::RASTER:
|
||||||
|
mRasterRenderer.beginRender(mScene, mScene.mRenderSettings.size);
|
||||||
|
mRasterRenderer.renderDefault(mScene);
|
||||||
|
if (mActive) mRasterRenderer.renderOutline(mScene.mCamera, *mActive);
|
||||||
|
mRasterRenderer.endRender();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RenderType::PATH_TRACER:
|
||||||
|
{
|
||||||
|
// TODO : include in render viewport method
|
||||||
|
// renderPathFrame();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint4 Editor::getViewportTexID() {
|
||||||
|
switch (mRenderType) {
|
||||||
|
case RenderType::PATH_TRACER:
|
||||||
|
return mPathRenderTexture;
|
||||||
|
|
||||||
|
case RenderType::RASTER:
|
||||||
|
return mRasterRenderer.getRenderBufferID();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::loadDefaults() {
|
||||||
|
mScene.load("rsc/scene/script.lua");
|
||||||
|
mResetCamera = mScene.mCamera;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::setViewportSize(const Vec2F& size) {
|
||||||
|
if (size.x <= 0 || size.y <= 0) return;
|
||||||
|
|
||||||
|
// TODO remove
|
||||||
|
// mScene.mCamera.rotate(0.01f, 0.0);
|
||||||
|
|
||||||
|
mScene.mRenderSettings.size = size;
|
||||||
|
|
||||||
|
mRasterRenderer.getRenderBuffer()->resize(size);
|
||||||
|
mScene.mCamera.setRatio(size.y / size.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
Editor::~Editor() {
|
||||||
|
glDeleteTextures(1, &mPathRenderTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::renderPathFrame() {
|
||||||
|
mScene.updateCache();
|
||||||
|
mPathRenderer.render(mScene, mPathTracerBuffers, mScene.mRenderSettings);
|
||||||
|
sendBuffersToGPU();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::sendBuffersToGPU() {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mPathRenderTexture);
|
||||||
|
const auto size = mPathTracerBuffers.color.size();
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RGBA32F,
|
||||||
|
(GLsizei) size.x,
|
||||||
|
(GLsizei) size.y,
|
||||||
|
0,
|
||||||
|
GL_RGBA,
|
||||||
|
GL_FLOAT,
|
||||||
|
mPathTracerBuffers.color.getBuff()
|
||||||
|
);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::denoisePathRenderBuffers() {
|
||||||
|
denoise();
|
||||||
|
sendBuffersToGPU();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::setRenderType(Editor::RenderType type) {
|
||||||
|
mRenderType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::navigationOrbit(const Vec2F& delta) {
|
||||||
|
mScene.mCamera.rotate(delta.x, delta.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::navigationPan(const Vec2F& pos, const Vec2F& prevPos) {
|
||||||
|
mScene.mCamera.move(pos, prevPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::navigationZoom(halnf factor) {
|
||||||
|
mScene.mCamera.zoom(factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::navigationReset() {
|
||||||
|
mScene.mCamera = mResetCamera;
|
||||||
|
// mScene.mCamera.lookAtPoint({ 0, 0, 0 }, { 1, 5, 1 }, { 0, 0, 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::selectObject(const Vec2F& screenPos) {
|
||||||
|
mScene.updateCache();
|
||||||
|
|
||||||
|
auto dir = (mScene.mCamera.project(screenPos) - mScene.mCamera.getPos()).normalize();
|
||||||
|
Ray ray = Ray( dir, mScene.mCamera.getPos() );
|
||||||
|
|
||||||
|
auto rayCastData = mScene.castRay(ray, 1000);
|
||||||
|
mActive = rayCastData.obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* Editor::getActiveObject() { return mActive; }
|
||||||
|
|
||||||
|
Scene* Editor::getScene() { return &mScene; }
|
||||||
55
3DEditor/public/Editor.hpp
Normal file
55
3DEditor/public/Editor.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RayTracer.hpp"
|
||||||
|
#include "RasterRender.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
class Editor {
|
||||||
|
public:
|
||||||
|
enum class RenderType { RASTER, PATH_TRACER };
|
||||||
|
|
||||||
|
public:
|
||||||
|
Editor();
|
||||||
|
~Editor();
|
||||||
|
|
||||||
|
void loadDefaults();
|
||||||
|
|
||||||
|
uint4 getViewportTexID();
|
||||||
|
|
||||||
|
void setViewportSize(const Vec2F& size);
|
||||||
|
void renderViewport();
|
||||||
|
|
||||||
|
void renderPathFrame();
|
||||||
|
void setRenderType(RenderType type);
|
||||||
|
void denoisePathRenderBuffers();
|
||||||
|
|
||||||
|
void navigationOrbit(const Vec2F& delta);
|
||||||
|
void navigationPan(const Vec2F& pos, const Vec2F& prevPos);
|
||||||
|
void navigationZoom(halnf factor);
|
||||||
|
void navigationReset();
|
||||||
|
|
||||||
|
void selectObject(const Vec2F& screenPos);
|
||||||
|
Object* getActiveObject();
|
||||||
|
|
||||||
|
Scene* getScene();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendBuffersToGPU();
|
||||||
|
void denoise();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene mScene;
|
||||||
|
|
||||||
|
Camera mResetCamera;
|
||||||
|
|
||||||
|
RenderType mRenderType = RenderType::RASTER;
|
||||||
|
|
||||||
|
RasterRender mRasterRenderer;
|
||||||
|
RayTracer mPathRenderer;
|
||||||
|
|
||||||
|
RayTracer::OutputBuffers mPathTracerBuffers;
|
||||||
|
uint4 mPathRenderTexture = 0;
|
||||||
|
|
||||||
|
Object* mActive = nullptr;
|
||||||
|
};
|
||||||
|
}
|
||||||
154
3DEditor/public/EditorWidget.hpp
Normal file
154
3DEditor/public/EditorWidget.hpp
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
#include "Widget.hpp"
|
||||||
|
#include "DockWidget.hpp"
|
||||||
|
|
||||||
|
#include "Editor.hpp"
|
||||||
|
#include "FloatingWidget.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class ViewportWidget : public Widget {
|
||||||
|
public:
|
||||||
|
explicit ViewportWidget(Canvas* canvas, Editor* editor) {
|
||||||
|
mEditor = editor;
|
||||||
|
mImage = canvas->createImageFromTextId(mEditor->getViewportTexID(), { 0, 0 });
|
||||||
|
mCanvas = canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ViewportWidget() override { mCanvas->deleteImageHandle(mImage); }
|
||||||
|
|
||||||
|
void process(const EventHandler& events) override {
|
||||||
|
mEditor->setViewportSize(getAreaT().size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Canvas& canvas) override {
|
||||||
|
mEditor->renderViewport();
|
||||||
|
|
||||||
|
canvas.updateTextureID(mImage, mEditor->getViewportTexID());
|
||||||
|
canvas.drawImage(getArea().relative(), &mImage, PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Editor* mEditor;
|
||||||
|
|
||||||
|
Canvas* mCanvas = nullptr;
|
||||||
|
Canvas::ImageHandle mImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditorWidget : public DockWidget {
|
||||||
|
public:
|
||||||
|
EditorWidget(Canvas* canvas, Editor* editor) :
|
||||||
|
mViewport(canvas, editor) {
|
||||||
|
mEditor = editor;
|
||||||
|
|
||||||
|
mPanel.setText("Controls");
|
||||||
|
mPanel.addToMenu(&mNavigationMenu);
|
||||||
|
mPanel.addToMenu(&mRenderMenu);
|
||||||
|
|
||||||
|
dockWidget(&mPanel, DockLayout::RIGHT);
|
||||||
|
setCenterWidget(&mViewport);
|
||||||
|
|
||||||
|
// Render
|
||||||
|
{
|
||||||
|
mRenderPathTracer.setText("Render with Path Tracer");
|
||||||
|
mRenderRaster.setText("Render with Raster");
|
||||||
|
mRenderDeNoise.setText("Denoise (IntelOpenImage)");
|
||||||
|
|
||||||
|
mRenderMenu.addToMenu(&mRenderPathTracer);
|
||||||
|
mRenderMenu.addToMenu(&mRenderRaster);
|
||||||
|
mRenderMenu.addToMenu(&mRenderDeNoise);
|
||||||
|
|
||||||
|
mRenderMenu.setText("Render");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
{
|
||||||
|
mNavigationPan.setText("Pan");
|
||||||
|
mNavigationOrbit.setText("Orbit");
|
||||||
|
mNavigationZoom.setText("Zoom");
|
||||||
|
mNavigationReset.setText("Reset");
|
||||||
|
mNavigationSelect.setText("Select");
|
||||||
|
|
||||||
|
mNavigationMenu.addToMenu(&mNavigationPan);
|
||||||
|
mNavigationMenu.addToMenu(&mNavigationOrbit);
|
||||||
|
mNavigationMenu.addToMenu(&mNavigationZoom);
|
||||||
|
mNavigationMenu.addToMenu(&mNavigationReset);
|
||||||
|
mNavigationMenu.addToMenu(&mNavigationSelect);
|
||||||
|
|
||||||
|
mNavigationMenu.setText("Navigation");
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderPathTracer.setAction([this]() {
|
||||||
|
mEditor->renderPathFrame();
|
||||||
|
mEditor->setRenderType(Editor::RenderType::PATH_TRACER);
|
||||||
|
});
|
||||||
|
|
||||||
|
mRenderRaster.setAction( [this]() { mEditor->setRenderType(Editor::RenderType::RASTER); });
|
||||||
|
mRenderDeNoise.setAction( [this]() { mEditor->denoisePathRenderBuffers(); });
|
||||||
|
mNavigationOrbit.setAction( [this]() { mNavigationType = ORBIT; });
|
||||||
|
mNavigationPan.setAction( [this]() { mNavigationType = PAN; });
|
||||||
|
mNavigationZoom.setAction( [this](){ mNavigationType = ZOOM; });
|
||||||
|
mNavigationSelect.setAction( [this](){ mNavigationType = SELECT; });
|
||||||
|
mNavigationReset.setAction( [this]() { mEditor->navigationReset(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void process(const EventHandler& events) override {
|
||||||
|
DockWidget::process(events);
|
||||||
|
|
||||||
|
if (auto obj = mEditor->getActiveObject()) { // dummy rotate active object
|
||||||
|
auto rotator = obj->mTopology.Basis.rotatorDir({1, 1, 1}, 0.1);
|
||||||
|
obj->mTopology.Basis = rotator * obj->mTopology.Basis;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEditor->getScene()->updateCache();
|
||||||
|
|
||||||
|
const auto& activeArea = mViewport.getArea();
|
||||||
|
|
||||||
|
auto pointer = events.getPointer();
|
||||||
|
auto pointerPrev = events.getPointerPrev();
|
||||||
|
auto pointerRelative = (((pointer - activeArea.pos) / activeArea.size) - 0.5f) * 2;
|
||||||
|
|
||||||
|
if (activeArea.isInside(pointer) && events.isDown(InputID::MOUSE1)) {
|
||||||
|
switch (mNavigationType) {
|
||||||
|
case ORBIT: mEditor->navigationOrbit(events.getPointerDelta() / activeArea.size * 3); break;
|
||||||
|
|
||||||
|
case PAN:
|
||||||
|
{
|
||||||
|
auto prevPointerRelative = (((pointerPrev - activeArea.pos) / activeArea.size) - 0.5f) * 2;
|
||||||
|
mEditor->navigationPan(prevPointerRelative, pointerRelative);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ZOOM: mEditor->navigationZoom(1 + (events.getPointerDelta().y / activeArea.size.y)); break;
|
||||||
|
case SELECT: mEditor->selectObject(pointerRelative * -1); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Canvas& canvas) override { canvas.rect(getArea().relative(), mBaseColor); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Editor* mEditor = nullptr;
|
||||||
|
|
||||||
|
ViewportWidget mViewport;
|
||||||
|
|
||||||
|
FloatingMenu mPanel;
|
||||||
|
|
||||||
|
// Controls
|
||||||
|
FloatingMenu mRenderMenu;
|
||||||
|
ButtonWidget mRenderPathTracer;
|
||||||
|
ButtonWidget mRenderRaster;
|
||||||
|
ButtonWidget mRenderDeNoise;
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
enum NavigationType { SELECT, ORBIT, PAN, ZOOM } mNavigationType = ORBIT;
|
||||||
|
|
||||||
|
FloatingMenu mNavigationMenu;
|
||||||
|
ButtonWidget mNavigationPan;
|
||||||
|
ButtonWidget mNavigationOrbit;
|
||||||
|
ButtonWidget mNavigationZoom;
|
||||||
|
ButtonWidget mNavigationReset;
|
||||||
|
ButtonWidget mNavigationSelect;
|
||||||
|
|
||||||
|
RGBA mBaseColor;
|
||||||
|
};
|
||||||
|
}
|
||||||
13
3DScene/CMakeLists.txt
Normal file
13
3DScene/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
project(3DScene)
|
||||||
|
|
||||||
|
### ---------------------- Static Library --------------------- ###
|
||||||
|
file(GLOB SOURCES "./private/*.cpp")
|
||||||
|
file(GLOB HEADERS "./public/*.hpp")
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||||
|
target_include_directories(${PROJECT_NAME} PRIVATE ../Externals/)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC Math)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE Lua)
|
||||||
223
3DScene/private/LuaFormat.cpp
Normal file
223
3DScene/private/LuaFormat.cpp
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
|
||||||
|
#include "Scene.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "lualib.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
tp::Vec3F tp::Scene::getVec3(lua_State* state, const char* name) {
|
||||||
|
int stackSize = lua_gettop(state);
|
||||||
|
|
||||||
|
// Access the "pos" field and validate it
|
||||||
|
lua_getfield(state, -1, name);
|
||||||
|
if (!lua_istable(state, -1) || lua_rawlen(state, -1) != 3) {
|
||||||
|
throw IOError(std::string("Invalid vec3 named ") + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the values from the table
|
||||||
|
float pos[3];
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
lua_rawgeti(state, -1, i + 1);
|
||||||
|
if (lua_isnumber(state, -1)) {
|
||||||
|
pos[i] = lua_tonumber(state, -1);
|
||||||
|
} else {
|
||||||
|
throw IOError("vec3 values must be numbers");
|
||||||
|
}
|
||||||
|
lua_pop(state, 1); // pop number
|
||||||
|
}
|
||||||
|
lua_pop(state, 1); // pop vec3
|
||||||
|
|
||||||
|
ASSERT(stackSize == lua_gettop(state))
|
||||||
|
|
||||||
|
return { pos[0], pos[1], pos[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::Vec2F tp::Scene::getVec2(lua_State* state, const char* name) {
|
||||||
|
int stackSize = lua_gettop(state);
|
||||||
|
|
||||||
|
// Access the "pos" field and validate it
|
||||||
|
lua_getfield(state, -1, name);
|
||||||
|
if (!lua_istable(state, -1) || lua_rawlen(state, -1) != 2) {
|
||||||
|
throw IOError(std::string("Invalid vec2 named ") + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the values from the table
|
||||||
|
float pos[2];
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
lua_rawgeti(state, -1, i + 1);
|
||||||
|
if (lua_isnumber(state, -1)) {
|
||||||
|
pos[i] = lua_tonumber(state, -1);
|
||||||
|
} else {
|
||||||
|
throw IOError("vec3 values must be numbers");
|
||||||
|
}
|
||||||
|
lua_pop(state, 1); // pop number
|
||||||
|
}
|
||||||
|
lua_pop(state, 1); // pop vec3
|
||||||
|
|
||||||
|
ASSERT(stackSize == lua_gettop(state))
|
||||||
|
|
||||||
|
return { pos[0], pos[1] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to read a Lua table representing RenderSettings
|
||||||
|
int readRenderSettings(lua_State* L, tp::RenderSettings& settings) {
|
||||||
|
lua_getglobal(L, "RenderSettings");
|
||||||
|
if (!lua_istable(L, -1)) {
|
||||||
|
printf("RenderSettings is not a table.\n");
|
||||||
|
return 0; // Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read depth field
|
||||||
|
lua_getfield(L, -1, "depth");
|
||||||
|
if (lua_isnumber(L, -1)) {
|
||||||
|
settings.depth = (int) lua_tonumber(L, -1);
|
||||||
|
} else {
|
||||||
|
printf("RenderSettings 'depth' field is missing or not a number.\n");
|
||||||
|
lua_pop(L, 1); // Pop the 'depth' field
|
||||||
|
return 0; // Error
|
||||||
|
}
|
||||||
|
lua_pop(L, 1); // Pop the 'depth' field
|
||||||
|
|
||||||
|
// Read spray field
|
||||||
|
lua_getfield(L, -1, "spray");
|
||||||
|
if (lua_isnumber(L, -1)) {
|
||||||
|
settings.spray = (int) lua_tonumber(L, -1);
|
||||||
|
} else {
|
||||||
|
printf("RenderSettings 'spray' field is missing or not a number.\n");
|
||||||
|
lua_pop(L, 1); // Pop the 'spray' field
|
||||||
|
return 0; // Error
|
||||||
|
}
|
||||||
|
lua_pop(L, 1); // Pop the 'spray' field
|
||||||
|
|
||||||
|
// Read depth field
|
||||||
|
lua_getfield(L, -1, "multisampling");
|
||||||
|
if (lua_isnumber(L, -1)) {
|
||||||
|
settings.multisampling = (int) lua_tonumber(L, -1);
|
||||||
|
} else {
|
||||||
|
printf("RenderSettings 'depth' field is missing or not a number.\n");
|
||||||
|
lua_pop(L, 1); // Pop the 'depth' field
|
||||||
|
return 0; // Error
|
||||||
|
}
|
||||||
|
lua_pop(L, 1); // Pop the 'depth' field
|
||||||
|
|
||||||
|
return 1; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to read a Lua table representing a light
|
||||||
|
int tp::Scene::readLight(lua_State* L, tp::PointLight* light) {
|
||||||
|
light->pos = getVec3(L, "pos");
|
||||||
|
|
||||||
|
lua_getfield(L, -1, "intensity"); // Get the "intensity" field from the light table
|
||||||
|
if (!lua_isnumber(L, -1)) {
|
||||||
|
printf("Light is missing the 'intensity' field or it's not a number.\n");
|
||||||
|
lua_pop(L, 1); // Pop the 'intensity' field
|
||||||
|
return 0; // Error
|
||||||
|
}
|
||||||
|
light->intensity = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1); // Pop the 'intensity' field
|
||||||
|
|
||||||
|
return 1; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tp::Scene::loadLuaFormat(const std::string& scenePath) {
|
||||||
|
lua_State* L = luaL_newstate();
|
||||||
|
luaL_openlibs(L);
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
fs::path fullPath(scenePath);
|
||||||
|
|
||||||
|
// Extract the filename
|
||||||
|
std::string fileName = fullPath.filename().string();
|
||||||
|
|
||||||
|
// Remove the filename from the path
|
||||||
|
fs::path directoryPath = fullPath.remove_filename();
|
||||||
|
|
||||||
|
if (luaL_dofile(L, scenePath.c_str()) != 0) {
|
||||||
|
lua_close(L);
|
||||||
|
printf("Cant open scene script.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getglobal(L, "Meshes");
|
||||||
|
|
||||||
|
if (lua_isstring(L, -1)) {
|
||||||
|
std::string meshesPath = lua_tostring(L, -1);
|
||||||
|
|
||||||
|
directoryPath /= meshesPath;
|
||||||
|
|
||||||
|
if (!loadOBJFormat(directoryPath.string())) {
|
||||||
|
printf("No 'meshes' loaded - check ur .obj path and validate content of .obj .\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
printf("No 'meshes' path given.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- camera
|
||||||
|
{
|
||||||
|
lua_getglobal(L, "Camera");
|
||||||
|
if (!lua_istable(L, -1)) {
|
||||||
|
printf("Camera is not a table.\n");
|
||||||
|
lua_close(L);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3F camPos = getVec3(L, "pos");
|
||||||
|
Vec3F camTarget = getVec3(L, "target");
|
||||||
|
Vec3F camUp = getVec3(L, "up");
|
||||||
|
Vec2F camSize = getVec2(L, "size");
|
||||||
|
|
||||||
|
mRenderSettings.size = camSize;
|
||||||
|
|
||||||
|
mCamera.lookAtPoint(camTarget, camPos, camUp);
|
||||||
|
mCamera.setFOV(3.14 / 4);
|
||||||
|
mCamera.setFar(100);
|
||||||
|
mCamera.setRatio((tp::halnf) camSize.y / (tp::halnf) camSize.x);
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- LIGHTS
|
||||||
|
{
|
||||||
|
lua_getglobal(L, "Lights");
|
||||||
|
if (!lua_istable(L, -1)) {
|
||||||
|
printf("Lights is not a table.\n");
|
||||||
|
lua_close(L);
|
||||||
|
return false; // Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and process each light in the "Lights" table
|
||||||
|
int numLights = lua_rawlen(L, -1); // Get the number of lights in the table
|
||||||
|
for (int i = 1; i <= numLights; i++) {
|
||||||
|
lua_rawgeti(L, -1, i); // Get the i-th element (light) from the table
|
||||||
|
if (lua_istable(L, -1)) {
|
||||||
|
tp::PointLight light;
|
||||||
|
if (!readLight(L, &light)) {
|
||||||
|
printf("Cant read lights data\n");
|
||||||
|
lua_close(L);
|
||||||
|
return false; // Error
|
||||||
|
}
|
||||||
|
mLights.append(light);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1); // Pop the i-th light table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------- settings --------------
|
||||||
|
if (!readRenderSettings(L, mRenderSettings)) {
|
||||||
|
printf("Cant Read Render Settings");
|
||||||
|
lua_close(L);
|
||||||
|
return false; // Error
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_close(L);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
86
3DScene/private/OBJFormat.cpp
Normal file
86
3DScene/private/OBJFormat.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
|
||||||
|
#include "Scene.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "lualib.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "obj/OBJ_Loader.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
bool tp::Scene::loadOBJFormat(const std::string& objetsPath) {
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
objl::Loader Loader;
|
||||||
|
|
||||||
|
if (!Loader.LoadFile(objetsPath)) {
|
||||||
|
std::cout << "Failed to Load File. May have failed to find it or it was not an .obj file.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& curMesh : Loader.LoadedMeshes) {
|
||||||
|
mObjects.append(Object());
|
||||||
|
|
||||||
|
auto object = &mObjects.last();
|
||||||
|
|
||||||
|
for (auto& vertex : curMesh.Vertices) {
|
||||||
|
// printf("{ %f, %f, %f }, \n", vertex.Position.X, vertex.Position.Y, vertex.Position.Z);
|
||||||
|
object->mTopology.Points.append(Vec3F{ vertex.Position.X, vertex.Position.Y, vertex.Position.Z });
|
||||||
|
object->mTopology.Normals.append(Vec3F{ vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < curMesh.Indices.size(); j += 3) {
|
||||||
|
auto idx1 = (uhalni) curMesh.Indices[j];
|
||||||
|
auto idx2 = (uhalni) curMesh.Indices[j + 1];
|
||||||
|
auto idx3 = (uhalni) curMesh.Indices[j + 2];
|
||||||
|
// printf("{ %i, %i, %i },\n", idx1, idx2, idx3);
|
||||||
|
object->mTopology.Indexes.append(Vec3<uhalni>{ idx1, idx2, idx3 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object->mTopology.Normals.size() != object->mTopology.Points.size()) {
|
||||||
|
printf("Logic error loading normals\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
object->mCache.Source = &object->mTopology;
|
||||||
|
object->mCache.updateCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mObjects.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const tp::RayCastData& tp::Scene::castRay(const Ray& ray, alnf farVal) {
|
||||||
|
auto& out = mRayCastData;
|
||||||
|
|
||||||
|
out.hit = false;
|
||||||
|
out.obj = nullptr;
|
||||||
|
|
||||||
|
farVal *= farVal;
|
||||||
|
|
||||||
|
for (auto obj : mObjects) {
|
||||||
|
for (auto trig : obj->mCache.TrigCaches) {
|
||||||
|
if (trig->castRay(ray)) {
|
||||||
|
|
||||||
|
auto dist = (TrigCache::getHitPos() - ray.pos).length2();
|
||||||
|
|
||||||
|
if (farVal > dist && dist > EPSILON) {
|
||||||
|
out.trig = &trig.data();
|
||||||
|
out.hitPos = TrigCache::getHitPos();
|
||||||
|
out.obj = &obj.data();
|
||||||
|
out.hit = true;
|
||||||
|
|
||||||
|
farVal = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mRayCastData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tp::Scene::updateCache() {
|
||||||
|
for (auto obj : mObjects) {
|
||||||
|
obj->mCache.updateCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
14
3DScene/private/Scene.cpp
Normal file
14
3DScene/private/Scene.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
#include "Scene.hpp"
|
||||||
|
|
||||||
|
bool tp::Scene::load(const std::string& scenePath) {
|
||||||
|
try {
|
||||||
|
auto res = loadLuaFormat(scenePath);
|
||||||
|
if (!res) throw IOError("Failed loading lua script");
|
||||||
|
} catch (const IOError& err) {
|
||||||
|
printf("Failed loading scene : %s\n", err.description.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
90
3DScene/public/Scene.hpp
Normal file
90
3DScene/public/Scene.hpp
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Topology.hpp"
|
||||||
|
#include "Buffer2D.hpp"
|
||||||
|
#include "Camera.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
struct RenderSettings {
|
||||||
|
uhalni depth = 2;
|
||||||
|
uhalni spray = 1;
|
||||||
|
ualni multisampling = 1;
|
||||||
|
Vec2<ualni> size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GPUBuffers {
|
||||||
|
public:
|
||||||
|
GPUBuffers() = default;
|
||||||
|
virtual ~GPUBuffers() = default;
|
||||||
|
|
||||||
|
virtual void drawCall() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Object {
|
||||||
|
public:
|
||||||
|
Object() = default;
|
||||||
|
|
||||||
|
~Object() {
|
||||||
|
delete mGUPBuffers;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Topology mTopology;
|
||||||
|
TopologyCache mCache;
|
||||||
|
GPUBuffers* mGUPBuffers = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PointLight {
|
||||||
|
Vec3F pos;
|
||||||
|
halnf fallOut = 1.f;
|
||||||
|
halnf intensity = 1.f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RayCastData {
|
||||||
|
Object* obj = nullptr;
|
||||||
|
TrigCache* trig = nullptr;
|
||||||
|
Vec3F hitPos = { 0, 0, 0 };
|
||||||
|
bool hit = false;
|
||||||
|
bool inv = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Scene {
|
||||||
|
struct IOError : public std::exception {
|
||||||
|
explicit IOError(std::string in) :
|
||||||
|
description(std::move(in)) {}
|
||||||
|
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Scene() = default;
|
||||||
|
|
||||||
|
bool load(const std::string& scenePath);
|
||||||
|
|
||||||
|
bool loadLuaFormat(const std::string& scenePath);
|
||||||
|
bool loadOBJFormat(const std::string& objectsPath);
|
||||||
|
|
||||||
|
const RayCastData& castRay(const Ray& ray, alnf farVal);
|
||||||
|
|
||||||
|
void updateCache();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vec3F getVec3(lua_State* state, const char* name);
|
||||||
|
Vec2F getVec2(lua_State* state, const char* name);
|
||||||
|
|
||||||
|
int readLight(lua_State* L, tp::PointLight* light);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buffer<Object> mObjects;
|
||||||
|
Buffer<PointLight> mLights;
|
||||||
|
Camera mCamera;
|
||||||
|
|
||||||
|
RenderSettings mRenderSettings;
|
||||||
|
|
||||||
|
RayCastData mRayCastData;
|
||||||
|
};
|
||||||
|
}
|
||||||
20
3DScene/rsc/scene/meshes.mtl
Normal file
20
3DScene/rsc/scene/meshes.mtl
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Blender MTL File: 'scene.blend'
|
||||||
|
# Material Count: 2
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 323.999994
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.800000 0.800000 0.800000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl None
|
||||||
|
Ns 500
|
||||||
|
Ka 0.8 0.8 0.8
|
||||||
|
Kd 0.8 0.8 0.8
|
||||||
|
Ks 0.8 0.8 0.8
|
||||||
|
d 1
|
||||||
|
illum 2
|
||||||
112
3DScene/rsc/scene/meshes.obj
Normal file
112
3DScene/rsc/scene/meshes.obj
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
# Blender v3.0.1 OBJ File: 'scene.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib meshes.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.039076 1.039076 1.792917
|
||||||
|
v -1.039076 1.039076 -1.285234
|
||||||
|
v 1.039076 1.039076 1.792917
|
||||||
|
v 1.039076 1.039076 -1.285234
|
||||||
|
v -1.039076 -1.039076 1.792917
|
||||||
|
v -1.039076 -1.039076 -1.285234
|
||||||
|
v 1.039076 -1.039076 1.792917
|
||||||
|
v 1.039076 -1.039076 -1.285234
|
||||||
|
vt 0.625000 0.500000
|
||||||
|
vt 0.625000 0.750000
|
||||||
|
vt 0.875000 0.750000
|
||||||
|
vt 0.875000 0.500000
|
||||||
|
vt 0.375000 0.750000
|
||||||
|
vt 0.375000 1.000000
|
||||||
|
vt 0.625000 1.000000
|
||||||
|
vt 0.375000 0.000000
|
||||||
|
vt 0.375000 0.250000
|
||||||
|
vt 0.625000 0.250000
|
||||||
|
vt 0.625000 0.000000
|
||||||
|
vt 0.125000 0.500000
|
||||||
|
vt 0.125000 0.750000
|
||||||
|
vt 0.375000 0.500000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1/1 3/2/1 7/3/1 5/4/1
|
||||||
|
f 4/5/2 8/6/2 7/7/2 3/2/2
|
||||||
|
f 8/8/3 6/9/3 5/10/3 7/11/3
|
||||||
|
f 6/12/4 8/13/4 4/5/4 2/14/4
|
||||||
|
f 6/9/5 2/14/5 1/1/5 5/10/5
|
||||||
|
o Cube.001
|
||||||
|
v 0.411013 -0.208216 -1.264212
|
||||||
|
v 0.411013 -0.208216 -0.612621
|
||||||
|
v -0.208216 -0.411013 -1.264212
|
||||||
|
v -0.208216 -0.411013 -0.612621
|
||||||
|
v 0.208216 0.411013 -1.264212
|
||||||
|
v 0.208216 0.411013 -0.612621
|
||||||
|
v -0.411013 0.208216 -1.264212
|
||||||
|
v -0.411013 0.208216 -0.612621
|
||||||
|
vt 0.375000 0.000000
|
||||||
|
vt 0.625000 0.000000
|
||||||
|
vt 0.625000 0.250000
|
||||||
|
vt 0.375000 0.250000
|
||||||
|
vt 0.625000 0.500000
|
||||||
|
vt 0.375000 0.500000
|
||||||
|
vt 0.625000 0.750000
|
||||||
|
vt 0.375000 0.750000
|
||||||
|
vt 0.625000 1.000000
|
||||||
|
vt 0.375000 1.000000
|
||||||
|
vt 0.125000 0.500000
|
||||||
|
vt 0.125000 0.750000
|
||||||
|
vt 0.875000 0.500000
|
||||||
|
vt 0.875000 0.750000
|
||||||
|
vn 0.3112 -0.9503 0.0000
|
||||||
|
vn -0.9503 -0.3112 0.0000
|
||||||
|
vn -0.3112 0.9503 0.0000
|
||||||
|
vn 0.9503 0.3112 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
usemtl None
|
||||||
|
s off
|
||||||
|
f 9/15/6 10/16/6 12/17/6 11/18/6
|
||||||
|
f 11/18/7 12/17/7 16/19/7 15/20/7
|
||||||
|
f 15/20/8 16/19/8 14/21/8 13/22/8
|
||||||
|
f 13/22/9 14/21/9 10/23/9 9/24/9
|
||||||
|
f 11/25/10 15/20/10 13/22/10 9/26/10
|
||||||
|
f 16/19/11 12/27/11 10/28/11 14/21/11
|
||||||
|
o Cube.002
|
||||||
|
v -0.351718 -0.467100 -0.602050
|
||||||
|
v -0.351718 -0.467100 0.049542
|
||||||
|
v -0.800825 0.004996 -0.602050
|
||||||
|
v -0.800825 0.004996 0.049542
|
||||||
|
v 0.120377 -0.017993 -0.602050
|
||||||
|
v 0.120377 -0.017993 0.049542
|
||||||
|
v -0.328730 0.454103 -0.602050
|
||||||
|
v -0.328730 0.454103 0.049542
|
||||||
|
vt 0.375000 0.000000
|
||||||
|
vt 0.625000 0.000000
|
||||||
|
vt 0.625000 0.250000
|
||||||
|
vt 0.375000 0.250000
|
||||||
|
vt 0.625000 0.500000
|
||||||
|
vt 0.375000 0.500000
|
||||||
|
vt 0.625000 0.750000
|
||||||
|
vt 0.375000 0.750000
|
||||||
|
vt 0.625000 1.000000
|
||||||
|
vt 0.375000 1.000000
|
||||||
|
vt 0.125000 0.500000
|
||||||
|
vt 0.125000 0.750000
|
||||||
|
vt 0.875000 0.500000
|
||||||
|
vt 0.875000 0.750000
|
||||||
|
vn -0.7245 -0.6892 0.0000
|
||||||
|
vn -0.6892 0.7245 0.0000
|
||||||
|
vn 0.7245 0.6892 0.0000
|
||||||
|
vn 0.6892 -0.7245 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
usemtl None
|
||||||
|
s off
|
||||||
|
f 17/29/12 18/30/12 20/31/12 19/32/12
|
||||||
|
f 19/32/13 20/31/13 24/33/13 23/34/13
|
||||||
|
f 23/34/14 24/33/14 22/35/14 21/36/14
|
||||||
|
f 21/36/15 22/35/15 18/37/15 17/38/15
|
||||||
|
f 19/39/16 23/34/16 21/36/16 17/40/16
|
||||||
|
f 24/33/17 20/41/17 18/42/17 22/35/17
|
||||||
26
3DScene/rsc/scene/script.lua
Normal file
26
3DScene/rsc/scene/script.lua
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
Meshes = "meshes.obj"
|
||||||
|
|
||||||
|
Camera = {
|
||||||
|
pos = { 0, 5, 0 },
|
||||||
|
target = { 0, 0, 0 },
|
||||||
|
up = { 0, 0, 1 },
|
||||||
|
size = { 600, 800 },
|
||||||
|
}
|
||||||
|
|
||||||
|
Lights = {
|
||||||
|
{
|
||||||
|
pos = { -0.5, 3.5, 1 },
|
||||||
|
intensity = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pos = { 0, 0, 1 },
|
||||||
|
intensity = 0.5
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSettings = {
|
||||||
|
depth = 1,
|
||||||
|
spray = 1,
|
||||||
|
multisampling = 1,
|
||||||
|
}
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.2)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
|
||||||
|
|
||||||
project(Allocators)
|
|
||||||
|
|
||||||
### ---------------------- Static Library --------------------- ###
|
|
||||||
file(GLOB SOURCES "./private/*.cpp")
|
|
||||||
file(GLOB HEADERS "./public/*.hpp")
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Utils)
|
|
||||||
|
|
||||||
### -------------------------- Tests -------------------------- ###
|
|
||||||
enable_testing()
|
|
||||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
|
||||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
|
||||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils)
|
|
||||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
|
||||||
|
|
||||||
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib)
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
# Profiling
|
|
||||||
|
|
||||||
## Memory Leaks
|
|
||||||
|
|
||||||
Example program with memory leaks:
|
|
||||||
|
|
||||||
```c++
|
|
||||||
#include "allocators.h"
|
|
||||||
|
|
||||||
void test_call22() { new int; }
|
|
||||||
void test_call21() { new float; }
|
|
||||||
|
|
||||||
void test_call11() {
|
|
||||||
test_call21();
|
|
||||||
test_call22();
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(char argc, char* argv[]) {
|
|
||||||
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleAllocators, NULL };
|
|
||||||
tp::ModuleManifest TestModule("Test", NULL, NULL, ModuleDependencies);
|
|
||||||
TestModule.initialize();
|
|
||||||
|
|
||||||
test_call11();
|
|
||||||
|
|
||||||
TestModule.deinitialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
If memory leaks were detected it will be loged in the output console.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Also debug.memleaks binary will be generated in the working directory that can be viewved with MemLeaks Viewver.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## Memory Usage Analisys
|
|
||||||
Currently outdated
|
|
||||||
|
|
||||||
## Benchmarks
|
|
||||||
Currently outdated
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
|
|
||||||
#include "Allocators.hpp"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
static void deinit(const tp::ModuleManifest* self) {
|
|
||||||
tp::HeapAllocGlobal::checkLeaks();
|
|
||||||
}
|
|
||||||
|
|
||||||
static tp::ModuleManifest* sModuleDependencies[] = { &tp::gModuleUtils, nullptr };
|
|
||||||
tp::ModuleManifest tp::gModuleAllocators = ModuleManifest("Allocators", nullptr, deinit, sModuleDependencies);
|
|
||||||
|
|
||||||
|
|
||||||
void* operator new(size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
|
|
||||||
void* operator new[](size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
|
|
||||||
void operator delete(void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
|
|
||||||
void operator delete[](void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
|
|
||||||
|
|
||||||
void* operator new(size_t aSize, tp::HeapAlloc& aAlloc) { return aAlloc.allocate(aSize); }
|
|
||||||
void* operator new[](size_t aSize, tp::HeapAlloc& aAlloc) { return aAlloc.allocate(aSize); }
|
|
||||||
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
|
|
||||||
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
|
|
||||||
|
|
||||||
void* operator new(size_t aSize, tp::HeapAllocGlobal& aAlloc) { return tp::HeapAllocGlobal::allocate(aSize); }
|
|
||||||
void* operator new[](size_t aSize, tp::HeapAllocGlobal& aAlloc) { return tp::HeapAllocGlobal::allocate(aSize); }
|
|
||||||
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }
|
|
||||||
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue