Giter Club home page Giter Club logo

imgui's Introduction

imgui

Immediate mode 3D2D UI for Garry's Mod. See some real-world uses here.

Features

  • Creating clickable buttons or tracking mouse in an area requires one line of code
  • Visibility optimizations to prevent UI from being rendered if it's not visible
  • Only a wrapper for cam.Start3D2D so all surface library functions are still usable
  • Error handling to prevent clients from crashing if a Lua error happens

Installation

Place imgui.lua somewhere in your addon or gamemode (eg. myaddon/lua/myaddon/imgui.lua) and make sure it is AddCSLuaFiled and available to your clientside rendering code.

Example

Using with entities:

-- 3D2D UI should be rendered in translucent pass, so this should be either TRANSLUCENT or BOTH
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT

function ENT:DrawTranslucent()
  -- While you can of course use the imgui.Start3D2D function for entities, IMGUI has some special syntax
  -- This function automatically calls LocalToWorld and LocalToWorldAngles respectively on position and angles 
  if imgui.Entity3D2D(self, Vector(0, 0, 50), Angle(0, 90, 90), 0.1) then
    -- render things
    
    imgui.End3D2D()
  end
end

Using with gamemode rendering hooks:

local imgui = include("imgui.lua") -- imgui.lua should be in same folder and AddCSLuaFile'd

hook.Add("PostDrawTranslucentRenderables", "PaintIMGUI", function(bDrawingSkybox, bDrawingDepth)
  -- Don't render during depth pass
  if bDrawingDepth then return end

  -- Starts the 3D2D context at given position, angle and scale.
  -- First 3 arguments are equivalent to cam.Start3D2D arguments.
  -- Fourth argument is the distance at which the UI panel won't be rendered anymore
  -- Fifth argument is the distance at which the UI will start fading away
  -- Function returns boolean indicating whether we should proceed with the rendering, hence the if statement
  -- These specific coordinates are for gm_construct at next to spawn
  if imgui.Start3D2D(Vector(980, -83, -79), Angle(0, 270, 90), 0.1, 200, 150) then
    -- This is a regular 3D2D context, so you can use normal surface functions to draw things
    surface.SetDrawColor(255, 127, 0)
    surface.DrawRect(0, 0, 100, 20)
    
    -- The main priority of the library is providing interactable panels
    -- This creates a clickable text button at x=0, y=30 with width=100, height=25
    -- The first argument is text to render inside button
    -- The second argument is special font syntax, that dynamically creates font "Roboto" at size 24
    -- The special syntax is just for convinience; you can use normal Garry's Mod font names in place
    -- The third, fourth, fith and sixth arguments are for x, y, width and height
    -- The seventh argument is the border width (optional)
    -- The last 3 arguments are for color, hover color, and press color (optional)
    if imgui.xTextButton("Foo bar", "!Roboto@24", 0, 30, 100, 25, 1, Color(255,255,255), Color(0,0,255), Color(255,0,0)) then
      -- the xTextButton function returns true, if user clicked on this area during this frame
      print("yay, we were clicked :D")
    end
  
    -- End the 3D2D context
    imgui.End3D2D()
  end
end)

Prefer entities over global hooks, since they work better with Source engine visiblity optimizations.

Debugging

image

Setting the developer convar to non-zero value draws a debugging panel on top of each IMGUI panel you draw. It shows few pieces of useful information:

  • The mouse coordinates or the reason why input is not enabled at the moment
  • World position of the TDUI panel, our distance from it and the distance at which the interface is hidden
  • World angles of the TDUI panel, the dot product between eye position and the panel and the angle between eye position and the panel
  • How many milliseconds did we spend on rendering this UI per frame (averaged over 100 frames/renders)

If you wish to hide the developer panel even with developer cvar, set imgui.DisableDeveloperMode = true right after importing the library.

API

3D2D Context

Start 3D2D context (calls cam.Start3D2D internally)

imgui.Start3D2D(pos, angles, scale, distanceHide, distanceFadeStart)

Start 3D2D context on an entity. Equivalent to imgui.Start3D2D, except a) pos/angles are automatically transformed from local entity coordinates into world coordinates and b) the entity will be ignored in mouse input collision checks.

