New widget: Enemy Spotter - Page 6

New widget: Enemy Spotter

Discuss Lua based Spring scripts (LuaUI widgets, mission scripts, gaia scripts, mod-rules scripts, scripted keybindings, etc...)

Moderator: Moderators

Post Reply
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: New widget: Enemy Spotter

Post by Argh »

Guess I have to do this the hard way. People can test the entire set of optimizations vs. your code.

This is the very last time I will help you, though, I don't help people who don't want to learn, and your attitude sucks.

Code: Select all

function widget:GetInfo()
  return {
    name      = "Enemy Spotter",
    desc      = "Shows a team-colored circle where bad guys' units are",
    author    = "Argh",
    date      = "December 16th, 2009",
    license   = "(C) Wolfe Games, released under GPL v. 2",
    layer     = 0,
    enabled   = true -- loaded by default?
  }
end

------------------------------------------------------------------------------LOCAL STUFF
local myUnitID, myDefID, myTeamID
local frame, oldframe = 1,0
local texture = "bitmaps/StaticCircle.tga"
local LocalTeam = Spring.GetLocalTeamID()
local teamColorTable = {}
local visibleTable = {}
local radiusTable = {}
------------------------------------------------------------------------------OPENGL LOCALS
local glColor = gl.Color
local glTexture = gl.Texture
local glDrawListAtUnit = gl.DrawListAtUnit
local glDeleteList = gl.DeleteList
local glBlending = gl.Blending
local glDepthMask = gl.DepthMask
local glTexCoord = gl.TexCoord
local glVertex = gl.Vertex
local glCreateList = gl.CreateList
local glBeginEnd = gl.BeginEnd
local GL_QUADS = GL.QUADS
local glDepthTest = gl.DepthTest
local GL_SRC_ALPHA = GL.SRC_ALPHA
local GL_ONE = GL.ONE

------------------------------------------------------------------------------SPRING LOCALS
local GetVisibleUnits = Spring.GetVisibleUnits
local GetUnitTeam = Spring.GetUnitTeam
local GetUnitDefID = Spring.GetUnitDefID
local GetTeamColor = Spring.GetTeamColor
local IsUnitVisible = Spring.IsUnitVisible

local GetDrawFrame = Spring.GetDrawFrame
local GetVisibleUnits = Spring.GetVisibleUnits
local ALL_UNITS       = Spring.ALL_UNITS


function widget:Initialize()
	--A simple quad
	SimpleCircle = glCreateList(function()
		glBeginEnd(GL_QUADS, function()
			glTexCoord(0.04,0.04)
			glVertex(-1,10,-1)
			glTexCoord(0.96,0.04)
			glVertex(1,10,-1)
			glTexCoord(0.96,0.96)
			glVertex(1,10,1)
			glTexCoord(0.04,0.96)
			glVertex(-1,10,1)
		end)
	end)
	--Little speedup, so we don't have to constantly look that up from Spring
	for i = 0,64 do
		r,g,b = GetTeamColor(i)
		if i ~= nil then
			table.insert(teamColorTable,i,{r = r,g = g,b =b})
		end
	end
	for i,k in ipairs (UnitDefs) do
		table.insert(radiusTable,{radius = k.xsize * 6})
	end
end

function widget:Shutdown()
	glDeleteList(SimpleCircle)
end



-- Drawing:
function widget:DrawWorldPreUnit()
	--Speedup of GetVisibleUnits
	frame = GetDrawFrame()
	if frame > oldframe then
		visibleTable = GetVisibleUnits(ALL_UNITS,LocalTeam,false)
		oldframe = frame + 5		
	end

	--Main drawing setup
	glBlending(GL_SRC_ALPHA, GL_ONE)
	glDepthTest(true)
	glDepthMask(false)
	for i=1,#visibleTable do
		myUnitID = visibleTable[i]
		myDefID = GetUnitDefID(myUnitID)
		myTeamID = GetUnitTeam(myUnitID)
		if (myTeamID) and myTeamID ~= LocalTeam then
			radius = radiusTable[myDefID].radius
			glColor(teamColorTable[myTeamID].r,teamColorTable[myTeamID].g,teamColorTable[myTeamID].b,1.0)
			glTexture(texture)
			glDrawListAtUnit(myUnitID, SimpleCircle, false, radius, 1.0, radius, 0, 0, 0, 0)
		end
	end
