Jump to content

Working car indicators


Rolplay

Recommended Posts

Hello Rolplay,

I have checked out the mod with Magic.TXD and the TXD does contain the following indicator textures named "p" and "l":

WeepKQK.png

In order to apply special effects to these textures I recommend using the engineApplyShaderToWorldTexture function with textures named "p" and "l". With this function you can multiply the color of the indicator lights to make it brighter or darker depending on your style ;) 

But you have to know how to code in HLSL to do this. Learning shader languages is really worth it!

Edited by The_GTA
  • Thanks 1
Link to comment

I have hacked together a little HLSL sample script for you. It is up to you to actually implement indicator light logic to this:

indicatorshader.fx

texture Tex0;

float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldViewProjection;
float Time;

sampler Sampler0 = sampler_state
{
    Texture = (Tex0);
};

struct VSInput
{
    float3 Position : POSITION;
    float4 Diffuse : COLOR0;
    float2 TexCoord : TEXCOORD0;
};

struct PSInput
{
    float4 Diffuse : COLOR0;
    float2 TexCoord : TEXCOORD0;
};

struct VSOutput
{
    PSInput psInput;
    float4 Position : POSITION;
};

VSOutput PassthroughVS(VSInput input)
{
    VSOutput output;
    output.psInput.Diffuse = input.Diffuse;
    output.psInput.TexCoord = input.TexCoord;
    //-- Transform vertex position (You nearly always have to do something like this)
    output.Position = mul(float4(input.Position, 1), WorldViewProjection);
    return output;
}

float4 IndicatorMultiply(PSInput input) : COLOR0
{
    return float4(1, 1, 0, 1);
}

technique indicators
{
    pass P0
    {
        VertexShader = compile vs_2_0 PassthroughVS();
        PixelShader = compile ps_2_0 IndicatorMultiply();
    }
};

client.Lua

local vehicleTXD = engineLoadTXD("car.txd");
engineImportTXD(vehicleTXD, 400);

local vehicleDFF = engineLoadDFF("car.dff", 400);
engineReplaceModel(vehicleDFF, 400);

local shader = dxCreateShader("indicatorshader.fx");

outputChatBox("Loaded indicator lights shader and car model!");

for m,n in ipairs(getElementsByType("vehicle")) do
    if (getElementModel(n) == 400) then
        engineApplyShaderToWorldTexture(shader, "p", n);
        engineApplyShaderToWorldTexture(shader, "l", n);
    end
end

As you can see the script uses the Landstalker vehicle as an example. Just spawn a Landstalker and start the resource. You should see the indicator lights in yellow color.

Take a look at the MTA wiki to find out more about shaders. You can find really cool effects over there!

Edited by The_GTA
  • Like 1
  • Thanks 1
Link to comment
6 minutes ago, Rolplay said:

Thanks, i try this currently. I need to export "p" and "l" from the police txd, or the script find it and use it on landstalker?

The script just works if you put the car.dff (copcarla.dff) and car.txd (copcarla.txd) into the resource because "p" and "l" are inside of the car.txd file, like shown in Magic.TXD above.

meta.xml

<meta>
    <file src="indicatorshader.fx" type="client" />
    <file src="car.dff" type="client" />
    <file src="car.txd" type="client" />
    <script src="client.Lua" type="client" />
</meta>

 

Edited by The_GTA
  • Thanks 1
Link to comment
34 minutes ago, Rolplay said:

That's didn't work for me: https://imgur.com/a/SH1BEWw

I try that, with an another model, an it worked. Thanks for helping!! Can i bind that to right and left click?

Sure! You can use the dxSetShaderValue function to set a float value "intensity" and define it as global in the HLSL script. Then you can multiply the color with it inside of the "IndicatorMultiply" pixel shader function. In your client.Lua script you set intensity to 0 if the indicator lights are disabled and to 1 if they are enabled.

Use the bindKey function with the "vehicle_left" and "vehicle_right" controls in combination with the intensity shader variable to achieve that. I have not investigated which of "p" or "l" is the left or right indicator texture. I would be very thankful if you could investigate and answer this question for us. :) 

  • Thanks 1
