Skip to content

Commit

Permalink
Samples update
Browse files Browse the repository at this point in the history
- Updated sample code to handle DPI
- Fixed some texture update issue on server
  • Loading branch information
sammyfreg committed Dec 29, 2023
1 parent d523139 commit 051d8cd
Show file tree
Hide file tree
Showing 23 changed files with 928 additions and 600 deletions.
10 changes: 5 additions & 5 deletions Code/Client/NetImgui_Api.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
//! @Name : NetImgui
//=================================================================================================
//! @author : Sammy Fatnassi
//! @date : 2023/12/24
//! @version : v1.9.6
//! @date : 2023/12/2
//! @version : v1.9.7
//! @Details : For integration info : https://github.com/sammyfreg/netImgui/wiki
//=================================================================================================
#define NETIMGUI_VERSION "1.9.6" // Server Support of DPI font regeneration
#define NETIMGUI_VERSION_NUM 10906
#define NETIMGUI_VERSION "1.9.7" // Update to samples, texture creation fix
#define NETIMGUI_VERSION_NUM 10907



Expand Down Expand Up @@ -190,7 +190,7 @@ NETIMGUI_API bool IsConnectionPending(void);
NETIMGUI_API bool IsDrawing(void);

//=================================================================================================
// True when we are currently drawinf on the NetImguiServer application
// True when we are currently drawing on the NetImguiServer application
// Means that we are between NewFrame() and EndFrame() of drawing for remote application
//=================================================================================================
NETIMGUI_API bool IsDrawingRemote(void);
Expand Down
2 changes: 1 addition & 1 deletion Code/Client/Private/NetImgui_Api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ bool NewFrame(bool bSupportFrameSkip)
ScopedBool scopedInside(client.mbInsideNewEnd, true);
assert(!client.mbIsDrawing);