end
Put the attached file into /bitmaps.

For advanced folks, there is at least one speedup left (and, ofc, if you don't like the circles clipping the ground, feel free to change that glDepthTest to false, it's that way because of other things in P.U.R.E.).
Attachments
StaticCircle.zip
(5.99 KiB) Downloaded 24 times
Last edited by Argh on 16 Dec 2009, 14:14, edited 1 time in total.
User avatar
TradeMark
Posts: 4867
Joined: 17 Feb 2006, 15:58

Re: New widget: Enemy Spotter

Post by TradeMark »

I didnt ask for help actually, im happy with my widget i made
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: New widget: Enemy Spotter

Post by Argh »

Well, you needed some. So, you're out of excuses. Test it and let us all know how much faster yours is.
User avatar
TradeMark
Posts: 4867
Joined: 17 Feb 2006, 15:58

Re: New widget: Enemy Spotter

Post by TradeMark »

i dont have the code needed to compare the speeds in a scientifical way

besides i never claimt my code is faster, i just said drawing textures will be slower than drawing single color
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: New widget: Enemy Spotter

Post by Argh »

It's here, in this Forum. Try the Search function, use "profiler".

And, gee, you could just spawn 1000 guys for team 1, show us a screenshot of your FPS.
User avatar
TradeMark
Posts: 4867
Joined: 17 Feb 2006, 15:58

Re: New widget: Enemy Spotter

Post by TradeMark »

the FPS is not a good way to measure things, most of the FPS is used by Spring engine other stuff, like 0.01% goes for that widget thing

and i dont actually need to test that speed via spring widget... i can just write openGL app to do the same with just the texture/no-texture speed diff
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: New widget: Enemy Spotter

Post by Argh »

No, that's absolutely wrong. Bad Widgets can and do eat FPS. Moreover, if the CPU is busy because of poorly-optimized code, the simulation will slow, and so will FPS.

And no, you can't test the texture / no-texture. You aren't using quads, you're building circles with polygons. And that's not what this is mainly about, anyhow.
Last edited by Argh on 16 Dec 2009, 14:22, edited 1 time in total.
User avatar
TradeMark
Posts: 4867
Joined: 17 Feb 2006, 15:58

Re: New widget: Enemy Spotter

Post by TradeMark »

i can notice barely 1 fps difference when the game has 1000 units around... so i dont think its a problem
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: New widget: Enemy Spotter

Post by Argh »

Show us some pictures, or it didn't happen.

For those just joining us, I released optimized source on the previous page, demonstrating everything I've been nattering on about. I need to take a nap now.
User avatar
TradeMark
Posts: 4867
Joined: 17 Feb 2006, 15:58

Re: New widget: Enemy Spotter

Post by TradeMark »

actually i cant see any FPS difference.

ill post a video soon? since screenshots wont prove anything...
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: New widget: Enemy Spotter

Post by Argh »

Just show us the screenshots already. Videos aren't exactly good science, the CPU's very busy making the video at that point.

I don't believe you've tested anything at all yet. 1000 Units makes an appreciable dent in anybody's FPS, even if you're one of those wankers who doesn't turn shadows / reflectivity on.
User avatar
TradeMark
Posts: 4867
Joined: 17 Feb 2006, 15:58

Re: New widget: Enemy Spotter

Post by TradeMark »

Hold on, here, 1800 units on screen:

Image


Image

I noticed the FPS is 15-16 when not using my widget, and when using it was 14-15
User avatar
very_bad_soldier
Posts: 1397
Joined: 20 Feb 2007, 01:10

Re: New widget: Enemy Spotter

Post by very_bad_soldier »

doublepost...
Last edited by very_bad_soldier on 16 Dec 2009, 16:04, edited 2 times in total.
User avatar
very_bad_soldier
Posts: 1397
Joined: 20 Feb 2007, 01:10

Re: New widget: Enemy Spotter

Post by very_bad_soldier »

Well, I came back to make some tests for myself, cause I am really curious whats fast now and whats not.

I compared Trademark's widget to the one Argh posted. They were tested in the exact same game with all the exact same settings and 1000 flashers in BA 7.04. Using Meltrax' Profiler ofc. Looking at fps ingame isnt a really good metric imo.

