How to disable/shut off a python script?


When the property changes it activates a shader python script, but it doesn’t seem like there’s a way to stop it from running. Is there a way to do that without restarting the scene?

It mostly depends on how the script is written. Only thing I can tell from your picture is that as long as the Property sensor evals to “positive” it will fire the Python Controller and its script.

1 Like

python can also set up things you can’t undo just by turning off a script

a shader is a program on the gpu - so you may need a second script to disable it.

1 Like

Ok, here’s the script.

import bge
from bge import logic, render, types
from bgl import *

render.setMipmapping(1)

controller = bge.logic.getCurrentController()
owner = controller.owner

winX = owner['winX']
winY = owner['winY']
isFS = owner['isFS']
displaySize = bge.render.getDisplayDimensions()

print(winX)
print(winY)
print(displaySize)

if isFS == 1 :
	psize = (displaySize[0])/20
	print("is Fullscreen")
	print("psize is", psize)
if isFS == 0 :
	psize = (winX)/20
	print("is not Fullscreen")
	print("psize is", psize)
######################################################
VERTEX_SHADER = """
uniform float width;
uniform float height;
uniform float pixelSize;

varying vec4 v_color;
varying vec3 v_lighting;
varying vec2 v_uv;
varying vec2 v_reflect;
varying float v_n;

void main() {
	// Snap vertex to pixel
	float ps = pixelSize;
	if (ps <= 0) { ps = 1.0; }
	else if (ps >= 10.0) { ps = 10.0; }

	float pw = width / ps;
	float ph = height / ps;
	vec4 P = gl_ModelViewMatrix * gl_Vertex;
	vec4 snap = gl_ModelViewProjectionMatrix * gl_Vertex;
	vec4 vertex = snap;
	vertex.xyz = snap.xyz / snap.w;
	vertex.x = floor(pw * vertex.x) / pw;
	vertex.y = floor(ph * vertex.y) / ph;
	vertex.xyz *= snap.w;

	// Basic vertex lighting
	vec3 N = normalize(gl_NormalMatrix * gl_Normal);
	vec3 V = -normalize(P.xyz);
	vec3 L = vec3(0.0);
	float attenuation = 1.0;
	vec3 lighting = gl_LightModel.ambient.rgb;

	for (int i = 0; i < gl_MaxLights; i++) {
		if (gl_LightSource[i].diffuse.a == 0.0) { continue; }
		if (0.0 == gl_LightSource[i].position.w) { // SUN
			attenuation = 1.0;
			L = normalize(gl_LightSource[i].position.xyz);
		} else { // POINT
			vec3 PL = (gl_LightSource[i].position - P).xyz;
			float distance = length(PL);
			attenuation = 1.0 / (distance + 0.0001);
			L = normalize(PL);
		}
		// TODO: SPOT
		float NdotL = dot(N, L);
		vec3 diff = attenuation 
					* gl_LightSource[i].diffuse.rgb
					* max(NdotL, 0.0);
		diff = clamp(diff, 0.0, 1.0);

		vec3 spec = vec3(0.0);
		if (NdotL >= 0.0) {
			spec = attenuation 
				* gl_LightSource[i].specular.rgb
				* gl_FrontMaterial.specular.rgb
				* pow(max(0.0, dot(reflect(-L, N), V)), gl_FrontMaterial.shininess);
			spec = clamp(spec, 0.0, 1.0);
		}
		lighting += clamp(diff + spec, 0.1, 1.0);
	}

	// Affine texture mapping
	float s = (lighting.r + lighting.g + lighting.b) / 3.0;
	float distance = length(P) + 0.0001;	
	vec4 affinePos = vertex;
	vec2 uv = gl_MultiTexCoord0.st;

	float vws = (vertex.w * (s * 8.0));
	uv *= distance + vws / distance / 2.0;

	gl_Position = vertex;
	v_color = gl_Color;
	v_lighting = lighting;
	v_n = distance + vws / distance / 2.0;
	v_uv = uv;

	vec3 R = reflect(V, N);
	float m = 2. * sqrt(
		pow(R.x, 2.0) +
		pow(R.y, 2.0) +
		pow(R.z + 1.0, 2.0)
	);
	v_reflect = (R.xy / m + 0.5) * distance + vws / distance / 2.0;
}
"""

