Compare commits

...
Sign in to create a new pull request.

70 commits

Author SHA1 Message Date
IlyaShurupov
63444be3d0 Ignoring GL unallocated? memory 2023-09-03 18:41:10 +03:00
Ilya
2c25667f72 Changing sizing in debug gui 2023-09-03 18:35:09 +03:00
IlushaShurupov
d3bc3a7a99 Debug UI tunes 2023-09-03 18:31:42 +03:00
IlushaShurupov
b36a782823 Enable docking 2023-09-03 18:31:42 +03:00
IlyaShurupov
8d990a0132 Update Clang Format 2023-09-03 10:53:20 +03:00
IlushaShurupov
2810e06b3e Adding outdated source code into master 2023-08-20 11:27:47 +03:00
IlushaShurupov
5cf467a421 Updated TODO 2023-08-14 20:53:34 +03:00
IlushaShurupov
01b6f9099c LR(1) Parser Initial 2023-08-14 20:06:32 +03:00
IlushaShurupov
616441e049 Checking for non productive rules and loops in cfg 2023-08-12 09:39:06 +03:00
IlushaShurupov
b205438601 CFG remove unused rules 2023-08-12 08:27:50 +03:00
IlushaShurupov
e6d9439ba9 Adding simple test fot cf grammar 2023-08-12 08:08:47 +03:00
IlushaShurupov
0a886bd8a8 Fixing list copy and grammar sentence generation 2023-08-11 18:57:39 +03:00
IlushaShurupov
43fe34dcbf Improve module initialization log 2023-08-11 16:42:47 +03:00
IlushaShurupov
7d49642376 Fixin cfg 2023-08-11 16:37:51 +03:00
IlushaShurupov
01b7d96ebd Fixin map 2023-08-11 16:21:30 +03:00
IlushaShurupov
6fcfa075f8 Generate sentences from cf grammar. Fix list initialization from copy constructor 2023-08-11 16:04:02 +03:00
IlushaShurupov
d888aeb2b4 Fixing tokenizer bug 2023-08-10 18:36:56 +03:00
IlushaShurupov
92f34e2a99 CF Grammar improvements 2023-08-10 18:35:48 +03:00
IlushaShurupov
424787c735 CF Grammar Initial 2023-08-10 18:35:40 +03:00
IlushaShurupov
eb712a352d Parser Initial 2023-08-10 18:35:29 +03:00
IlushaShurupov
5fab9ee507 Adding some tokinizer checks for strings and comments 2023-08-10 18:35:17 +03:00
IlushaShurupov
9c8771a378 Editing TODO 2023-08-07 19:03:17 +03:00
Ilusha
9a7e44a96d
Update cmake.yml - sudo apt-get update before installing pacages 2023-08-07 18:56:03 +03:00
IlushaShurupov
112fea2f04 Adding objects GUI initial. Changing TODO. Some fixes along side 2023-08-07 18:37:11 +03:00
IlushaShurupov
f9d62c324d "Added new test 'Complex' and improved error debugging"
This revision adds a complex test to the 'TestInterpreter.cpp' file to test functionalities such as classes, variable initializations, loops, conditionals and methods in the interpreter. The token parser has also been updated with a reset method in the 'parser.cpp' file for cleaning up any previous state before parsing a new script. This ensures the parser starts fresh for each new parse request. It also improves the debugging process in 'function.cpp' by printing the description of parser errors. Few completed tasks are removed from the TODO list.
2023-08-03 21:15:27 +03:00
IlushaShurupov
55571ca3dd Load and destroy methods revised for proper reference counting
The update enhances object management by involving scope-based reference counting. The change affects loading and destruction operations in the Object and several other classes, ensuring the release or retention of objects adhere to their usage context. A function for logging type data has also been introduced to provide better clarity during debugging. Also, tests in script & interpreter have been altered to run in separate module initializations to avoid cross-test interference. Overall, it provides better memory management and dependable tests.
2023-08-01 20:06:34 +03:00
IlushaShurupov
b06e1da529 Add Interpreter tests and improve Parser error logging
A set of tests for the InterpreterObject has been added to enhance its reliability and maintainability. The tests check the essential functionalities such as its creation, execution, saving, loading, and destruction. Furthermore, the error logging for the Parser has been improved, now providing more precise location of detected errors. The changes improve the robustness and debugability of the code.
2023-08-01 18:57:36 +03:00
IlushaShurupov
0cefb47b66 Refactor save size calculation with SaveSizeCounter
SaveSizeCounter is introduced and used for calculating the save size of objects. The previous method of calculating save size directly in each class was replaced with a call to the SaveSizeCounter's calc method. This results in a cleaner, more maintainable code as the size calculation logic is now centralized in one class. It is more efficient and scalable as any changes to the calculation can be made in one place and will be reflected everywhere.
2023-08-01 07:41:09 +03:00
IlushaShurupov
a918c83ec1 Objects adding dict test & fixes 2023-07-31 22:10:46 +03:00
IlushaShurupov
2c8e1470d1 Adding Simple Objest test. Fixes some bugs 2023-07-31 20:16:05 +03:00
IlushaShurupov
64e1f78739 Objects Compiled 2023-07-31 08:04:14 +03:00
IlushaShurupov
ba95747ef9 Merge branch 'Archiver' 2023-07-30 08:32:21 +03:00
IlyaShurupov
3575cbc543 Archiver Initial 2023-07-30 08:28:31 +03:00
IlushaShurupov
01ba8160ef Generating permutations and small buffer checks 2023-07-26 23:30:38 +03:00
IlushaShurupov
939e365a4f Objects Initial 2023-07-25 19:13:27 +03:00
IlushaShurupov
803ce23169 Objects Initial 2023-07-25 08:11:19 +03:00
IlushaShurupov
00bc875846 Freeze on no memory available 2023-07-24 20:39:28 +03:00
IlushaShurupov
5f186164a0 Graphics Animations & Renaming 2023-07-23 22:11:14 +03:00
Ilusha
3a68e70f03 Update cmake.yml to build Graphics 2023-07-23 17:05:35 +03:00
IlushaShurupov
e9c6a97a07 Reorganize a little 2023-07-23 16:50:51 +03:00
IlushaShurupov
3770c72ec0 Adding nanovg 2023-07-23 15:32:02 +03:00
IlushaShurupov
c4a7f91d56 New placement header 2023-07-23 15:32:02 +03:00
IlushaShurupov
6db1406d68 Graphics module Initial (And some more fixes embedded) 2023-07-23 15:31:34 +03:00
Ilusha
e81449eddf
Update cmake.yml - checkout submodules 2023-07-22 20:36:06 +03:00
IlushaShurupov
7595ae3926 Small changes 2023-07-22 20:32:03 +03:00
IlushaShurupov
e9dbee6667 Restructure Storage Module -> Connection module 2023-07-21 19:55:31 +03:00
IlushaShurupov
fa4d1d72dc Merge branch 'Storage' 2023-07-21 18:57:17 +03:00
IlushaShurupov
0301f608bd Fixed bug in map 2023-07-20 22:31:36 +03:00
IlushaShurupov
a543568e1d Restructure 2023-07-20 00:10:29 +03:00
IlushaShurupov
576a3565f7 Command Line INterpreter with fixes 2023-07-19 21:29:57 +03:00
IlushaShurupov
62cb2bb8b7 Fix File test 2023-07-18 23:48:54 +03:00
IlushaShurupov
8e00882bb3 Networking Initial 2023-07-18 23:37:04 +03:00
IlushaShurupov
df3767df29 Storage initial 2023-07-18 23:36:51 +03:00
IlushaShurupov
90998e2279 CommandLine parser initial 2023-07-18 22:37:53 +03:00
IlushaShurupov
6bca7431b7 Adding Strings tests 2023-07-17 22:32:55 +03:00
Ilusha
91b00817e3
Update cmake.yml 2023-07-17 20:49:19 +03:00
Ilusha
d80ea40848
Update cmake.yml 2023-07-17 20:45:05 +03:00
Ilusha
bedd88be2e
Try coverage cmake.yml 2023-07-17 20:43:45 +03:00
IlushaShurupov
bc892da992 Fixes 2023-07-16 18:28:24 +03:00
IlushaShurupov
fabceb52d3 Update Todo 2023-07-15 20:43:24 +03:00
IlushaShurupov
b68539cc0c Tokenizer Test 2023-07-15 20:03:52 +03:00
IlushaShurupov
44bad77e93 Tokenizer (No tests) 2023-07-15 18:58:31 +03:00
IlushaShurupov
e63843c6bb Remove Cmd Arg parser for now 2023-07-15 13:43:55 +03:00
IlushaShurupov
692994c2d3 Tokenizer Initial 2023-07-15 13:43:55 +03:00
IlushaShurupov
facc17ec1b Buffer 2d (No tests) 2023-07-15 13:43:23 +03:00
IlushaShurupov
4c9691e192 Remove old testing 2023-07-15 11:15:54 +03:00
IlushaShurupov
c75cb9fb48 Testing 2023-07-15 11:12:10 +03:00
IlushaShurupov
d362d8c3b3 Removing TextEditor from strings for now 2023-07-15 11:12:10 +03:00
IlushaShurupov
eb9210de1c Strings Initial 2023-07-15 11:12:10 +03:00
EgorPanteleev
9cf541a6ba
Update README.MD (#1) 2023-07-13 20:14:38 +03:00
226 changed files with 53920 additions and 274 deletions

View file

@ -1,21 +1,55 @@
# Generated from CLion C/C++ Code Style settings
---
BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignArrayOfStructures: Left
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: Align
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
@ -23,44 +57,172 @@ BraceWrapping:
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAfterAttributes: Never
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeConceptDeclarations: Always
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 0
BreakStringLiterals: true
ColumnLimit: 180
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: ^"(llvm|llvm-c|clang|clang-c)/
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: ^(<|"(gtest|gmock|isl|json)/)
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: .*
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: (Test)?$
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: true
IndentCaseLabels: true
IndentPPDirectives: None
IndentExternBlock: Indent
IndentGotoLabels: true
IndentPPDirectives: BeforeHash
IndentRequiresClause: true
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
IndentWrappedFunctionNames: false
InsertBraces: true
InsertNewlineAtEOF: true
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
Language: Cpp
LineEnding: DeriveLF
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PPIndentWidth: -1
PackConstructorInitializers: CurrentLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: false
QualifierAlignment: Custom
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveSemicolon: true
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Always
ShortNamespaceLines: 1000
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: false
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 2
UseTab: Always
UseTab: Never
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
QualifierOrder:
- inline
- static
- const
- type

View file

@ -20,11 +20,25 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Install LLVM
run: sudo apt-get install -y llvm
- name: Setup externals
shell: bash
run: |
# 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:"
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
@ -40,3 +54,5 @@ jobs:
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{env.BUILD_TYPE}}

15
.gitmodules vendored Normal file
View file

@ -0,0 +1,15 @@
[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"]
path = Externals/imgui
url = https://github.com/IlyaShurupov/imgui.git
[submodule "Externals/glew"]
path = Externals/glew
url = https://github.com/IlyaShurupov/glew.git
[submodule "Externals/nanovg"]
path = Externals/nanovg
url = https://github.com/IlyaShurupov/nanovg.git

View file

@ -0,0 +1,943 @@
/*
EasyTab.h - Single-header multi-platform tablet library
https://github.com/ApoorvaJ/EasyTab
----------------------------------------------------------------------------
USAGE
----------------------------------------------------------------------------
1) Add the following lines in exactly one of your cpp files to compile the
implementation.
#define EASYTAB_IMPLEMENTATION
#include "easytab.h"
2) Call EasyTab_Load() with correct parameters to initialize EasyTab. These
parameters vary per OS, so look at the function declarations or examples
below. Function returns EASYTAB_OK if initialization was successful.
3) Call EasyTab_HandleEvent() in your message-handling code. The function
returns EASYTAB_OK if the message was a tablet message, and
EASYTAB_EVENT_NOT_HANDLED otherwise.
4) Call EasyTab_Unload() in your shutdown code.
5) Once initialized, you can query tablet state using the EasyTab pointer.
e.g.:
EasyTab->PosX // X position of the pen
EasyTab->PosY // Y position of the pen
EasyTab->Pressure // Pressure of the pen ranging from 0.0f to 1.0f
For more info, have a look at the EasyTabInfo struct below.
* Add -lXi to compiler options to link XInput on Linux.
----------------------------------------------------------------------------
EXAMPLES
----------------------------------------------------------------------------
1) Windows:
int CALLBACK WinMain(...)
{
HWND Window;
...
if (EasyTab_Load(Window) != EASYTAB_OK) // Load
{
OutputDebugStringA("Tablet init failed\n");
}
...
// Once you've set up EasyTab loading, unloading and event handling,
// use the EasyTab variable at any point in your program to access
// the tablet state:
// EasyTab->PosX
// EasyTab->PosY
// EasyTab->Pressure
// For more tablet information, look at the EasyTabInfo struct.
...
EasyTab_Unload(); // Unload
}
LRESULT CALLBACK WindowProc(
HWND Window,
UINT Message,
WPARAM WParam,
LPARAM LParam)
{
if (EasyTab_HandleEvent(Window, Message, LParam, WParam) == EASYTAB_OK) // Event
{
return true; // Tablet event handled
}
switch (Message)
{
...
}
}
2) Linux:
int main(...)
{
Display* Disp;
Window Win;
...
if (EasyTab_Load(Disp, Win) != EASYTAB_OK) // Load
{
printf("Tablet init failed\n");
}
...
while (XPending(Disp)) // Event loop
{
XEvent Event;
XNextEvent(XlibDisplay, &Event);
if (EasyTab_HandleEvent(&Event) == EASYTAB_OK) // Event
{
continue; // Tablet event handled
}
switch (Event.type)
{
...
}
}
...
// Once you've set up EasyTab loading, unloading and event handling,
// use the EasyTab variable at any point in your program to access
// the tablet state:
// EasyTab->PosX
// EasyTab->PosY
// EasyTab->Pressure
// For more tablet information, look at the EasyTabInfo struct.
...
EasyTab_Unload(); // Unload
}
----------------------------------------------------------------------------
CREDITS
----------------------------------------------------------------------------
Apoorva Joshi apoorvaj.io
Sergio Gonzalez s3rg.io
This library is coded in the spirit of the stb libraries and follows the stb
guidelines.
*/
// TODO: Null checks and warnings for EasyTab
// TODO: Differentiate between stylus and eraser in the API
// TODO: Linux support for relative mode
// TODO: Documentation for relative mode
// =============================================================================
// EasyTab header section
// =============================================================================
#ifndef EASYTAB_H
#define EASYTAB_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef __linux__
#include <X11/extensions/XInput.h>
#endif // __linux__
#ifdef _WIN32
#include <windows.h>
#endif // _WIN32
typedef enum
{
EASYTAB_OK = 0,
// Errors
EASYTAB_MEMORY_ERROR = -1,
EASYTAB_X11_ERROR = -2,
EASYTAB_DLL_LOAD_ERROR = -3,
EASYTAB_WACOM_WIN32_ERROR = -4,
EASYTAB_INVALID_FUNCTION_ERROR = -5,
EASYTAB_EVENT_NOT_HANDLED = -16,
} EasyTabResult;
typedef enum
{
EASYTAB_TRACKING_MODE_SYSTEM = 0,
EASYTAB_TRACKING_MODE_RELATIVE = 1,
} EasyTabTrackingMode;
#ifdef WIN32
// -----------------------------------------------------------------------------
// wintab.h
// -----------------------------------------------------------------------------
#if 1
DECLARE_HANDLE(HMGR);
DECLARE_HANDLE(HCTX);
typedef DWORD WTPKT;
typedef DWORD FIX32;
// Messages
#if 1
#define WT_DEFBASE 0x7FF0
#define WT_MAXOFFSET 0xF
#define _WT_PACKET(b) ((b)+0)
#define _WT_CTXOPEN(b) ((b)+1)
#define _WT_CTXCLOSE(b) ((b)+2)
#define _WT_CTXUPDATE(b) ((b)+3)
#define _WT_CTXOVERLAP(b) ((b)+4)
#define _WT_PROXIMITY(b) ((b)+5)
#define _WT_INFOCHANGE(b) ((b)+6)
#define _WT_CSRCHANGE(b) ((b)+7) /* 1.1 */
#define _WT_PACKETEXT(b) ((b)+8) /* 1.4 */
#define _WT_MAX(b) ((b)+WT_MAXOFFSET)
#define WT_PACKET _WT_PACKET(WT_DEFBASE)
#define WT_CTXOPEN _WT_CTXOPEN(WT_DEFBASE)
#define WT_CTXCLOSE _WT_CTXCLOSE(WT_DEFBASE)
#define WT_CTXUPDATE _WT_CTXUPDATE(WT_DEFBASE)
#define WT_CTXOVERLAP _WT_CTXOVERLAP(WT_DEFBASE)
#define WT_PROXIMITY _WT_PROXIMITY(WT_DEFBASE)
#define WT_INFOCHANGE _WT_INFOCHANGE(WT_DEFBASE)
#define WT_CSRCHANGE _WT_CSRCHANGE(WT_DEFBASE) /* 1.1 */
#define WT_PACKETEXT _WT_PACKETEXT(WT_DEFBASE) /* 1.4 */
#define WT_MAX _WT_MAX(WT_DEFBASE)
#endif // Messages
// Flags
#if 1
#define CTX_NAME 1
#define CTX_OPTIONS 2
#define CTX_STATUS 3
#define CTX_LOCKS 4
#define CTX_MSGBASE 5
#define CTX_DEVICE 6
#define CTX_PKTRATE 7
#define CTX_PKTDATA 8
#define CTX_PKTMODE 9
#define CTX_MOVEMASK 10
#define CTX_BTNDNMASK 11
#define CTX_BTNUPMASK 12
#define CTX_INORGX 13
#define CTX_INORGY 14
#define CTX_INORGZ 15
#define CTX_INEXTX 16
#define CTX_INEXTY 17
#define CTX_INEXTZ 18
#define CTX_OUTORGX 19
#define CTX_OUTORGY 20
#define CTX_OUTORGZ 21
#define CTX_OUTEXTX 22
#define CTX_OUTEXTY 23
#define CTX_OUTEXTZ 24
#define CTX_SENSX 25
#define CTX_SENSY 26
#define CTX_SENSZ 27
#define CTX_SYSMODE 28
#define CTX_SYSORGX 29
#define CTX_SYSORGY 30
#define CTX_SYSEXTX 31
#define CTX_SYSEXTY 32
#define CTX_SYSSENSX 33
#define CTX_SYSSENSY 34
#define CTX_MAX 34
// Context option values
#define CXO_SYSTEM 0x0001
#define CXO_PEN 0x0002
#define CXO_MESSAGES 0x0004
#define CXO_MARGIN 0x8000
#define CXO_MGNINSIDE 0x4000
#define CXO_CSRMESSAGES 0x0008 /* 1.1 */
#define DVC_NAME 1
#define DVC_HARDWARE 2
#define DVC_NCSRTYPES 3
#define DVC_FIRSTCSR 4
#define DVC_PKTRATE 5
#define DVC_PKTDATA 6
#define DVC_PKTMODE 7
#define DVC_CSRDATA 8
#define DVC_XMARGIN 9
#define DVC_YMARGIN 10
#define DVC_ZMARGIN 11
#define DVC_X 12
#define DVC_Y 13
#define DVC_Z 14
#define DVC_NPRESSURE 15
#define DVC_TPRESSURE 16
#define DVC_ORIENTATION 17
#define DVC_ROTATION 18 /* 1.1 */
#define DVC_PNPID 19 /* 1.1 */
#define DVC_MAX 19
#define PK_CONTEXT 0x0001 // reporting context
#define PK_STATUS 0x0002 // status bits
#define PK_TIME 0x0004 // time stamp
#define PK_CHANGED 0x0008 // change bit vector
#define PK_SERIAL_NUMBER 0x0010 // packet serial number
#define PK_CURSOR 0x0020 // reporting cursor
#define PK_BUTTONS 0x0040 // button information
#define PK_X 0x0080 // x axis
#define PK_Y 0x0100 // y axis
#define PK_Z 0x0200 // z axis
#define PK_NORMAL_PRESSURE 0x0400 // normal or tip pressure
#define PK_TANGENT_PRESSURE 0x0800 // tangential or barrel pressure
#define PK_ORIENTATION 0x1000 // orientation info: tilts
#define PK_ROTATION 0x2000 // rotation info; 1.1
// constants for use with pktdef.h
#define PKEXT_ABSOLUTE 1
#define PKEXT_RELATIVE 2
#define WTI_DEFCONTEXT 3
#define WTI_DEFSYSCTX 4
#define WTI_DEVICES 100
#define WTI_DDCTXS 400 /* 1.1 */
#define WTI_DSCTXS 500 /* 1.1 */
#endif // Flags
typedef struct tagAXIS {
LONG axMin;
LONG axMax;
UINT axUnits;
FIX32 axResolution;
} AXIS, *PAXIS, NEAR *NPAXIS, FAR *LPAXIS;
#define LCNAMELEN 40
typedef struct tagLOGCONTEXTA {
char lcName[LCNAMELEN];
UINT lcOptions;
UINT lcStatus;
UINT lcLocks;
UINT lcMsgBase;
UINT lcDevice;
UINT lcPktRate;
WTPKT lcPktData;
WTPKT lcPktMode;
WTPKT lcMoveMask;
DWORD lcBtnDnMask;
DWORD lcBtnUpMask;
LONG lcInOrgX;
LONG lcInOrgY;
LONG lcInOrgZ;
LONG lcInExtX;
LONG lcInExtY;
LONG lcInExtZ;
LONG lcOutOrgX;
LONG lcOutOrgY;
LONG lcOutOrgZ;
LONG lcOutExtX;
LONG lcOutExtY;
LONG lcOutExtZ;
FIX32 lcSensX;
FIX32 lcSensY;
FIX32 lcSensZ;
BOOL lcSysMode;
int lcSysOrgX;
int lcSysOrgY;
int lcSysExtX;
int lcSysExtY;
FIX32 lcSysSensX;
FIX32 lcSysSensY;
} LOGCONTEXTA, *PLOGCONTEXTA, NEAR *NPLOGCONTEXTA, FAR *LPLOGCONTEXTA;
typedef struct tagEXTENSIONBASE { /* 1.4 */
HCTX nContext;
UINT nStatus;
DWORD nTime;
UINT nSerialNumber;
} EXTENSIONBASE;
#endif // wintab.h
// -----------------------------------------------------------------------------
#define PACKETDATA PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE
#define PACKETMODE 0
// -----------------------------------------------------------------------------
// pktdef.h
// -----------------------------------------------------------------------------
#if 1
// TODO: Simplify this file if we have a fixed packet format.
// The macros here are too ugly.
#ifndef PACKETNAME
/* if no packet name prefix */
#define __PFX(x) x
#define __IFX(x,y) x ## y
#else
/* add prefixes and infixes to packet format names */
#define __PFX(x) __PFX2(PACKETNAME,x)
#define __PFX2(p,x) __PFX3(p,x)
#define __PFX3(p,x) p ## x
#define __IFX(x,y) __IFX2(x,PACKETNAME,y)
#define __IFX2(x,i,y) __IFX3(x,i,y)
#define __IFX3(x,i,y) x ## i ## y
#endif
#define __SFX2(x,s) __SFX3(x,s)
#define __SFX3(x,s) x ## s
#define __TAG __IFX(tag,PACKET)
#define __TYPES __PFX(PACKET), * __IFX(P,PACKET), NEAR * __IFX(NP,PACKET), FAR * __IFX(LP,PACKET)
#define __TAGE __IFX(tag,PACKETEXT)
#define __TYPESE __PFX(PACKETEXT), * __IFX(P,PACKETEXT), NEAR * __IFX(NP,PACKETEXT), FAR * __IFX(LP,PACKETEXT)
#define __DATA (__PFX(PACKETDATA))
#define __MODE (__PFX(PACKETMODE))
#define __EXT(x) __SFX2(__PFX(PACKET),x)
typedef struct __TAG {
#if (__DATA & PK_CONTEXT)
HCTX pkContext;
#endif
#if (__DATA & PK_STATUS)
UINT pkStatus;
#endif
#if (__DATA & PK_TIME)
DWORD pkTime;
#endif
#if (__DATA & PK_CHANGED)
WTPKT pkChanged;
#endif
#if (__DATA & PK_SERIAL_NUMBER)
UINT pkSerialNumber;
#endif
#if (__DATA & PK_CURSOR)
UINT pkCursor;
#endif
#if (__DATA & PK_BUTTONS)
DWORD pkButtons;
#endif
#if (__DATA & PK_X)
LONG pkX;
#endif
#if (__DATA & PK_Y)
LONG pkY;
#endif
#if (__DATA & PK_Z)
LONG pkZ;
#endif
#if (__DATA & PK_NORMAL_PRESSURE)
#if (__MODE & PK_NORMAL_PRESSURE)
/* relative */
int pkNormalPressure;
#else
/* absolute */
UINT pkNormalPressure;
#endif
#endif
#if (__DATA & PK_TANGENT_PRESSURE)
#if (__MODE & PK_TANGENT_PRESSURE)
/* relative */
int pkTangentPressure;
#else
/* absolute */
UINT pkTangentPressure;
#endif
#endif
#if (__DATA & PK_ORIENTATION)
ORIENTATION pkOrientation;
#endif
#if (__DATA & PK_ROTATION)
ROTATION pkRotation; /* 1.1 */
#endif
#ifndef NOWTEXTENSIONS
/* extensions begin here. */
#if (__EXT(FKEYS) == PKEXT_RELATIVE) || (__EXT(FKEYS) == PKEXT_ABSOLUTE)
UINT pkFKeys;
#endif
#if (__EXT(TILT) == PKEXT_RELATIVE) || (__EXT(TILT) == PKEXT_ABSOLUTE)
TILT pkTilt;
#endif
#endif
} __TYPES;
#ifndef NOWTEXTENSIONS
typedef struct __TAGE {
EXTENSIONBASE pkBase;
#if (__EXT(EXPKEYS) == PKEXT_RELATIVE) || (__EXT(EXPKEYS) == PKEXT_ABSOLUTE)
EXPKEYSDATA pkExpKeys; /* 1.4 */
#endif
#if (__EXT(TOUCHSTRIP) == PKEXT_RELATIVE) || (__EXT(TOUCHSTRIP) == PKEXT_ABSOLUTE)
SLIDERDATA pkTouchStrip; /* 1.4 */
#endif
#if (__EXT(TOUCHRING) == PKEXT_RELATIVE) || (__EXT(TOUCHRING) == PKEXT_ABSOLUTE)
SLIDERDATA pkTouchRing; /* 1.4 */
#endif
} __TYPESE;
#endif
#undef PACKETNAME
#undef __TAG
#undef __TAGE
#undef __TAG2
#undef __TYPES
#undef __TYPESE
#undef __TYPES2
#undef __DATA
#undef __MODE
#undef __PFX
#undef __PFX2
#undef __PFX3
#undef __IFX
#undef __IFX2
#undef __IFX3
#undef __SFX2
#undef __SFX3
#endif // pktdef.h
// -----------------------------------------------------------------------------
typedef UINT (WINAPI * WTINFOA) (UINT, UINT, LPVOID);
typedef HCTX (WINAPI * WTOPENA) (HWND, LPLOGCONTEXTA, BOOL);
typedef BOOL (WINAPI * WTGETA) (HCTX, LPLOGCONTEXTA);
typedef BOOL (WINAPI * WTSETA) (HCTX, LPLOGCONTEXTA);
typedef BOOL (WINAPI * WTCLOSE) (HCTX);
typedef BOOL (WINAPI * WTENABLE) (HCTX, BOOL);
typedef BOOL (WINAPI * WTPACKET) (HCTX, UINT, LPVOID);
typedef BOOL (WINAPI * WTOVERLAP) (HCTX, BOOL);
typedef BOOL (WINAPI * WTSAVE) (HCTX, LPVOID);
typedef BOOL (WINAPI * WTCONFIG) (HCTX, HWND);
typedef HCTX (WINAPI * WTRESTORE) (HWND, LPVOID, BOOL);
typedef BOOL (WINAPI * WTEXTSET) (HCTX, UINT, LPVOID);
typedef BOOL (WINAPI * WTEXTGET) (HCTX, UINT, LPVOID);
typedef BOOL (WINAPI * WTQUEUESIZESET) (HCTX, int);
typedef int (WINAPI * WTDATAPEEK) (HCTX, UINT, UINT, int, LPVOID, LPINT);
typedef int (WINAPI * WTPACKETSGET) (HCTX, int, LPVOID);
typedef HMGR (WINAPI * WTMGROPEN) (HWND, UINT);
typedef BOOL (WINAPI * WTMGRCLOSE) (HMGR);
typedef HCTX (WINAPI * WTMGRDEFCONTEXT) (HMGR, BOOL);
typedef HCTX (WINAPI * WTMGRDEFCONTEXTEX) (HMGR, UINT, BOOL);
#endif // WIN32
// -----------------------------------------------------------------------------
// Enums
// -----------------------------------------------------------------------------
/*
Use this enum in conjunction with EasyTab->Buttons to check for tablet button
presses.
e.g. To check for lower pen button press, use:
if (EasyTab->Buttons & EasyTab_Buttons_Pen_Lower)
{
// Lower button is pressed
}
*/
enum EasyTab_Buttons_
{
EasyTab_Buttons_Pen_Touch = 1 << 0, // Pen is touching tablet
EasyTab_Buttons_Pen_Lower = 1 << 1, // Lower pen button is pressed
EasyTab_Buttons_Pen_Upper = 1 << 2, // Upper pen button is pressed
};
// -----------------------------------------------------------------------------
// Structs
// -----------------------------------------------------------------------------
typedef struct
{
int32_t PosX, PosY;
float Pressure; // Range: 0.0f to 1.0f
int32_t Buttons; // Bit field. Use with the EasyTab_Buttons_ enum.
int32_t RangeX, RangeY;
int32_t MaxPressure;
#ifdef __linux__
XDevice* Device;
uint32_t MotionType;
XEventClass EventClasses[1024];
uint32_t NumEventClasses;
#endif // __linux__
#ifdef WIN32
HINSTANCE Dll;
HCTX Context;
WTINFOA WTInfoA;
WTOPENA WTOpenA;
WTGETA WTGetA;
WTSETA WTSetA;
WTCLOSE WTClose;
WTPACKET WTPacket;
WTENABLE WTEnable;
WTOVERLAP WTOverlap;
WTSAVE WTSave;
WTCONFIG WTConfig;
WTRESTORE WTRestore;
WTEXTSET WTExtSet;
WTEXTGET WTExtGet;
WTQUEUESIZESET WTQueueSizeSet;
WTDATAPEEK WTDataPeek;
WTPACKETSGET WTPacketsGet;
WTMGROPEN WTMgrOpen;
WTMGRCLOSE WTMgrClose;
WTMGRDEFCONTEXT WTMgrDefContext;
WTMGRDEFCONTEXTEX WTMgrDefContextEx;
#endif // WIN32
} EasyTabInfo;
extern EasyTabInfo* EasyTab;
// -----------------------------------------------------------------------------
// Function declarations
// -----------------------------------------------------------------------------
#if defined(__linux__)
EasyTabResult EasyTab_Load(Display* Disp, Window Win);
EasyTabResult EasyTab_HandleEvent(XEvent* Event);
void EasyTab_Unload(Display* Disp);
#elif defined(_WIN32)
EasyTabResult EasyTab_Load(HWND Window);
EasyTabResult EasyTab_Load_Ex(HWND Window,
EasyTabTrackingMode Mode,
float RelativeModeSensitivity,
int32_t MoveCursor);
EasyTabResult EasyTab_HandleEvent(HWND Window,
UINT Message,
LPARAM LParam,
WPARAM WParam);
void EasyTab_Unload();
#else
// Save some trouble when porting.
#error "Unsupported platform."
#endif // __linux__ _WIN32
// -----------------------------------------------------------------------------
#endif // EASYTAB_H
// =============================================================================
// EasyTab implementation section
// =============================================================================
#ifdef EASYTAB_IMPLEMENTATION
EasyTabInfo* EasyTab;
// -----------------------------------------------------------------------------
// Linux implementation
// -----------------------------------------------------------------------------
#ifdef __linux__
EasyTabResult EasyTab_Load(Display* Disp, Window Win)
{
EasyTab = (EasyTabInfo*)calloc(1, sizeof(EasyTabInfo)); // We want init to zero, hence calloc.
if (!EasyTab) { return EASYTAB_MEMORY_ERROR; }
int32_t Count;
XDeviceInfoPtr Devices = (XDeviceInfoPtr)XListInputDevices(Disp, &Count);
if (!Devices) { return EASYTAB_X11_ERROR; }
for (int32_t i = 0; i < Count; i++)
{
if (!strstr(Devices[i].name, "stylus") &&
!strstr(Devices[i].name, "eraser")) { continue; }
EasyTab->Device = XOpenDevice(Disp, Devices[i].id);
XAnyClassPtr ClassPtr = Devices[i].inputclassinfo;
for (int32_t j = 0; j < Devices[i].num_classes; j++)
{
#if defined(__cplusplus)
switch (ClassPtr->c_class)
#else
switch (ClassPtr->class)
#endif
{
case ValuatorClass:
{
XValuatorInfo *Info = (XValuatorInfo *)ClassPtr;
// X
if (Info->num_axes > 0)
{
int32_t min = Info->axes[0].min_value;
EasyTab->RangeX = Info->axes[0].max_value;
//printf("Max/min x values: %d, %d\n", min, EasyTab->RangeX); // TODO: Platform-print macro
}
// Y
if (Info->num_axes > 1)
{
int32_t min = Info->axes[1].min_value;
EasyTab->RangeY = Info->axes[1].max_value;
//printf("Max/min y values: %d, %d\n", min, EasyTab->RangeY);
}
// Pressure
if (Info->num_axes > 2)
{
int32_t min = Info->axes[2].min_value;
EasyTab->MaxPressure = Info->axes[2].max_value;
//printf("Max/min pressure values: %d, %d\n", min, EasyTab->MaxPressure);
}
XEventClass EventClass;
DeviceMotionNotify(EasyTab->Device, EasyTab->MotionType, EventClass);
if (EventClass)
{
EasyTab->EventClasses[EasyTab->NumEventClasses] = EventClass;
EasyTab->NumEventClasses++;
}
} break;
}
ClassPtr = (XAnyClassPtr) ((uint8_t*)ClassPtr + ClassPtr->length); // TODO: Access this as an array to avoid pointer arithmetic?
}
XSelectExtensionEvent(Disp, Win, EasyTab->EventClasses, EasyTab->NumEventClasses);
}
XFreeDeviceList(Devices);
if (EasyTab->Device != 0) { return EASYTAB_OK; }
else { return EASYTAB_X11_ERROR; }
}
EasyTabResult EasyTab_HandleEvent(XEvent* Event)
{
if (Event->type != EasyTab->MotionType) { return EASYTAB_EVENT_NOT_HANDLED; }
XDeviceMotionEvent* MotionEvent = (XDeviceMotionEvent*)(Event);
EasyTab->PosX = MotionEvent->x;
EasyTab->PosY = MotionEvent->y;
EasyTab->Pressure = (float)MotionEvent->axis_data[2] / (float)EasyTab->MaxPressure;
return EASYTAB_OK;
}
void EasyTab_Unload(Display* Disp)
{
XCloseDevice(Disp, EasyTab->Device);
free(EasyTab);
EasyTab = NULL;
}
#endif // __linux__
// -----------------------------------------------------------------------------
// Windows implementation
// -----------------------------------------------------------------------------
#ifdef WIN32
#define GETPROCADDRESS(type, func) \
EasyTab->func = (type)GetProcAddress(EasyTab->Dll, #func); \
if (!EasyTab->func) \
{ \
OutputDebugStringA("Function " #func " not found in Wintab32.dll.\n"); \
return EASYTAB_INVALID_FUNCTION_ERROR; \
}
EasyTabResult EasyTab_Load(HWND Window)
{
return EasyTab_Load_Ex(Window, EASYTAB_TRACKING_MODE_SYSTEM, 0, 1);
}
EasyTabResult EasyTab_Load_Ex(HWND Window,
EasyTabTrackingMode TrackingMode,
float RelativeModeSensitivity,
int32_t MoveCursor)
{
EasyTab = (EasyTabInfo*)calloc(1, sizeof(EasyTabInfo)); // We want init to zero, hence calloc.
if (!EasyTab) { return EASYTAB_MEMORY_ERROR; }
// Load Wintab DLL and get function addresses
{
EasyTab->Dll = LoadLibraryA("Wintab32.dll");
if (!EasyTab->Dll)
{
OutputDebugStringA("Wintab32.dll not found.\n");
return EASYTAB_DLL_LOAD_ERROR;
}
GETPROCADDRESS(WTINFOA , WTInfoA);
GETPROCADDRESS(WTOPENA , WTOpenA);
GETPROCADDRESS(WTGETA , WTGetA);
GETPROCADDRESS(WTSETA , WTSetA);
GETPROCADDRESS(WTCLOSE , WTClose);
GETPROCADDRESS(WTPACKET , WTPacket);
GETPROCADDRESS(WTENABLE , WTEnable);
GETPROCADDRESS(WTOVERLAP , WTOverlap);
GETPROCADDRESS(WTSAVE , WTSave);
GETPROCADDRESS(WTCONFIG , WTConfig);
GETPROCADDRESS(WTRESTORE , WTRestore);
GETPROCADDRESS(WTEXTSET , WTExtSet);
GETPROCADDRESS(WTEXTGET , WTExtGet);
GETPROCADDRESS(WTQUEUESIZESET , WTQueueSizeSet);
GETPROCADDRESS(WTDATAPEEK , WTDataPeek);
GETPROCADDRESS(WTPACKETSGET , WTPacketsGet);
GETPROCADDRESS(WTMGROPEN , WTMgrOpen);
GETPROCADDRESS(WTMGRCLOSE , WTMgrClose);
GETPROCADDRESS(WTMGRDEFCONTEXT , WTMgrDefContext);
GETPROCADDRESS(WTMGRDEFCONTEXTEX , WTMgrDefContextEx);
}
if (!EasyTab->WTInfoA(0, 0, NULL))
{
OutputDebugStringA("Wintab services not available.\n");
return EASYTAB_WACOM_WIN32_ERROR;
}
// Open context
{
LOGCONTEXTA LogContext = {0};
AXIS RangeX = {0};
AXIS RangeY = {0};
AXIS Pressure = {0};
EasyTab->WTInfoA(WTI_DDCTXS, 0, &LogContext);
EasyTab->WTInfoA(WTI_DEVICES, DVC_X, &RangeX);
EasyTab->WTInfoA(WTI_DEVICES, DVC_Y, &RangeY);
EasyTab->WTInfoA(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
LogContext.lcPktData = PACKETDATA; // ??
LogContext.lcOptions |= CXO_MESSAGES;
if (MoveCursor) { LogContext.lcOptions |= CXO_SYSTEM; }
LogContext.lcPktMode = PACKETMODE;
LogContext.lcMoveMask = PACKETDATA;
LogContext.lcBtnUpMask = LogContext.lcBtnDnMask;
LogContext.lcOutOrgX = 0;
LogContext.lcOutOrgY = 0;
LogContext.lcOutExtX = GetSystemMetrics(SM_CXSCREEN);
LogContext.lcOutExtY = -GetSystemMetrics(SM_CYSCREEN);
LogContext.lcSysOrgX = 0;
LogContext.lcSysOrgY = 0;
LogContext.lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
LogContext.lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
if (TrackingMode == EASYTAB_TRACKING_MODE_RELATIVE)
{
LogContext.lcPktMode |= PK_X | PK_Y; // TODO: Should this be included in the
// PACKETMODE macro define up top?
LogContext.lcSysMode = 1;
if (RelativeModeSensitivity > 1.0f)
{
RelativeModeSensitivity = 1.0f;
}
else if (RelativeModeSensitivity < 0.0f)
{
RelativeModeSensitivity = 0.0f;
}
// Wintab expects sensitivity to be a 32-bit fixed point number
// with the radix point between the two words. Thus, the type
// contains 16 bits to the left of the radix point and 16 bits to
// the right of it.
//
// 0x10000 Hex
// = 65,536 Decimal
// = 0000 0000 0000 0001 . 0000 0000 0000 0000 Binary
// = 1.0 Fixed Point
uint32_t Sensitivity = (uint32_t)(0x10000 * RelativeModeSensitivity);
if (MoveCursor)
{
LogContext.lcSysSensX = LogContext.lcSysSensY = Sensitivity;
}
else
{
LogContext.lcSensX = LogContext.lcSensY = Sensitivity;
}
}
EasyTab->Context = EasyTab->WTOpenA(Window, &LogContext, TRUE);
if (!EasyTab->Context)
{
OutputDebugStringA("Wintab context couldn't be opened.\n");
return EASYTAB_WACOM_WIN32_ERROR;
}
// Get tablet capabilites
{
EasyTab->MaxPressure = Pressure.axMax;
EasyTab->RangeX = RangeX.axMax;
EasyTab->RangeY = RangeY.axMax;
}
}
return EASYTAB_OK;
}
#undef GETPROCADDRESS
EasyTabResult EasyTab_HandleEvent(HWND Window, UINT Message, LPARAM LParam, WPARAM WParam)
{
PACKET Packet = { 0 };
if (Message == WT_PACKET &&
(HCTX)LParam == EasyTab->Context &&
EasyTab->WTPacket(EasyTab->Context, (UINT)WParam, &Packet))
{
POINT Point = { 0 };
Point.x = Packet.pkX;
Point.y = Packet.pkY;
ScreenToClient(Window, &Point);
EasyTab->PosX = Point.x;
EasyTab->PosY = Point.y;
EasyTab->Pressure = (float)Packet.pkNormalPressure / (float)EasyTab->MaxPressure;
EasyTab->Buttons = Packet.pkButtons;
return EASYTAB_OK;
}
return EASYTAB_EVENT_NOT_HANDLED;
}
void EasyTab_Unload()
{
if (EasyTab->Context) { EasyTab->WTClose(EasyTab->Context); }
if (EasyTab->Dll) { FreeLibrary(EasyTab->Dll); }
free(EasyTab);
EasyTab = NULL;
}
#endif // WIN32
// -----------------------------------------------------------------------------
#endif // EASYTAB_IMPLEMENTATION

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,19 @@
#pragma once
#include "env.h"
#ifdef ENV_OS_ANDROID
#include <EGL/egl.h>
#include <GLES3/gl32.h>
#else
#include "GL/glew.h"
#endif
#ifdef ENV_OS_ANDROID
#define GLW_CONTEXT_DEPTH_BITS 16
#define GLW_CONTEXT_DEPTH_COMPONENT GL_DEPTH_COMPONENT16
#else
#define GLW_CONTEXT_DEPTH_BITS 32
#define GLW_CONTEXT_DEPTH_COMPONENT GL_DEPTH_COMPONENT32
#endif

View file

@ -0,0 +1,53 @@
#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&);
};
};
};

View file

@ -0,0 +1,84 @@
#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();
};
};
};