Results:
Time hanging around in DrawWorldPreUnit:
Argh: 4.71ms
Tradermark: 3.20ms

And the winner is Tradermark. Arghs version seems to be about 50% slower than Tradermarks.

Look at the screenies for full Profiler output.
Attachments
trademark.jpg
(747.13 KiB) Downloaded 2 times
argh.jpg
(707.28 KiB) Downloaded 2 times
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: New widget: Enemy Spotter

Post by AF »

Thank you trademark for beign stubborn and wasting your time arguing a pointless point instead of working on a competing project.
User avatar
TradeMark
Posts: 4867
Joined: 17 Feb 2006, 15:58

Re: New widget: Enemy Spotter

Post by TradeMark »

Nice, i was right after all... gg no re

Seems like Argh doesnt know a jack about how GPU's work

Writing long messages with meaningless crap doesnt make you any more right...
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: New widget: Enemy Spotter

Post by AF »

Writing long messages with meaningless crap doesnt make you any more right...
erm.... lol
User avatar
TradeMark
Posts: 4867
Joined: 17 Feb 2006, 15:58

Re: New widget: Enemy Spotter

Post by TradeMark »

loolloloolloo XD
User avatar
lurker
Posts: 3842
Joined: 08 Jan 2007, 06:13

Re: New widget: Enemy Spotter

Post by lurker »

Argh, as much as you're right about getting rid of extra lines of code, you're dead wrong about local variables. Nothing is allocated for them in normal use, they are part of the stack.

Code: Select all

local a = tellmeA()
if a == 5 then end

0+ params, 2 slots, 0 upvalues, 1 local, 2 constants, 0 functions
        1       [1]     GETGLOBAL       0 -1    ; tellmeA
        2       [1]     CALL            0 1 2
        3       [2]     EQ              0 0 -2  ; - 5
        4       [2]     JMP             0       ; to 5
        5       [2]     RETURN          0 1

Code: Select all

if tellmeA() == 5 then end

0+ params, 2 slots, 0 upvalues, 0 locals, 2 constants, 0 functions
        1       [1]     GETGLOBAL       0 -1    ; tellmeA
        2       [1]     CALL            0 1 2
        3       [1]     EQ              0 0 -2  ; - 5
        4       [1]     JMP             0       ; to 5
        5       [1]     RETURN          0 1
You can see that whether you store it in a 'local' or not you get the same exact code. 'local's are just names you stick on the registers lua stores values in. Occasionally you can end up with an extra MOVE instruction, but those are really cheap.


And beyond, you suggested something that would actually make performance (slightly) worse. If you have a 'local' at the top of a widget, then inside a function it's not 'local' any more, it's what's called an 'upvalue'. You spend an extra (really cheap) lua instruction every time you get or set them.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: New widget: Enemy Spotter

Post by Argh »

And the winner is Tradermark. Arghs version seems to be about 50% slower than Tradermarks.
Well, mine also shows the real TeamColors, instead of just blue, and uses textures so that it can be very visually flexible, amongst other things. I guess I padded out the features too much.

I also forgot to move the glTexture callout to the start of the main draw function. That should help a bit.



@Lurker: Eh, really? My understanding about this was that if we localized like this:

local GetUnitPosition = Spring.GetUnitPosition

...then we're saving an upvalue call on a regular basis, because that memory address was localized within the application at runtime. What you're saying implies that it's being re-localized every pass, and therefore the cost savings are zero.

And, at least in the case of anywhere where we need to call a value in multiple places, it seems counterintuitive that we'd actually improve speed by doing this:

Code: Select all

subfunction(value)
  ... do stuff to value
  return value
end

function blah()
  local value
  ... do stuff to value
  subfunction(value)
  value = value
end
I mean, if that's actually better, fine, it just seems counterintuitive, I thought variable initialization wasn't something we should waste cycles on, though.

Anyhow, here's a fix with the glTexture callout moved to the right place. Should help a bit, in terms of raw speed:

Code: Select all