// ImGui Newframe handled by remote connection settings
// ImGui Newframe handled by remote connection settings
if( NetImgui::IsConnected() )
{
ImGui::SetCurrentContext(client.mpContext);
Expand Down
177 changes: 140 additions & 37 deletions Code/Sample/Common/Sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,147 @@
//=================================================================================================

#include <NetImgui_Api.h>
#include "..\Common\Sample.h"
#include <math.h>
#include "Sample.h"
#include "../../ServerApp/Source/Fonts/Roboto_Medium.cpp"

// Since NetImgui is disabled in this sample, it doesn't already include this header
// When NetImgui is disabled, it doesn't include these needed headers
#if !NETIMGUI_ENABLED
#include "imgui.h"
namespace SampleClient { void ClientUtil_ImGuiContent_Common(const char*, NetImgui::ThreadFunctPtr, NetImgui::FontCreationFuncPtr){} }
#include "imgui.h"
#include <stdint.h>
#endif

#else
//=================================================================================================
// FontCreationCallback_Default
//-------------------------------------------------------------------------------------------------
// Default handling of remote server request to adjust the font DPI
// This is optional, when no callback is specified on connection function, we use
// 'ImGui::GetIO().FontGlobalScale' to adjust the font display size. Simple but blurier results.
//=================================================================================================
void FontCreationCallback_Default(float PreviousDPIScale, float NewDPIScale)
{
IM_UNUSED(PreviousDPIScale); IM_UNUSED(NewDPIScale);
#if NETIMGUI_ENABLED
if (GetSample().UpdateFont(NewDPIScale, false))
{
uint8_t* pPixelData(nullptr); int width(0), height(0);
ImGui::GetIO().Fonts->GetTexDataAsAlpha8(&pPixelData, &width, &height);
NetImgui::SendDataTexture(ImGui::GetIO().Fonts->TexID, pPixelData, static_cast<uint16_t>(width), static_cast<uint16_t>(height), NetImgui::eTexFormat::kTexFmtA8);
}
#endif
}

namespace SampleClient
//=================================================================================================
// Constructor
//-------------------------------------------------------------------------------------------------
//
//=================================================================================================
SampleClient_Base::SampleClient_Base(const char* sampleName)
: mSampleName(sampleName)
{
#if NETIMGUI_ENABLED
mConnect_PortClient = NetImgui::kDefaultClientPort;
mConnect_PortServer = NetImgui::kDefaultServerPort;
mCallback_FontGenerate = FontCreationCallback_Default;
#endif
}

static int sClientPort = NetImgui::kDefaultClientPort;
static int sServerPort = NetImgui::kDefaultServerPort;
static char sServerHostname[128] = {"localhost"};
static bool sbShowDemoWindow = false;
//=================================================================================================
// Startup
//-------------------------------------------------------------------------------------------------
//
//=================================================================================================
bool SampleClient_Base::Startup()
{
mpContextLocal = mpContextMain = ImGui::GetCurrentContext();
#if NETIMGUI_ENABLED
if( !NetImgui::Startup() )
return false;
#endif
return true;
}

//=================================================================================================
// ClientUtil_ImGuiContent_Common
// Shutdown
//-------------------------------------------------------------------------------------------------
// Function called by all samples, to display the Connection Options, and some other default
// MainMenu entries.
//
//=================================================================================================
void SampleClient_Base::Shutdown()
{
#if NETIMGUI_ENABLED
NetImgui::Shutdown();
#endif
}

//=================================================================================================
// UpdateFont
//-------------------------------------------------------------------------------------------------
// Called from the main function and by remote server, to regnerate our font texture
// with the appropriate character pixel size. This is to handle monitor with DPI scaling to make
// small text readable on high resolution screens.
//
// @param zAppName: Name displayed in the Main Menu bar
// @param customThreadLauncher: Optional thread launcher function to pass along NetImgui
// #param FontCreateFunction: Optional font generation function to pass along NetImgui. Used to adjust to remote server monitor DPI
// The DPI scaling can also be entirely ignored by generating the font texture once
// to a fixed size, paired with 'ImGui::GetIO().FontGlobalScale' for the text size increase.
// However, this create blurier text. See 'SampleFontDPI' for more details
//=================================================================================================
bool SampleClient_Base::UpdateFont(float fontScaleDPI, bool isLocal)
{
IM_UNUSED(isLocal);
constexpr float kFontPixelSize = 16.f;

#if NETIMGUI_ENABLED
// Ignore local font resize when remotely drawing to this context
bool isLocalFontWithRemoteContext = isLocal && NetImgui::IsConnected() && mpContextMain == ImGui::GetCurrentContext();
if( !isLocalFontWithRemoteContext )
#endif
{
// We detect if the current scaling result in a different pixel size
// When handling many font, each different font size would have to be tested
int pixelSizeCurrent = static_cast<int>(roundf(kFontPixelSize * mGeneratedFontScaleDPI));
int pixelSizeWanted = static_cast<int>(roundf(kFontPixelSize * fontScaleDPI));
if(pixelSizeCurrent != pixelSizeWanted)
{
ImFontConfig FontConfig = {};
ImFontAtlas* FontAtlas = ImGui::GetIO().Fonts;
mGeneratedFontScaleDPI = fontScaleDPI;
FontConfig.SizePixels = static_cast<float>(pixelSizeWanted);
FontAtlas->Clear();

#if 1
// Using Roboto Font with DPI awareness
StringCopy(FontConfig.Name, "Roboto Medium");
ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(Roboto_Medium_compressed_data, Roboto_Medium_compressed_size, FontConfig.SizePixels, &FontConfig);
#else
// But could as easily rely on the default font
FontAtlas->AddFontDefault(&FontConfig);
#endif

FontAtlas->Build();
// Regenerate the Font Texture (only if used by local context)
extern void ExtraSampleBackend_UpdateFontTexture();
if( ImGui::GetCurrentContext() == mpContextLocal ){
ExtraSampleBackend_UpdateFontTexture();
}
return true;
}
}
return false;
}

//=================================================================================================
// Draw_Connect
//-------------------------------------------------------------------------------------------------
// Function called by all samples, to display the Connection Options, and some other default
// MainMenu entries.
//=================================================================================================
void ClientUtil_ImGuiContent_Common(const char* zAppName, NetImgui::ThreadFunctPtr customThreadLauncher, NetImgui::FontCreationFuncPtr FontCreateFunction)
void SampleClient_Base::Draw_Connect()
{
#if NETIMGUI_ENABLED
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3,6) );
if( ImGui::BeginMainMenuBar() )
{
ImGui::AlignTextToFramePadding();
ImGui::TextColored(ImVec4(0.1, 1, 0.1, 1), "%s", zAppName);
ImGui::TextColored(ImVec4(0.1, 1, 0.1, 1), "%s", mSampleName);
ImGui::SameLine(0,32);

//-----------------------------------------------------------------------------------------
Expand All @@ -48,7 +155,7 @@ void ClientUtil_ImGuiContent_Common(const char* zAppName, NetImgui::ThreadFunctP
ImGui::TextUnformatted("Status: Connected");
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3, 3));
ImGui::SetCursorPosY(3);
if( ImGui::Button("Disconnect", ImVec2(120,0)) )
if( ImGui::Button(" Disconnect ") )
{
NetImgui::Disconnect();
}
Expand All @@ -62,7 +169,7 @@ void ClientUtil_ImGuiContent_Common(const char* zAppName, NetImgui::ThreadFunctP
ImGui::TextUnformatted("Status: Waiting Server");
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3, 3));
ImGui::SetCursorPosY(3);
if (ImGui::Button("Cancel", ImVec2(120,0)))
if (ImGui::Button(" Cancel "))
{
NetImgui::Disconnect();
}
Expand All @@ -74,19 +181,19 @@ void ClientUtil_ImGuiContent_Common(const char* zAppName, NetImgui::ThreadFunctP
//-----------------------------------------------------------------------------------------
{
//-------------------------------------------------------------------------------------
if( ImGui::BeginMenu("[ Connect to ]") )
if( ImGui::BeginMenu("[ Connect To ]") )
//-------------------------------------------------------------------------------------
{
ImGui::TextColored(ImVec4(0.1, 1, 0.1, 1), "Server Settings");
ImGui::InputText("Hostname", sServerHostname, sizeof(sServerHostname));
ImGui::InputText("Hostname", mConnect_HostnameServer, sizeof(mConnect_HostnameServer));
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Address of PC running the netImgui server application. Can be an IP like 127.0.0.1");
ImGui::InputInt("Port", &sServerPort);
ImGui::InputInt("Port", &mConnect_PortServer);
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("Connect", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
NetImgui::ConnectToApp(zAppName, sServerHostname, sServerPort, customThreadLauncher, FontCreateFunction);
NetImgui::ConnectToApp(mSampleName, mConnect_HostnameServer, mConnect_PortServer, mCallback_ThreadLaunch, mCallback_FontGenerate);
}
ImGui::EndMenu();
}
Expand All @@ -99,12 +206,12 @@ void ClientUtil_ImGuiContent_Common(const char* zAppName, NetImgui::ThreadFunctP
//-------------------------------------------------------------------------------------
{
ImGui::TextColored(ImVec4(0.1, 1, 0.1, 1), "Client Settings");
ImGui::InputInt("Port", &sClientPort);
ImGui::InputInt("Port", &mConnect_PortClient);
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("Listen", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
NetImgui::ConnectFromApp(zAppName, sClientPort, customThreadLauncher, FontCreateFunction);
NetImgui::ConnectFromApp(mSampleName, mConnect_PortClient, mCallback_ThreadLaunch, mCallback_FontGenerate);
}
ImGui::EndMenu();
}
Expand All @@ -115,23 +222,19 @@ void ClientUtil_ImGuiContent_Common(const char* zAppName, NetImgui::ThreadFunctP
ImGui::SameLine(0,40);
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.8,0.8,0.8,0.9) );
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3, 3));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, sbShowDemoWindow ? 1.f : 0.f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, mbShowDemoWindow ? 1.f : 0.f);
ImGui::SetCursorPosY(3);
if( ImGui::Button("Show ImGui Demo", ImVec2(120,0)) )
{
sbShowDemoWindow = !sbShowDemoWindow;
}
if( ImGui::Button(" Show ImGui Demo ") ){
mbShowDemoWindow = !mbShowDemoWindow;
}
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
ImGui::EndMainMenuBar();
}
ImGui::PopStyleVar();