View file

@ -0,0 +1,48 @@
#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();
};
};
};

View file

@ -0,0 +1,40 @@
#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();
};
};
};

View file

@ -0,0 +1,167 @@
#pragma once
namespace tp {
// basically copy of glfw keys
enum class Keycode {
/* Printable keys */
SPACE = 32,
APOSTROPHE = 39, /* ' */
COMMA = 44, /* , */
MINUS = 45, /* - */
PERIOD = 46, /* . */
SLASH = 0xBF, /* \ */
N0 = 48,
N1 = 49,
N2 = 50,
N3 = 51,
N4 = 52,
N5 = 53,
N6 = 54,
N7 = 55,
N8 = 56,
N9 = 57,
SEMICOLON = 59, /* ; */
EQUAL = 61, /* = */
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LEFT_BRACKET = 91, /* [ */
BACKSLASH = 92, /* \ */
RIGHT_BRACKET = 93, /* ] */
GRAVE_ACCENT = 96, /* ` */
WORLD_1 = 161, /* non-US #1 */
WORLD_2 = 162, /* non-US #2 */
/* function keys */
ESCAPE = 256,
ENTER = 257,
TAB = 258,
BACKSPACE = 259,
INSERT = 260,
DELETE = 261,
RIGHT = 262,
LEFT = 263,
DOWN = 264,
UP = 265,
PAGE_UP = 266,
PAGE_DOWN = 267,
HOME = 268,
END = 269,
CAPS_LOCK = 280,
SCROLL_LOCK = 281,
NUM_LOCK = 282,
PRINT_SCREEN = 283,
PAUSE = 284,
F1 = 290,
F2 = 291,
F3 = 292,
F4 = 293,
F5 = 294,
F6 = 295,
F7 = 296,
F8 = 297,
F9 = 298,
F10 = 299,
F11 = 300,
F12 = 301,
F13 = 302,
F14 = 303,
F15 = 304,
F16 = 305,
F17 = 306,
F18 = 307,
F19 = 308,
F20 = 309,
F21 = 310,
F22 = 311,
F23 = 312,
F24 = 313,
F25 = 314,
KP_0 = 320,
KP_1 = 321,
KP_2 = 322,
KP_3 = 323,
KP_4 = 324,
KP_5 = 325,
KP_6 = 326,
KP_7 = 327,
KP_8 = 328,
KP_9 = 329,
KP_DECIMAL = 330,
KP_DIVIDE = 331,
KP_MULTIPLY = 332,
KP_SUBTRACT = 333,
KP_ADD = 334,
KP_ENTER = 335,
KP_EQUAL = 336,
LEFT_SHIFT = 340,
LEFT_CONTROL = 341,
LEFT_ALT = 342,
LEFT_SUPER = 343,
RIGHT_SHIFT = 344,
RIGHT_CONTROL = 345,
RIGHT_ALT = 346,
RIGHT_SUPER = 347,
MENU = 348,
INV_SLASH = 0xDC,
BRA = 0xDB,
KET = 0xDD,
TILDA = 0xC0,
DOUBLE_DOT = 0xBA,
QUOTES = 0xDE,
MOUSE1 = 501,
MOUSE2 = 502,
MOUSE3 = 503,
MOUSE4 = 504,
MOUSE5 = 505,
MOUSE_UP = 506,
MOUSE_DOWN = 507,
};
enum class Keystate {
PRESSED,
RELEASED,
HOLD,
REPEAT,
NONE,
};
struct KeyEvent {
Keycode code;
enum class EventState {
RELEASED = 0,
PRESSED = 1,
REPEAT = 2,
} event_state;
};
};

