Skip to content

Commit 91c6d41

Browse files
Merge pull request #424 from Pulsar4xDevs/imgui.net
Update to ImGui.NET 1.92.5 with new texture system
2 parents 7aa0d52 + f8485f5 commit 91c6d41

26 files changed

Lines changed: 114 additions & 106 deletions

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "Pulsar4X/external/ImGui.NET"]
2+
path = Pulsar4X/external/ImGui.NET
3+
url = https://github.com/behindcurtain3/ImGui.NET.git

Pulsar4X/GameData/basemod/ScenarioFiles/systems/sol/earth.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
{ "Id": "default-design-factory", "Amount": 1 },
6060
{ "Id": "default-design-shipyard", "Amount": 1 },
6161
{ "Id": "default-design-spaceport", "Amount": 1 },
62-
{ "Id": "default-design-research-lab", "Amount": 1 },
62+
{ "Id": "default-design-research-lab", "Amount": 2 },
6363
{ "id": "default-design-city-hall", "amount": 1 },
6464
{ "Id": "default-design-local-construction", "Amount": 1}
6565
],

Pulsar4X/GameEngine/Engine/ManagerSubPulse.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ internal void AddEntityInterupt(DateTime nextDateTime, string actionProcessor, E
148148
_instanceProcessorsQueue.Add(nextDateTime, (actionProcessor, entity));
149149
}
150150
}
151-
151+
152152
/// <summary>
153153
/// this type of interupt will attempt to run the action processor on all entities within the system
154154
/// </summary>
@@ -184,7 +184,7 @@ internal void AddSystemInterupt(DateTime nextDateTime, Type dbType)
184184
return processor.RunFrequency;
185185
return null;
186186
}
187-
187+
188188

189189
internal void AddSystemInterupt(BaseDataBlob db)
190190
{
@@ -208,7 +208,7 @@ internal void AddSystemInterupt(BaseDataBlob db)
208208
DateTime nextDT = _processToDateTime + next;
209209

210210
if(nextDT < StarSysDateTime) throw new Exception("Trying to add an interrupt in the past");
211-
211+
212212
Type dbType = db.GetType();
213213
AddSystemInterupt(nextDT, dbType);
214214

@@ -319,11 +319,11 @@ private void ProcessToNextInterupt()
319319
Trace.WriteLine(String.Format("[{0:u}|{1:u}] running hotloop processor: {2} with entity manager: {3}",
320320
StarSysDateTime, _subStepDateTime, type.Name, _entityManager.ManagerID));
321321
#endif
322-
Performance.Start(type.Name);
322+
Performance.Start(_entityManager.ManagerID + "-" + type.Name);
323323
CurrentProcess = type.ToString();
324324
var proc = _game.ProcessorManager.HotloopProcessors[type];
325325
int count = proc.ProcessManager(_entityManager, deltaSeconds);
326-
Performance.Stop(type.Name);
326+
Performance.Stop(_entityManager.ManagerID + "-" + type.Name);
327327

328328
if (count == 0)
329329
HotLoopProcessorsNextRun[type] = null;

Pulsar4X/Pulsar4X.Client/IMGUISDL/ImGuiSDL3.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,7 @@ public unsafe ImFontPtr LoadFont(string path, string file, float fontSize, strin
403403
font = fontAtlas.AddFontFromFileTTF(filePath, fontSize, config, ranges.Data);
404404
}
405405

406-
if(merge)
407-
fontAtlas.Build();
406+
// Note: In ImGui 1.92+, font atlas is built automatically when needed
408407

409408
return font;
410409
}

Pulsar4X/Pulsar4X.Client/IMGUISDL/ImGuiSDL3Renderer.cs

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,70 @@ public ImGuiSDL3Renderer(nint renderer)
2929

3030
ImGuiIOPtr io = ImGui.GetIO();
3131
io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset;
32+
io.BackendFlags |= ImGuiBackendFlags.RendererHasTextures;
33+
34+
// Mark that we support the new texture system
35+
io.Fonts.RendererHasTextures = true;
3236
}
3337

3438
public void Dispose()
3539
{
3640
DestroyDeviceObjects();
3741
}
3842