Link to comment
local vehicleTXD = engineLoadTXD("skodafinal.txd");
engineImportTXD(vehicleTXD, 597);

myShader = dxCreateShader( "indicatorshader.fx" )

local vehicleDFF = engineLoadDFF("skodafinal.dff", 597);
engineReplaceModel(vehicleDFF, 597);

local shader = dxCreateShader("indicatorshader.fx");

outputChatBox("Loaded indicator lights shader and car model!");

function bindTurnIndicators(player)
	bindKey(player, "mouse1", "down", "vehicle_left")
	bindKey(player, "mouse2", "down", "vehicle_right")
end

for m,n in ipairs(getElementsByType("vehicle")) do
    if (getElementModel(n) == 597) then
        engineApplyShaderToWorldTexture(shader, "p", n);
        engineApplyShaderToWorldTexture(shader, "l", n);
    end
end

function vehicle_left
	dxSetShaderValue(myShader, "intensity", 1);
end

function vehicle_left
	dxSetShaderValue(myShader, "intensity", 0);
end

This is my Lua now. But i have an error: https://imgur.com/MI7v97c

texture Tex0;

float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldViewProjection;
float Time;
float intensity;

sampler Sampler0 = sampler_state
{
	Texture = (Tex0);
};

struct VSInput
{
	float3 Position : POSITION;
	float4 Diffuse : COLOR0;
	float2 TexCoord : TEXCOORD0;
};

struct PSInput
{
	float4 Diffuse : COLOR0;
	float2 TexCoord : TEXCOORD0;
};

struct VSOutput
{
	PSInput psInput;
	float4 Position : POSITION;
};

VSOutput PassthroughVS(VSInput input)
{
	VSOutput output;
	output.psInput.Diffuse = input.Diffuse;
	output.psInput.TexCoord = input.TexCoord;
	//-- Transform vertex position (You nearly always have to do something like this)
	output.Position = mul(float4(input.Position, 1), WorldViewProjection);
	return output;
}

float4 IndicatorMultiply(PSInput input) : COLOR0
{
	return float4(1, 1, 0, 1);
}

technique indicators
{
	pass P0
	{
		VertexShader = compile vs_2_0 PassthroughVS();
		PixelShader = compile ps_2_0 IndicatorMultiply();
	}
};

And this is my shader now, i only add "float Intensity" string.

Link to comment

I am back after sleeping (GMT+1). So let's hook up your functions to a key bind, shall we? Here is the improved sample code:

improved shader code:

texture Tex0 < string textureState="0,Texture"; >;

float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldViewProjection;
float Time;
float intensity = 0;

sampler Sampler0 = sampler_state
{
	Texture = (Tex0);
};

struct VSInput
{
	float3 Position : POSITION;
	float4 Diffuse : COLOR0;
	float2 TexCoord : TEXCOORD0;
};

struct PSInput
{
	float4 Diffuse : COLOR0;
	float2 TexCoord : TEXCOORD0;
};

struct VSOutput
{
	PSInput psInput;
	float4 Position : POSITION;
};

VSOutput PassthroughVS(VSInput input)
{
	VSOutput output;
	output.psInput.Diffuse = input.Diffuse;
	output.psInput.TexCoord = input.TexCoord;
	//-- Transform vertex position (You nearly always have to do something like this)
	output.Position = mul(float4(input.Position, 1), WorldViewProjection);
	return output;
}

float4 IndicatorMultiply(PSInput input) : COLOR0
{
    float4 texColor = tex2D(Sampler0, input.TexCoord);
	return texColor * intensity;
}

technique indicators
{
	pass P0
	{
		VertexShader = compile vs_2_0 PassthroughVS();
		PixelShader = compile ps_2_0 IndicatorMultiply();
	}
};

client-side Lua code:

local vehicleTXD = engineLoadTXD("car.txd");
engineImportTXD(vehicleTXD, 400);

local vehicleDFF = engineLoadDFF("car.dff", 400);
engineReplaceModel(vehicleDFF, 400);