imgui.Entity3D2D(ent, lpos, lang, scale, distanceHide, distanceFadeStart)

Ends 3D2D Context

imgui.End3D2D()

Cursor

Retrieves cursor position in 3D2D space. mx/my are null if player is not looking at the interface

local mx, my = imgui.CursorPos()

Whether player's 3D2D cursor is within given bounds

local hovering = imgui.IsHovering(x, y, w, h)

Whether player is currently pressing

local pressing = imgui.IsPressing()

Whether player is pressed during this frame. This is guaranteed to only be called once per click

local pressed = imgui.IsPressed()

UI functions (prefixed by x to separate them from core functionality)

Draws a rectangle button without any text or content

local wasPressed = imgui.xButton(x, y, w, h, borderWidth, borderClr, hoverClr, pressColor)

Draws a button with text inside. The font parameter is passed through imgui.xFont, so special font syntax is supported. The text is automatically centered within the button.

local wasPressed = imgui.xTextButton(text, font, x, y, w, h, borderWidth, color, hoverClr, pressColor)

Draws a cursor IF the cursor is within given bounds. Note: x,y,w,h should be the bounds for your whole IMGUI interface, eg. 0, 0, 512, 512 if you draw into the 3d2d space within those bounds.

imgui.xCursor(x, y, w, h)

Utility

Retrieves font name usable for Garry's Mod functions based on parameter. See Special font API section below

local fontName = imgui.xFont("!Roboto@24")

Expands the entity's render bounds to cover the whole rectangle passed as 3D2D coordinates. Note: x,y,w,h should be the bounds for your whole IMGUI interface, eg. 0, 0, 512, 512 if you draw into the 3d2d space within those bounds. (only usable inside imgui.Entity3D2D block, before imgui.End3D2D call)

imgui.ExpandRenderBoundsFromRect(x, y, w, h)

Error recovery

One of the goals of the library is to not crash the client even if something throws an error during the 3D2D context. This is achieved by halting all rendering library-wide if we detect attempt at starting a new 3D2D context without never having called End3D2D in between.

The recovery protocol triggers automatically if you try to nest 3D2D contexts due to error or any other reason. You'll be notified with a [IMGUI] Starting a new IMGUI context when previous one is still rendering. Shutting down rendering pipeline to prevent crashes.. message in console if that happens. The only way to recover from this error state is to re-initialize the whole library to reset the internal global state of IMGUI. There is no programmatic way to do this at the moment, but you can re-save the imgui.lua to trigger Lua autorefresh on it, or just reimport it.

Special font API

IMGUI comes with a simplified method for creating fonts. If you use the built-in functions, such as imgui.xTextButton, the passed font argument will automatically go through the font syntax parser, but you can also access it directly with imgui.xFont.

Here's an example of using imgui.xFont for drawing normal text:

-- Draw 'Foo bar' using Roboto font at font size 30 at 0, 0
draw.SimpleText("Foo bar", imgui.xFont("!Roboto@30"), 0, 0)

Networking data

You'll probably want to network data from client to server on button press or other clientside action at some point. IMGUI doesn't support this by itself, but netdata is a pretty good fit for entity-based UIs.

Here's an example entity with IMGUI + netdata:

ENT.Type = "anim"

if SERVER then
    function ENT:Initialize()
        self:SetModel("models/props_phx/construct/glass/glass_plate1x1.mdl")
        self:PhysicsInit(SOLID_VPHYSICS)
        self.Greeters = {} 
    end

    function ENT:ReceiveNetAction(cl)
        table.insert(self.Greeters, cl:Nick())
        self:NetDataUpdate()
    end
    
    function ENT:NetDataWrite()
        net.WriteTable(self.Greeters)
    end
