How Are Weapon Sprites Scaled And Rendered?

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
22alpha22
Posts: 308
Joined: Fri Feb 21, 2014 5:04 pm
Graphics Processor: nVidia with Vulkan support
Location: Montana, USA

How Are Weapon Sprites Scaled And Rendered?

Post by 22alpha22 »

I've been trying to render a weapon's sprites via a ZScript HUD because the 35 tic rate is too limiting for this particular weapon's animations but I'm having a hard time figuring out how to scale and offset it. It is obvious weapon sprites are scaled based on the resolution of the viewport, but how? Do they use the horizontal or vertical resolution? If they used both, then weapons would be deformed on non 4:3 resolutions which obviously isn't the case.

Finally, how are weapon offsets calculated? My assumption was that it uses the offsets set on the image the sprite uses, these offsets must then be added to the PSprite offsets and multiplied by the scale the weapon's resolution scale. Problem is, DrawImage doesn't seem to use the images offsets like a normal HUDWeapon does and even when I tried adding the offsets manually to offset field in DrawImage, the weapon still did not appear in the correct location on screen.

Here is a simple function I created to test drawing the weapon to the screen:

Code: Select all

Void DrawMachinegun(Void)
	{
		If (Plr)
		{
			If (Plr.Player.ReadyWeapon Is 'AlphaMachinegun')
			{
				Vector2 WScale = (VWidth / 320.0,VHeight / 200.0);
				Let PWSprite = Plr.Player.GetPSprite(PSP_WEAPON);

				DrawImage("MGUNTEST",((PWSprite.X - 134) * WScale.X,(PWSprite.Y - 113) * WScale.Y),0,1.0,(-1,-1),(WScale.X * PWSprite.Scale.X,WScale.Y * PWSprite.Scale.Y),STYLE_Normal);
			}
		}
	}
This screenshot shows the weapon rendered normally with offsets (-134, -113) and with the weapon rendered with the above function via a custom ZScript statusbar.
Taken at 640x480 resolution, scaled down to 320x240 because of upload file size limitations.
Taken at 640x480 resolution, scaled down to 320x240 because of upload file size limitations.
Screenshot_Doom_20220601_105848.png (92.98 KiB) Viewed 329 times
It seems like I have the scaling right but I can't figure out the offsets.

EDIT:
Looking at the screenshot, it occurred to me that HUDWeapons are affected by sector light levels, how is this done as that is something I will also have to replicate.
User avatar
Dan_The_Noob
Posts: 880
Joined: Tue May 07, 2019 12:24 pm
Graphics Processor: nVidia with Vulkan support
Contact:

Re: How Are Weapon Sprites Scaled And Rendered?

Post by Dan_The_Noob »

I think the offset is from the bottom left of the sprite by default but depends on how it is aligned in the sprite thing in SLADE etc? ( I haven't done much sprite stuff, but that's how it was if i remember right)
User avatar
22alpha22
Posts: 308
Joined: Fri Feb 21, 2014 5:04 pm
Graphics Processor: nVidia with Vulkan support
Location: Montana, USA

Re: How Are Weapon Sprites Scaled And Rendered?

Post by 22alpha22 »

I still don't know exactly how weapon scaling and offsets are calculated normally but I have managed to get my weapon rendered through a ZScript statusbar to align correctly at all resolutions and aspect ratios. For this particular weapon, I only needed a few frames during the Fire and Hold states to render faster than the 35 hz tic rate, so all I needed was a simple function in my statusbar and an ANIMDEFS entry.

Code: Select all

Void DrawMachinegun(Void)
	{
		If (Plr)
		{
			If (Plr.Player.ReadyWeapon Is 'AlphaMachinegun')
			{
				Vector2 WScale = ((VHeight / 200.0) / 1.2,VHeight / 200.0);
				Int ClrR;
				Int ClrG;
				Int ClrB;
				Color WeaponColor;
				Double LightAdjustment;
				//Int LightLevel;
				Let PWSprite = Plr.Player.GetPSprite(PSP_WEAPON);

				WScale = (WScale.X * PWSPrite.Scale.X,WScale.Y * PWSprite.Scale.Y);
				LightAdjustment = Plr.CurSector.LightLevel / 255.0;
				ClrR = Plr.CurSector.ColorMap.LightColor.R;
				ClrG = Plr.CurSector.ColorMap.LightColor.G;
				ClrB = Plr.CurSector.ColorMap.LightColor.B;
				ClrR = Clamp(Round(ClrR * LightAdjustment),0,255);
				ClrG = Clamp(Round(ClrG * LightAdjustment),0,255);
				ClrB = Clamp(Round(ClrB * LightAdjustment),0,255);
				//LightLevel = Clamp(Round(255.0 * LightAdjustment),0,255);
				WeaponColor = Color(255,ClrR,ClrG,ClrB);

				If ((Actor.InStateSequence(PWSprite.CurState,Plr.Player.ReadyWeapon.FindState("Fire",True) + 3) && !Actor.InStateSequence(PWSprite.CurState,Plr.Player.ReadyWeapon.FindState("Fire",True) + 7)) || (Actor.InStateSequence(PWSprite.CurState,Plr.Player.ReadyWeapon.FindState("Hold",True) + 3) && !Actor.InStateSequence(PWSprite.CurState,Plr.Player.ReadyWeapon.FindState("Hold",True) + 7)))
				{
					DrawImage("MGUNI0",(CenterX + ((PWSprite.X - 52.75) * WScale.X),(PWSprite.Y - 109.5) * WScale.Y),DI_ITEM_LEFT_TOP,1.0,(-1,-1),(WScale.X,WScale.Y),STYLE_Normal,WeaponColor);
				}
			}
		}
	}

Code: Select all

Texture MGUNI0
Pic MGUND0 Tics 0.5
Pic MGUNE0 Tics 0.5
Pic MGUNF0 Tics 0.5
Pic MGUNG0 Tics 0.5
Pic MGUNF0 Tics 0.5
Pic MGUNE0 Tics 0.5
Pic MGUND0 Tics 0.5
Pic MGUNH0 Tics 0.5
The entirety of a weapon's states could probably be rendered this way if it was really necessary.
Post Reply

Return to “Scripting”