View file

@ -0,0 +1,36 @@
#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();
};
};
};

View file

@ -0,0 +1,71 @@
#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);
};
};
};

View file

@ -0,0 +1,31 @@
#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);
};
};
};

View file

@ -0,0 +1,114 @@
#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();
};
};
};

View file

@ -0,0 +1,25 @@
#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;

View file

@ -0,0 +1,804 @@
// 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

View file

@ -0,0 +1,453 @@
/*
* 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);
}

View file

@ -0,0 +1,350 @@
/*
* 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

View file

@ -0,0 +1,115 @@
#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));
}

View file

@ -0,0 +1,378 @@
#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;
}

View file

@ -0,0 +1,877 @@
#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;
}

View file

@ -0,0 +1,116 @@
#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; }
};

View file

@ -0,0 +1,282 @@
#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;
}

View file

@ -0,0 +1,170 @@
#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;
}
};

View file

@ -0,0 +1,164 @@
#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;
}

View file

@ -0,0 +1,216 @@
#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.

View file

@ -0,0 +1,107 @@
#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();
}

View file

@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 23)
project(Allocator)
project(Allocators)
### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp")

View file

@ -3,8 +3,12 @@
#include <cstdlib>
static tp::ModuleManifest* sModuleDependencies[] = { &tp::gModuleBase, nullptr };
tp::ModuleManifest tp::gModuleAllocators = ModuleManifest("Allocators", nullptr, nullptr, sModuleDependencies);
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); }

View file

@ -6,6 +6,7 @@
#include "Utils.hpp"
#include "Debugging.hpp"
#include <cstdio>
#include <cstdlib>
using namespace tp;
@ -22,6 +23,8 @@ HeapAllocGlobal::~HeapAllocGlobal() = default;
tp::MemHead* tp::HeapAllocGlobal::mEntry = nullptr;
tp::ualni tp::HeapAllocGlobal::mNumAllocations = 0;
tp::Mutex tp::HeapAllocGlobal::mMutex;
bool tp::HeapAllocGlobal::mIgnore;
// ----------------------- Debug Implementation ---------------------------- //
// |----------------|
@ -38,7 +41,8 @@ namespace tp {
struct MemHead {
MemHead* mPrev;
MemHead* mNext;
ualni mBlockSize;
uhalni mBlockSize;
uhalni mIgnored;
#ifdef MEM_STACK_TRACE
const CallStackCapture::CallStack* mCallStack;
#endif
@ -63,18 +67,25 @@ void* HeapAllocGlobal::allocate(ualni aBlockSize) {
}
// 1) Allocate the block
ALLOCATE:
auto head = (MemHead*)malloc(aBlockSize + WRAP_SIZE * 2 + HEAD_SIZE);
if (!head) {
printf("WARNING : Cant allocate memory. Trying again\n");
goto ALLOCATE; // Just freeze if no memory is available
}
auto wrap_top = (int1*)(head + 1);
auto data = wrap_top + WRAP_SIZE;
auto wrap_bottom = data + aBlockSize;
if (!head) { return nullptr; }
head->mBlockSize = aBlockSize;
head->mIgnored = mIgnore;
// 2) Link with existing blocks
mMutex.lock();
mNumAllocations++;
if (mEntry) {
DEBUG_ASSERT(!mEntry->mNext)
DEBUG_ASSERT(mEntry->mNext == nullptr)
head->mNext = nullptr;
head->mPrev = mEntry;
mEntry->mNext = head;
@ -84,15 +95,18 @@ void* HeapAllocGlobal::allocate(ualni aBlockSize) {
}
mEntry = head;
// 3) Wrap fill
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
// 4) Trace the stack
// 3) Trace the stack
#ifdef MEM_STACK_TRACE
head->mCallStack = gCSCapture->getSnapshot();
#endif
mMutex.unlock();
// 4) Wrap fill
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
// 5) clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(data, aBlockSize, CLEAR_ALLOC_VAL);
@ -102,6 +116,8 @@ void* HeapAllocGlobal::allocate(ualni aBlockSize) {
}
void HeapAllocGlobal::deallocate(void* aPtr) {
if (!aPtr) return;
// 1) Restore the pointers
auto head = ((MemHead*)((int1*)aPtr - WRAP_SIZE)) - 1;
auto wrap_top = (int1*)(head + 1);
@ -109,6 +125,7 @@ void HeapAllocGlobal::deallocate(void* aPtr) {
auto wrap_bottom = data + head->mBlockSize;
// 2) Unlink with blocks
mMutex.lock();
mNumAllocations--;
DEBUG_ASSERT(!mEntry->mNext)
if (head->mNext) head->mNext->mPrev = head->mPrev;
@ -116,34 +133,65 @@ void HeapAllocGlobal::deallocate(void* aPtr) {
if (head == mEntry) {
mEntry = head->mPrev;
}
mMutex.unlock();
if (!head->mIgnored) {
// 3) Check the wrap
ASSERT(!memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
ASSERT(!memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
if (memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL)) {
CallStackCapture::printSnapshot(head->mCallStack);
ASSERT(!"Allocated Block Wrap Corrupted!")
}
if (memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL)) {
CallStackCapture::printSnapshot(head->mCallStack);
ASSERT(!"Allocated Block Wrap Corrupted!")
}
// 4) clear data
#ifdef MEM_CLEAR_ON_ALLOC
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(data, head->mBlockSize, CLEAR_DEALLOC_VAL);
#endif
#endif
}
// 5) free the block
free(head);
}
bool HeapAllocGlobal::checkLeaks() {
ualni ignoredCount = 0;
for (auto iter = mEntry; iter; iter = iter->mPrev) {
ignoredCount += iter->mIgnored;
}
// 1) Check for not deallocated memory
if (mNumAllocations) {
if (mNumAllocations && ignoredCount < mNumAllocations) {
#ifdef MEM_STACK_TRACE
gCSCapture->logLeaks();
for (auto iter = mEntry; iter; iter = iter->mPrev) {
if (!iter->mIgnored) CallStackCapture::printSnapshot(iter->mCallStack);
}
#endif
DEBUG_BREAK("Destruction of not freed Allocator")
printf(" Count : %llu", mNumAllocations - ignoredCount);
ASSERT(!"Destruction of not freed Allocator")
return true;
}
return false;
}
void HeapAllocGlobal::startIgnore() {
mMutex.lock();
mIgnore = true;
mMutex.unlock();
}
void HeapAllocGlobal::stopIgnore() {
mMutex.lock();
mIgnore = false;
mMutex.unlock();
}
HeapAllocGlobal::~HeapAllocGlobal() = default;
#endif

View file

@ -1,6 +1,6 @@
#pragma once
#include "Module.hpp"
#include "Utils.hpp"
#include "HeapAllocatorGlobal.hpp"
#include "HeapAllocator.hpp"
@ -11,8 +11,6 @@ namespace tp {
extern ModuleManifest gModuleAllocators;
}
inline void* operator new(std::size_t aSize, void* aWhere) noexcept { return aWhere; }
void* operator new(std::size_t aSize);
void* operator new[](std::size_t aSize);
void operator delete(void* aPtr) noexcept;

View file

@ -14,6 +14,7 @@
* 2) updating list entry to that block.
*/
#include "HeapAllocatorGlobal.hpp"
#include "Environment.hpp"
#include "PrivateConfig.hpp"