FRAGMENT_SHADER = """
varying vec4 v_color;
varying vec3 v_lighting;
varying vec2 v_reflect;
varying vec2 v_uv;
varying float v_n;

uniform sampler2D tex0;
uniform sampler2D tex1;
uniform float tex0Enabled;
uniform float tex1Enabled;

void main() {
	vec4 tex = vec4(1.0);
	if (tex0Enabled >= 1.0) {
		tex *= texture2D(tex0, v_uv / vec2(v_n));
	}
	if (tex1Enabled >= 1.0) {
		vec4 col = texture2D(tex1, v_reflect / vec2(v_n));
		if (tex0Enabled >= 1.0) {
			tex += col;
		} else {
			tex.rgb *= mix(tex.rgb, col.rgb, col.a);
		}
	}
	tex.rgb = clamp(tex.rgb, 0.0, 1.0);
	gl_FragColor = vec4(v_lighting * v_color.rgb * tex.rgb, v_color.a * tex.a);
}
"""
######################################################

lightStatus = [False] * 16
pixelSize = (psize)

sce = bge.logic.getCurrentScene()

for obj in sce.objects:
    if not obj.name.startswith("PASS"):
        for mesh in obj.meshes:
            for material in mesh.materials:
                shader = material.getShader()
                shader.setSource(VERTEX_SHADER, FRAGMENT_SHADER, True)
                shader.setUniform1f("width", render.getWindowWidth())
                shader.setUniform1f("height", render.getWindowHeight())
                shader.setUniform1f("pixelSize", pixelSize)
                shader.setUniform1f("tex0Enabled", 0)
                shader.setUniform1f("tex1Enabled", 0)
                shader.setSampler("tex0", 0)
                shader.setSampler("tex1", 1)
                if material.textures[0] is not None:
                    shader.setUniform1f("tex0Enabled", 1.0)
                if material.textures[1] is not None:
                    shader.setUniform1f("tex1Enabled", 1.0)

Basically I am trying to get the vertex shader to change depending on the resolution to make (psize) 1/20 the window width so it works on all monitors and resets every time the window size is changed (via properties).

image
image

Note - the original script is by Twister but I’ve modified (or attempted to modify) it so it changes based on the window’s resolution while the game is running. I have another script in the scene that swaps the resolution of the game window and toggles fullscreen based on the F keys.

EDIT - To clarify I am trying to find a way to have this shader change the vertex snapping depending on the window size, and the only way it seems to do this is to try to have the script refresh/disable for a frame when the window size changes while the game is running in windowed mode.

1 Like

I don’t know how to revert back to the default shader… But if you want your custom shader to update, there’s a couple things to manage:

  1. Only set the shader source once (when you need the shader program to be changed)
  2. Only set uniforms when their value changes (or every frame? I don’t recall, you should try stuff)

So the easiest way would be to put your Property “equal” sensor in pulse mode (making it run your script on each tick that the property is equal to “1”). In your script you can detect if a connected sensor went from “positive” to “negative” by doing the following test:

if all(sensor.positive for sensor in controller.sensors):
    print("all sensors are positive, we should do stuff")
else:
    print("at least one sensor is not positive, tear down here")

This seems to be partially working! I have no idea why using pulse mode on the properties didn’t occur to me. I’ll update when it works 100% but it seems to be updating the shader real-time (now I have to fix it so it updates correctly for each resolution mode)

BGE only triggers controllers on state change by default, when you set pulse mode it will keep on firing based on the mode you enabled (positive and/or negative pulse mode).

But then you have to keep track of what was already initialized before or not in your script.

I second. Checking for changes to either of two values once every frame is cheaper than outright setting them, for every other object no less. Unless you’re constantly resizing the window, it’s just redundant.

shader.delSource() reverts back to the materials original shader, but texture slots are wiped clean in the process and I don’t remember how to set them back. Texture module probably.

1 Like