39-
public void NewFrame()
43+
public unsafe void NewFrame()
4044
{
41-
if (_fontTexture == IntPtr.Zero)
45+
// Handle texture updates for the new ImGui 1.92+ texture system
46+
ImGuiIOPtr io = ImGui.GetIO();
47+
var texList = io.Fonts.TexList;
48+
49+
for (int i = 0; i < texList.Size; i++)
4250
{
43-
CreateDeviceObjects();
51+
var texData = texList[i];
52+
var status = texData.Status;
53+
54+
if (status == ImTextureStatus.WantCreate || status == ImTextureStatus.WantUpdates)
55+
{
56+
// Create or update the texture
57+
int width = texData.Width;
58+
int height = texData.Height;
59+
byte* pixels = (byte*)texData.Pixels;
60+
61+
if (width > 0 && height > 0 && pixels != null)
62+
{
63+
// Create SDL texture
64+
var surface = SDL.CreateSurfaceFrom(width, height, SDL.PixelFormat.RGBA8888, (IntPtr)pixels, width * 4);
65+
if (surface != IntPtr.Zero)
66+
{
67+
var texture = SDL.CreateTextureFromSurface(Renderer, surface);
68+
if (texture != IntPtr.Zero)
69+
{
70+
SDL.UpdateTexture(texture, IntPtr.Zero, (IntPtr)pixels, width * 4);
71+
SDL.SetTextureBlendMode(texture, SDL.BlendMode.Blend);
72+
SDL.SetTextureScaleMode(texture, SDL.ScaleMode.Nearest);
73+
74+
// Store the texture ID
75+
texData.SetTexID(texture);
76+
texData.SetStatus(ImTextureStatus.OK);
77+
78+
// Track font texture for cleanup
79+
if (i == 0)
80+
_fontTexture = texture;
81+
}
82+
SDL.DestroySurface(surface);
83+
}
84+
}
85+
}
86+
else if (status == ImTextureStatus.WantDestroy)
87+
{
88+
var texId = texData.TexID;
89+
if (texId != IntPtr.Zero)
90+
{
91+
SDL.DestroyTexture(texId);
92+
texData.SetTexID(IntPtr.Zero);
93+
}
94+
texData.SetStatus(ImTextureStatus.Destroyed);
95+
}
4496
}
4597
}
4698

@@ -245,57 +297,10 @@ private void DestroyDeviceObjects()
245297
DestroyFontsTexture();
246298
}
247299