View file

@ -1,6 +1,7 @@
#pragma once
#include "Module.hpp"
#include "Multithreading.hpp"
namespace tp {
@ -9,6 +10,8 @@ namespace tp {
#ifdef MEM_DEBUG
static ualni mNumAllocations;
static struct MemHead* mEntry;
static Mutex mMutex;
static bool mIgnore;
#endif
public:
@ -20,6 +23,9 @@ namespace tp {
static void deallocate(void* aPtr);
static bool checkLeaks();
static void startIgnore();
static void stopIgnore();
public:
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {}

View file

@ -0,0 +1,6 @@
#pragma once
#include "Common.hpp"
inline void* operator new(std::size_t aSize, void* aWhere) noexcept { return aWhere; }
inline void* operator new[](std::size_t aSize, void* aWhere) noexcept { return aWhere; }

View file

@ -10,8 +10,18 @@ project(Types)
add_compile_definitions(MEM_DEBUG)
set(EXTERNALS ../Externals)
add_subdirectory(Modules)
add_subdirectory(Utils)
add_subdirectory(Containers)
add_subdirectory(Math)
add_subdirectory(Allocators)
add_subdirectory(Strings)
add_subdirectory(Tokenizer)
add_subdirectory(Parser)
add_subdirectory(CommandLine)
add_subdirectory(Externals)
add_subdirectory(Connection)
add_subdirectory(Graphics)
add_subdirectory(Objects)

15
CMakeSettings.json Normal file
View file

@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
}
]
}

View file

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 23)
project(CommandLine)
### ---------------------- 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 Tokenizer Connection)
### -------------------------- 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)

View file

@ -0,0 +1,122 @@
#include "NewPlacement.hpp"
#include "CmdLineInterpreter.hpp"
#define MAX_LINE_LENGTH 1024
#include <cstdio>
#include <cstring>
using namespace tp;
static bool helpFunction(CmdLineInterpreter* self, const CommandLine& args) {
self->help(args);
return true;
}
void CmdLineInterpreter::help(const CommandLine& args) const {
auto commandName = args.getString("CommandName");
auto allCommands = commandName == "_none_";
if (allCommands) {
printf("Commands:\n");
for (auto command : mCommands) {
printf(" %s\n", command->key.read());
}
return;
}
auto idx = mCommands.presents(commandName);
if (!idx) {
printf("Command '%s' not found\n", commandName.read());
return;
}
printf("Command '%s'\n", commandName.read());
auto command = &mCommands.getSlotVal(idx);
command->args->help();
}
CmdLineInterpreter::CmdLineInterpreter() {
auto helpArgs = new CommandLine{
{ "CommandName", "_none_" }
};
addCommand("help", helpArgs, (CommandFunction) helpFunction, this);
}
void CmdLineInterpreter::addCommand(const String& id, CommandLine* args, CommandFunction function, void* customData) {
ASSERT(!mCommands.presents(id))
mCommands.put(id, { args, function, customData });
}
void CmdLineInterpreter::run() {
char buffer[MAX_LINE_LENGTH];
printf("Command Line Interpreter (or type 'exit' to quit):\n");
while (true) {
printf("%s >> ", mName.read());
// Read input from the user
if (fgets(buffer, MAX_LINE_LENGTH, stdin) == nullptr) {
printf("Error reading input.\n");
return;
}
// Remove the trailing newline character if it exists
auto length = strlen(buffer);
if (length > 0 && buffer[length - 1] == '\n') {
buffer[length - 1] = '\0';
}
// Check if the user wants to exit
if (strcmp(buffer, "exit") == 0) {
return;
}
// Process the input here
processCommand(buffer);
}
}
bool CmdLineInterpreter::processCommand(int1* commandString) {
ualni commandLen = 0;
for (auto i = commandString; *i != 0; i++) {
if (*i == ' ') break;
commandLen++;
}
commandString[commandLen] = 0;
auto args = commandString + commandLen + 1;
auto idx = mCommands.presents(commandString);
if (!idx) {
printf("ERROR: Command '%s' is not found\n", commandString);
printf("Please execute 'help' for more information\n\n");
return true;
}
auto command = &mCommands.getSlotVal(idx);
command->args->parse(args);
if (command->args->mError) {
printf("ERROR: Command call '%s' has invalid arguments\n", commandString);
command->args->resetError();
return true;
}
if (!command->function(command->customData, *command->args)) {
printf("ERROR: Command call '%s' failed\n", commandString);
return true;
}
return true;
}
CmdLineInterpreter::~CmdLineInterpreter() {
for (auto cmd : mCommands) {
delete cmd->val.args;
}
}

View file

@ -0,0 +1,412 @@
#include "NewPlacement.hpp"
#include "CommandLine.hpp"
using namespace tp;
static ModuleManifest* sModuleDependencies[] = { &gModuleTokenizer, &gModuleConnection, nullptr };
ModuleManifest tp::gModuleCommandLine = ModuleManifest("CommandLine", nullptr, nullptr, sModuleDependencies);
const char* regexSpace = "\n|\t| |\r";
const char* regexFalse = "N|n|(False)|(false)";
const char* regexTrue = "Y|y|(True)|(true)";
const char* regexInt = "((\\-)|(\\+))?[0-9]+";
const char* regexFloat = R"(((\-)|(\+))?([0-9]+)(\.)([0-9]*)?)";
const char* regexString = "'{'-'}*'";
CommandLine::Arg::Arg(const Arg& arg) {
mId = arg.mId;
switch (arg.mType) {
case CommandLine::Arg::INT: mType = INT; mInt = arg.mInt; break;
case CommandLine::Arg::FLOAT: mType = FLOAT; mFloat = arg.mFloat; break;
case CommandLine::Arg::BOOL: mType = BOOL; mBool = arg.mBool; break;
case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); mStr = arg.mStr; break;
case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); mFile = arg.mFile; break;
default:
ASSERT(false)
}
mOptional = arg.mOptional;
}
CommandLine::Arg::Arg(const String& id, Type type) {
mId = id;
switch (type) {
case CommandLine::Arg::INT: mType = INT; new (&mInt) IntArg(); break;
case CommandLine::Arg::FLOAT: mType = FLOAT; new (&mFloat) FloatArg(); break;
case CommandLine::Arg::BOOL: mType = BOOL; new (&mBool) BoolArg(); break;
case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); break;
case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); break;
default: ASSERT(false)
}
mOptional = false;
}
CommandLine::Arg::Arg(const String& id, const Range<alni>& aAcceptingRange) {
mId = id;
mType = FLOAT;
mInt = { 0, 0, aAcceptingRange };
mOptional = false;
}
CommandLine::Arg::Arg(const String& id, const Range<alnf>& aAcceptingRange) {
mId = id;
mType = FLOAT;
mFloat = { 0, 0, aAcceptingRange };
mOptional = false;
}
CommandLine::Arg::Arg(const String& id, const Range<alni>& aAcceptingRange, alni aDefault) {
mId = id;
mType = INT;
mInt = { 0, aDefault, aAcceptingRange };
}
CommandLine::Arg::Arg(const String& id, const Range<alnf>& aAcceptingRange, alnf aDefault) {
mId = id;
mType = FLOAT;
mFloat = { 0, aDefault, aAcceptingRange };
}
CommandLine::Arg::Arg(const String& id, bool aDefault) {
mId = id;
mType = BOOL;
mBool.mDefault = aDefault;
}
CommandLine::Arg::Arg(const String& id, const char* aDefault) {
mId = id;
mType = STR;
new (&mStr) StringArg();
mStr.mDefault = aDefault;
}
CommandLine::Arg::~Arg() {
switch (mType) {
case CommandLine::Arg::STR:
mStr.~StringArg();
break;
case CommandLine::Arg::FILE_IN:
mFile.~FileInputArg();
break;
default:
break;
}
}
CommandLine::CommandLine(const InitialierList<Arg>& args) {
bool optional_start = false;
for (auto& arg : args) {
ASSERT(!mArgs.presents(arg.mId) && "Argument Redefinition")
auto copy_arg = new Arg(arg);
mArgs.put(arg.mId, copy_arg);
mArgsOrder.pushBack(mArgs.get(arg.mId));
if (arg.mOptional) {
mOptionals++;
}
if (optional_start) {
ASSERT(arg.mOptional && "Not Optional Argument After Optionals")
}
else if (arg.mOptional) {
optional_start = true;
}
}
mTokenizer.build({
{ regexSpace, TokType::SPACE },
{ regexFalse, TokType::BOOL_FALSE },
{ regexTrue, TokType::BOOL_TRUE },
{ regexInt, TokType::INT },
{ regexFloat, TokType::FLOAT },
{ regexString, TokType::STR },
});
ASSERT(mTokenizer.isBuild() && "Internal Error")
mArgumentTokenizer.build({
{ regexSpace, ArgTokType::SPACE },
{ "{ - }*", ArgTokType::ARG }
});
ASSERT(mTokenizer.isBuild() && "Internal Error")
}
CommandLine::~CommandLine() {
for (auto arg : mArgsOrder) {
delete arg.data();
}
}
bool CommandLine::parse(char argc, const char* argv[], bool logError, ualni skipArgs) {
// discard some arguments
argc -= (char) skipArgs;
argv += skipArgs;
if (argc < mArgs.size() - mOptionals) {
ErrInvalidArgCount();
if (logError) {
ErrLog();
}
return false;
}
ualni idx = 0;
for (auto arg : mArgsOrder) {
if (idx < argc) {
parseArg(*arg.data(), argv[idx]);
} else {
initDefault(*arg.data());
}
if (mError) {
if (logError) ErrLog();
return false;
}
idx++;
}
return true;
}
bool CommandLine::parse(const char* args, bool logError) {
mArgumentTokenizer.bindSource(args);
mArgumentTokenizer.reset();
ualni argc = 0;
auto tok = mArgumentTokenizer.readTok();
auto argument = mArgsOrder.first();
while (tok != ArgTokType::FAILURE && tok != ArgTokType::END) {
if (tok != ArgTokType::ARG) {
tok = mArgumentTokenizer.readTok();
continue;
}
if (!argument) {
ErrInvalidArgCount();
if (logError) ErrLog();
return false;
}
parseArg(*argument->data, mArgumentTokenizer.extractVal().read());
if (mError && logError) {
ErrLog();
return false;
}
argc++;
argument = argument->next;
tok = mArgumentTokenizer.readTok();
}
ualni idx = 0;
for (auto arg : mArgsOrder) {
if (idx >= argc) {
initDefault(*arg.data());
}
if (mError) {
if (logError) ErrLog();
return false;
}
idx++;
}
return true;
}
alni CommandLine::getInt(const String& id) const { auto& arg = getArg(id, Arg::INT); return arg.mInt.mVal; }
alnf CommandLine::getFloat(const String& id) const { auto& arg = getArg(id, Arg::FLOAT); return arg.mFloat.mVal; }
bool CommandLine::getBool(const String& id) const { auto& arg = getArg(id, Arg::BOOL); return arg.mBool.mFlag; }
const String& CommandLine::getString(const String& id) const { auto& arg = getArg(id, Arg::STR); return arg.mStr.mStr; }
const LocalConnection::Location& CommandLine::getFile(const String& id) const { auto& arg = getArg(id, Arg::FILE_IN); return arg.mFile.mFileLocation; }
CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) {
auto idx = mArgs.presents(id);
ASSERT(idx && "Invalid Id")
auto& arg = mArgs.getSlotVal(idx);
ASSERT(arg->mType == type && "Invalid Type Requested")
return *arg;
}
const CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) const {
auto idx = mArgs.presents(id);
ASSERT(idx && "Invalid Id")
auto& arg = mArgs.getSlotVal(idx);
ASSERT(arg->mType == type && "Invalid Type Requested")
return *arg;
}
void CommandLine::ErrInvalidArgCount() { mError = { "Invalid Number Of Arguments Passed", nullptr }; }
void CommandLine::ErrInvalidArgSyntax(Arg* arg) { mError = { "Invalid Syntax Of Argument", arg }; }
void CommandLine::ErrInvalidArgType(Arg* arg) { mError = { "Invalid Type Of Argument", arg }; }
void CommandLine::ErrFileNotExists(Arg* arg) { mError = { "File Not Exists", arg }; }
void CommandLine::ErrFileCouldNotOpen(Arg* arg) { mError = { "Could Not Open File", arg }; }
void CommandLine::ErrValNotinRange(Arg* arg) { mError = { "Value Not In Range", arg }; }
void CommandLine::ErrLog() {
printf("\nERROR : Invalid Command Line\n");
if (mError.mArg) {
alni idx = 0;
for (auto arg : mArgsOrder) {
if (mError.mArg == arg.data()) break;
idx++;
}
printf("\nArgument: %lli\n", idx);
logArg(*mError.mArg);
}
printf("Error Description: %s. \n", mError.mDescr);
printf("\nExpected Arguments are: \n");
ualni idx = 0;
for (auto arg : mArgsOrder) {
printf(" -- %lli -- \n", idx);
logArg(*arg.data());
idx++;
}
printf("\nNote regex for types are:\n");
printf(" False - %s\n", regexFalse);
printf(" True - %s\n", regexTrue);
printf(" Int - %s\n", regexInt);
printf(" Float - %s\n", regexFloat);
printf(" String - %s\n", regexString);
printf(" File - else\n");
}
void CommandLine::logArg(const Arg& arg) {
switch (arg.mType) {
case Arg::INT: {
printf("Type : Int\n");
printf("Range : %lli - %lli\n", arg.mInt.mAcceptingRange.mBegin, arg.mInt.mAcceptingRange.mEnd);
if (arg.mOptional) {
printf("Default : %lli\n", arg.mInt.mDefault);
}
printf("Value : %lli\n", arg.mInt.mVal);
} break;
case Arg::FLOAT: {
printf("Type : Float\n");
printf("Range : %f - %f\n", (halnf) arg.mFloat.mAcceptingRange.mBegin, (halnf) arg.mFloat.mAcceptingRange.mEnd);
if (arg.mOptional) {
printf("Default : %f\n", arg.mFloat.mDefault);
}
printf("Value : %f\n", arg.mFloat.mVal);
} break;
case Arg::BOOL: {
printf("Type : Bool\n");
if (arg.mOptional) {
printf("Default : %s\n", arg.mBool.mDefault ? "True" : "False");
}
printf("Value : %s\n", arg.mBool.mFlag ? "True" : "False");
} break;
case Arg::STR: {
printf("Type : String\n");
if (arg.mOptional) {
printf("Default : %s\n", arg.mStr.mDefault.read());
}
printf("Value : %s\n", arg.mStr.mStr.read());
} break;
case Arg::FILE_IN: {
printf("Type : File Input\n");
printf("Value Path : %s\n", arg.mFile.mFileLocation.getLocation().read());
} break;
default: ASSERT(false)
}
}
void CommandLine::initDefault(Arg& arg) {
switch (arg.mType) {
case Arg::INT: arg.mInt.mVal = arg.mInt.mDefault; break;
case Arg::FLOAT: arg.mFloat.mVal = arg.mFloat.mDefault; break;
case Arg::BOOL: arg.mBool.mFlag = arg.mBool.mDefault; break;
case Arg::STR: arg.mStr.mStr = arg.mStr.mDefault; break;
default:
break;
}
}
void CommandLine::parseArg(Arg& arg, const char* src) {
mTokenizer.reset();
mTokenizer.bindSource(src);
auto tok = mTokenizer.readTok();
if (tok < TokType::INT || tok > TokType::STR) {
ErrInvalidArgSyntax(&arg);
return;
}
auto val = mTokenizer.extractVal();
switch (arg.mType) {
case Arg::INT: {
if (tok != TokType::INT) {
ErrInvalidArgType(&arg);
return;
}
auto converted = String::Logic::convertStringToValue(val.read(), arg.mInt.mVal);
if (converted && arg.mInt.mVal < arg.mInt.mAcceptingRange.mBegin || arg.mInt.mVal > arg.mInt.mAcceptingRange.mEnd) {
ErrValNotinRange(&arg);
return;
}
} break;
case Arg::FLOAT: {
if (tok != TokType::FLOAT) {
ErrInvalidArgType(&arg);
return;
}
auto converted = String::Logic::convertStringToValue(val.read(), arg.mFloat.mVal);
if (converted && arg.mFloat.mVal < arg.mFloat.mAcceptingRange.mBegin || arg.mFloat.mVal > arg.mFloat.mAcceptingRange.mEnd) {
ErrValNotinRange(&arg);
return;
}
} break;
case Arg::STR: {
if (tok != TokType::STR) {
ErrInvalidArgType(&arg);
return;
}
arg.mStr.mStr.resize(val.size() - 2);
memCopy(arg.mStr.mStr.write(), val.read() + 1, val.size() - 2);
} break;
case Arg::BOOL: {
if (tok != TokType::BOOL_FALSE && tok != TokType::BOOL_TRUE) {
ErrInvalidArgType(&arg);
return;
}
arg.mBool.mFlag = tok == TokType::BOOL_TRUE;
} break;
case Arg::FILE_IN: {
if (tok != TokType::STR) {
ErrInvalidArgType(&arg);
return;
}
arg.mFile.mFileLocation.setLocation(val);
if (!arg.mFile.mFileLocation.exists()) {
ErrFileNotExists(&arg);
return;
}
} break;
default: ASSERT(false)
}
arg.mIsPassed = true;
}
void CommandLine::help() const {
printf("Arguments:\n");
for (auto arg : mArgsOrder) {
logArg(*arg.data());
}
}

View file

