How to get the Canvas of a Viewport?

Discussions about Coding and Scripting
Post Reply
User avatar
PrinceOfFunky
Godlike
Posts: 1200
Joined: Mon Aug 31, 2015 10:31 pm

How to get the Canvas of a Viewport?

Post by PrinceOfFunky »

I know Viewport is native and we cannot access its properties through UnrealScript, but I was trying to get the Canvas of a player's Viewport. I know how to iterate through all the objects of a certain class, but the only useful property I found into Canvas to get close to the player owning it, is "viewport", I guess I could do a cross check some way, but, how does a Viewport work? I know Viewport is a subclass of Player, so let's suppose I'm a Player, do I have a viewport or I am the viewport itself?

EDIT: I see that Player has "viewport" variable too, but I cannot manage to find a Canvas object in the map, I iterate through all objects of a certain class and I call DynamicLoadObject("CertainClass"$index, class'CertainClass', false), but it always fails and reurns None. Any idea of why it returns None? Is it possible there is no any Canvas object in the Level?

EDIT 2: I just looked inside the UT source code and I found out UViewport contains this piece of code:

Code: Select all

	// Referenced objects.
	class UCanvas*		 Canvas;	// Viewport's painting canvas.
But if I try to use viewport.Canvas, I cannot compile it, ucc says Viewport has no Canvas property. I'm not sure if it's cause it isn't Viewport but UViewport, anyway, I see I can call viewport.Actor, but from what I understood in the source code, it looks like the property Actor is common in any class, why can I use viewport.Actor but not viewport.Canvas?
"Your stuff is known to be buggy and unfinished/not properly tested"
User avatar
ExpEM
Adept
Posts: 298
Joined: Wed Nov 09, 2016 1:48 am

Re: How to get the Canvas of a Viewport?

Post by ExpEM »

I can't help with getting the canvas from a viewport (looks to me like canvas is handed down from engine so you would have to look at the native code).
However, to simply draw on any PlayerPawns canvas you can give that player a custom inventory that draws using the PostRender function.
Signature goes here.
User avatar
PrinceOfFunky
Godlike
Posts: 1200
Joined: Mon Aug 31, 2015 10:31 pm

Re: How to get the Canvas of a Viewport?

Post by PrinceOfFunky »

ExpEM wrote:I can't help with getting the canvas from a viewport (looks to me like canvas is handed down from engine so you would have to look at the native code).
However, to simply draw on any PlayerPawns canvas you can give that player a custom inventory that draws using the PostRender function.
Well yes that should work, can I clean what was drawn before(the previous overlay I mean)?
I'm trying to clean what this code prints(from within Console.uc):

Code: Select all

simulated function DrawConsoleView( Canvas C )
{
	local int Y, I, Line;
	local float XL, YL;

	// Console is visible; display console view.
	Y = ConsoleLines - 1;
	MsgText[(TopLine + 1 + MaxLines) % MaxLines] = "(>"@TypedStr;
	for ( I = Scrollback; I < (NumLines + 1); I++ )
	{
		// Display all text in the buffer.
		Line = (TopLine + MaxLines*2 - (I-1)) % MaxLines;
		
		C.Font = C.MedFont;

		if (( MsgType[Line] == 'Say' ) || ( MsgType[Line] == 'TeamSay' ))
			C.StrLen( MsgPlayer[Line].PlayerName$":"@MsgText[Line], XL, YL );				
		else
			C.StrLen( MsgText[Line], XL, YL );
		
		// Half-space blank lines.
		if ( YL == 0 )
			YL = 5;
			
		Y -= YL;
		if ( (Y + YL) < 0 )
			break;
		C.SetPos(4, Y);
		C.Font = C.MedFont;

		if (( MsgType[Line] == 'Say' ) || ( MsgType[Line] == 'TeamSay' ))
			C.DrawText( MsgPlayer[Line].PlayerName$":"@MsgText[Line], false );
		else
			C.DrawText( MsgText[Line], false );
	}				
}
Note this line:

Code: Select all