end
if CLIENT then
    ENT.RenderGroup = RENDERGROUP_BOTH

    function ENT:NetDataRead()
        self.Greeters = net.ReadTable()
    end

    function ENT:DrawTranslucent()
        local imgui = resort.bar.imgui

        if imgui.Entity3D2D(self, Vector(0, 0, 3.5), Angle(0, 0, 0), 0.1) then
            if imgui.xTextButton("Say hello", "!Roboto@24", -100, -200, 200, 50, 1) then
                self:StartNetAction()
                net.SendToServer()
            end

            if self.Greeters then
                for i, nick in pairs(self.Greeters) do
                    draw.SimpleText(nick, "DermaLarge", 0, -160 + i * 25, nil, TEXT_ALIGN_CENTER)
                end
            end

            imgui.End3D2D()
        end
    end
end

imgui's People

Contributors

emperorsuper avatar nykez avatar someoneyouspite avatar tomdotbat avatar wyozi avatar xaviergmail avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

imgui's Issues

Errorless CTD on physgun interactions and re-entering render range

I've been getting routine CTDs when I pull out my physgun near a panel, move an entity the panel is tied to, or when I leave the rendering distance specified in imgui.Start3D2D and then return again.

This happens even when the code is just an empty context:

imgui.Start3D2D(self:GetPos() + self:GetForward () * 42.5 + self:GetUp() * 48.75, ang, 0.01)
imgui.End3D2D()

Could be an error on my part but the lack of error messages has me stumped. This doesn't happen with regular cam.Start3D2D.

(Fantastic work by the way - this is really cool stuff)

Imgui End Problems

When ever i walk away from my imgui creation i get this error

[DarkRP] addons/fallout_chems/lua/entities/chem_workbench/imgui.lua:294: tried to end invalid render instance

  1. error - [C]:-1
  2. End3D2D - gamemodes/darkrp/gamemode/modules/workarounds/sh_workarounds.lua:164
    3. End3D2D - addons/fallout_chems/lua/entities/chem_workbench/imgui.lua:294
    4. unknown - addons/fallout_chems/lua/entities/chem_workbench/cl_init.lua:436

The line of code on cl_init is

imgui.End3D2D()

and the line of code in imgui is

cam.End3D2D()

Trying to permanently change a button's color

Hi, Sorry if the issues tab isn't the right place for this.

I am trying to have a button start as one color, and once it is pressed have it change to another color until it's changed elsewhere.

I've tried a couple different things to do this, but I'm having trouble figuring it out.

Also, I'd like to have the button's background color be solid rather than just transparent with a border.

Are these things possible? Thank you.

Can you do this?

if (imgui.Entity3D2D(LocalPlayer(), Vector(0,0,0), Angle(0,0,0), 1)) then
    if (imgui.xButton(250, 0, 0, 1000, 1000, Color(255, 255, 255), Color(255, 0, 0), Color(0, 0, 255))) then
        chat.AddText("PRESSED IT")
    end

    draw.RoundedBox(10, 0, 0, 500, 500, Color(255,0,0))
    imgui.End3D2D()
end

Preset positions for models

Presets that can be used directly with entities using Entity3D2D

models/props_phx/construct/glass/glass_plate1x1.mdl

Vector(0, 0, 3.5), Angle(0, 0, 0), 0.1
Draw area: (-235, -235, 470, 470)