@ -0,0 +1,36 @@
#pragma once
#include "CommandLine.hpp"
#include "Map.hpp"
namespace tp {
class CmdLineInterpreter {
public:
typedef bool (*CommandFunction)(void* customData, const CommandLine& args);
private:
struct Command {
CommandLine* args;
CommandFunction function;
void* customData = nullptr;
};
Map<String, Command> mCommands;
String mName = "InterpName";
public:
CmdLineInterpreter();
~CmdLineInterpreter();
void setName(const String& name) { mName = name; }
[[nodiscard]] const String& getName() const { return mName; }
void help(const CommandLine& args) const;
void addCommand(const String& id, CommandLine* args, CommandFunction function, void* customData = nullptr);
void run();
bool processCommand(int1* command);
};
}

View file

@ -0,0 +1,114 @@
#pragma once
#include "Map.hpp"
#include "LocalConnection.hpp"
#include "Tokenizer.hpp"
namespace tp {
extern ModuleManifest gModuleCommandLine;
struct CommandLine {
struct IntArg {
alni mVal = 0;
alni mDefault = 0;
Range<alni> mAcceptingRange = { -(std::numeric_limits<alni>::max() - 1), std::numeric_limits<alni>::max() };
};
struct FloatArg {
alnf mVal = 0.f;
alnf mDefault = 0.f;
Range<alnf> mAcceptingRange = { -(std::numeric_limits<alnf>::max() - 1), std::numeric_limits<alnf>::max() };
};
struct BoolArg {
bool mFlag = false;
bool mDefault = false;
};
struct StringArg {
String mStr;
String mDefault;
};
struct FileInputArg {
LocalConnection::Location mFileLocation;
};
struct Arg {
String mId;
enum Type { INT, FLOAT, BOOL, STR, FILE_IN, NONE } mType = NONE;
union {
IntArg mInt;
FloatArg mFloat;
BoolArg mBool;
StringArg mStr;
FileInputArg mFile;
};
bool mOptional = true;
bool mIsPassed = false;
Arg(const Arg& arg);
Arg(const String& id, Type type);
Arg(const String& id, const Range<alni>& aAcceptingRange);
Arg(const String& id, const Range<alnf>& aAcceptingRange);
Arg(const String& id, const Range<alni>& aAcceptingRange, alni aDefault);
Arg(const String& id, const Range<alnf>& aAcceptingRange, alnf aDefault);
Arg(const String& id, bool aDefault);
Arg(const String& id, const char* aDefault);
~Arg();
};
struct Error {
const char* mDescr = nullptr;
Arg* mArg = nullptr;
operator bool() { return mDescr != nullptr; }
} mError;
CommandLine(const InitialierList<Arg>& args);
~CommandLine();
void resetError() { mError.mDescr = nullptr; }
bool parse(char argc, const char* argv[], bool logError = true, ualni skipArgs = 1);
bool parse(const char* args, bool logError = true);
void help() const;
[[nodiscard]] alni getInt(const String& id) const;
[[nodiscard]] alnf getFloat(const String& id) const;
[[nodiscard]] bool getBool(const String& id) const;
[[nodiscard]] const String& getString(const String& id) const;
[[nodiscard]] const LocalConnection::Location& getFile(const String& id) const;
const CommandLine& operator=(const CommandLine&) = delete;
private:
enum class TokType { SPACE, INT, FLOAT, BOOL_FALSE, BOOL_TRUE, STR, NONE, FAILURE, END, };
typedef SimpleTokenizer<char, TokType, TokType::NONE, TokType::FAILURE, TokType::END> Tokenizer;
Tokenizer mTokenizer;
Map<String, Arg*> mArgs;
List<Arg*> mArgsOrder;
ualni mOptionals = 0;
enum class ArgTokType { SPACE, ARG, NONE, FAILURE, END, };
SimpleTokenizer<char, ArgTokType, ArgTokType::NONE, ArgTokType::FAILURE, ArgTokType::END> mArgumentTokenizer;
Arg& getArg(const String& id, Arg::Type type);
[[nodiscard]] const Arg& getArg(const String& id, Arg::Type type) const;
void ErrInvalidArgCount();
void ErrInvalidArgSyntax(Arg* arg);
void ErrInvalidArgType(Arg* arg);
void ErrFileNotExists(Arg* arg);
void ErrFileCouldNotOpen(Arg* arg);
void ErrValNotinRange(Arg* arg);
void ErrLog();
static void logArg(const Arg& arg);
static void initDefault(Arg& arg);
void parseArg(Arg& arg, const char* src);
};
}

View file

@ -0,0 +1,25 @@
#include "NewPlacement.hpp"
#include "Tests.hpp"
using namespace tp;
static CommandLine createCmdLine() {
CommandLine cmd({
{ "bool", CommandLine::Arg::BOOL },
{ "int", CommandLine::Arg::INT },
{ "string", CommandLine::Arg::STR },
{ "float", CommandLine::Arg::FLOAT },
});
return cmd;
}
TEST_DEF_STATIC(Simple) {
auto cmd = createCmdLine();
const char* args[] = { "false", "2", "'str'", "-0.15" };
cmd.parse(4, args, true, 0);
}
TEST_DEF(CommandLine) {
testSimple();
}

View file

@ -0,0 +1,36 @@
#include "NewPlacement.hpp"
#include "Tests.hpp"
#include "CmdLineInterpreter.hpp"
using namespace tp;
TEST_DEF_STATIC(Simple) {
struct TestStruct {
int val = 0;
static bool print(TestStruct* self, const CommandLine& args) {
printf("Test Val - %i\n", (int) args.getBool("bool"));
return false;
}
};
TestStruct self;
CmdLineInterpreter interp;
interp.addCommand("test", new CommandLine{ { "bool", CommandLine::Arg::BOOL } }, (CmdLineInterpreter::CommandFunction) TestStruct::print);
printf("test false\n", stdin);
printf("help\n", stdin);
printf("help test\n", stdin);
printf("exit\n", stdin);
interp.run();
}
TEST_DEF(Interpreter) {
//testSimple();
}

View file

@ -0,0 +1,18 @@
#include "NewPlacement.hpp"
#include "Tests.hpp"
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleTokenizer, nullptr };
tp::ModuleManifest testModule("CommandLineTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
// testCommandLine();
testInterpreter();
testModule.deinitialize();
}

View file

@ -0,0 +1,8 @@
#pragma once
#include "Testing.hpp"
#include "Allocators.hpp"
#include "CommandLine.hpp"
void testCommandLine();
void testInterpreter();

25
Connection/CMakeLists.txt Normal file
View file

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 23)
project(Connection)
set(BINDINGS_INCLUDE ./../Externals/asio/asio/include)
### ---------------------- 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_include_directories(${PROJECT_NAME} PRIVATE ${BINDINGS_INCLUDE})
target_link_libraries(${PROJECT_NAME} PUBLIC Strings)
### -------------------------- 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)

View file

@ -0,0 +1,9 @@
#include "ConnectionCommon.hpp"
static tp::ModuleManifest* sModuleDependencies[] = {
&tp::gModuleStrings,
nullptr
};
tp::ModuleManifest tp::gModuleConnection = ModuleManifest("Storage", nullptr, nullptr, sModuleDependencies);

View file

@ -0,0 +1,92 @@
#include "NewPlacement.hpp"
#include "LocalConnection.hpp"
#include "bindings/Disk.hpp"
#include <cstdio>
using namespace tp;
bool LocalConnection::Location::exists() const {
FILE* file = fopen(mLocation.read(), "r");
if (file) {
// File exists, close it and return 1
fclose(file);
return true;
}
return false;
}
bool LocalConnection::connect(const Location& location, const Type& connectionInfo) {
DEBUG_ASSERT(!mStatus.isOpened());
if (mStatus.isOpened()) return false;
auto handle = new LocalConnectionContext();
switch (connectionInfo.getType()) {
case Type::READ:
handle->open(location.getLocation().read(), true);
break;
case Type::WRITE:
handle->open(location.getLocation().read(), false);
break;
default:
break;
};
if (!handle->isOpen()) {
mStatus.setStatus(Status::DENIED);
delete handle;
return false;
}
mStatus.setStatus(Status::OPENED);
mHandle = handle;
mConnectionType = connectionInfo;
return true;
}
bool LocalConnection::disconnect() {
DEBUG_ASSERT(mStatus.isOpened());
if (!mStatus.isOpened() || !mHandle) return false;
mHandle->close();
delete mHandle;
mStatus.setStatus(Status::CLOSED);
return true;
}
bool LocalConnection::setPointer(BytePointer pointer) {
DEBUG_ASSERT(mStatus.isOpened());
if (!mStatus.isOpened()) return false;
mPointer = pointer;
return true;
}
bool LocalConnection::readBytes(Byte* bytes, SizeBytes size) {
DEBUG_ASSERT(mStatus.isOpened() && mConnectionType.isRead());
if (!mStatus.isOpened() || !mConnectionType.isRead()) return false;
mHandle->seekp(mPointer);
mHandle->read(bytes, size);
mPointer += size;
return true;
}
bool LocalConnection::writeBytes(const Byte* bytes, SizeBytes size) {
DEBUG_ASSERT(mStatus.isOpened() && mConnectionType.isWrite());
if (!mStatus.isOpened() || !mConnectionType.isWrite()) return false;
mHandle->seekp(mPointer);
mHandle->write(bytes, size);
mPointer += size;
return true;
}
LocalConnection::SizeBytes LocalConnection::size() {
DEBUG_ASSERT(mStatus.isOpened());
if (!mStatus.isOpened() || !mHandle) return 0;
return mHandle->size();
}

View file

@ -0,0 +1,2 @@
#include "RemoteConnection.hpp"

View file

@ -0,0 +1,57 @@
#include "Disk.hpp"
#include <fstream>
using namespace tp;
ualni tp::LocalConnectionContext::size() {
auto strm = (std::fstream*) stream;
ualni out = 0;
strm->seekg(0, std::ios::beg);
out = strm->tellg();
strm->seekg(0, std::ios::end);
out = (ualni) strm->tellg() - out;
return out;
}
LocalConnectionContext::LocalConnectionContext() {
stream = new std::fstream();
}
LocalConnectionContext::~LocalConnectionContext() {
auto strm = (std::fstream*) stream;
delete strm;
}
bool LocalConnectionContext::isOpen() {
auto strm = (std::fstream*) stream;
return strm->is_open();
}
void LocalConnectionContext::close() {
auto strm = (std::fstream*) stream;
strm->close();
}
void LocalConnectionContext::seekp(ualni in) {
auto strm = (std::fstream*) stream;
strm->seekp(in);
}
void LocalConnectionContext::read(int1* in, ualni size) {
auto strm = (std::fstream*) stream;
strm->read(in, size);
}
void LocalConnectionContext::write(const int1* in, ualni size) {
auto strm = (std::fstream*) stream;
strm->write(in, size);
}
void LocalConnectionContext::open(const char* path, bool read) {
auto strm = (std::fstream*) stream;
if (read)
strm->open(path, std::ios::in | std::ios::binary | std::ios::app);
else
strm->open(path, std::ios::out | std::ios::binary | std::ios::trunc);
}

View file

@ -0,0 +1,17 @@
#include "Common.hpp"
namespace tp {
class LocalConnectionContext {
void* stream;
public:
LocalConnectionContext();
~LocalConnectionContext();
void open(const char*, bool);
bool isOpen();
void close();
void seekp(ualni);
void read(int1*, ualni);
void write(const int1*, ualni);
ualni size();
};
}

View file

@ -0,0 +1,130 @@
#include "Network.hpp"
#include "asio.hpp"
#include <iostream>
using namespace tp;
class tp::ServerContext {
friend class Server;
asio::io_context context;
asio::ip::tcp::acceptor socket;
typedef asio::ip::tcp::socket Socket;
ServerContext() : socket(context) {}
~ServerContext() {
context.stop();
socket.close();
}
};
class tp::ClientContext {
friend Client;
asio::io_context context;
asio::ip::tcp::socket socket;
public:
ClientContext() : socket(context) {}
~ClientContext() {
context.stop();
socket.close();
}
};
// --------------------------------------------------------------------------------------- //
Server::Server() {
mContext = new ServerContext();
}
Server::~Server() {
delete mContext;
assert(0);
}
void Server::start(ualni port) {
mContext->socket.open(asio::ip::tcp::v4());
mContext->socket.bind(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port));
mContext->socket.listen();
std::cout << "Server listening on port " << port << std::endl;
}
Server::Socket Server::accept() {
auto clientSocket = new asio::ip::tcp::socket(mContext->context);
mContext->socket.accept(*clientSocket);
std::cout << "New client accepted "<< std::endl;
return clientSocket;
}
int1* Server::read(Socket client) {
short messageSize;
if (asio::read(*(ServerContext::Socket*)client, asio::buffer(&messageSize, 2)) == -1) {
std::cerr << "Failed to read from socket" << std::endl;
((ServerContext::Socket*)client)->close();
return nullptr;
}
auto message = new char[messageSize + 1];
message[messageSize] = '\0';
if (asio::read(*(ServerContext::Socket*)client, asio::buffer(message, messageSize)) == -1) {
std::cerr << "Failed to read from socket" << std::endl;
memcpy(message, "Client wanna say something but i cant read", 100);
}
return message;
}
void Server::write(Socket client, const char* message) {
auto messageSize = (short) strlen(message);
if (asio::write(*(ServerContext::Socket*)client, asio::buffer(&messageSize, 2)) == -1) {
std::cerr << "Failed to write to socket" << std::endl;
}
if (asio::write(*(ServerContext::Socket*)client, asio::buffer(message, messageSize)) == -1) {
std::cerr << "Failed to write to socket" << std::endl;
}
}
// --------------------------------------------------------------------------------------- //
Client::Client() {
mContext = new ClientContext();
}
Client::~Client() {
delete mContext;
assert(0);
}
void Client::connect(const char* IP, ualni PORT) {
asio::ip::tcp::endpoint endpoint(asio::ip::address::from_string(IP), PORT);
mContext->socket.connect(endpoint);
}
char* Client::read() {
short messageSize;
if (asio::read(mContext->socket, asio::buffer(&messageSize, 2)) == -1) {
std::cerr << "Failed to read from socket" << std::endl;
return nullptr;
}
auto message = new char[messageSize + 1];
message[messageSize] = '\0';
if (asio::read(mContext->socket, asio::buffer(message, messageSize)) == -1) {
std::cerr << "Failed to read from socket" << std::endl;
memcpy(message, "Cant wanna say something but i cant read", 100);
}
return message;
}
void Client::write( const char* message ) {
auto messageSize = (short) strlen(message);
if (asio::write(mContext->socket, asio::buffer(&messageSize, 2)) == -1) {
std::cerr << "Failed to write to socket" << std::endl;
}
if (asio::write(mContext->socket, asio::buffer(message, messageSize)) == -1) {
std::cerr << "Failed to write to socket" << std::endl;
}
}

View file

@ -0,0 +1,36 @@
#pragma once
#include "Common.hpp"
namespace tp {
class ServerContext;
class ClientContext;
class Server {
ServerContext* mContext;
public:
typedef void* Socket;
public:
Server();
~Server();
void start(ualni port);
Socket accept();
static int1* read(Socket client);
static void write(Socket client, const int1* message);
};
class Client {
ClientContext* mContext;
public:
Client();
~Client();
void connect(const int1* IP, ualni PORT);
int1* read();
void write(const int1* message);
};
}

View file

@ -0,0 +1,65 @@
#pragma once
#include "Strings.hpp"
namespace tp {
extern ModuleManifest gModuleConnection;
class Connection {
public:
typedef ualni SizeBytes;
typedef ualni BytePointer;
typedef int1 Byte;
class Status {
public:
enum State {
NONE,
OPENED,
CLOSED,
DENIED,
INVALID,
};
private:
State mStatus = NONE;
public:
Status() = default;
[[nodiscard]] State getStatus() const { return mStatus; }
void setStatus(State status) { mStatus = status; }
[[nodiscard]] bool isOpened() const { return mStatus == OPENED; }
};
class Type {
public:
enum State {
WRITE,
READ,
READ_WRITE,
NONE,
};
private:
State mHandleType = NONE;
public:
Type() = default;
explicit Type(bool read) : mHandleType((State) read) {}
explicit Type(State handleType) : mHandleType(handleType) {}
[[nodiscard]] State getType() const { return mHandleType; }
[[nodiscard]] bool isRead() const { return mHandleType == READ; }
[[nodiscard]] bool isWrite() const { return mHandleType == WRITE; }
};
protected:
Status mStatus;
Type mConnectionType;
public:
Connection() = default;
virtual const Status& getConnectionStatus() { return mStatus; }
virtual const Type& getConnectionType() { return mConnectionType; }
};
}

View file

@ -0,0 +1,51 @@
#pragma once
#include "ConnectionCommon.hpp"
namespace tp {
class LocalConnectionContext;
class LocalConnection : public Connection {
public:
class Location {
String mLocation;
public:
Location() : mLocation("tmp") {};
explicit Location(const String& location) : mLocation(location) {}
void setLocation(const String& location) { mLocation = location; }
[[nodiscard]] const String& getLocation() const { return mLocation; }
[[nodiscard]] bool exists() const;
};
public:
LocalConnection() {
MODULE_SANITY_CHECK(gModuleConnection)
};
virtual ~LocalConnection() {
if (mStatus.isOpened()) LocalConnection::disconnect();
}
public:
virtual bool connect(const Location& location, const Type& connectionInfo);
virtual bool disconnect();
public:
virtual const Status& getConnectionStatus() { return mStatus; }
virtual const Type& getConnectionType() { return mConnectionType; }
virtual const Location& getLocation() { return mLocation; }
public:
virtual bool setPointer(BytePointer pointer);
virtual bool readBytes(Byte* bytes, SizeBytes size);
virtual bool writeBytes(const Byte* bytes, SizeBytes size);
public:
virtual SizeBytes size();
private:
LocalConnectionContext* mHandle = nullptr;
Location mLocation;
BytePointer mPointer = 0;
};
}

View file