MsgText[(TopLine + 1 + MaxLines) % MaxLines] = "(>"@TypedStr;
That's what I want to change, the symbol "(>" which is hardcoded in this function, into something else.
"Your stuff is known to be buggy and unfinished/not properly tested"
User avatar
ExpEM
Adept
Posts: 298
Joined: Wed Nov 09, 2016 1:48 am

Re: How to get the Canvas of a Viewport?

Post by ExpEM »

If it's just for your use then subclass console to do what you want and set the custom console as "Console=CustomConsole" in UnrealTournament.ini
Signature goes here.
User avatar
PrinceOfFunky
Godlike
Posts: 1200
Joined: Mon Aug 31, 2015 10:31 pm

Re: How to get the Canvas of a Viewport?

Post by PrinceOfFunky »

ExpEM wrote:If it's just for your use then subclass console to do what you want and set the custom console as "Console=CustomConsole" in UnrealTournament.ini
Well no, it has to work for everyone in the same level, I managed to modify Console without sublassing it, but I cannot modify its functions. You talked about RenderOverlays within Inventory, I gave an Inventory item to the player, but the event isn't called, the inventory cannot be selected cause it's not a weapon, do I need a weapon and the pawn to have it selected, to make the RenderOverlays function be called?
"Your stuff is known to be buggy and unfinished/not properly tested"
User avatar
Barbie
Godlike
Posts: 2792
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: How to get the Canvas of a Viewport?

Post by Barbie »

PrinceOfFunky wrote:You talked about RenderOverlays within Inventory, I gave an Inventory item to the player, but the event isn't called, the inventory cannot be selected cause it's not a weapon, do I need a weapon and the pawn to have it selected, to make the RenderOverlays function be called?
Maybe ExpEM's idea was to access the canvas by PlayerPawn(Inventory.Owner).PostRender()?
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
User avatar
PrinceOfFunky
Godlike
Posts: 1200
Joined: Mon Aug 31, 2015 10:31 pm

Re: How to get the Canvas of a Viewport?

Post by PrinceOfFunky »

Barbie wrote:
PrinceOfFunky wrote:You talked about RenderOverlays within Inventory, I gave an Inventory item to the player, but the event isn't called, the inventory cannot be selected cause it's not a weapon, do I need a weapon and the pawn to have it selected, to make the RenderOverlays function be called?
Maybe ExpEM's idea was to access the canvas by PlayerPawn(Inventory.Owner).PostRender()?
I would need to subclass PlayerPawn tho, right? I'm trying to not to sublacc anything, that's why I need the get the Canvas, cause I cannot use any function which gives me the Canvas as a parameter.
I see there's a function called "DrawStatusIconAt()" in Inventory.uc, but it is not overwritten anywhere in its sublasses, or maybe I didn't found it yet, I think that could be used without having the player to select any Inventory, I have a TournamentPickup used as weapon Affector and inserted inside the Inventory of the player, but none of those two functions gets called.
"Your stuff is known to be buggy and unfinished/not properly tested"
User avatar
Barbie
Godlike
Posts: 2792
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: How to get the Canvas of a Viewport?

Post by Barbie »

Code: Select all

MsgText[(TopLine + 1 + MaxLines) % MaxLines] = "(>"@TypedStr;
If you want to change the ">" I recommend subclassing "Console". Anything else would be an ugly hack.
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
User avatar
PrinceOfFunky
Godlike
Posts: 1200
Joined: Mon Aug 31, 2015 10:31 pm

Re: How to get the Canvas of a Viewport?

Post by PrinceOfFunky »

Barbie wrote:

Code: Select all

MsgText[(TopLine + 1 + MaxLines) % MaxLines] = "(>"@TypedStr;
If you want to change the ">" I recommend subclassing "Console". Anything else would be an ugly hack.
I'm just afraid that the console could be swapped at runtime. But well, if the hack wouldn't be worth, then yeah, I will subclassing Console, or just don't give a crap about that "(>" XD.

EDIT: So, I managed to get the Canvas using PostRender() function into the mutator, now, if I use this code:

Code: Select all