function widget:GetInfo()
  return {
    name      = "Enemy Spotter",
    desc      = "Shows a team-colored circle where bad guys' units are",
    author    = "Argh",
    date      = "December 16th, 2009",
    license   = "(C) Wolfe Games, released under GPL v. 2",
    layer     = 0,
    enabled   = true -- loaded by default?
  }
end

------------------------------------------------------------------------------LOCAL STUFF
local myUnitID, myDefID, myTeamID
local frame, oldframe = 1,0
local texture = "bitmaps/StaticCircle.tga"
local LocalTeam = Spring.GetLocalTeamID()
local teamColorTable = {}
local visibleTable = {}
local radiusTable = {}
------------------------------------------------------------------------------OPENGL LOCALS
local glColor = gl.Color
local glTexture = gl.Texture
local glDrawListAtUnit = gl.DrawListAtUnit
local glDeleteList = gl.DeleteList
local glBlending = gl.Blending
local glDepthMask = gl.DepthMask
local glTexCoord = gl.TexCoord
local glVertex = gl.Vertex
local glCreateList = gl.CreateList
local glBeginEnd = gl.BeginEnd
local GL_QUADS = GL.QUADS
local glDepthTest = gl.DepthTest
local GL_SRC_ALPHA = GL.SRC_ALPHA
local GL_ONE = GL.ONE

------------------------------------------------------------------------------SPRING LOCALS
local GetVisibleUnits = Spring.GetVisibleUnits
local GetUnitTeam = Spring.GetUnitTeam
local GetUnitDefID = Spring.GetUnitDefID
local GetTeamColor = Spring.GetTeamColor
local IsUnitVisible = Spring.IsUnitVisible

local GetDrawFrame = Spring.GetDrawFrame
local GetVisibleUnits = Spring.GetVisibleUnits
local ALL_UNITS       = Spring.ALL_UNITS


function widget:Initialize()
	--A simple quad
	SimpleCircle = glCreateList(function()
		glBeginEnd(GL_QUADS, function()
			glTexCoord(0.04,0.04)
			glVertex(-1,10,-1)
			glTexCoord(0.96,0.04)
			glVertex(1,10,-1)
			glTexCoord(0.96,0.96)
			glVertex(1,10,1)
			glTexCoord(0.04,0.96)
			glVertex(-1,10,1)
		end)
	end)
	--Little speedup, so we don't have to constantly look that up from Spring
	for i = 0,64 do
		r,g,b = GetTeamColor(i)
		if i ~= nil then
			table.insert(teamColorTable,i,{r = r,g = g,b =b})
		end
	end
	for i,k in ipairs (UnitDefs) do
		table.insert(radiusTable,{radius = k.xsize * 6})
	end
end

function widget:Shutdown()
	glDeleteList(SimpleCircle)
end



-- Drawing:
function widget:DrawWorldPreUnit()
	visibleTable = GetVisibleUnits(ALL_UNITS,LocalTeam,false)

	--Main drawing setup
	glBlending(GL_SRC_ALPHA, GL_ONE)
	glDepthTest(true)
	glDepthMask(false)
	glTexture(texture)
	for i=1,#visibleTable do
		myUnitID = visibleTable[i]
		myDefID = GetUnitDefID(myUnitID)
		myTeamID = GetUnitTeam(myUnitID)
		if (myTeamID) and myTeamID ~= LocalTeam then
			radius = radiusTable[myDefID].radius
			glColor(teamColorTable[myTeamID].r,teamColorTable[myTeamID].g,teamColorTable[myTeamID].b,1.0)
			glDrawListAtUnit(myUnitID, SimpleCircle, false, radius, 1.0, radius, 0, 0, 0, 0)
		end
	end
end
If that doesn't push it over the top, CPU-wise, there are a couple more things I can do, while keeping the extra features, although it's going to get a little harder to squeeze it at that point. In testing over here, mine runs fast enough that I really just don't see much of a difference in total load while it's operating, so I think it's fair to say it's "fast".

However, that said... now that I've tested TradeMark's a bit... where are all these complaints about speed coming from?

I mean, seriously, I am guilty of just reading the complaints and looking for speedups here... which I found, but they aren't earth-shattering.

Are people playing games with Pentium II's here? Neither one of these Widgets are a real load, ever.
Last edited by Argh on 17 Dec 2009, 07:39, edited 1 time in total.
Post Reply

Return to “Lua Scripts”