@ -0,0 +1,42 @@
#pragma once
#include "ConnectionCommon.hpp"
#include "List.hpp"
namespace tp {
class RemoteConnectionContext;
class RemoteConnection : public Connection {
public:
class Location {
ualni mId = 0;
public:
Location() = default;
};
public:
RemoteConnection() {
MODULE_SANITY_CHECK(gModuleConnection)
};
virtual ~RemoteConnection() {
if (mStatus.isOpened()) RemoteConnection::disconnect();
}
public:
virtual bool connect(const Location& location, const Type& connectionInfo);
virtual bool disconnect();
public:
virtual const Location& getLocation() { return mLocation; }
public:
virtual bool readBytes(Byte* bytes, SizeBytes size);
virtual bool writeBytes(const Byte* bytes, SizeBytes size);
private:
RemoteConnectionContext* mHandle = nullptr;
Location mLocation;
};
}

View file

@ -0,0 +1,35 @@
#include "NewPlacement.hpp"
#include "LocalConnection.hpp"
#include "Testing.hpp"
using namespace tp;
TEST_DEF_STATIC(Simple) {
const int1* data = "abcde\0";
int1 dataRead[6]{};
{
LocalConnection file;
file.connect(LocalConnection::Location(String("tmp2.txt")), LocalConnection::Type(false));
file.writeBytes(data, 6);
file.disconnect();
}
{
LocalConnection file;
file.connect(LocalConnection::Location(String("tmp2.txt")), LocalConnection::Type(true));
file.readBytes(dataRead, 6);
file.disconnect();
}
for (auto i = 0; i < 5; i++) {
TEST(data[i] == dataRead[i]);
}
}
TEST_DEF(LocalConnection) {
testSimple();
}

View file

@ -0,0 +1,19 @@
#include "ConnectionCommon.hpp"
#include "Testing.hpp"
void testLocalConnection();
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleConnection, nullptr };
tp::ModuleManifest testModule("ConnectionTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
testLocalConnection();
testModule.deinitialize();
}

View file

@ -16,7 +16,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Modules)
enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils)
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Allocators)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib)

View file

@ -20,42 +20,140 @@ namespace tp {
template<typename tType, ualni tSize>
class ConstSizeBuffer {
SelCopyArg<tType> Arg;
typedef SelectValueOrReference<tType> Arg;
private:
tType mBuff[tSize];
ualni mLoad = 0;
public:
ConstSizeBuffer() = default;
~ConstSizeBuffer() {
for (auto i = 0; i < mLoad; i++) {
mBuff[i].~tType();
}
}
public:
[[nodiscard]] ualni size() const { return tSize; }
[[nodiscard]] ualni size() const { return mLoad; }
[[nodiscard]] ualni getBuffSize() const { return tSize; }
tType& first() {
DEBUG_ASSERT(mLoad)
return *mBuff;
}
const tType& first() const {
DEBUG_ASSERT(mLoad)
return *mBuff;
}
tType& last() {
return mBuff[tSize - 1];
DEBUG_ASSERT(mLoad)
return mBuff[mLoad - 1];
}
const tType& last() const {
return mBuff[tSize - 1];
DEBUG_ASSERT(mLoad)
return mBuff[mLoad - 1];
}
tType& operator[](ualni aIdx) {
DEBUG_ASSERT(aIdx >= 0 && aIdx < tSize)
DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad)
return mBuff[aIdx];
}
const tType& operator[](ualni aIdx) const {
DEBUG_ASSERT(aIdx >= 0 && aIdx < tSize)
DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad)
return mBuff[aIdx];
}
void append(Arg data) {
ASSERT(mLoad != tSize)
new (&mBuff[mLoad]) tType(data);
mLoad++;
}
void pop() {
DEBUG_ASSERT(mLoad)
mBuff[mLoad].~tType();
mLoad--;
}
ConstSizeBuffer& operator=(const tp::InitialierList<tType>& init) {
for (auto arg : init) {
append(arg);
}
return *this;
}
void clear() {
this->~ConstSizeBuffer();
new (this) ConstSizeBuffer();
}
public:
class IteratorPointer {
protected:
tType* mIter;
public:
IteratorPointer() = default;
tType& operator->() { return *mIter; }
const tType& operator->() const { return *mIter; }
};
class IteratorReference {
protected:
tType* mIter;
public:
IteratorReference() = default;
tType* operator->() { return mIter; }
const tType* operator->() const { return mIter; }
};
class Iterator : public TypeSelect<TypeTraits<tType>::isPointer, IteratorPointer, IteratorReference>::Result {
public:
explicit Iterator(tType* iter) { this->mIter = iter; }
const Iterator& operator*() const { return *this; }
Iterator& operator++() {
this->mIter++;
return *this;
}
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
};
[[nodiscard]] Iterator begin() const {
return Iterator(mBuff);
}
[[nodiscard]] Iterator end() const {
return Iterator(mBuff + mLoad);
}
public:
template<class tArchiver>
void archiveWrite(tArchiver& ar) const {
ar << mLoad;
for (auto item : *this) {
ar << item.data();
}
}
template<class tArchiver>
void archiveRead(tArchiver& ar) {
clear();
ar >> mLoad;
for (auto i = 0; i < mLoad; i++) {
ar >> mBuff[i];
}
}
};
template<
@ -66,7 +164,7 @@ namespace tp {
ualni tMinSize = 4
>
class Buffer {
typedef SelCopyArg<tType> Arg;
typedef SelectValueOrReference<tType> Arg;
private:
tType* mBuff;
@ -80,7 +178,7 @@ namespace tp {
}
explicit Buffer(ualni size) : mSize(size), mLoad(0) {
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * tMinSize);
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * size);
}
Buffer(const Buffer& in) : mSize(in.mSize), mLoad(in.mLoad) {
@ -88,10 +186,14 @@ namespace tp {
for (ualni i = 0; i < mLoad; i++) new (&mBuff[i]) tType(in.mBuff[i]);
}
void clear() {
this->~Buffer();
new (this) Buffer();
}
Buffer& operator=(const Buffer& in) {
if (this == &in) return *this;
this->~Buffer();
new (this) Buffer(in);
clear();
return *this;
}
@ -150,6 +252,14 @@ namespace tp {
}
public:
Buffer& operator=(const tp::InitialierList<tType>& init) {
// TODO : optimize
for (auto arg : init) {
append(arg);
}
return *this;
}
void append(Arg data) {
if (mLoad == mSize) resizeBuffer(tResizePolicy(mSize));
new (&mBuff[mLoad]) tType(data);
@ -175,6 +285,83 @@ namespace tp {
if (prevSize > mLoad) resizeBuffer(prevSize);
}
void reserve(ualni aSize) {
for (ualni i = 0; i < mLoad; i++) mBuff[i].~tType();
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * aSize);
mSize = aSize;
mLoad = aSize;
for (ualni i = 0; i < mLoad; i++) new (mBuff + i) tType();
}
public:
class IteratorPointer {
protected:
tType* mIter;
public:
IteratorPointer() = default;
tType& operator->() { return *mIter; }
const tType& operator->() const { return *mIter; }
};
class IteratorReference {
protected:
tType* mIter;
public:
IteratorReference() = default;
tType* operator->() { return mIter; }
const tType* operator->() const { return mIter; }
};
class Iterator : public TypeSelect<TypeTraits<tType>::isPointer, IteratorPointer, IteratorReference>::Result {
public:
explicit Iterator(tType* iter) { this->mIter = iter; }
const Iterator& operator*() const { return *this; }
tType& data() {
return *this->mIter;
}
Iterator& operator++() {
this->mIter++;
return *this;
}
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
};
[[nodiscard]] Iterator begin() const {
return Iterator(mBuff);
}
[[nodiscard]] Iterator end() const {
return Iterator(mBuff + mLoad);
}
public:
template<class tArchiver>
void archiveWrite(tArchiver& ar) const {
ar << mLoad;
for (auto item : *this) {
ar << item.data();
}
}
template<class tArchiver>
void archiveRead(tArchiver& ar) {
clear();
decltype(mLoad) len;
ar >> len;
for (auto i = len; i; i--) {
// TODO : optimize
if (mLoad == mSize) resizeBuffer(tResizePolicy(mSize));
ar >> mBuff[mLoad];
mLoad++;
}
}
private:
void resizeBuffer(ualni newSize) {
@ -187,4 +374,36 @@ namespace tp {
mSize = newSize;
}
};
template<typename tType>
void generatePermutations(const Buffer<Buffer<tType>>& in, Buffer<Buffer<tType>>& out) {
typedef long long Idx;
// sanity check
for (const auto & vec : in) {
if (!vec.size()) return;
}
out.resize(in.size());
auto len = Idx(1);
for (const auto & vec : in) len *= (Idx) vec.size();
for (auto i = 0; i < in.size(); i++) out[i].resize(len);
auto dub = Idx(1);
for (auto power = (Idx) in.size() - 1; power >= 0; power--) {
auto& vec = in[power];
long long i = 0;
while (i < len) {
for (auto val : vec) {
for (auto j = 0; j < dub; j++) {
out[power][i] = val;
i++;
}
}
}
dub *= (Idx) vec.size();
}
}
}

View file

@ -0,0 +1,112 @@
#include "Buffer.hpp"
#include "Utils.hpp"
namespace tp {
template< typename tType, ualni tSizeX, ualni tSizeY >
using ConstSizeBuffer2D = ConstSizeBuffer<ConstSizeBuffer<tType, tSizeX>, tSizeY>;
template <
typename tType,
class tAllocator = DefaultAllocator
>
class Buffer2D {
public:
typedef ualni Index;
typedef Pair<Index, Index> Index2D;
typedef SelectValueOrReference<tType> tTypeArg;
private:
tAllocator mAlloc;
tType* mBuff = nullptr;
Index2D mSize = { 0, 0 };
void deleteBuffer() {
if (!mBuff) return;
for (ualni i = 0; i < mSize.x * mSize.y; i++) mBuff[i].~tType();
mAlloc.deallocate(mBuff);
}
void allocateBuffer(Index2D size) {
deleteBuffer();
mBuff = (tType*) mAlloc.allocate(sizeof(tType) * size.x * size.y);
for (ualni i = 0; i < mSize.x * mSize.y; i++) new (mBuff + i) tType();
}
public:
Buffer2D() = default;
~Buffer2D() {
deleteBuffer();
mSize = { 0, 0 };
}
explicit Buffer2D(Index2D aSize) {
reserve(aSize);
}
[[nodiscard]] Index2D size() const {
return { mSize.x, mSize.y };
}
tType* getBuff() const {
return mBuff;
}
inline tType& get(const Index2D& at) {
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
return *(mBuff + mSize.x * at.y + at.x);
}
inline const tType& get(const Index2D& at) const {
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
return *(mBuff + mSize.x * at.y + at.x);
}
inline void set(const Index2D& at, tTypeArg value) {
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
*(mBuff + mSize.x * at.y + at.x) = value;
}
void reserve(const Index2D& newSize) {
if (mSize.x != newSize.x || mSize.y != newSize.y) {
allocateBuffer(newSize);
mSize = newSize;
}
}
void assign(tType value) {
DEBUG_ASSERT(mBuff);
Index len = mSize.x * mSize.y;
for (Index i = 0; i < len; i++) {
mBuff[i] = value;
}
}
public:
template<class tArchiver>
void archiveWrite(tArchiver& ar) const {
ar << mSize;
for (auto i = 0; i < mSize.x; i++) {
for (auto j = 0; j < mSize.y; j++) {
ar << get(i, j);
}
}
}
template<class tArchiver>
void archiveRead(tArchiver& ar) {
decltype(mSize) size;
deleteBuffer();
ar >> size;
reserve(size);
for (auto i = 0; i < mSize.x; i++) {
for (auto j = 0; j < mSize.y; j++) {
ar >> get(i, j);
}
}
}
};
}

View file