canvas.StrLen("test", XL, YL);
canvas.SetPos(0, 0);
canvas.Font = canvas.MedFont;
canvas.DrawText("test", false);
If I use it inside PostRender(), it renders correctly, but if I use it outside of of the PostRender() function(in my case inside the Tick() function), it gives me this GPF:
GPF.PNG
GPF.PNG (11.78 KiB) Viewed 2111 times
EDIT 2: I added a cal to "canvas.Reset()" now, before of the code above, I get this:
FGP.PNG
It's not a big difference from the one above but at least now it says it's a failed assertion.
I would like to view this assertion on line 335 of UnCanvas.cpp, but I don't have UnCanvas.cpp file, I have UnCamera.cpp where UCanvas is declared, but nothing about UnCanvas.
Is there somewhere I can get the source from? (I only have this one: "ut432pubsrc.zip")

EDIT 3: Oh well, I will just use PostRender() function from within my mutator then. Thanks everyone :D
"Your stuff is known to be buggy and unfinished/not properly tested"
User avatar
Wormbo
Adept
Posts: 258
Joined: Sat Aug 24, 2013 6:04 pm
Contact:

Re: How to get the Canvas of a Viewport?

Post by Wormbo »

Important: The canvas is only ever valid during rendering. If you can't easily get hold of a canvas reference, there likely isn't any canvas to work with in the first place.
Chris
Experienced
Posts: 134
Joined: Mon Nov 24, 2014 9:27 am

Re: How to get the Canvas of a Viewport?

Post by Chris »

The error is pretty damn obvious... Since you're calling the canvas at the Tick part of the main loop, the font is not set. the PostRender in the HUD has already drawn on the Canvas by the time it reaches the Mutator PostRender and therefore it uses the previous set font and the assert doesn't fail. How do you plan to measure the string size if you don't have a font set? Move

Code: Select all

canvas.Font = canvas.MedFont;
above

Code: Select all

canvas.StrLen("test", XL, YL);
User avatar
PrinceOfFunky
Godlike
Posts: 1200
Joined: Mon Aug 31, 2015 10:31 pm

Re: How to get the Canvas of a Viewport?

Post by PrinceOfFunky »

Wormbo wrote:Important: The canvas is only ever valid during rendering. If you can't easily get hold of a canvas reference, there likely isn't any canvas to work with in the first place.
Tick is something done before of a rendering right? If so, I guess Tick is the last function to be called before of the rendering? Cause it has lot of sense, code execution makes all the logical changes and at the end those changes are "rendering" on screen. If that is right, the Canvas cannot execute anything before of the rendering, unless the engine fires an event telling you that you can use the canvas at that moment(like on PostRendering()). Is this what you meant?

EDIT: So I just tried to use the canvas into another render event which doesn't have a Canvas as parameter, it works!
That's the event:

Code: Select all

class STest expands ClientScriptedTexture;

var Canvas canvas;

simulated function FindCanvas()
{
	local AdvancedMutator AM, currAM;
	local PlayerPawn P;

	foreach AllActors(class'AdvancedMutator', AM)
		currAM = AM;
		
	foreach AllActors(class'PlayerPawn', P)
		if(Viewport(P.Player) != None)
			canvas = currAM.getObjectOI(P).ownerCanvas;
}

simulated event RenderTexture(ScriptedTexture Tex)
{
	FindCanvas();
	canvas.font = Canvas.MedFont;
	canvas.DrawText("ST", false);
}
"AdvancedMutator" is the mutator which takes the Canvas given to the "PostRender()" event and puts it into the "ownerCanvas" of an actor which is associated to the PlayerPawn.
That is cool cause the text appears only if there's at least one pixel of the specified ScriptedTexture. It became a mix of the ScriptedTexture rendering behaviour and the canvas one.

EDIT 2: Looks like someone already thought about using Canvas outside of usual render events: https://wiki.beyondunreal.com/Legacy:RotatedText
"Your stuff is known to be buggy and unfinished/not properly tested"
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: How to get the Canvas of a Viewport?

Post by sektor2111 »

Note:
That "Advanced Mutator" uses a lousy way of TWO iterators for TWO things since it could be simplified in a Single One for BOTH things reducing processing cycles in Levels with a lot of crap.
Post Reply