248-
public unsafe IntPtr CreateFontsTexture(ImFontPtr font)
249-
{
250-
ImGuiIOPtr io = ImGui.GetIO();
251-
252-
// Build texture atlas
253-
io.Fonts.GetTexDataAsRGBA32(out byte* pixels, out int width, out int height);
254-
255-
// Create surface from pixel data
256-
var surface = SDL.CreateSurfaceFrom(width, height, SDL.PixelFormat.RGBA8888, (IntPtr)pixels, width * 4);
257-
if(surface == IntPtr.Zero)
258-
{
259-
SDL.LogError(SDL.LogCategory.Application, $"Failed to create font surface: {SDL.GetError()}");
260-
return IntPtr.Zero;
261-
}
262-
263-
// Create texture
264-
var fontTexture = SDL.CreateTextureFromSurface(Renderer, surface);
265-
if (fontTexture == IntPtr.Zero)
266-
{
267-
SDL.LogError(SDL.LogCategory.Application, $"Failed to create font texture: {SDL.GetError()}");
268-
return IntPtr.Zero;
269-
}
270-
271-
// Update texture directly without converting pixel format
272-
if (!SDL.UpdateTexture(fontTexture, IntPtr.Zero, (IntPtr)pixels, width * 4))
273-
{
274-
SDL.LogError(SDL.LogCategory.Application, $"Failed to update font texture: {SDL.GetError()}");
275-
return IntPtr.Zero;
276-
}
277-
278-
// Ensure proper blending for font rendering
279-
SDL.SetTextureBlendMode(fontTexture, SDL.BlendMode.Blend);
280-
281-
// Use nearest neighbor filtering for crisp font rendering at small sizes
282-
SDL.SetTextureScaleMode(fontTexture, SDL.ScaleMode.Nearest);
283-
284-
// Store our identifier
285-
io.Fonts.SetTexID(fontTexture);
286-
287-
SDL.DestroySurface(surface);
288-
io.Fonts.ClearTexData();
289-
290-
return fontTexture;
291-
}
292-
293300
private void DestroyFontsTexture()
294301
{
295-
ImGuiIOPtr io = ImGui.GetIO();
296302
if(_fontTexture != IntPtr.Zero)
297303
{
298-
io.Fonts.SetTexID(IntPtr.Zero);
299304
SDL.DestroyTexture(_fontTexture);
300305
_fontTexture = IntPtr.Zero;
301306
}

Pulsar4X/Pulsar4X.Client/Interface/DisplayHelpers.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ namespace Pulsar4X.Client
1616
public static class DisplayHelpers
1717
{
1818
private static Dictionary<string, int> _peopleChooserSelections = new();
19+
20+
/// <summary>
21+
/// Creates an ImTextureRef from an IntPtr texture ID for use with ImGui.Image and ImGui.ImageButton.
22+
/// </summary>
23+
public static unsafe ImTextureRef ToTextureRef(this IntPtr textureId)
24+
{
25+
return new ImTextureRef { _TexData = null, _TexID = textureId };
26+
}
1927
public static void Header(string text, string? tooltip = null)
2028
{
2129
ImGui.PushStyleColor(ImGuiCol.Text, Styles.DescriptiveColor);
@@ -288,7 +296,7 @@ public static int PeopleChooser(GlobalUIState state, int currentlySelectedId, Co
288296
IntPtr portraitTexture = state.Img_Character();
289297
if(portraitTexture != IntPtr.Zero)
290298
{
291-
ImGui.Image(portraitTexture, new Vector2(portraitSize, portraitSize));
299+
ImGui.Image(portraitTexture.ToTextureRef(), new Vector2(portraitSize, portraitSize));
292300
ImGui.SameLine();
293301
}
294302

Pulsar4X/Pulsar4X.Client/Interface/Displays/IndustryDisplay.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ public void ProductionLineDisplay(GlobalUIState state)
250250
if (batchJob.Auto)
251251
{
252252
ImGui.SameLine();
253-
ImGui.Image(state.Img_Repeat(), new Vector2(16, 16));
253+
ImGui.Image(state.Img_Repeat().ToTextureRef(), new Vector2(16, 16));
254254
}
255255

256256
ImGui.TableNextColumn();

Pulsar4X/Pulsar4X.Client/Interface/Displays/IndustryPanel.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public void ProdLineDisplay()
193193
if (batchJob.Auto)
194194
{
195195
ImGui.SameLine();
196-
ImGui.Image(_state.Img_Repeat(), new Vector2(16, 16));
196+
ImGui.Image(_state.Img_Repeat().ToTextureRef(), new Vector2(16, 16));
197197
}
198198

199199
ImGui.NextColumn();
@@ -222,21 +222,21 @@ void EditButtonsDisplay()
222222
//ImGui.BeginChild("Buttons", new Vector2(116, 100), true, ImGuiWindowFlags.ChildWindow);
223223
ImGui.BeginGroup();
224224

225-
if (ImGui.ImageButton("up", _state.Img_Up(), new Vector2(16, 8)) && _selectedExistingConJob != null)
225+
if (ImGui.ImageButton("up", _state.Img_Up().ToTextureRef(), new Vector2(16, 8)) && _selectedExistingConJob != null)
226226
{
227227
var cmd = IndustryOrder2.CreateChangePriorityOrder(_factionID, _selectedEntity, _selectedProdLine, _selectedExistingConJob.JobID, -1);
228228
_uiState.Game.OrderHandler.HandleOrder(cmd);
229229
}
230230

231-
if (ImGui.ImageButton("down", _state.Img_Down(), new Vector2(16, 8)) && _selectedExistingConJob != null)
231+
if (ImGui.ImageButton("down", _state.Img_Down().ToTextureRef(), new Vector2(16, 8)) && _selectedExistingConJob != null)
232232
{
233233
var cmd = IndustryOrder2.CreateChangePriorityOrder(_factionID, _selectedEntity, _selectedProdLine, _selectedExistingConJob.JobID, 1);
234234
_uiState.Game.OrderHandler.HandleOrder(cmd);
235235
}
236236

237237
ImGui.EndGroup();
238238
ImGui.SameLine();
239-
if (ImGui.ImageButton("repeat", _state.Img_Repeat(), new Vector2(16, 16)) && _selectedExistingConJob != null)
239+
if (ImGui.ImageButton("repeat", _state.Img_Repeat().ToTextureRef(), new Vector2(16, 16)) && _selectedExistingConJob != null)
240240
{
241241

242242
var jobcount = _selectedExistingConJob.NumberOrdered;
@@ -247,7 +247,7 @@ void EditButtonsDisplay()
247247
}
248248

249249
ImGui.SameLine();
250-
if (ImGui.ImageButton("cancel", _state.Img_Cancel(), new Vector2(16, 16)) && _selectedExistingConJob != null)
250+
if (ImGui.ImageButton("cancel", _state.Img_Cancel().ToTextureRef(), new Vector2(16, 16)) && _selectedExistingConJob != null)
251251
{
252252
//new ConstructCancelJob(_uiState.Faction.Guid, _selectedEntity.Guid, _selectedEntity.StarSysDateTime, _selectedExistingConJob.JobID);
253253
var cmd = IndustryOrder2.CreateCancelJobOrder(_factionID, _selectedEntity, _selectedProdLine, _selectedExistingConJob.JobID);

Pulsar4X/Pulsar4X.Client/Interface/HUD/Selector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class Selector : PulsarGuiWindow
2424
//constructs the toolbar with the given buttons
2525
private Selector()
2626
{
27-
_flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoDocking;
27+
_flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoBackground;
2828

2929
_uiState.OnStarSystemAdded += SystemAdded;
3030
_uiState.OnFactionChanged += FactionChanged;

Pulsar4X/Pulsar4X.Client/Interface/HUD/TimeControl.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ internal override void Display()
8383
var buttonTexture = isPaused ? _uiState.Img_Play() : _uiState.Img_Pause();
8484

8585
ImGui.SameLine();
86-
if (ImGui.ImageButton("playpause", buttonTexture, _iconSize))
86+
if (ImGui.ImageButton("playpause", buttonTexture.ToTextureRef(), _iconSize))
8787
{
8888
PausePlayPressed();
8989
}
@@ -92,7 +92,7 @@ internal override void Display()
9292
if (isPaused)
9393
{
9494
ImGui.SameLine();
95-
if (ImGui.ImageButton("onestep", _uiState.Img_OneStep(), _iconSize))
95+
if (ImGui.ImageButton("onestep", _uiState.Img_OneStep().ToTextureRef(), _iconSize))
9696
{
9797
OneStepPressed();
9898
}

0 commit comments

Comments
 (0)