@ -10,7 +10,7 @@ namespace tp {
template <typename Type, class Allocator = DefaultAllocator>
class List {
typedef SelCopyArg<Type> TypeArg;
typedef SelectValueOrReference<Type> TypeArg;
typedef ualni Index;
public:
@ -72,8 +72,8 @@ namespace tp {
public:
List() = default;
List(const init_list<Type>& list) { operator=(list); }
List(const List& in) { this->operator=(in); }
List(const InitialierList<Type>& list) { operator=(list); }
[[nodiscard]] inline Node* first() const { return mFirst; }
[[nodiscard]] inline Node* last() const { return mLast; }
@ -146,7 +146,7 @@ namespace tp {
}
[[nodiscard]] Node* findIdx(Index idx) const {
DEBUG_ASSERT(!mFirst || idx > mLength - 1)
DEBUG_ASSERT(mFirst && idx < mLength && idx >= 0)
Node* found = mFirst;
for (int i = 0; i != idx; i++) {
found = found->next;
@ -157,6 +157,7 @@ namespace tp {
[[nodiscard]] Node* find(const TypeArg data) const {
Node* found = mFirst;
for (alni i = 0; data != found->data; i++) {
if (i == length()) return nullptr;
if (!found->next) {
return nullptr;
}
@ -177,8 +178,9 @@ namespace tp {
void popBack() {
DEBUG_ASSERT(mLast)
auto const tmp = mLast;
detach(mLast);
deleteNode(mLast);
deleteNode(tmp);
}
void popFront() {
@ -221,7 +223,7 @@ namespace tp {
return *this;
}
List& operator+=(const init_list<Type>& list) {
List& operator+=(const InitialierList<Type>& list) {
for (auto item : list) {
pushBack(item);
}
@ -235,14 +237,14 @@ namespace tp {
return *this;
}
List& operator=(const init_list<Type>& list) {
List& operator=(const InitialierList<Type>& list) {
removeAll();
*this += list;
return *this;
}
[[nodiscard]] bool operator==(const List& in) const {
if (in == *this) { return true; }
if (&in == this) { return true; }
if (in.length() != length()) {
return false;
}
@ -252,6 +254,8 @@ namespace tp {
if (left->data != right->data) {
return false;
}
left = left->next;
right = right->next;
}
if (left != right) {
return false;
@ -295,22 +299,23 @@ namespace tp {
}
}
template<class Saver>
void write(Saver& file) const {
file.write(mLength);
public:
template<class tArchiver>
void archiveWrite(tArchiver& ar) const {
ar << mLength;
for (auto item : *this) {
file.write(item.data());
ar << item.data();
}
}
template<class Loader>
void read(Loader& file) {
template<class tArchiver>
void archiveRead(tArchiver& ar) {
removeAll();
ualni len;
file.read(len);
decltype(mLength) len;
ar >> len;
for (auto i = len; i; i--) {
auto node = newNodeNotConstructed();
file.read(node->data);
ar >> node->data;
pushBack(node);
}
}

View file

@ -7,11 +7,11 @@
namespace tp {
template<typename Key>
ualni DefaultHashFunc(SelCopyArg<Key> key) {
ualni DefaultHashFunc(SelectValueOrReference<Key> key) {
return hash(key);
}
template<typename tKey, typename tVal, class tAllocator = DefaultAllocator, ualni(*tHashFunc)(SelCopyArg<tKey>) = DefaultHashFunc<tKey>, int tTableInitialSize = 4>
template<typename tKey, typename tVal, class tAllocator = DefaultAllocator, ualni(*tHashFunc)(SelectValueOrReference<tKey>) = DefaultHashFunc<tKey>, int tTableInitialSize = 4>
class Map {
enum {
@ -20,8 +20,8 @@ namespace tp {
MAP_MAX_LOAD_PERCENTAGE = 66,
};
typedef SelCopyArg<tKey> KeyArg;
typedef SelCopyArg<tVal> ValArg;
typedef SelectValueOrReference<tKey> KeyArg;
typedef SelectValueOrReference<tVal> ValArg;
public:
@ -35,12 +35,13 @@ namespace tp {
struct Idx {
alni idx = -1;
operator bool() { return idx != -1; }
[[nodiscard]] bool isValid() const { return bool(*this); }
explicit operator bool() const { return idx != -1; }
};
private:
tAllocator mAlloc;
Node** mTable;
Node** mTable = nullptr;
ualni mNSlots = 0;
ualni mNEntries = 0;
@ -180,6 +181,10 @@ namespace tp {
mTable = newTable(mNSlots);
}
Map(const Map& in) {
this->operator=(in);
}
Node** buff() const {
return mTable;
}
@ -201,8 +206,9 @@ namespace tp {
if (!mTable[idx] || isDeletedNode(mTable[idx])) {
mTable[idx] = newNode(key, val);
mNEntries++;
}
} else {
mTable[idx]->val = val;
}
if ((halnf) mNEntries / mNSlots > maxLoadFactor()) {
rehash();
}
@ -247,7 +253,7 @@ namespace tp {
const tVal& getSlotVal(Idx slot) const {
DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error")
return mTable[slot]->val;
return mTable[slot.idx]->val;
}
tVal& getSlotVal(Idx slot) {
@ -365,28 +371,35 @@ namespace tp {
return mNSlots;
}
template<class Saver>
void write(Saver& file) {
file.write(mNEntries);
template<class Archiver>
void archiveWrite(Archiver& ar) const {
ar << mNEntries;
for (auto item : *this) {
file.write(item->val);
file.write(item->key);
ar << item->val;
ar << item->key;
}
}
template<class Loader>
void read(Loader& file) {
template<class Archiver>
void archiveRead(Archiver& ar) {
removeAll();
ualni len;
file.read(len);
decltype(mNSlots) len;
ar >> len;
for (auto i = len; i; i--) {
auto node = newNodeNotConstructed();
file.read(node->val);
file.read(node->key);
ar >> node->val;
ar >> node->key;
put(node);
}
}
~Map() { removeAll(); }
~Map() {
for (ualni i = 0; i < mNSlots; i++) {
if (mTable[i] && !isDeletedNode(mTable[i])) {
deleteNode(mTable[i]);
}
}
deleteTable(mTable);
}
};
}

View file

@ -25,8 +25,8 @@ namespace tp {
template <typename Key, typename Data, class Allocator = DefaultAllocator>
class AvlTree {
typedef SelCopyArg<Key> KeyArg;
typedef SelCopyArg<Data> DataArg;
typedef SelectValueOrReference<Key> KeyArg;
typedef SelectValueOrReference<Data> DataArg;
public:
class Node {
@ -369,5 +369,32 @@ namespace tp {
}
bool isValid() { return findInvalidNode(head()) == nullptr; }
template<typename tFunctor>
void traverse(Node* node, bool after, tFunctor functor) {
if (!after) functor(node);
if (node->mLeft) traverse(node->mLeft, after, functor);
if (node->mRight) traverse(node->mRight, after, functor);
if (after) functor(node);
}
void removeAll() {
traverse(mRoot, true, [this](Node* node) {
deleteNode(node);
});
mRoot = nullptr;
mSize = 0;
}
public:
template<class tArchiver>
void archiveWrite(tArchiver& file) const {
FAIL("not implemented")
}
template<class tArchiver>
void archiveRead(tArchiver&) {
FAIL("not implemented")
}
};
}

View file

@ -0,0 +1,25 @@
#include "NewPlacement.hpp"
#include "Tests.hpp"
#include "Testing.hpp"
#include "Buffer2D.hpp"
using namespace tp;
const ualni size = 1000;
TEST_DEF_STATIC(Simple1) {
Buffer2D<int, HeapAlloc> buff;
buff.reserve({ 4, 4 });
buff.set( { 2, 2 }, 5);
TEST(buff.get( { 2, 2 } ) == 5);
}
TEST_DEF_STATIC(Simple2) {
// TEST(false);
}
TEST_DEF(Buffer2d) {
testSimple1();
testSimple2();
}

View file

@ -1,18 +1,15 @@
#include "NewPlacement.hpp"
#include "Tests.hpp"
#include "Buffer.hpp"
#include "Testing.hpp"
#include <iostream>
using namespace tp;
const ualni size = 1000;
TEST_DEF_STATIC(Simple1) {
Buffer<TestClass> buff;
Buffer<TestClass, HeapAlloc> buff;
TEST(buff.size() == 0);
for (auto i : Range(size * 10)) {
buff.append(TestClass(i));
@ -23,7 +20,7 @@ TEST_DEF_STATIC(Simple1) {
}
TEST_DEF_STATIC(Simple2) {
Buffer<TestClass> buff(size);
Buffer<TestClass, HeapAlloc> buff(size);
TEST(buff.size() == 0);
for (auto i : Range(size * 10)) buff.append(TestClass(i));
TEST(buff.size() == size * 10);

View file

@ -1,13 +1,13 @@
#include "NewPlacement.hpp"
#include "Tests.hpp"
#include "Testing.hpp"
#include <iostream>
#include "Archiver.hpp"
using namespace tp;
TEST_DEF_STATIC(SimpleReference) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
tp::List<TestClass, HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
list.pushBack(TestClass(5));
list.pushFront(TestClass(0));
@ -21,11 +21,10 @@ TEST_DEF_STATIC(SimpleReference) {
TEST(i == 5);
list.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0);
}
TEST_DEF_STATIC(SimplePointer) {
tp::List<TestClass*, TestAllocator> list = { new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4) };
tp::List<TestClass*, HeapAlloc> list = { new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4) };
list.pushBack(new TestClass(5));
list.pushFront(new TestClass(0));
@ -38,36 +37,36 @@ TEST_DEF_STATIC(SimplePointer) {
TEST(i == 5);
list.removeAll();
for (auto iter : list) {
delete iter.data();
}
TEST(list.getAllocator().getAllocationsCount() == 0);
list.removeAll();
}
TEST_DEF_STATIC(Copy) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
tp::List<TestClass, TestAllocator> list2 = list;
tp::List<TestClass, HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
tp::List<TestClass, HeapAlloc> list2 = list;
TEST_EQUAL(list, list2);
list.removeAll();
list2.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0);
TEST(list2.getAllocator().getAllocationsCount() == 0);
}
TEST_DEF_STATIC(SaveLoad) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
TEST_DEF_STATIC(Serialization) {
tp::List<TestClass, HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
TestFile file;
ArchiverExample<1024, false> write;
ArchiverExample<1024, true> read;
list.write(file);
write % list;
list.removeAll();
file.setAddress(0);
memCopy(read.mBuff, write.mBuff, sizeof(write.mBuff));
list.read(file);
read % list;
ualni i = 0;
for (auto iter : list) {
@ -77,12 +76,10 @@ TEST_DEF_STATIC(SaveLoad) {
TEST(i == 4);
list.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0);
}
TEST_DEF(List) {
testSimplePointer();
testSimpleReference();
testSaveLoad();
testSerialization();
}

View file

@ -1,15 +1,14 @@
#include "NewPlacement.hpp"
#include "Tests.hpp"
#include "Testing.hpp"
#include "Map.hpp"
#include <iostream>
#include "Archiver.hpp"
using namespace tp;
TEST_DEF_STATIC(SimpleReference) {
tp::Map<tp::ualni, TestClass, TestAllocator> map;
tp::Map<tp::ualni, TestClass, HeapAlloc> map;
for (auto i : Range(1000, 100000)) {
map.put(i, TestClass(i));
@ -40,12 +39,10 @@ TEST_DEF_STATIC(SimpleReference) {
}
map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1);
}
TEST_DEF_STATIC(SimplePointer) {
tp::Map<tp::ualni, TestClass*, TestAllocator> map;
tp::Map<tp::ualni, TestClass*, HeapAlloc> map;
for (auto i : Range(1000)) {
map.put(i, new TestClass(i));
@ -57,11 +54,14 @@ TEST_DEF_STATIC(SimplePointer) {
}
for (auto i : Range(1000)) {
auto del = map.get(i);
map.put(i, new TestClass(i));
delete del;
}
for (auto i : Range(900, 1000)) {
TEST(map.presents(i));
delete map.get(i);
map.remove(i);
TEST(!map.presents(i));
}
@ -77,48 +77,44 @@ TEST_DEF_STATIC(SimplePointer) {
}
map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1);
}
TEST_DEF_STATIC(Copy) {
tp::Map<tp::ualni, TestClass, TestAllocator> map;
tp::Map<tp::ualni, TestClass, HeapAlloc> map;
for (auto i : Range(10)) {
map.put(i, TestClass(i));
}
tp::Map<tp::ualni, TestClass, TestAllocator> map2 = map;
tp::Map<tp::ualni, TestClass, HeapAlloc> map2 = map;
TEST_EQUAL(map, map2);
map.removeAll();
map2.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1);
TEST(map2.getAllocator().getAllocationsCount() == 1);
}
TEST_DEF_STATIC(SaveLoad) {
tp::Map<tp::ualni, TestClass, TestAllocator> map;
tp::Map<tp::ualni, TestClass, HeapAlloc> map;
for (auto i : Range(10)) {
map.put(i, TestClass(i));
}
TestFile file;
ArchiverExample<1024, false> write;
ArchiverExample<1024, true> read;
map.write(file);
write % map;
map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1);
TEST(map.size() == 0);
file.setAddress(0);
memCopy(read.mBuff, write.mBuff, sizeof(write.mBuff));
map.read(file);
read % map;
TEST(map.getAllocator().getAllocationsCount() == 11);
TEST(map.size() == 10);
for (auto i : Range(10)) {
TEST(map.presents(i));
@ -126,8 +122,6 @@ TEST_DEF_STATIC(SaveLoad) {
}
map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1);
}
TEST_DEF(Map) {

View file

@ -1,32 +1,15 @@
#include "Tests.hpp"
#include "Testing.hpp"
#include <cstdlib>
static bool init(const tp::ModuleManifest* self) {
tp::gTesting.setRootName(self->getName());
return true;
}
void* TestAllocator::allocate(tp::ualni size) {
nAllocations++;
return malloc(size);
}
void TestAllocator::deallocate(void* p) {
nAllocations--;
free(p);
}
tp::ualni TestAllocator::getAllocationsCount() const {
return nAllocations;
}
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleContainers, &tp::gModuleUtils, nullptr };
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleAllocators, nullptr };
tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps);
if (!testModule.initialize()) {
@ -37,6 +20,7 @@ int main() {
testMap();
testAvl();
testBuffer();
testBuffer2d();
testModule.deinitialize();
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "Utils.hpp"
#include "Allocators.hpp"
class TestClass {
tp::ualni val2 = 0;
@ -27,48 +28,9 @@ public:
void setVal(tp::ualni val) { val1 = val; }
};
class TestAllocator {
tp::ualni nAllocations = 0;
public:
TestAllocator() = default;
void* allocate(tp::ualni size);
void deallocate(void* p);
[[nodiscard]] tp::ualni getAllocationsCount() const;
};
class TestFile {
tp::ualni mem[1024] = { 0 };
tp::ualni address = 0;
public:
TestFile() = default;
template<typename Type>
void write(const Type& val) {
val.write(*this);
}
template<>
void write<tp::ualni>(const tp::ualni& val) {
mem[address] = val;
address++;
}
void setAddress(tp::ualni addr) { address = addr; }
template<typename Type>
void read(Type& val) {
val.read(*this);
}
template<>
void read<tp::ualni>(tp::ualni& val) {
val = mem[address];
address++;
}
};
void testList();
void testMap();
void testAvl();
void testBuffer();
void testBuffer2d();

View file

@ -1,16 +1,13 @@
#include "NewPlacement.hpp"
#include "Tests.hpp"
#include "Tree.hpp"
#include "Testing.hpp"
#include <iostream>
using namespace tp;
TEST_DEF_STATIC(Simple) {
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
AvlTree<AvlNumericKey<alni>, TestClass, HeapAlloc> tree;
TEST(tree.size() == 0);
TEST(tree.head() == nullptr);
@ -27,7 +24,7 @@ TEST_DEF_STATIC(Simple) {
}
TEST_DEF_STATIC(Persistance) {
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
AvlTree<AvlNumericKey<alni>, TestClass, HeapAlloc> tree;
const auto size = 1000;
@ -46,7 +43,7 @@ TEST_DEF_STATIC(Persistance) {
// random load
ualni loadSize = 0;
while (loadSize < size / 2) {
ualni idx = rand() % (size - 1);
auto idx = ualni(randomFloat() * (size - 1));
DEBUG_ASSERT(idx < size)
if (!buff[idx].presents) {
tree.insert((alni) buff[idx].data.getVal(), buff[idx].data);
@ -86,7 +83,7 @@ TEST_DEF_STATIC(Persistance) {
// random unload
ualni unloadSize = 0;
while (unloadSize < size / 2) {
ualni idx = rand() % (size - 1);
auto idx = ualni(randomFloat() * (size - 1));
if (buff[idx].presents) {
tree.remove((alni) buff[idx].data.getVal());

28
Externals/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,28 @@
add_subdirectory(glew/build/cmake/)
target_compile_definitions(glew_s PUBLIC GLEW_NO_GLU)
add_subdirectory(glfw)
project(Imgui)
set(${PROJECT_NAME}_SOURCES
imgui/imgui.cpp
imgui/imgui_draw.cpp
imgui/imgui_tables.cpp
imgui/imgui_widgets.cpp
imgui/backends/imgui_impl_glfw.cpp
imgui/backends/imgui_impl_opengl3.cpp
)
add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_SOURCES})
include_directories(${PROJECT_NAME} ./glfw/include)
target_include_directories(${PROJECT_NAME} PUBLIC ./imgui/ ./imgui/backends/)
project(Nanovg)
set(${PROJECT_NAME}_SOURCES
nanovg/src/nanovg.c
)
add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ./nanovg/src/ ./nanovg/obsolete/)

1
Externals/asio vendored Submodule

@ -0,0 +1 @@
Subproject commit d6b95c0188e0359a8cdbdb6571f0cbacf11a538c

1
Externals/glew vendored Submodule

@ -0,0 +1 @@
Subproject commit a98195b83df746202bdf5a6f92e9d4e86b497045

1
Externals/glfw vendored Submodule

@ -0,0 +1 @@
Subproject commit 3eaf1255b29fdf5c2895856c7be7d7185ef2b241

1
Externals/imgui vendored Submodule

@ -0,0 +1 @@
Subproject commit 4144d7d772a800f08693b8b13f7c81f1f22a73c4

1
Externals/nanovg vendored Submodule

@ -0,0 +1 @@
Subproject commit 7544c114e83db7cf67bd1c9e012349b70caacc2f

34
Graphics/CMakeLists.txt Normal file
View file

@ -0,0 +1,34 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 23)
project(Graphics)
### ---------------------- Externals --------------------- ###
set(BINDINGS_INCLUDE ${EXTERNALS}/glfw/include ${EXTERNALS}/glew/include)
set(BINDINGS_LIBS glfw glew_s Imgui Nanovg)
### ---------------------- 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_include_directories(${PROJECT_NAME} PRIVATE ${BINDINGS_INCLUDE})
target_link_libraries(${PROJECT_NAME} PUBLIC Strings Math Utils)
target_link_libraries(${PROJECT_NAME} PRIVATE ${BINDINGS_LIBS})
### -------------------------- Examples -------------------------- ###
add_executable(${PROJECT_NAME}Example ./examples/Example.cpp)
target_link_libraries(${PROJECT_NAME}Example ${PROJECT_NAME} ${BINDINGS_LIBS})
target_include_directories(${PROJECT_NAME}Example PRIVATE ${BINDINGS_INCLUDE})
### -------------------------- 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)

View file

@ -0,0 +1,31 @@
#include "Window.hpp"
#include "imgui.h"
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleGraphics, nullptr };
tp::ModuleManifest testModule("Example", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
{
auto window = tp::Window::createWindow(800, 600, "Window 1");
if (window) {
while (!window->shouldClose()) {
window->processEvents();
window->getGraphics().getDebugGui().drawDebugInfoWindow();
window->draw();
}
}
tp::Window::destroyWindow(window);
}
testModule.deinitialize();
}

View file

@ -0,0 +1,104 @@
#include "Animations.hpp"
using namespace tp;
bool AnimValue::gInTransition = false;
halnf AnimValue::interpolate() const {
if (!mTimeAnim) {
return mVal;
}
auto dt = gCurrentTime - mTimeStart;
if (dt > mTimeAnim) dt = mTimeAnim;
auto t = (halnf)dt / (halnf)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() = default;
void AnimValue::setAnimTime(halni time) {
mTimeAnim = time;
}
AnimValue::AnimValue(halnf val) {
mVal = val;
mValPrev = mVal;
mTimeStart = gCurrentTime;
}
bool AnimValue::inTransition() const {
auto timePassed = gCurrentTime - mTimeStart >= mTimeAnim;
return !timePassed;
}
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 {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));
}

View file

@ -0,0 +1,6 @@
#include "GraphicsCommon.hpp"
namespace tp {
static ModuleManifest* deps[] = { &gModuleStrings, &gModuleMath, nullptr };
ModuleManifest gModuleGraphics = ModuleManifest("Graphics", nullptr, nullptr, deps);
}

View file

@ -0,0 +1,59 @@
#include "Window.hpp"
// -------- OpenGL -------- //
#include <GL/glew.h>
#include "WindowContext.hpp"
// -------- Canvas -------- //
#define NANOVG_GL3_IMPLEMENTATION
#include <nanovg.h>
#include <nanovg_gl.h>
namespace tp {
class Graphics::Canvas::Context {
public:
NVGcontext* vg;
};
}
using namespace tp;
Graphics::Canvas::Canvas() {
mContext = new Context();
}
Graphics::Canvas::~Canvas() {
delete mContext;
}
void Graphics::Canvas::init() {
mContext->vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
}
void Graphics::Canvas::deinit() {
// Cleanup
nvgDeleteGL3(mContext->vg);
}
void Graphics::Canvas::proc() {
auto width = 600;
auto height = 600;
// Start NanoVG rendering
nvgBeginFrame(mContext->vg, width, height, 1.0);
// Draw a rectangle
nvgBeginPath(mContext->vg);
nvgRect(mContext->vg, 50, 50, 50, 50);
nvgFillColor(mContext->vg, nvgRGBf(0.8f, 0.4f, 0.1f));
nvgFill(mContext->vg);
// End NanoVG rendering
nvgEndFrame(mContext->vg);
}
void Graphics::Canvas::draw() {
// End NanoVG rendering
nvgEndFrame(mContext->vg);
}

View file

@ -0,0 +1,267 @@
#include "Window.hpp"
#include "Timing.hpp"
#include "WindowContext.hpp"
// -------- Debug UI -------- //
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include "DefaultFont.bin"
namespace tp {
class Graphics::GUI::Context {
public:
ImGuiIO* io{};
ImGuiContext* ctx{};
halnf dpmm = 3;
halnf uiScale = 1;
halnf fontSizeMM = 3.55f;
Timer timer = Timer(1000);
ualni fps {};
ualni frames = 0;
};
}
using namespace tp;
Graphics::GUI::GUI() {
mContext = new Context();
}
Graphics::GUI::~GUI() {
delete mContext;
}
void Graphics::GUI::init(Window* window) {
IMGUI_CHECKVERSION();
mContext->ctx = ImGui::CreateContext();
mContext->io = &ImGui::GetIO();
mContext->io->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
// Initialize ImGui with GLFW and OpenGL
ImGui_ImplGlfw_InitForOpenGL(window->getContext()->window, true);
ImGui_ImplOpenGL3_Init("#version 330");
mContext->dpmm = (window->getMonitor().pixelSize.x / window->getMonitor().mmSize.x);
setStyle();
}
void Graphics::GUI::deinit() {
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
}
void Graphics::GUI::proc() {
tp::HeapAllocGlobal::startIgnore();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
tp::HeapAllocGlobal::stopIgnore();
// ImGui::DockSpaceOverViewport(NULL, ImGuiDockNodeFlags_PassthruCentralNode);
}
void Graphics::GUI::draw() {
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
mContext->frames++;
if (mContext->timer.isTimeout()) {
mContext->fps = mContext->frames;
mContext->frames = 0;
mContext->timer.reset();
}
}
halnf Graphics::GUI::getFontSize() const { return mContext->fontSizeMM; }
halnf Graphics::GUI::getUIScale() const { return mContext->uiScale; }
void Graphics::GUI::setDPMM(ualni dpmm) { mContext->dpmm = dpmm; }
void Graphics::GUI::setFontSize(ualni size) { mContext->fontSizeMM = size; }
void Graphics::GUI::setUIScale(ualni scale) { mContext->uiScale = scale; }
void Graphics::GUI::drawDebugInfoWindow() {
ImGui::Begin("Debug Info");
ImGui::Text("FPS : %llu", mContext->fps);
ImGui::SliderFloat("UI Scale", &mContext->uiScale, 0, 10);
ImGui::SliderFloat("Font Size MM", &mContext->fontSizeMM, 3, 20);
ImGui::SliderFloat("DPMM", &mContext->dpmm, 2, 10);
setStyle();
ImGui::End();
}
void Graphics::GUI::setStyle() {
auto dpmm = mContext->dpmm;
auto font_size_mm = mContext->fontSizeMM;
auto ui_scale = mContext->uiScale;
#define VAL(val) (val * dpmm * ui_scale)
#define VEC(x, y) ImVec2(x * dpmm, y * dpmm * ui_scale)
ImGuiStyle* style = &ImGui::GetStyle();
auto& io = *mContext->io;
bool first_init = io.Fonts->Fonts.Size == 0;
auto font_path = ".";
//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);
ImFontConfig font_cfg_template;
font_cfg_template.FontDataOwnedByAtlas = false;
io.Fonts->AddFontFromMemoryTTF(CONSOLAB_TTF, CONSOLAB_TTF_len, font_sizes[i] * 1, &font_cfg_template);
}
}
// 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;
}
}
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(1);
auto pudding = VEC(1, 1);
// 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(1, 2);
style->ItemInnerSpacing = VEC(1, 1);
style->CellPadding = pudding;
style->TouchExtraPadding = pudding;
style->IndentSpacing = VAL(3);
style->ColumnsMinSpacing = VAL(1.2);
style->ScrollbarSize = VAL(5);
style->ScrollbarRounding = rounding;
style->GrabMinSize = VAL(0.6);
style->GrabRounding = rounding;
style->LogSliderDeadzone = VAL(0.6);
style->TabRounding = rounding;
style->TabMinWidthForCloseButton = VAL(1.3);
style->DisplayWindowPadding = pudding;
style->DisplaySafeAreaPadding = pudding;
// style->MouseCursorScale = VAL(1.3);
// style->FrameBorderSize = VAL(0);
style->WindowBorderSize = VAL(0.5);
style->ChildBorderSize = VAL(0.6);
// style->WindowTitleAlign = VEC(0.1f, 0.2f);
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;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,172 @@
#include "Window.hpp"
// -------- OpenGL -------- //
#include <GL/glew.h>
#include "WindowContext.hpp"
#include <cstdio>
namespace tp {
class Graphics::GL::Context {
public:
// Showoff data
GLuint vao{};
GLuint vbo{};
GLfloat vertices[9] = {
-0.0f, -0.0f, 0.0f, // Left vertex
1.0f, 0.0f, 0.0f, // Right vertex
0.5f, 1.0f, 0.0f // Top vertex
};
};
}
using namespace tp;
Graphics::GL::GL() {
mContext = new Context();
}
Graphics::GL::~GL() {
delete mContext;
}
void Graphics::GL::init() {
// Create a Vertex Array Object (VAO)
glGenVertexArrays(1, &mContext->vao);
glBindVertexArray(mContext->vao);
// Create a Vertex Buffer Object (VBO)
glGenBuffers(1, &mContext->vbo);
glBindBuffer(GL_ARRAY_BUFFER, mContext->vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(mContext->vertices), mContext->vertices, GL_STATIC_DRAW);
// Set up vertex attributes
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*) nullptr);
glEnableVertexAttribArray(0);
}
void Graphics::GL::deinit() {
glDeleteBuffers(1, &mContext->vbo);
glDeleteVertexArrays(1, &mContext->vao);
}
void Graphics::GL::proc() {
glClear(GL_COLOR_BUFFER_BIT);
}
void Graphics::GL::draw() {
tp::HeapAllocGlobal::startIgnore();
glDrawArrays(GL_TRIANGLES, 0, 3);
tp::HeapAllocGlobal::stopIgnore();
}
void Graphics::init(Window* window) {
mGl.init();
mGui.init(window);
mCanvas.init();
}
void Graphics::deinit() {
mCanvas.deinit();
mGui.deinit();
mGl.deinit();
}
void Graphics::proc() {
mGl.proc();
mCanvas.proc();
mGui.proc();
}
void Graphics::draw() {
mGl.draw();
mCanvas.draw();
mGui.draw();
}
Window::Window(int width, int height, const char* title) {
mContext = new Context();
// Create a window and OpenGL context
mContext->window = glfwCreateWindow(width, height, title, nullptr, nullptr);
if (!mContext->window) {
printf("Failed to create GLFW window\n");
return;
}
glfwMakeContextCurrent(mContext->window);
// Initialize GLEW
if (glewInit() != GLEW_OK) {
printf("Failed to initialize GLEW\n");
return;
}
// get some common information. maybe call it in loop to pick up monitor changes
int width_mm, height_mm;
auto monitor = glfwGetPrimaryMonitor();
glfwGetMonitorPhysicalSize(monitor, &width_mm, &height_mm);
mMonitor.mmSize = { width_mm, height_mm };
const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
mMonitor.pixelSize = { mode->width, mode->height };
mMonitor.refreshRate = mode->refreshRate;
mGraphics.init(this);
}
Window::~Window() {
mGraphics.deinit();
glfwDestroyWindow(mContext->window);
delete mContext;
}
Window* Window::createWindow(int width, int height, const char* title) {
tp::HeapAllocGlobal::startIgnore();
static int count = 1;
if (!count) {
printf("Window class is a singleton\n");
return nullptr;
}
count--;
// Initialize GLFW
if (!glfwInit()) {
printf("Failed to initialize GLFW\n");
return nullptr;
}
// Set the GLFW error callback
glfwSetErrorCallback([] (int error, const char* description) {
printf("GLFW Error: %i %s\n", error, description);
});
auto out = new Window(width, height, title);
tp::HeapAllocGlobal::stopIgnore();
return out;
}
void Window::destroyWindow(Window* window) {
delete window;
glfwTerminate();
}
bool Window::shouldClose() const {
return glfwWindowShouldClose(mContext->window);
}
void Window::processEvents() {
glfwPollEvents();
mGraphics.proc();
}
void Window::draw() {
mGraphics.draw();
glfwSwapBuffers(mContext->window);
}
auto Window::getContext() -> Context* { return mContext; }

View file

@ -0,0 +1,16 @@
#pragma once
// -------- Window Context -------- //
#include <GLFW/glfw3.h>
namespace tp {
class Window;
class Window::Context {
friend Graphics::GL;
friend Graphics::GUI;
friend Graphics::Canvas;
public:
GLFWwindow* window;
};
}

View file

@ -0,0 +1,53 @@
#pragma once
#include "GraphicsCommon.hpp"
namespace tp {
class AnimValue {
halnf mValPrev = 0;
halnf mVal = 0;
time_ms mTimeStart = 0;
halni mTimeAnim = 250;
static bool gInTransition;
private:
[[nodiscard]] halnf interpolate() const;
public:
AnimValue();
explicit AnimValue(halnf val);
[[nodiscard]] halnf prev() const { return mValPrev; }
void set(halnf val);
void setNoTransition(halnf);
void setAnimTime(halni time);
[[nodiscard]] halnf get() const;
[[nodiscard]] halnf getTarget() const;
[[nodiscard]] bool inTransition() const;
explicit operator halnf() const;
void operator=(halnf val);
};
class AnimRect : Rect<AnimValue> {
public:
AnimRect() {
set({ 0, 0, 0, 0 });
setAnimTime(450);
}
[[nodiscard]] RectF get() const;
[[nodiscard]] RectF getTarget() const;
void setNoTransition(RectF);
void set(const RectF&);
void setAnimTime(halni time_ms);
};
class AnimColor {
AnimRect mColor;
public:
[[nodiscard]] RGBA get() const;
void set(const RGBA&);
};
};

View file

@ -0,0 +1,89 @@
#pragma once
#include "GraphicsCommon.hpp"
namespace tp {
class Window;
class Graphics {
public:
class GL {
class Context;
Context* mContext;
private:
friend Graphics;
GL();
~GL();
void init();
void deinit();
static void proc();
static void draw();
public:
// TODO : API
};
class GUI {
class Context;
Context* mContext;
private:
friend Graphics;
GUI();
~GUI();
void init(Window* window);
void deinit();
void proc();
void draw();
void setStyle();
public:
void drawDebugInfoWindow();
halnf getFontSize() const;
halnf getUIScale() const;
void setDPMM(ualni);
void setFontSize(ualni);
void setUIScale(ualni);
};
class Canvas {
class Context;
Context* mContext;
private:
friend Graphics;
Canvas();
~Canvas();
void init();
void deinit();
void proc();
void draw();
public:
// TODO : API
};
private:
friend Window;
Graphics() = default;
void init(Window* window);
void deinit();
void draw();
void proc();
public:
GUI& getDebugGui() { return mGui; }
private:
GUI mGui;
GL mGl;
Canvas mCanvas;
};
}

View file

@ -0,0 +1,10 @@
#pragma once
#include "Strings.hpp"
#include "Rect.hpp"
#include "Color.hpp"
#include "Timing.hpp"
namespace tp {
extern ModuleManifest gModuleGraphics;
}

View file

@ -0,0 +1,166 @@
#pragma once
namespace tp {
// basically copy of glfw keys
enum class Keycode {
/* Printable keys */
SPACE = 32,
APOSTROPHE = 39, /* ' */
COMMA = 44, /* , */
MINUS = 45, /* - */
PERIOD = 46, /* . */
SLASH = 0xBF, /* \ */
N0 = 48,
N1 = 49,
N2 = 50,
N3 = 51,
N4 = 52,
N5 = 53,
N6 = 54,
N7 = 55,
N8 = 56,
N9 = 57,
SEMICOLON = 59, /* ; */
EQUAL = 61, /* = */
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LEFT_BRACKET = 91, /* [ */
BACKSLASH = 92, /* \ */
RIGHT_BRACKET = 93, /* ] */
GRAVE_ACCENT = 96, /* ` */
WORLD_1 = 161, /* non-US #1 */
WORLD_2 = 162, /* non-US #2 */
/* function keys */
ESCAPE = 256,
ENTER = 257,
TAB = 258,
BACKSPACE = 259,
INSERT = 260,
DELETE = 261,
RIGHT = 262,
LEFT = 263,
DOWN = 264,
UP = 265,
PAGE_UP = 266,
PAGE_DOWN = 267,
HOME = 268,
END = 269,
CAPS_LOCK = 280,
SCROLL_LOCK = 281,
NUM_LOCK = 282,
PRINT_SCREEN = 283,
PAUSE = 284,
F1 = 290,
F2 = 291,
F3 = 292,
F4 = 293,
F5 = 294,
F6 = 295,
F7 = 296,
F8 = 297,
F9 = 298,
F10 = 299,
F11 = 300,
F12 = 301,
F13 = 302,
F14 = 303,
F15 = 304,
F16 = 305,
F17 = 306,
F18 = 307,
F19 = 308,
F20 = 309,
F21 = 310,
F22 = 311,
F23 = 312,
F24 = 313,
F25 = 314,
KP_0 = 320,
KP_1 = 321,
KP_2 = 322,
KP_3 = 323,
KP_4 = 324,
KP_5 = 325,
KP_6 = 326,
KP_7 = 327,
KP_8 = 328,
KP_9 = 329,
KP_DECIMAL = 330,
KP_DIVIDE = 331,
KP_MULTIPLY = 332,
KP_SUBTRACT = 333,
KP_ADD = 334,
KP_ENTER = 335,
KP_EQUAL = 336,
LEFT_SHIFT = 340,
LEFT_CONTROL = 341,
LEFT_ALT = 342,
LEFT_SUPER = 343,
RIGHT_SHIFT = 344,
RIGHT_CONTROL = 345,
RIGHT_ALT = 346,
RIGHT_SUPER = 347,
MENU = 348,
INV_SLASH = 0xDC,
BRA = 0xDB,
KET = 0xDD,
TILDA = 0xC0,
DOUBLE_DOT = 0xBA,
QUOTES = 0xDE,
MOUSE1 = 501,
MOUSE2 = 502,
MOUSE3 = 503,
MOUSE4 = 504,
MOUSE5 = 505,
MOUSE_UP = 506,
MOUSE_DOWN = 507,
};
enum class KeyState {
PRESSED,
RELEASED,
HOLD,
REPEAT,
NONE,
};
struct KeyEvent {
Keycode code;
enum class EventState {
RELEASED = 0,
PRESSED = 1,
REPEAT = 2,
} event_state;
};
};

View file

@ -0,0 +1,52 @@
#pragma once
#include "Graphics.hpp"
#include "Buffer.hpp"
#include "Keycodes.hpp"
namespace tp {
class Window {
class Context;
public:
struct Event {
enum Type {
KEY,
MOUSE,
};
};
struct Monitor {
ualni refreshRate = 60;
Vec2F pixelSize;
Vec2F mmSize;
};
private:
Window(int width, int height, const char* title);
~Window();
public:
static Window* createWindow(int width, int height, const char* title);
static void destroyWindow(Window* window);
public:
void draw();
void processEvents();
[[nodiscard]] bool shouldClose() const;
auto getContext() -> Context*;
Graphics& getGraphics() { return mGraphics; }
[[nodiscard]] const Monitor& getMonitor() const { return mMonitor; }
private:
Context* mContext;
Graphics mGraphics;
Buffer<Event> mEvents;
Monitor mMonitor;
};
}

BIN
Graphics/rsc/CONSOLAB.TTF Normal file

Binary file not shown.

3
Graphics/tests/tests.cpp Normal file
View file

@ -0,0 +1,3 @@
int main() {
}

View file

@ -67,7 +67,7 @@ Vec3F Camera::project(Vec2F normalized) {
halnf w = halnf((mTarget - mPos).length());
Vec4<halnf> world_pos4(normalized.x * w, normalized.y * w, z, w);
return inv * world_pos4;
return Vec3F(inv * world_pos4);
}
Vec2F Camera::project(const Vec3F& world) {

View file

@ -94,7 +94,7 @@ namespace tp {
// argument isInside
bool isInside(const Vec2<Type>& p) const {
return (p.each_compre(pos) && (pos + size).each_compre(p));
return isInside(p.x, p.y);
}
bool isInside(Type x, Type y) const {

View file

@ -6,7 +6,7 @@ namespace tp {
template <typename Type, const ualni tSize>
class Vec {
typedef SelCopyArg<Type> TypeArg;
typedef SelectValueOrReference<Type> TypeArg;
private:
Type mBuff[tSize];
@ -21,7 +21,7 @@ namespace tp {
MODULE_SANITY_CHECK(gModuleMath)
}
Vec(TypeArg val) {
explicit Vec(TypeArg val) {
assign(val);
}
@ -185,7 +185,7 @@ namespace tp {
return dot(in);
}
alnf length2() const {
[[nodiscard]] alnf length2() const {
alnf sum = 0;
for (ualni i = 0; i < tSize; i++) {
Type val = get(i);
@ -194,7 +194,7 @@ namespace tp {
return sum;
}
alnf length() const {
[[nodiscard]] alnf length() const {
return sqrt(length2());
}
@ -250,18 +250,18 @@ namespace tp {
}
template <typename TypeIn>
Vec(TypeIn Vec[2]) {
explicit Vec(TypeIn Vec[2]) {
x = (Type) Vec[0];
y = (Type) Vec[1];
}
template <typename TypeIn>
Vec(TypeIn val) {
explicit Vec(TypeIn val) {
x = y = (Type) val;
}
template <typename TypeIn>
Vec(Vec<TypeIn, 2>& Vec) {
explicit Vec(Vec<TypeIn, 2>& Vec) {
x = (Type) Vec.x;
y = (Type) Vec.y;
}
@ -381,11 +381,11 @@ namespace tp {
return { -y, x };
}
alnf length2() const {
[[nodiscard]] alnf length2() const {
return (x * x + y * y);
}
alnf length() const {
[[nodiscard]] alnf length() const {
Type const tmp = (Type) (x * x + y * y);
return sqrt(tmp);
}
@ -419,9 +419,9 @@ namespace tp {
Type z;
// Initialization
Vec() {}
Vec() = default;
Vec(const Vec<Type, 4>& in) {
explicit Vec(const Vec<Type, 4>& in) {
x = in[0];
y = in[1];
z = in[2];
@ -433,13 +433,13 @@ namespace tp {
z = aZ;
}
Vec(Type Vec[3]) {
explicit Vec(Type Vec[3]) {
x = Vec[0];
y = Vec[1];
z = Vec[2];
}
Vec(Type x) {
explicit Vec(Type x) {
assign(x);
}
@ -584,7 +584,7 @@ namespace tp {
return (x * in.x + y * in.y + z * in.z);
}
alnf length() const {
[[nodiscard]] alnf length() const {
return sqrt((halnf) (x * x + y * y + z * z));
}
@ -632,11 +632,11 @@ namespace tp {
z = (Type) (tmp * sinA + z * cosA);
}
halnf angelX() const {
[[nodiscard]] halnf angelX() const {
return (halnf) atan2(y, z);
}
halnf angelY() const {
[[nodiscard]] halnf angelY() const {
return (halnf) atan2(x, z);
}
};

View file

@ -14,7 +14,7 @@ void testMath();
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps);
tp::ModuleManifest testModule("MathTest", init, nullptr, deps);
if (!testModule.initialize()) {
return 1;

BIN
Modules/.vs/slnx.sqlite Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more