local shader_left = dxCreateShader("indicatorshader.fx");
local shader_right = dxCreateShader("indicatorshader.fx");

outputChatBox("Loaded indicator lights shader and car model!");

for m,n in ipairs(getElementsByType("vehicle")) do
    if (getElementModel(n) == 400) then
        engineApplyShaderToWorldTexture(shader_right, "p", n);
        engineApplyShaderToWorldTexture(shader_left, "l", n);
    end
end

-- Starting time in milliseconds for the indicators.
local indicator_blink_duration_ms = 500;    -- time in milliseconds that the indicator should blink.
local indicator_left_on = false;    -- is the left indicator on?
local indicator_left_start;
local indicator_right_on = false;
local indicator_right_start;

local function vehicle_left_down()
    indicator_left_on = true;
    indicator_left_start = getTickCount();
end
bindKey("vehicle_left", "down", vehicle_left_down)

local function vehicle_left_up()
    dxSetShaderValue(shader_left, "intensity", 0);
    indicator_left_on = false;
end
bindKey("vehicle_left", "up", vehicle_left_up)

-- TODO: add key binds for the right indicator.

addEventHandler("onClientRender", root, function()
        local now = getTickCount();

        if (indicator_left_on) then
            local passed_time_ms = now - indicator_left_start;
            local period = 1 - math.floor(( passed_time_ms / indicator_blink_duration_ms ) % 2);
            
            -- TODO: write 1 to intensity if the blinker is on, write 0 if the blinker if off.
            -- the blinker is off if the variable "period" is 0, the blinker is on if it is 1.
            dxSetShaderValue(shader_left, "intensity", 1);
        end
        
        -- TODO: add the same for the right indicator.
    end
);

-- TODO: make sure the logic is synchronized across clients.
-- TODO: make sure that each vehicle has its own indicator blinking start time, on/off switch, shader; right now each vehicle shares the same indicator logic.

I did some non-trivial improvement on the shader code so that it reads from the GTA:SA texture instead of a fixed color.

Seeing that you have some trouble coding in Lua I have helped you out again. The Lua code is not done yet. There are several exercises left for you:

  1. how do you implement blinking to the left indicator? (easy)
  2. how do you implement the indicator light for the right indicators? (easy)
  3. how to synchronize the indicator lights across multiple game clients? (medium)
  4. how to allow indicator lights for each vehicle separately? (hard)

Try doing the above exercises to finish your indicator lights script. I think that you should be able to do the first two points. If you have any trouble further down the line then feel free to ask :) 

  • Thanks 1
Link to comment

I should make the blinking with a timer? 

I mean like this:         

        if (indicator_right_on) then
            local passed_time_ms = now - indicator_right_start;
            local period = 1 - math.floor(( passed_time_ms / indicator_blink_duration_ms ) % 2);
            dxSetShaderValue(shader_right, "intensity", 1);
			setTimer ( period, 500, 0,0)
        end

 

Link to comment

 

28 minutes ago, Rolplay said:

I should make the blinking with a timer? 

I mean like this:    

No, you just have to replace the 1 within the original script with something more fitting.

I don't want to give it away, it is the point of the exercise, it is really easy, but you have to understand how Lua scripting works. Let's say that I did the groundwork already. :) 

Hint #1: the variable period is a number that switches between 1 and 0 in 500ms time distances.

 

Edited by The_GTA
  • Like 1
Link to comment
myShader = [[
float Time : TIME;
float4 color = float4(1,1,1,1);
float4 GetColor()
{float4 tColor = float4(cos(Time*7),cos(Time*7),cos(Time*7),255);
return tColor * color;}
technique tec0
{
pass P0
{
MaterialEmissive = GetColor();
EmissiveMaterialSource = Material;
ColorOp[0] = SELECTARG1;
ColorArg1[0] = Diffuse;
Lighting = true;
}}
]]
local ID = 597
engineImportTXD(engineLoadTXD("car.txd"),ID)
engineReplaceModel(engineLoadDFF("car.dff",ID),ID)
---
local shader = dxCreateShader(myShader) 