if( sbShowDemoWindow )
{
ImGui::ShowDemoWindow(&sbShowDemoWindow);
if( mbShowDemoWindow ){
ImGui::ShowDemoWindow(&mbShowDemoWindow);
}
#endif // #if NETIMGUI_ENABLED
}

} // namespace SampleClient
#endif
68 changes: 54 additions & 14 deletions Code/Sample/Common/Sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

#include <NetImgui_Api.h>

// forward declares when NetImgui not enabled
// Forward declares when NetImgui is not enabled
#if !NETIMGUI_ENABLED
struct ImGuiContext;
struct ImDrawData;
namespace NetImgui
{
Expand All @@ -12,20 +13,59 @@
}
#endif

namespace SampleClient
class SampleClient_Base
{
//-----------------------------------------------------------------------------
// Methods implemented in each samples
//-----------------------------------------------------------------------------
bool Client_Startup();
void Client_Shutdown();
ImDrawData* Client_Draw();

//-----------------------------------------------------------------------------
// Utility methods available in Samples
//-----------------------------------------------------------------------------
void ClientUtil_ImGuiContent_Common(const char* zAppName, NetImgui::ThreadFunctPtr customThreadLauncher=nullptr, NetImgui::FontCreationFuncPtr FontCreateFunction=nullptr);
public:
SampleClient_Base(const char* sampleName); //!< Constructor receiving pointer to constant string that must remains valid
virtual bool Startup(); //!< Called once when starting
virtual void Shutdown(); //!< Called once when exiting
virtual bool UpdateFont(float fontScaleDPI, bool isLocal); //!< Receive command to create/update the Font Atlas and its texture data
virtual ImDrawData* Draw() = 0; //!< Each sample should have their Dear ImGui drawing routines in this overloaded method

protected:
void Draw_Connect(); //!< Display UI for initiating a connection to the remote NetImgui server application
const char* mSampleName = nullptr; //!< Name displayed in the Main Menu bar (must receive string pointer in constructor that remains valid)
ImGuiContext* mpContextMain = nullptr; //!< Pointer to main context created in main.cpp (used to detect when to update font texture)
ImGuiContext* mpContextLocal = nullptr; //!< Pointer to context used for local draw. Most sample leave it to the same as mpContextMain (used to detect when to update font texture)
NetImgui::ThreadFunctPtr mCallback_ThreadLaunch = nullptr; //!< [Optional] Thread launcher callback assigned on NetImgui connection. Used to start a new thread for coms with NetImgui server
NetImgui::FontCreationFuncPtr mCallback_FontGenerate = nullptr; //!< [Optional] Font generation callback assigned on NetImgui connection. Used to adjust the font data to remote server DPI
float mGeneratedFontScaleDPI = 0.f; //!< Current generated font texture DPI
bool mbShowDemoWindow = false; //!< If we should show the Dear ImGui demo window
char mConnect_HostnameServer[128] = {"localhost"}; //!< IP/Hostname used to send a connection request when when trying to reach the server
int mConnect_PortServer = 0; //!< Port used to send a connection request when when trying to reach the server
int mConnect_PortClient = 0; //!< Port opened when waiting for a server connection request
};

//=============================================================================
// The _s string functions are a mess. There's really no way to do this right
// in a cross-platform way. Best solution I've found is to just use strncpy,
// infer the buffer length, and null terminate. Still need to suppress
// the warning on Windows.
// See https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
// and many other discussions online on the topic.
//=============================================================================
template <size_t charCount>
inline void StringCopy(char (&output)[charCount], const char* pSrc, size_t srcCharCount=0xFFFFFFFE)
{
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning (push)
#pragma warning (disable: 4996) // warning C4996: 'strncpy': This function or variable may be unsafe.
#endif

size_t charToCopyCount = charCount < srcCharCount + 1 ? charCount : srcCharCount + 1;
strncpy(output, pSrc, charToCopyCount - 1);
output[charCount - 1] = 0;

#if defined(_MSC_VER) && defined(__clang__)
#pragma clang diagnostic pop
#elif defined(_MSC_VER)
#pragma warning (pop)
#endif
}

#include <Client/Private/NetImgui_WarningDisable.h>
SampleClient_Base& GetSample(); // Each Sample must implement this function and return a valid sample object

#include <Client/Private/NetImgui_WarningDisable.h>
Loading

0 comments on commit 051d8cd

Please sign in to comment.