Developer mode when developer cvar > 0

  • Debug physics collisions (show if we're blocking input due to colliding with input)
  • Possibly utilities for quickly moving the UI around to find the final local pos/ang

Game Crashes

Ever since ive got imgui my game crashes heres the script

''include("shared.lua")
local imgui = include("imgui.lua")

surface.CreateFont( "Font", {
font = "Arial", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name
extended = false,
size = 100,
weight = 500,
blursize = 0,
scanlines = 0,
antialias = true,
underline = false,
italic = false,
strikeout = false,
symbol = false,
rotary = false,
shadow = false,
additive = false,
outline = false,
} )

surface.CreateFont( "Font2", {
font = "Arial", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name
extended = false,
size = 30,
weight = 500,
blursize = 0,
scanlines = 0,
antialias = true,
underline = false,
italic = false,
strikeout = false,
symbol = false,
rotary = false,
shadow = false,
additive = false,
outline = false,
} )

function ENT:Draw()

self:DrawModel()

local Pos = self:GetPos()
local Ang = self:GetAngles()
local temp = LocalPlayer():GetNetworkedInt( "temp", 0)

Ang:RotateAroundAxis(Ang:Up(), 90)

cam.Start3D2D(Pos + Ang:Up() * 10.6, Ang, 0.11 )
imgui.Start3D2D(Pos + Ang:Up() * 10.6, Ang, 0.11 )

draw.WordBox(8, -80, -150, "", "Font", Color(120, 120, 255, 0), Color(255, 255, 255, 0))
draw.RoundedBox(0, -135, -145, 275, 290, Color(120,120,120,255))
draw.SimpleText("$"..self.Entity:GetMoneyAmount(), "Font", 0, -100, Color(255, 255, 255, 255),1 ,1)
draw.RoundedBox(0, -102, -32, 204, 30, Color(75,75,75,255))
draw.RoundedBox(0, -102, 28, 204, 30, Color(75,75,75,255))

draw.RoundedBox(0, -100, -30,  self.Entity:GetTemp() * 2, 25, Color(100,100,100,255))
draw.RoundedBox(0, -100, 30,  self.Entity:GetPower() * 2, 25, Color(100,100,100,255))

draw.SimpleText("Temperature: "..self.Entity:GetTemp(), "Font2", 0, -18, Color(255, 255, 255, 255),1 ,1)
draw.SimpleText("Power: "..self.Entity:GetPower(), "Font2", 0, 43, Color(255, 255, 255, 255),1 ,1)

if imgui.xTextButton("Foo bar", "!Roboto@24", -100, 100, 200, 25) then
  -- the xTextButton function returns true, if user clicked on this area during this frame
  print("yay, we were clicked :D")
end

cam.End3D2D()
imgui.End3D2D()

end''

Render different stuff

It's maybe my bad but how to create different render for different player?
For example, I want to create a bank system where player could log into their account and show their money. But what happens to me is that when you press button on 1. entity, it's pressed on 2. entity that is elsewhere, so when player pressed login, it displayed his money on every single entity on the map.

Lost how how to get it working ;3;

i dont know what goes where and i dont know what im doing can someone please help me ;3; reply to this or dm me on discord

{Toby the kat}#7246

Insert image in 3D2D

Is it possible to load and insert images with imgui? Or is there any other way for me to display an image in 3D2D?

Error when fade out

I get a error when it fades out and the error is at line 428 which is imgui.End3D2D(). Ive been having this problem for a while but waited to fix it because it wasnt a game breaking bug so it was at the bottom of my list to fix. Can you please help me.

Any chance of an examples folder?

Been trying to figure this out. Want to attach this to a "models/hunter/plates/plate2x4.mdl" entity and have a sort of placeable scoreboard. I honestly cant figure out how to parent it to the entities position and angle, I also can't figure out how to make my entity still visible as well.

I figure a couple quick examples would do to help me figure this out.

DrawTexturedRect with "color" material

imgui/imgui.lua

Lines 363 to 369 in 35473f1

surface.SetDrawColor(borderColor)
surface.SetMaterial(colorMat)
surface.DrawTexturedRect(x, y, w, borderWidth)
surface.DrawTexturedRect(x, y, borderWidth, h)
surface.DrawTexturedRect(x, y+h-borderWidth, w, borderWidth)
surface.DrawTexturedRect(x+w-borderWidth, y, borderWidth, h)

Is there a reason for using DrawTexturedRect opposed to DrawRect, seeing as colorMat can't be changed?

Consider switching to MIT license or other

I would like to use this library without the GPL having a leash on me, more specifically needing to publish source code along with installation instructions to the public.

This is unfortunately a blocking issue for my commissioned work as well as other personal projects.

Network Send

Im trying to make a purchasing system but net.Send keeps breaking imgui.

      net.Start("PurchaseItem")
      net.Send( LocalPlayer() )

ImGUI on viewmodel doesn't properly find cursor position

**
image
**

the white crosss is imgui.CursorPos as reported by imgui, the mouse is the actual cursor pos
the imgui panel is attached to the player's viewmodel
at screen middle they're the same

i'm thinking this might be an issue with EyePos being too close to the viewmodel?

FOV causing out of sync cursor

Hey.

I'm working on some 3D2D stuff on a ViewModel, and I found that the FOV makes the cursor fall out of sync with the UI. I looked at #9, which seems to share my issue, but I'm not too keen on his solution. Is there anything else I can do to get around this? It could be that I just have a monkey brain and am missing something really obvious.

A video example.

A code snippet:

function SWEP:PostDrawViewModel(entity, weapon, ply)
	if imgui.Entity3D2D(entity, Vector(9.99, 3.36, 2.17), Angle(0, -90, 89), 0.01) then
		draw.RoundedBox(0, 0, 0, 100, 100, color_white)
		imgui.xCursor(0, 0, 612, 396)
	imgui.End3D2D() end
end

Any help on this would be amazing.

imgui, FOV inconsistent on swep.

I'm trying to make a swep that works similarly to the pipboy, however the viewmodel of the swep's fov and the players fov seems to make the buttons not work correctly.

Bug

https://youtu.be/Yg83ksJCOfo

lul

`function ENT:DrawTranslucent()
self:DrawModel()
if LocalPlayer():GetPos():Distance(self:GetPos())>500 then return end

    local w = 1000
    local h = 376


    if imgui.Entity3D2D(self,Vector(22, -20, 30), Angle(0, 90, 90), 0.1, 200, 150) then


        draw.RoundedBox(0,0,0,350,500,Color(130,70,30,200))
        if imgui.xTextButton("Soda", "!Roboto@24", 30, 30, 100, 100) then
            -- the xTextButton function returns true, if user clicked on this area during this frame
            print("yay, we were clicked :D")
          end
        
        imgui.End3D2D()
      end
end`

Many scenes | I need help

Hello
I writing because I have a problem. I want to make 3d2d menu with multi scenes, I mean you have a main scene and there you have a button for example "test1" when you click "test1" then will open a new scene. I don't know how can I make something like that or is it possible.
Have a nice day
Soberaja

Ran into a Problem

I believe that the problem is just with me but I honestly can't get it to work. Iam getting this error when spawning in my entity. If anyone would be able to help me that would be amazing I just started gmod lua and have no idea what Iam doing wrong.

image

shared.lua
image

init.lua
image

cl_init.lua
image

Pressing a button in :Draw presses it twice

see title; i am not sure what kind of debug output would be more helpful/informative. i've been able to get around this by specifying a cooldown until the code in the condition runs again after pressing the button but this seems hacky.

IMGUI in the wild

I'd appreciate a simple screenshot or link if you use IMGUI in your own project, to satisfy my curiosity :)

How to rotate TextButton and text ?

Hi guys. I wanted to make a custom printer for classic DarkRP and I stuck in rotating procces. As far as I know imgui doesn't support rotating directly. I've tried to ask Copilot and Chat-GPT 3.5 but both of them didn't satisfy me. Here's the pic:
Screenshot 2024-03-28 203813
With red pen I marked where I'd love to see the button.

Part of my code (cl_init.lua):

 function ENT:Draw()
	self:DrawModel()
	if imgui.Entity3D2D(self, Vector(-12, 12, 7.9), Angle(0, 0, 0), 0.1) then
		self:SetColor(Color(70, 70, 70))
    	surface.SetDrawColor(70, 70, 70)
    	surface.DrawRect(10, 10, 210, 220)
    	draw.SimpleTextOutlined(self:GetMoneyAmount(), "MoneyFont", 0, 0, Color( 255, 255, 255), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 1, Color( 255, 255, 255 ))

    	if imgui.xTextButton("Take", "!Roboto@24", 0, 30, 100, 25, 1, Color(255,255,255), Color(180,180,180), Color(120,120,120)) then
	      net.Start("TakeMoney")
	      net.WriteEntity(self)
	      net.SendToServer()
	    end

    	imgui.End3D2D()
  	end
end

Buttons wont work

The button wont work for some reason i dont have anymore to say cause idk whats making it not get hightlighted

Garry's Mod Screenshot 2020 04 18 - 16 43 27 91

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.