function SetShaderApply(Apply,Remove,r,g,b)
local Vehicle = getPedOccupiedVehicle ( getLocalPlayer() )
if ( Vehicle ) then
if getElementModel(Vehicle) == ID then                                        
dxSetShaderValue(shader, 'color',r,g,b) 
engineRemoveShaderFromWorldTexture(shader,Remove,Vehicle )
engineApplyShaderToWorldTexture(shader,Apply,Vehicle )
end
end
end
function left()
SetShaderApply('l','p',255,0,0)
end
bindKey ("vehicle_left","both",left)

function right()
SetShaderApply('p','l',255,0,0)
end
bindKey ("vehicle_right","both",right)

 try this

Edited by #\_oskar_/#
Link to comment
3 hours ago, #\_oskar_/# said:

myShader = [[
float Time : TIME;
float4 color = float4(1,1,1,1);
float4 GetColor()
{float4 tColor = float4(cos(Time*7),cos(Time*7),cos(Time*7),255);
return tColor * color;}
technique tec0
{
pass P0
{
MaterialEmissive = GetColor();
EmissiveMaterialSource = Material;
ColorOp[0] = SELECTARG1;
ColorArg1[0] = Diffuse;
Lighting = true;
}}
]]
local ID = 597
engineImportTXD(engineLoadTXD("car.txd"),ID)
engineReplaceModel(engineLoadDFF("car.dff",ID),ID)
---
local shader = dxCreateShader(myShader) 

function SetShaderApply(Apply,Remove,r,g,b)
local Vehicle = getPedOccupiedVehicle ( getLocalPlayer() )
if ( Vehicle ) then
if getElementModel(Vehicle) == ID then                                        
dxSetShaderValue(shader, 'color',r,g,b) 
engineRemoveShaderFromWorldTexture(shader,Remove,Vehicle )
engineApplyShaderToWorldTexture(shader,Apply,Vehicle )
end
end
end
function left()
SetShaderApply('l','p',255,0,0)
end
bindKey ("vehicle_left","both",left)

function right()
SetShaderApply('p','l',255,0,0)
end
bindKey ("vehicle_right","both",right)

 try this

Don't work for me :=( i try to copy getPedOccupiedVehicle, but i can't. 

I think i need to use getPedOccupiedVehicle function, but now i dont know how to.

Link to comment

I have the same problems now, i try to copy functions of @#\_oskar_/# 's script but my script is very different from it. 

I have this problems now:

  • All players in the car can use the indicator(i binded the function to mouse1 and mouse2)
  • Only visible for the localPlayer.
  • If i use indicator on a car, all spawned cars turn on indicators.
Link to comment
On 30/03/2020 at 17:28, Rolplay said:

I didn't find any solving for this two: 

  1. how to synchronize the indicator lights across multiple game clients? (medium)
  2. how to allow indicator lights for each vehicle separately? (hard)

Can you give me a hint again please? :D

Hello Rolplay,

I see that other people attempted to help by posting their own solutions to light indicators. While it is quite interesting, let's continue with the mentioned points:

  1. for this point you have to create a server-side Lua script! open up that meta.xml file and add the following line inside the <meta> node:
    <script src="server.Lua" type="server" />

    Then you have to create a server.Lua file in the resource. If you want to synchronize data between the server and game client you have to use MTA events. The necessary functions for that are addEvent, addEventHandler, triggerServerEvent and triggerClientEvent. In the game client we have four actions: turning on the left/right indicator, turning off the left/right indicator. Thus we want to create events that represent those actions: onVehicleTurnOnIndicator, onVehicleTurnOffIndicator, onClientVehicleTurnOnIndicator, onClientVehicleTurnOffIndicator. Then we have to use triggerServerEvent with the mentioned event names as first argument to tell the server that the vehicle indicator light should turn on. Then the server can tell all players about the event using the onClient eventname.

  2. here we require more book-keeping than previously: for every vehicle we should store the parameters left indicator on, right indicator on, left indicator start time, right indicator start time, left indicator shader, right indicator shader (shaders only on the clientside). Thus we need to create a table called "vehicle_indicator_lights" on both the server-side and the client-side. Using the events we created in point 1 we write data directly into the table instead of global variables.

