diff --git a/.outdated/graphics/ext/easytab.h b/.outdated/graphics/ext/easytab.h new file mode 100644 index 0000000..2d39dd4 --- /dev/null +++ b/.outdated/graphics/ext/easytab.h @@ -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 +#include +#include + +#ifdef __linux__ +#include +#endif // __linux__ + +#ifdef _WIN32 +#include +#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 diff --git a/.outdated/graphics/ext/objloader.h b/.outdated/graphics/ext/objloader.h new file mode 100644 index 0000000..5e1bad6 --- /dev/null +++ b/.outdated/graphics/ext/objloader.h @@ -0,0 +1,1191 @@ +// OBJ_Loader.h - A Single Header OBJ Model Loader + +/* +MIT License + +Copyright(c) 2016 Robert Smith + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this softwareand associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright noticeand this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +// Iostream - STD I/O Library +#include + +// Vector - STD Vector/Array Library +#include + +// String - STD String Library +#include + +// fStream - STD File I/O Library +#include + +// Math.h - STD math Library +#include + +// Print progress to console while loading (large models) +#define OBJL_CONSOLE_OUTPUT + +// Namespace: OBJL +// +// Description: The namespace that holds eveyrthing that +// is needed and used for the OBJ Model Loader +namespace objl +{ + // Structure: Vector2 + // + // Description: A 2D Vector that Holds Positional Data + struct Vector2 + { + // Default Constructor + Vector2() + { + X = 0.0f; + Y = 0.0f; + } + // Variable Set Constructor + Vector2(float X_, float Y_) + { + X = X_; + Y = Y_; + } + // Bool Equals Operator Overload + bool operator==(const Vector2& other) const + { + return (this->X == other.X && this->Y == other.Y); + } + // Bool Not Equals Operator Overload + bool operator!=(const Vector2& other) const + { + return !(this->X == other.X && this->Y == other.Y); + } + // Addition Operator Overload + Vector2 operator+(const Vector2& right) const + { + return Vector2(this->X + right.X, this->Y + right.Y); + } + // Subtraction Operator Overload + Vector2 operator-(const Vector2& right) const + { + return Vector2(this->X - right.X, this->Y - right.Y); + } + // Float Multiplication Operator Overload + Vector2 operator*(const float& other) const + { + return Vector2(this->X *other, this->Y * other); + } + + // Positional Variables + float X; + float Y; + }; + + // Structure: Vector3 + // + // Description: A 3D Vector that Holds Positional Data + struct Vector3 + { + // Default Constructor + Vector3() + { + X = 0.0f; + Y = 0.0f; + Z = 0.0f; + } + // Variable Set Constructor + Vector3(float X_, float Y_, float Z_) + { + X = X_; + Y = Y_; + Z = Z_; + } + // Bool Equals Operator Overload + bool operator==(const Vector3& other) const + { + return (this->X == other.X && this->Y == other.Y && this->Z == other.Z); + } + // Bool Not Equals Operator Overload + bool operator!=(const Vector3& other) const + { + return !(this->X == other.X && this->Y == other.Y && this->Z == other.Z); + } + // Addition Operator Overload + Vector3 operator+(const Vector3& right) const + { + return Vector3(this->X + right.X, this->Y + right.Y, this->Z + right.Z); + } + // Subtraction Operator Overload + Vector3 operator-(const Vector3& right) const + { + return Vector3(this->X - right.X, this->Y - right.Y, this->Z - right.Z); + } + // Float Multiplication Operator Overload + Vector3 operator*(const float& other) const + { + return Vector3(this->X * other, this->Y * other, this->Z * other); + } + // Float Division Operator Overload + Vector3 operator/(const float& other) const + { + return Vector3(this->X / other, this->Y / other, this->Z / other); + } + + // Positional Variables + float X; + float Y; + float Z; + }; + + // Structure: Vertex + // + // Description: Model Vertex object that holds + // a Position, Normal, and Texture Coordinate + struct Vertex + { + // Position Vector + Vector3 Position; + + // Normal Vector + Vector3 normal; + + // Texture Coordinate Vector + Vector2 TextureCoordinate; + }; + + struct Material + { + Material() + { + name; + Ns = 0.0f; + Ni = 0.0f; + d = 0.0f; + illum = 0; + } + + // Material Name + std::string name; + // Ambient Color + Vector3 Ka; + // Diffuse Color + Vector3 Kd; + // Specular Color + Vector3 Ks; + // Specular Exponent + float Ns; + // Optical Density + float Ni; + // Dissolve + float d; + // Illumination + int illum; + // Ambient Texture Map + std::string map_Ka; + // Diffuse Texture Map + std::string map_Kd; + // Specular Texture Map + std::string map_Ks; + // Specular Hightlight Map + std::string map_Ns; + // Alpha Texture Map + std::string map_d; + // Bump Map + std::string map_bump; + }; + + // Structure: Mesh + // + // Description: A Simple Mesh Object that holds + // a name, a vertex list, and an index list + struct Mesh + { + // Default Constructor + Mesh() + { + + } + // Variable Set Constructor + Mesh(std::vector& _Vertices, std::vector& _Indices) + { + Vertices = _Vertices; + Indices = _Indices; + } + // Mesh Name + std::string MeshName; + // Vertex List + std::vector Vertices; + // Index List + std::vector Indices; + + // Material + Material MeshMaterial; + }; + + // Namespace: Math + // + // Description: The namespace that holds all of the math + // functions need for OBJL + namespace math + { + // Vector3 Cross Product + Vector3 CrossV3(const Vector3 a, const Vector3 b) + { + return Vector3(a.Y * b.Z - a.Z * b.Y, + a.Z * b.X - a.X * b.Z, + a.X * b.Y - a.Y * b.X); + } + + // Vector3 Magnitude Calculation + float MagnitudeV3(const Vector3 in) + { + return (sqrtf(powf(in.X, 2) + powf(in.Y, 2) + powf(in.Z, 2))); + } + + // Vector3 DotProduct + float DotV3(const Vector3 a, const Vector3 b) + { + return (a.X * b.X) + (a.Y * b.Y) + (a.Z * b.Z); + } + + // Angle between 2 Vector3 Objects + float AngleBetweenV3(const Vector3 a, const Vector3 b) + { + float angle = DotV3(a, b); + angle /= (MagnitudeV3(a) * MagnitudeV3(b)); + return angle = acosf(angle); + } + + // Projection Calculation of a onto b + Vector3 ProjV3(const Vector3 a, const Vector3 b) + { + Vector3 bn = b / MagnitudeV3(b); + return bn * DotV3(a, bn); + } + } + + // Namespace: Algorithm + // + // Description: The namespace that holds all of the + // Algorithms needed for OBJL + namespace algorithm + { + // Vector3 Multiplication Opertor Overload + Vector3 operator*(const float& left, const Vector3& right) + { + return Vector3(right.X * left, right.Y * left, right.Z * left); + } + + // A test to see if P1 is on the same side as P2 of a line segment ab + bool SameSide(Vector3 p1, Vector3 p2, Vector3 a, Vector3 b) + { + Vector3 cp1 = math::CrossV3(b - a, p1 - a); + Vector3 cp2 = math::CrossV3(b - a, p2 - a); + + if (math::DotV3(cp1, cp2) >= 0) + return true; + else + return false; + } + + // Generate a cross produect normal for a triangle + Vector3 GenTriNormal(Vector3 t1, Vector3 t2, Vector3 t3) + { + Vector3 u = t2 - t1; + Vector3 v = t3 - t1; + + Vector3 normal = math::CrossV3(u,v); + + return normal; + } + + // Check to see if a Vector3 Point is within a 3 Vector3 Triangle + bool inTriangle(Vector3 point, Vector3 tri1, Vector3 tri2, Vector3 tri3) + { + // Test to see if it is within an infinite prism that the triangle outlines. + bool within_tri_prisim = SameSide(point, tri1, tri2, tri3) && SameSide(point, tri2, tri1, tri3) + && SameSide(point, tri3, tri1, tri2); + + // If it isn't it will never be on the triangle + if (!within_tri_prisim) + return false; + + // Calulate Triangle's Normal + Vector3 n = GenTriNormal(tri1, tri2, tri3); + + // Project the point onto this normal + Vector3 proj = math::ProjV3(point, n); + + // If the distance from the triangle to the point is 0 + // it lies on the triangle + if (math::MagnitudeV3(proj) == 0) + return true; + else + return false; + } + + // Split a String into a string array at a given token + inline void split(const std::string &in, + std::vector &out, + std::string token) + { + out.clear(); + + std::string temp; + + for (int i = 0; i < int(in.size()); i++) + { + std::string test = in.substr(i, token.size()); + + if (test == token) + { + if (!temp.empty()) + { + out.push_back(temp); + temp.clear(); + i += (int)token.size() - 1; + } + else + { + out.push_back(""); + } + } + else if (i + token.size() >= in.size()) + { + temp += in.substr(i, token.size()); + out.push_back(temp); + break; + } + else + { + temp += in[i]; + } + } + } + + // Get tail of string after first token and possibly following spaces + inline std::string tail(const std::string &in) + { + size_t token_start = in.find_first_not_of(" \t"); + size_t space_start = in.find_first_of(" \t", token_start); + size_t tail_start = in.find_first_not_of(" \t", space_start); + size_t tail_end = in.find_last_not_of(" \t"); + if (tail_start != std::string::npos && tail_end != std::string::npos) + { + return in.substr(tail_start, tail_end - tail_start + 1); + } + else if (tail_start != std::string::npos) + { + return in.substr(tail_start); + } + return ""; + } + + // Get first token of string + inline std::string firstToken(const std::string &in) + { + if (!in.empty()) + { + size_t token_start = in.find_first_not_of(" \t"); + size_t token_end = in.find_first_of(" \t", token_start); + if (token_start != std::string::npos && token_end != std::string::npos) + { + return in.substr(token_start, token_end - token_start); + } + else if (token_start != std::string::npos) + { + return in.substr(token_start); + } + } + return ""; + } + + // Get element at given index position + template + inline const T & getElement(const std::vector &elements, std::string &index) + { + int idx = std::stoi(index); + if (idx < 0) + idx = int(elements.size()) + idx; + else + idx--; + return elements[idx]; + } + } + + // Class: Loader + // + // Description: The OBJ Model Loader + class Loader + { + public: + // Default Constructor + Loader() + { + + } + ~Loader() + { + LoadedMeshes.clear(); + } + + // Load a file into the loader + // + // If file is loaded return true + // + // If the file is unable to be found + // or unable to be loaded return false + bool LoadFile(std::string Path) + { + // If the file is not an .obj file return false + if (Path.substr(Path.size() - 4, 4) != ".obj") + return false; + + + std::ifstream file(Path); + + if (!file.is_open()) + return false; + + LoadedMeshes.clear(); + LoadedVertices.clear(); + LoadedIndices.clear(); + + std::vector Positions; + std::vector TCoords; + std::vector Normals; + + std::vector Vertices; + std::vector Indices; + + std::vector MeshMatNames; + + bool listening = false; + std::string meshname; + + Mesh tempMesh; + + #ifdef OBJL_CONSOLE_OUTPUT + const unsigned int outputEveryNth = 1000; + unsigned int outputIndicator = outputEveryNth; + #endif + + std::string curline; + while (std::getline(file, curline)) + { + #ifdef OBJL_CONSOLE_OUTPUT + if ((outputIndicator = ((outputIndicator + 1) % outputEveryNth)) == 1) + { + if (!meshname.empty()) + { + std::cout + << "\r- " << meshname + << "\t| vertices > " << Positions.size() + << "\t| texcoords > " << TCoords.size() + << "\t| normals > " << Normals.size() + << "\t| triangles > " << (Vertices.size() / 3) + << (!MeshMatNames.empty() ? "\t| material: " + MeshMatNames.back() : ""); + } + } + #endif + + // Generate a Mesh Object or Prepare for an object to be created + if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g" || curline[0] == 'g') + { + if (!listening) + { + listening = true; + + if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g") + { + meshname = algorithm::tail(curline); + } + else + { + meshname = "unnamed"; + } + } + else + { + // Generate the mesh to put into the array + + if (!Indices.empty() && !Vertices.empty()) + { + // Create Mesh + tempMesh = Mesh(Vertices, Indices); + tempMesh.MeshName = meshname; + + // Insert Mesh + LoadedMeshes.push_back(tempMesh); + + // Cleanup + Vertices.clear(); + Indices.clear(); + meshname.clear(); + + meshname = algorithm::tail(curline); + } + else + { + if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g") + { + meshname = algorithm::tail(curline); + } + else + { + meshname = "unnamed"; + } + } + } + #ifdef OBJL_CONSOLE_OUTPUT + std::cout << std::endl; + outputIndicator = 0; + #endif + } + // Generate a Vertex Position + if (algorithm::firstToken(curline) == "v") + { + std::vector spos; + Vector3 vpos; + algorithm::split(algorithm::tail(curline), spos, " "); + + vpos.X = std::stof(spos[0]); + vpos.Y = std::stof(spos[1]); + vpos.Z = std::stof(spos[2]); + + Positions.push_back(vpos); + } + // Generate a Vertex Texture Coordinate + if (algorithm::firstToken(curline) == "vt") + { + std::vector stex; + Vector2 vtex; + algorithm::split(algorithm::tail(curline), stex, " "); + + vtex.X = std::stof(stex[0]); + vtex.Y = std::stof(stex[1]); + + TCoords.push_back(vtex); + } + // Generate a Vertex Normal; + if (algorithm::firstToken(curline) == "vn") + { + std::vector snor; + Vector3 vnor; + algorithm::split(algorithm::tail(curline), snor, " "); + + vnor.X = std::stof(snor[0]); + vnor.Y = std::stof(snor[1]); + vnor.Z = std::stof(snor[2]); + + Normals.push_back(vnor); + } + // Generate a Face (vertices & indices) + if (algorithm::firstToken(curline) == "f") + { + // Generate the vertices + std::vector vVerts; + GenVerticesFromRawOBJ(vVerts, Positions, TCoords, Normals, curline); + + // Add Vertices + for (int i = 0; i < int(vVerts.size()); i++) + { + Vertices.push_back(vVerts[i]); + + LoadedVertices.push_back(vVerts[i]); + } + + std::vector iIndices; + + VertexTriangluation(iIndices, vVerts); + + // Add Indices + for (int i = 0; i < int(iIndices.size()); i++) + { + unsigned int indnum = (unsigned int)((Vertices.size()) - vVerts.size()) + iIndices[i]; + Indices.push_back(indnum); + + indnum = (unsigned int)((LoadedVertices.size()) - vVerts.size()) + iIndices[i]; + LoadedIndices.push_back(indnum); + + } + } + // Get Mesh Material Name + if (algorithm::firstToken(curline) == "usemtl") + { + MeshMatNames.push_back(algorithm::tail(curline)); + + // Create new Mesh, if Material changes within a group + if (!Indices.empty() && !Vertices.empty()) + { + // Create Mesh + tempMesh = Mesh(Vertices, Indices); + tempMesh.MeshName = meshname; + int i = 2; + while(1) { + tempMesh.MeshName = meshname + "_" + std::to_string(i); + + for (auto &m : LoadedMeshes) + if (m.MeshName == tempMesh.MeshName) + continue; + break; + } + + // Insert Mesh + LoadedMeshes.push_back(tempMesh); + + // Cleanup + Vertices.clear(); + Indices.clear(); + } + + #ifdef OBJL_CONSOLE_OUTPUT + outputIndicator = 0; + #endif + } + // Load Materials + if (algorithm::firstToken(curline) == "mtllib") + { + // Generate LoadedMaterial + + // Generate a path to the material file + std::vector temp; + algorithm::split(Path, temp, "/"); + + std::string pathtomat = ""; + + if (temp.size() != 1) + { + for (int i = 0; i < temp.size() - 1; i++) + { + pathtomat += temp[i] + "/"; + } + } + + + pathtomat += algorithm::tail(curline); + + #ifdef OBJL_CONSOLE_OUTPUT + std::cout << std::endl << "- find materials in: " << pathtomat << std::endl; + #endif + + // Load Materials + LoadMaterials(pathtomat); + } + } + + #ifdef OBJL_CONSOLE_OUTPUT + std::cout << std::endl; + #endif + + // Deal with last mesh + + if (!Indices.empty() && !Vertices.empty()) + { + // Create Mesh + tempMesh = Mesh(Vertices, Indices); + tempMesh.MeshName = meshname; + + // Insert Mesh + LoadedMeshes.push_back(tempMesh); + } + + file.close(); + + // Set Materials for each Mesh + for (int i = 0; i < MeshMatNames.size(); i++) + { + std::string matname = MeshMatNames[i]; + + // Find corresponding material name in loaded materials + // when found copy material variables into mesh material + for (int j = 0; j < LoadedMaterials.size(); j++) + { + if (LoadedMaterials[j].name == matname) + { + LoadedMeshes[i].MeshMaterial = LoadedMaterials[j]; + break; + } + } + } + + if (LoadedMeshes.empty() && LoadedVertices.empty() && LoadedIndices.empty()) + { + return false; + } + else + { + return true; + } + } + + // Loaded Mesh Objects + std::vector LoadedMeshes; + // Loaded Vertex Objects + std::vector LoadedVertices; + // Loaded Index Positions + std::vector LoadedIndices; + // Loaded Material Objects + std::vector LoadedMaterials; + + private: + // Generate vertices from a list of positions, + // tcoords, normals and a face line + void GenVerticesFromRawOBJ(std::vector& oVerts, + const std::vector& iPositions, + const std::vector& iTCoords, + const std::vector& iNormals, + std::string icurline) + { + std::vector sface, svert; + Vertex vVert; + algorithm::split(algorithm::tail(icurline), sface, " "); + + bool noNormal = false; + + // For every given vertex do this + for (int i = 0; i < int(sface.size()); i++) + { + // See What type the vertex is. + int vtype; + + algorithm::split(sface[i], svert, "/"); + + // Check for just position - v1 + if (svert.size() == 1) + { + // Only position + vtype = 1; + } + + // Check for position & texture - v1/vt1 + if (svert.size() == 2) + { + // Position & Texture + vtype = 2; + } + + // Check for Position, Texture and Normal - v1/vt1/vn1 + // or if Position and Normal - v1//vn1 + if (svert.size() == 3) + { + if (svert[1] != "") + { + // Position, Texture, and Normal + vtype = 4; + } + else + { + // Position & Normal + vtype = 3; + } + } + + // Calculate and store the vertex + switch (vtype) + { + case 1: // P + { + vVert.Position = algorithm::getElement(iPositions, svert[0]); + vVert.TextureCoordinate = Vector2(0, 0); + noNormal = true; + oVerts.push_back(vVert); + break; + } + case 2: // P/T + { + vVert.Position = algorithm::getElement(iPositions, svert[0]); + vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]); + noNormal = true; + oVerts.push_back(vVert); + break; + } + case 3: // P//N + { + vVert.Position = algorithm::getElement(iPositions, svert[0]); + vVert.TextureCoordinate = Vector2(0, 0); + vVert.normal = algorithm::getElement(iNormals, svert[2]); + oVerts.push_back(vVert); + break; + } + case 4: // P/T/N + { + vVert.Position = algorithm::getElement(iPositions, svert[0]); + vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]); + vVert.normal = algorithm::getElement(iNormals, svert[2]); + oVerts.push_back(vVert); + break; + } + default: + { + break; + } + } + } + + // take care of missing normals + // these may not be truly acurate but it is the + // best they get for not compiling a mesh with normals + if (noNormal) + { + Vector3 A = oVerts[0].Position - oVerts[1].Position; + Vector3 B = oVerts[2].Position - oVerts[1].Position; + + Vector3 normal = math::CrossV3(A, B); + + for (int i = 0; i < int(oVerts.size()); i++) + { + oVerts[i].normal = normal; + } + } + } + + // Triangulate a list of vertices into a face by printing + // inducies corresponding with triangles within it + void VertexTriangluation(std::vector& oIndices, + const std::vector& iVerts) + { + // If there are 2 or less verts, + // no triangle can be created, + // so exit + if (iVerts.size() < 3) + { + return; + } + // If it is a triangle no need to calculate it + if (iVerts.size() == 3) + { + oIndices.push_back(0); + oIndices.push_back(1); + oIndices.push_back(2); + return; + } + + // Create a list of vertices + std::vector tVerts = iVerts; + + while (true) + { + // For every vertex + for (int i = 0; i < int(tVerts.size()); i++) + { + // pPrev = the previous vertex in the list + Vertex pPrev; + if (i == 0) + { + pPrev = tVerts[tVerts.size() - 1]; + } + else + { + pPrev = tVerts[i - 1]; + } + + // pCur = the current vertex; + Vertex pCur = tVerts[i]; + + // pNext = the next vertex in the list + Vertex pNext; + if (i == tVerts.size() - 1) + { + pNext = tVerts[0]; + } + else + { + pNext = tVerts[i + 1]; + } + + // Check to see if there are only 3 verts left + // if so this is the last triangle + if (tVerts.size() == 3) + { + // Create a triangle from pCur, pPrev, pNext + for (int j = 0; j < int(tVerts.size()); j++) + { + if (iVerts[j].Position == pCur.Position) + oIndices.push_back(j); + if (iVerts[j].Position == pPrev.Position) + oIndices.push_back(j); + if (iVerts[j].Position == pNext.Position) + oIndices.push_back(j); + } + + tVerts.clear(); + break; + } + if (tVerts.size() == 4) + { + // Create a triangle from pCur, pPrev, pNext + for (int j = 0; j < int(iVerts.size()); j++) + { + if (iVerts[j].Position == pCur.Position) + oIndices.push_back(j); + if (iVerts[j].Position == pPrev.Position) + oIndices.push_back(j); + if (iVerts[j].Position == pNext.Position) + oIndices.push_back(j); + } + + Vector3 tempVec; + for (int j = 0; j < int(tVerts.size()); j++) + { + if (tVerts[j].Position != pCur.Position + && tVerts[j].Position != pPrev.Position + && tVerts[j].Position != pNext.Position) + { + tempVec = tVerts[j].Position; + break; + } + } + + // Create a triangle from pCur, pPrev, pNext + for (int j = 0; j < int(iVerts.size()); j++) + { + if (iVerts[j].Position == pPrev.Position) + oIndices.push_back(j); + if (iVerts[j].Position == pNext.Position) + oIndices.push_back(j); + if (iVerts[j].Position == tempVec) + oIndices.push_back(j); + } + + tVerts.clear(); + break; + } + + // If Vertex is not an interior vertex + float angle = (float)math::AngleBetweenV3(pPrev.Position - pCur.Position, pNext.Position - pCur.Position) * (float) (180 / 3.14159265359); + if (angle <= 0 && angle >= 180) + continue; + + // If any vertices are within this triangle + bool inTri = false; + for (int j = 0; j < int(iVerts.size()); j++) + { + if (algorithm::inTriangle(iVerts[j].Position, pPrev.Position, pCur.Position, pNext.Position) + && iVerts[j].Position != pPrev.Position + && iVerts[j].Position != pCur.Position + && iVerts[j].Position != pNext.Position) + { + inTri = true; + break; + } + } + if (inTri) + continue; + + // Create a triangle from pCur, pPrev, pNext + for (int j = 0; j < int(iVerts.size()); j++) + { + if (iVerts[j].Position == pCur.Position) + oIndices.push_back(j); + if (iVerts[j].Position == pPrev.Position) + oIndices.push_back(j); + if (iVerts[j].Position == pNext.Position) + oIndices.push_back(j); + } + + // Delete pCur from the list + for (int j = 0; j < int(tVerts.size()); j++) + { + if (tVerts[j].Position == pCur.Position) + { + tVerts.erase(tVerts.begin() + j); + break; + } + } + + // reset i to the start + // -1 since loop will add 1 to it + i = -1; + } + + // if no triangles were created + if (oIndices.size() == 0) + break; + + // if no more vertices + if (tVerts.size() == 0) + break; + } + } + + // Load Materials from .mtl file + bool LoadMaterials(std::string path) + { + // If the file is not a material file return false + if (path.substr(path.size() - 4, path.size()) != ".mtl") + return false; + + std::ifstream file(path); + + // If the file is not found return false + if (!file.is_open()) + return false; + + Material tempMaterial; + + bool listening = false; + + // Go through each line looking for material variables + std::string curline; + while (std::getline(file, curline)) + { + // new material and material name + if (algorithm::firstToken(curline) == "newmtl") + { + if (!listening) + { + listening = true; + + if (curline.size() > 7) + { + tempMaterial.name = algorithm::tail(curline); + } + else + { + tempMaterial.name = "none"; + } + } + else + { + // Generate the material + + // Push Back loaded Material + LoadedMaterials.push_back(tempMaterial); + + // Clear Loaded Material + tempMaterial = Material(); + + if (curline.size() > 7) + { + tempMaterial.name = algorithm::tail(curline); + } + else + { + tempMaterial.name = "none"; + } + } + } + // Ambient Color + if (algorithm::firstToken(curline) == "Ka") + { + std::vector temp; + algorithm::split(algorithm::tail(curline), temp, " "); + + if (temp.size() != 3) + continue; + + tempMaterial.Ka.X = std::stof(temp[0]); + tempMaterial.Ka.Y = std::stof(temp[1]); + tempMaterial.Ka.Z = std::stof(temp[2]); + } + // Diffuse Color + if (algorithm::firstToken(curline) == "Kd") + { + std::vector temp; + algorithm::split(algorithm::tail(curline), temp, " "); + + if (temp.size() != 3) + continue; + + tempMaterial.Kd.X = std::stof(temp[0]); + tempMaterial.Kd.Y = std::stof(temp[1]); + tempMaterial.Kd.Z = std::stof(temp[2]); + } + // Specular Color + if (algorithm::firstToken(curline) == "Ks") + { + std::vector temp; + algorithm::split(algorithm::tail(curline), temp, " "); + + if (temp.size() != 3) + continue; + + tempMaterial.Ks.X = std::stof(temp[0]); + tempMaterial.Ks.Y = std::stof(temp[1]); + tempMaterial.Ks.Z = std::stof(temp[2]); + } + // Specular Exponent + if (algorithm::firstToken(curline) == "Ns") + { + tempMaterial.Ns = std::stof(algorithm::tail(curline)); + } + // Optical Density + if (algorithm::firstToken(curline) == "Ni") + { + tempMaterial.Ni = std::stof(algorithm::tail(curline)); + } + // Dissolve + if (algorithm::firstToken(curline) == "d") + { + tempMaterial.d = std::stof(algorithm::tail(curline)); + } + // Illumination + if (algorithm::firstToken(curline) == "illum") + { + tempMaterial.illum = std::stoi(algorithm::tail(curline)); + } + // Ambient Texture Map + if (algorithm::firstToken(curline) == "map_Ka") + { + tempMaterial.map_Ka = algorithm::tail(curline); + } + // Diffuse Texture Map + if (algorithm::firstToken(curline) == "map_Kd") + { + tempMaterial.map_Kd = algorithm::tail(curline); + } + // Specular Texture Map + if (algorithm::firstToken(curline) == "map_Ks") + { + tempMaterial.map_Ks = algorithm::tail(curline); + } + // Specular Hightlight Map + if (algorithm::firstToken(curline) == "map_Ns") + { + tempMaterial.map_Ns = algorithm::tail(curline); + } + // Alpha Texture Map + if (algorithm::firstToken(curline) == "map_d") + { + tempMaterial.map_d = algorithm::tail(curline); + } + // Bump Map + if (algorithm::firstToken(curline) == "map_Bump" || algorithm::firstToken(curline) == "map_bump" || algorithm::firstToken(curline) == "bump") + { + tempMaterial.map_bump = algorithm::tail(curline); + } + } + + // Deal with last material + + // Push Back loaded Material + LoadedMaterials.push_back(tempMaterial); + + // Test to see if anything was loaded + // If not return false + if (LoadedMaterials.empty()) + return false; + // If so return true + else + return true; + } + }; +} \ No newline at end of file diff --git a/.outdated/graphics/inc/GraphicsLibApi.h b/.outdated/graphics/inc/GraphicsLibApi.h new file mode 100644 index 0000000..8926a14 --- /dev/null +++ b/.outdated/graphics/inc/GraphicsLibApi.h @@ -0,0 +1,19 @@ + +#pragma once + +#include "env.h" + +#ifdef ENV_OS_ANDROID +#include +#include +#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 \ No newline at end of file diff --git a/.outdated/graphics/inc/animations.h b/.outdated/graphics/inc/animations.h new file mode 100644 index 0000000..8f41f3d --- /dev/null +++ b/.outdated/graphics/inc/animations.h @@ -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 { + + 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&); + }; + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/inc/canvas.h b/.outdated/graphics/inc/canvas.h new file mode 100644 index 0000000..e40d9e7 --- /dev/null +++ b/.outdated/graphics/inc/canvas.h @@ -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(); + }; + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/inc/debugui.h b/.outdated/graphics/inc/debugui.h new file mode 100644 index 0000000..f3cee0a --- /dev/null +++ b/.outdated/graphics/inc/debugui.h @@ -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(); + }; + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/inc/fbuffer.h b/.outdated/graphics/inc/fbuffer.h new file mode 100644 index 0000000..f353313 --- /dev/null +++ b/.outdated/graphics/inc/fbuffer.h @@ -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(); + }; + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/inc/keycodes.h b/.outdated/graphics/inc/keycodes.h new file mode 100644 index 0000000..e947363 --- /dev/null +++ b/.outdated/graphics/inc/keycodes.h @@ -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; + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/inc/shader.h b/.outdated/graphics/inc/shader.h new file mode 100644 index 0000000..8335a8b --- /dev/null +++ b/.outdated/graphics/inc/shader.h @@ -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(); + }; + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/inc/simplegui.h b/.outdated/graphics/inc/simplegui.h new file mode 100644 index 0000000..2d6eaf5 --- /dev/null +++ b/.outdated/graphics/inc/simplegui.h @@ -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); + }; + + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/inc/texture.h b/.outdated/graphics/inc/texture.h new file mode 100644 index 0000000..6a7c3d5 --- /dev/null +++ b/.outdated/graphics/inc/texture.h @@ -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& 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); + }; + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/inc/window.h b/.outdated/graphics/inc/window.h new file mode 100644 index 0000000..23c1b32 --- /dev/null +++ b/.outdated/graphics/inc/window.h @@ -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 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 mCaptionsAddArea; + tp::Array 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 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(); + }; + }; +}; \ No newline at end of file diff --git a/.outdated/graphics/rsc/fonts/CONSOLAB.TTF b/.outdated/graphics/rsc/fonts/CONSOLAB.TTF new file mode 100644 index 0000000..ef6d555 Binary files /dev/null and b/.outdated/graphics/rsc/fonts/CONSOLAB.TTF differ diff --git a/.outdated/graphics/src/android_api.h b/.outdated/graphics/src/android_api.h new file mode 100644 index 0000000..d590d32 --- /dev/null +++ b/.outdated/graphics/src/android_api.h @@ -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 events; + +}; + +extern AndroidApi* gAndroidApi; \ No newline at end of file diff --git a/.outdated/graphics/src/android_main.cpp b/.outdated/graphics/src/android_main.cpp new file mode 100644 index 0000000..bcc64af --- /dev/null +++ b/.outdated/graphics/src/android_main.cpp @@ -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 +#include +#include +#include +#include +#include + +// jni +//#include +//#include +//#include +//#include +#include +//#include +//#include + +// opengl +#include +#include +//#include "GL/glew.h" + +// glue +#include +#include +#include +#include <../../../android/native_app_glue/android_native_app_glue.h> + +// AcquireASensorManagerInstance +#include + +#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 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 + +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 +//#include + +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 \ No newline at end of file diff --git a/.outdated/graphics/src/android_native_app_glue.c b/.outdated/graphics/src/android_native_app_glue.c new file mode 100644 index 0000000..db624a1 --- /dev/null +++ b/.outdated/graphics/src/android_native_app_glue.c @@ -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 + +#include +#include +#include +#include + +#include + +#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); +} diff --git a/.outdated/graphics/src/android_native_app_glue.h b/.outdated/graphics/src/android_native_app_glue.h new file mode 100644 index 0000000..89eafe3 --- /dev/null +++ b/.outdated/graphics/src/android_native_app_glue.h @@ -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 +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The native activity interface provided by + * 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 diff --git a/.outdated/graphics/src/animations.cpp b/.outdated/graphics/src/animations.cpp new file mode 100644 index 0000000..84df77a --- /dev/null +++ b/.outdated/graphics/src/animations.cpp @@ -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)); +} \ No newline at end of file diff --git a/.outdated/graphics/src/canvas.cpp b/.outdated/graphics/src/canvas.cpp new file mode 100644 index 0000000..899784a --- /dev/null +++ b/.outdated/graphics/src/canvas.cpp @@ -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; +} diff --git a/.outdated/graphics/src/debugui.cpp b/.outdated/graphics/src/debugui.cpp new file mode 100644 index 0000000..dfcc0f3 --- /dev/null +++ b/.outdated/graphics/src/debugui.cpp @@ -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 +#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 +#include +#include +#include +#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; +} diff --git a/.outdated/graphics/src/fbuffer.cpp b/.outdated/graphics/src/fbuffer.cpp new file mode 100644 index 0000000..369caa0 --- /dev/null +++ b/.outdated/graphics/src/fbuffer.cpp @@ -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; } + +}; \ No newline at end of file diff --git a/.outdated/graphics/src/linux_window.cpp b/.outdated/graphics/src/linux_window.cpp new file mode 100644 index 0000000..1162d2f --- /dev/null +++ b/.outdated/graphics/src/linux_window.cpp @@ -0,0 +1,282 @@ + +#include "window.h" + +#include "GL/glew.h" +#include "GLFW/glfw3.h" + +#include +#include + +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; +} diff --git a/.outdated/graphics/src/shader.cpp b/.outdated/graphics/src/shader.cpp new file mode 100644 index 0000000..b630b5a --- /dev/null +++ b/.outdated/graphics/src/shader.cpp @@ -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 + +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 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 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; + } + +}; \ No newline at end of file diff --git a/.outdated/graphics/src/simplegui.cpp b/.outdated/graphics/src/simplegui.cpp new file mode 100644 index 0000000..daed0e3 --- /dev/null +++ b/.outdated/graphics/src/simplegui.cpp @@ -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; +} \ No newline at end of file diff --git a/.outdated/graphics/src/texture.cpp b/.outdated/graphics/src/texture.cpp new file mode 100644 index 0000000..94fa96e --- /dev/null +++ b/.outdated/graphics/src/texture.cpp @@ -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& 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 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 + } +}; + + diff --git a/.outdated/graphics/src/windows_window.cpp b/.outdated/graphics/src/windows_window.cpp new file mode 100644 index 0000000..ca721cc Binary files /dev/null and b/.outdated/graphics/src/windows_window.cpp differ diff --git a/.outdated/graphics/tests/tests.cpp b/.outdated/graphics/tests/tests.cpp new file mode 100644 index 0000000..b1d5304 --- /dev/null +++ b/.outdated/graphics/tests/tests.cpp @@ -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(); +} \ No newline at end of file