Hopefully you can follow my points. Feel free to ask questions. If you don't get them done by the weekend I will help you out with the synchronization bit :) 

I am not available all the time due to work and social life. But if I am away from the forums it means that I will return to your issue as soon as possible! So don't let yourself get confused.

Edited by The_GTA
  • Thanks 1
Link to comment

A question about the first: 

Quote

In the game client we have four actions: turning on the left/right indicator, turning off the left/right indicator. Thus we want to create events that represent those actions: onVehicleTurnOnIndicator, onVehicleTurnOffIndicator, onClientVehicleTurnOnIndicator, onClientVehicleTurnOffIndicator. 

i need to create this 4 event at client side, and if i created, then i need to call this events with triggerClientEvent on server side?

Link to comment
22 minutes ago, Rolplay said:

A question about the first: 

i need to create this 4 event at client side, and if i created, ...

You create the first two on the clientside, the second two on the server-side. For example like this:

client-side:

addEvent("onClientVehicleTurnOnIndicator", true);
addEventHandler("onClientVehicleTurnOnIndicator", root, function(indicator_side)
    -- source is the vehicle for which we turn on the indicator lights
  end
);

addEvent("onClientVehicleTurnOffIndicator", true);
addEventHandler("onClientVehicleTurnOffIndicator", root, function(indicator_side)
    -- similar to above.
  end
);

The serverside should be made similar, but for the onVehicle version of events.

27 minutes ago, Rolplay said:

then i need to call this events with triggerClientEvent on server side?

For the onClient ones, yes.

Link to comment
14 minutes ago, The_GTA said:

You create the first two on the clientside, the second two on the server-side. For example like this:

client-side:


addEvent("onClientVehicleTurnOnIndicator", true);
addEventHandler("onClientVehicleTurnOnIndicator", root, function(indicator_side)
    -- source is the vehicle for which we turn on the indicator lights
  end
);

addEvent("onClientVehicleTurnOffIndicator", true);
addEventHandler("onClientVehicleTurnOffIndicator", root, function(indicator_side)
    -- similar to above.
  end
);

The serverside should be made similar, but for the onVehicle version of events.

For the onClient ones, yes.

My serverside look like this now: 

addEvent("onVehicleTurnOnIndicator", true);
addEventHandler("onVehicleTurnOnIndicator", root, function(rightindicator)
		local vehicle = getPedOccupiedVehicle (localPlayer)
		if vehicle then
			triggerClientEvent ( playerSource, "onClientVehicleTurnOnIndicator", playerSource)
		end
  end
);

addEvent("onVehicleTurnOffIndicator", true);
addEventHandler("onVehicleTurnOffIndicator", root, function(right_indicator)
	 local vehicle = getPedOccupiedVehicle (localPlayer)
	 if vehicle then
		triggerClientEvent ( playerSource, "onClientVehicleTurnOnIndicator", playerSource)
	 end
  end
);

Any my client side is like this: 

function left_indicator()
        --right side turn on and turn off function
    end
addEventHandler("onClientRender", root, left_indicator)
addEvent("onClientVehicleTurnOnIndicator", true);
addEventHandler("onClientVehicleTurnOnIndicator", root, function(left_indicator)
  end
);

addEvent("onClientVehicleTurnOffIndicator", true);
addEventHandler("onClientVehicleTurnOffIndicator", root, function(left_indicator)
  end
);


function right_indicator()
        --right side turn on and turn off function
    end
addEventHandler("onClientRender", root, right_indicator)
addEvent("onClientVehicleTurnOnIndicator", true);
addEventHandler("onClientVehicleTurnOnIndicator", root, function(right_indicator)
  end
);

addEvent("onClientVehicleTurnOffIndicator", true);
addEventHandler("onClientVehicleTurnOffIndicator", root, function(right_indicator)
  end
);

It is good? 

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...