Posted: 18th Jun 2020 6:47
GlobalToLocal3D()
This function will take a world point and convert it to the co-ordinate space of an object. (A bit like GetSpriteXFromWorld() only for objects)
It is very handy to determine a point relative to an object.
So if the returned x value is positive then the point is on the right hand side
If the returned z value is negative then the point is behind the object
If the returned y value is positive then the point is above the object

For this to work you need to fix an object to the center/pivot of your object and pass that id to the function.

+ Code Snippet
// Project: test562 
// Created: 20-06-18

// show all errors

SetErrorMode(2)

// set window properties
SetWindowTitle( "test562" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window

// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 )

global object as integer
object = CreateObjectCone(24, 12, 16)
RotateObjectLocalX(object, 90)
SetObjectPosition(object, 0, 0, 12)
FixObjectPivot(object)

global center as integer
center = CreateObjectSphere(2,16,16)
SetObjectColor(center, 0, 0xff, 0, 0xff)

FixObjectToObject(center, object)

type tPoint
	x as float
	y as float
	z as float
endtype

point  as tPoint
time as float

SetCameraPosition(1, 0, 250, -100)

global pos as integer
pos = CreateObjectPlane(4,4)
SetObjectColor(pos, 0xff, 0, 0, 0xff)

time = timer() + 1

do
	if timer() > time
		localPoint(point)
		time = time + 5
	endif
			
	SetCameraLookAt(1, GetObjectX(object),  GetObjectY(object),  GetObjectZ(object), 0)	
	print("Local=("+str(point.x,2)+","+str(point.y,2)+","+str(point.z,2)+")")
	print("Global=("+str(GetObjectX(pos),2)+","+str(GetObjectY(pos),2)+","+str(GetObjectZ(pos),2)+")")	
	
	if point.x > 0
		print("Right")
	elseif point.x < 0
		print("Left")		
	else
		print("aligned")		
	endif
	
	if point.z > 0
		print("Front")
	elseif point.z < 0
		print("Behind")		
	else
		print("aligned")		
	endif
	
	if point.y > 0
		print("Above")
	elseif point.y < 0
		print("Below")		
	else
		print("aligned")		
	endif
	
    Sync()
loop


function LocalPoint(r ref as tPoint)
	dist as float
	t as tPoint
	f as tPoint
			
	t.x = random(0, 100) - 50
	t.y = random(0, 100) - 50
	t.z = random(0, 100) - 50	

	SetObjectPosition(pos, t.x, t.y, t.z)

	SetObjectPosition(object, random(0, 100) - 50,  random(0, 100) - 50,  random(0, 100) - 50)
	SetObjectRotation(object, 0,  random(0, 360),  0)

	r = GlobalToLocal3D(center, t)

endfunction


function GlobalToLocal3D(obj as integer, point as tPoint)
	r as tpoint
	f as tPoint
	
	SetObjectPosition(obj, 0, 0, 0)
	SetObjectLookAt(obj, point.x, point.y, point.z, 0)
	
	f.x = GetObjectWorldX(obj)
	f.y = GetObjectWorldY(obj)	
	f.z = GetObjectWorldZ(obj)		
	
	dist = Distance3D(f, point)
	
	MoveObjectLocalZ(obj, dist)
	
	r.x = GetObjectX(center)
	r.y = GetObjectY(center)	
	r.z = GetObjectZ(center)

endfunction r

function Distance3D(fp as tPoint, tp as tPoint)
	dist as float
	dist = sqrt((tp.x - fp.x)^2 + (tp.y - fp.y)^2 + (tp.z - fp.z)^2 )				
endfunction dist
Posted: 18th Jun 2020 10:23
thanks blink you always have such great things to contribute to the community

anyone else feel free to add stuff
Posted: 10th Jul 2020 3:55
For those that didnt follow my Macroaction Thread, here is shader that turns all objects above a given range transparent
and all objects below a given range. This may help when people are recreating a 2.5d game with several floor levels as you
really only want to have the floor the player is on in full visibility

+ Code Snippet
#constant KEY_LEFT  =  37 //the left arrow key scancode
#constant KEY_UP =  38    //the up arrow key scancode
#constant KEY_RIGHT = 39  //the right arrow key scancode
#constant KEY_DOWN  =  40 //the down arrow key scancode
// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default font
x#=0:y#=0:z#=0
createShader()
obj=CreateObjectBox(2,15,2)
SetObjectImage(obj,createTexture(makecolor(255,255,255)),0)
SetObjectPosition(obj,x#,y#,z#)
SetObjectTransparency(obj,1)
SetObjectDepthWrite(obj,1)
fadeShader=LoadShader("fade.vs","fade.ps")
SetObjectShader(obj,fadeShader)
SetShaderConstantByName(fadeShader,"alpha",0.2,0,0,0)
//SetShaderConstantByName(fadeShader,"myColor",3,3,3,3)

do
	if GetRawKeyState(KEY_UP)
		y#=y#+.2
		SetObjectPosition(obj,x#,y#,z#)
	endif
	
	if GetRawKeyState(KEY_DOWN)
		y#=y#-.2
		SetObjectPosition(obj,x#,y#,z#)
	endif
	//The idea this should be calculated from the player position
	SetShaderConstantByName(fadeShader,"myCoord",-5,5,1,1)	//the y coords you want it to go transparent notice there are two
	sync()
loop	

function createTexture(color)
    SetClearColor(0,0,0)
    ClearScreen()
    Render()
    drawbox(0,0,10, 10, color, color,color,color, 1)
    Render()
    //img = getimage(0,0,sizex, sizey)
    ImgId=getimage(0,0,10, 10)
    Swap()
 endfunction imgId

function createShader()
file = OpenToWrite("fade.vs")
WriteLine(file,"attribute highp vec3 position;")
WriteLine(file,"attribute mediump vec3 normal;")
WriteLine(file,"attribute mediump vec2 uv;")
WriteLine(file,"varying highp vec3 posVarying;")
WriteLine(file,"varying mediump vec3 normalVarying;")
WriteLine(file,"varying mediump vec2 uvVarying;")
WriteLine(file,"varying mediump vec3 lightVarying;")
WriteLine(file,"uniform highp mat3 agk_WorldNormal;")
WriteLine(file,"uniform highp mat4 agk_World;")
WriteLine(file,"uniform highp mat4 agk_ViewProj;")
WriteLine(file,"uniform mediump vec4 uvBounds0;")
WriteLine(file,"mediump vec3 GetVSLighting( mediump vec3 normal, highp vec3 pos );")

//added this sectio for bone animations to work proper
WriteLine(file,"attribute highp vec4 boneweights;")
WriteLine(file,"attribute mediump vec4 boneindices;")
WriteLine(file,"uniform highp vec4 agk_bonequats1[30];")
WriteLine(file,"uniform highp vec4 agk_bonequats2[30];")
WriteLine(file,"highp vec3 transformDQ( highp vec3 p, highp vec4 q1, highp vec4 q2 )")
WriteLine(file,"{")
WriteLine(file,"    p += 2.0 * cross( q1.xyz, cross(q1.xyz, p) + q1.w*p );")
WriteLine(file,"    p += 2.0 * (q1.w*q2.xyz - q2.w*q1.xyz + cross(q1.xyz,q2.xyz));")
WriteLine(file,"    return p;")
WriteLine(file,"}")

WriteLine(file,"void main()")
WriteLine(file,"{") 
WriteLine(file,"    uvVarying = uv * uvBounds0.xy + uvBounds0.zw;")
WriteLine(file,"    highp vec4 pos = agk_World * vec4(position,1.0);")
WriteLine(file,"    gl_Position = agk_ViewProj * pos;")
WriteLine(file,"    mediump vec3 norm = normalize(agk_WorldNormal * normal);")

//added this section for bone animation to animate properly aswell
WriteLine(file,"    highp vec4 q1 = agk_bonequats1[ int(boneindices.x) ] * boneweights.x;")
WriteLine(file,"    q1 += agk_bonequats1[ int(boneindices.y) ] * boneweights.y;")
WriteLine(file,"    q1 += agk_bonequats1[ int(boneindices.z) ] * boneweights.z;")
WriteLine(file,"    q1 += agk_bonequats1[ int(boneindices.w) ] * boneweights.w;")
WriteLine(file,"    highp vec4 q2 = agk_bonequats2[ int(boneindices.x) ] * boneweights.x;")
WriteLine(file,"    q2 += agk_bonequats2[ int(boneindices.y) ] * boneweights.y;")
WriteLine(file,"    q2 += agk_bonequats2[ int(boneindices.z) ] * boneweights.z;")
WriteLine(file,"    q2 += agk_bonequats2[ int(boneindices.w) ] * boneweights.w;")
WriteLine(file,"    highp float len = 1.0/length(q1);")
WriteLine(file,"    q1 *= len;")
WriteLine(file,"    q2 = (q2 - q1*dot(q1,q2)) * len;")
WriteLine(file,"//    highp vec4 pos = vec4( transformDQ(position,q1,q2), 1.0 );")


WriteLine(file,"    posVarying = pos.xyz;")
WriteLine(file,"    normalVarying = norm;")
WriteLine(file,"    lightVarying = GetVSLighting( norm, posVarying );")
WriteLine(file,"}") 
CloseFile(file)

//pixel shader
file = OpenToWrite("fade.ps")
WriteLine(file,"uniform sampler2D texture0;")
WriteLine(file,"varying highp vec3 posVarying;")
WriteLine(file,"varying mediump vec3 normalVarying;")
WriteLine(file,"varying mediump vec2 uvVarying;")
WriteLine(file,"varying mediump vec3 lightVarying;")
WriteLine(file,"mediump vec3 GetPSLighting( mediump vec3 normal, highp vec3 pos );")
WriteLine(file,"mediump vec3 ApplyFog( mediump vec3 color, highp vec3 pointPos );")
WriteLine(file,"uniform mediump vec3 agk_MeshDiffuse;")
WriteLine(file,"uniform mediump vec3 myCoord;")
WriteLine(file,"varying vec4 verpos;")
WriteLine(file,"void main()")
WriteLine(file,"{")
WriteLine(file,"mediump vec3 norm = normalize(normalVarying);")
WriteLine(file,"mediump vec3 light = lightVarying + GetPSLighting( norm, posVarying );")
WriteLine(file,"vec3 colorA = texture2D(texture0, uvVarying).rgb*light *agk_MeshDiffuse;")
WriteLine(file,"if (posVarying.y>myCoord.y)")
WriteLine(file,"{")
WriteLine(file,"    colorA = clamp(colorA,0.0,1.0);") //restricts color range
WriteLine(file,"	mediump vec3 color = ApplyFog( colorA, posVarying );")
WriteLine(file,"	gl_FragColor = vec4(color,0.1);")
WriteLine(file,"}else{")
WriteLine(file,"	if (posVarying.y<myCoord.x)")
WriteLine(file,"	{")
WriteLine(file,"		mediump vec3 color = ApplyFog( colorA, posVarying );")
WriteLine(file,"		gl_FragColor = vec4(color,0.1);")
WriteLine(file,"	}else{")
WriteLine(file,"		mediump vec3 color = ApplyFog( colorA, posVarying );")
WriteLine(file,"		gl_FragColor = vec4(color,1.0);")
WriteLine(file,"	}")
WriteLine(file,"}")
WriteLine(file,"}")

CloseFile(file)
endfunction


this line SetShaderConstantByName(fadeShader,"myCoord",-5,5,1,1) //should be used with a calculation from the players y coords
eg SetShaderConstantByName(fadeShader,"myCoord",getObjectY(player.collisionID)-5,(getObjectY(player.collisionID)+12),1,1)

the above version of the shader makes it transparent above and below given ranges the following variation restricts the transparency between the height parameters
note it now has x coords and y coords to pass (myCoordX and myCoordY)
+ Code Snippet
function createShader()
file = OpenToWrite("fade.vs")
WriteLine(file,"attribute highp vec3 position;")
WriteLine(file,"attribute mediump vec3 normal;")
WriteLine(file,"attribute mediump vec2 uv;")
WriteLine(file,"varying highp vec3 posVarying;")
WriteLine(file,"varying mediump vec3 normalVarying;")
WriteLine(file,"varying mediump vec2 uvVarying;")
WriteLine(file,"varying mediump vec3 lightVarying;")
WriteLine(file,"uniform highp mat3 agk_WorldNormal;")
WriteLine(file,"uniform highp mat4 agk_World;")
WriteLine(file,"uniform highp mat4 agk_ViewProj;")
WriteLine(file,"uniform mediump vec4 uvBounds0;")
WriteLine(file,"mediump vec3 GetVSLighting( mediump vec3 normal, highp vec3 pos );")

//added this sectio for bone animations to work proper
WriteLine(file,"attribute highp vec4 boneweights;")
WriteLine(file,"attribute mediump vec4 boneindices;")
WriteLine(file,"uniform highp vec4 agk_bonequats1[30];")
WriteLine(file,"uniform highp vec4 agk_bonequats2[30];")
WriteLine(file,"highp vec3 transformDQ( highp vec3 p, highp vec4 q1, highp vec4 q2 )")
WriteLine(file,"{")
WriteLine(file,"    p += 2.0 * cross( q1.xyz, cross(q1.xyz, p) + q1.w*p );")
WriteLine(file,"    p += 2.0 * (q1.w*q2.xyz - q2.w*q1.xyz + cross(q1.xyz,q2.xyz));")
WriteLine(file,"    return p;")
WriteLine(file,"}")

WriteLine(file,"void main()")
WriteLine(file,"{") 
WriteLine(file,"    uvVarying = uv * uvBounds0.xy + uvBounds0.zw;")
WriteLine(file,"    highp vec4 pos = agk_World * vec4(position,1.0);")
WriteLine(file,"    gl_Position = agk_ViewProj * pos;")
WriteLine(file,"    mediump vec3 norm = normalize(agk_WorldNormal * normal);")

//added this section for bone animation to animate properly aswell
WriteLine(file,"    highp vec4 q1 = agk_bonequats1[ int(boneindices.x) ] * boneweights.x;")
WriteLine(file,"    q1 += agk_bonequats1[ int(boneindices.y) ] * boneweights.y;")
WriteLine(file,"    q1 += agk_bonequats1[ int(boneindices.z) ] * boneweights.z;")
WriteLine(file,"    q1 += agk_bonequats1[ int(boneindices.w) ] * boneweights.w;")
WriteLine(file,"    highp vec4 q2 = agk_bonequats2[ int(boneindices.x) ] * boneweights.x;")
WriteLine(file,"    q2 += agk_bonequats2[ int(boneindices.y) ] * boneweights.y;")
WriteLine(file,"    q2 += agk_bonequats2[ int(boneindices.z) ] * boneweights.z;")
WriteLine(file,"    q2 += agk_bonequats2[ int(boneindices.w) ] * boneweights.w;")
WriteLine(file,"    highp float len = 1.0/length(q1);")
WriteLine(file,"    q1 *= len;")
WriteLine(file,"    q2 = (q2 - q1*dot(q1,q2)) * len;")
WriteLine(file,"//    highp vec4 pos = vec4( transformDQ(position,q1,q2), 1.0 );")


WriteLine(file,"    posVarying = pos.xyz;")
WriteLine(file,"    normalVarying = norm;")
WriteLine(file,"    lightVarying = GetVSLighting( norm, posVarying );")
WriteLine(file,"}") 
CloseFile(file)

//pixel shader
file = OpenToWrite("fade.ps")
WriteLine(file,"uniform sampler2D texture0;")
WriteLine(file,"varying highp vec3 posVarying;")
WriteLine(file,"varying mediump vec3 normalVarying;")
WriteLine(file,"varying mediump vec2 uvVarying;")
WriteLine(file,"varying mediump vec3 lightVarying;")
WriteLine(file,"mediump vec3 GetPSLighting( mediump vec3 normal, highp vec3 pos );")
WriteLine(file,"mediump vec3 ApplyFog( mediump vec3 color, highp vec3 pointPos );")
WriteLine(file,"uniform mediump vec3 agk_MeshDiffuse;")
WriteLine(file,"uniform mediump vec3 myCoordX;")
WriteLine(file,"uniform mediump vec3 myCoordY;")
WriteLine(file,"varying vec4 verpos;")
WriteLine(file,"void main()")
WriteLine(file,"{")
WriteLine(file,"mediump vec3 norm = normalize(normalVarying);")
WriteLine(file,"mediump vec3 light = lightVarying + GetPSLighting( norm, posVarying );")
WriteLine(file,"vec3 colorA = texture2D(texture0, uvVarying).rgb*light *agk_MeshDiffuse;")
WriteLine(file,"mediump vec3 color = ApplyFog( colorA, posVarying );")
WriteLine(file,"gl_FragColor = vec4(color,1.0);")
WriteLine(file,"if (posVarying.y<myCoordY.y)")
WriteLine(file,"{")
WriteLine(file,"	if (posVarying.y>myCoordY.x)")
WriteLine(file,"	{")
WriteLine(file,"		if (posVarying.x<myCoordX.y)")
WriteLine(file,"		{")
WriteLine(file,"			if (posVarying.x>myCoordX.x)")
WriteLine(file,"			{")

WriteLine(file,"    			colorA = clamp(colorA,0.0,1.0);") //restricts color range
WriteLine(file,"				mediump vec3 color = ApplyFog( colorA, posVarying );")
WriteLine(file,"				gl_FragColor = vec4(color,0.1);")
WriteLine(file,"		}")
WriteLine(file,"	}")
WriteLine(file,"}")
WriteLine(file,"}")
WriteLine(file,"}")

CloseFile(file)
endfunction
Posted: 14th Jul 2020 2:42
Ive attached the source code to the following video
i couldnt get the bones perfectly in side the model but i worked around that
by creating a second shader which is an inverse effect of the first
The animations created in Mixamo
Posted: 14th Nov 2020 1:16
Handy function to help debug sprites. Just add a call to DumpDebug() where you want to examine where sprites are
+ Code Snippet
// File: debug.agc
// Created: 20-10-03


type tDebug
	sprite as integer
	image as string
	text as integer
	x as float
	y as float
	z as float
endtype

function DumpDebug()
	i as integer
	n as string
	t as integer
	c as integer
	id as integer
	d as tDebug
	sprites as tDebug[]
	
	for i=1 to 1000000
		d.sprite = i
		
		if GetSpriteExists(d.sprite) <> 1
			continue
		endif
		
		d.x = GetSpriteX(d.sprite)
		d.y = GetSpriteY(d.sprite)
		
		if GetImageExists(GetSpriteImageID(d.sprite))
			n = GetImageFilename(GetSpriteImageID(i))
			c = CountStringTokens(n, "/")
			if c > 1
				n = GetStringToken(n,"/",c)
			endif	
			d.image = n		
		else
			d.image = "No image"
		endif
		
		d.text = CreateText(d.image)
		SetTextSize(d.text, 12)
		SetTextPosition(d.text, d.x, d.y)
		SetTextDepth(d.text,2)
		sprites.insert(d)
	next

	repeat	
		for i=0 to sprites.length
			d = sprites[i]
			DrawBox(d.x, d.y, d.x + GetSpriteWidth(d.sprite), d.y + GetSpriteHeight(d.sprite), 0xffffffff,  0xffffffff,  0xffffffff,  0xffffffff,0)
			DrawText(d.text)
		next
		sync()
	until GetRawKeyPressed(27)
	
	
	for i=0 to sprites.length
		d = sprites[i]
		DeleteText(d.text)
	next
endfunction
Posted: 14th Nov 2020 18:16
getting the location of a sprite and angle so as a bullet can be positioned correctly can be a little tricky sometimes
usually its as simple as
+ Code Snippet
    SetSpritePositionbyoffset(launch,GetSpriteXByOffset(cannon),GetSpriteYByOffset(cannon))
    SetSpriteAngle(launch, GetSpriteAngle(cannon))

but sometimes you need to use more advanced methods
1>
+ Code Snippet
// Courtesy of Bengismo
// Thread: https://forum.thegamecreators.com/thread/222633
// Positions and rotates a sprite relative to its parent sprite
// spr is the sprite to be positioned relative to its parent
// x,y are the relative offset of spr1 to the parent 
// parent is the sprite toposition relative to
function SetSpritePositionRelative(spr as integer, x as float, y as float, parent as integer)
 
    // First copy the rotation
    angle# = GetSpriteAngle(parent)
    SetSpriteAngle(spr,angle#)
 
    // translate the relative position
    xn#= x*cos(angle#) - y*sin(angle#) +GetSpriteXByOffset(parent)
    yn#= y*cos(angle#) + x*sin(angle#) +GetSpriteYByOffset(parent)
 
    // set sprite position
    SetSpritePositionByOffset(spr,xn#,yn#)
 
endfunction

2>courtesy of virtual nomad
+ Code Snippet
// show all errors
SetErrorMode(2)

// set window properties
SetWindowSize( 1080, 720, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window

// set display properties
SetVirtualResolution( 1080, 720 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts

Ship = CreateSprite(0)            :    SetSpriteSize(Ship,32,64)    :    SetSpritePositionByOffset(Ship, GetWindowWidth()/2.0, GetWindowHeight()/2.0)
Cannon1 = CreateSprite(0)        :    SetSpriteSize(Cannon1,4,4)    :    SetSpriteColor(Cannon1,255,0,0,255)

do
    ShipAngle# = GetSpriteAngle(Ship) + GetRawKeyState(39) - GetRawKeyState(37) 
    
    SetSpriteAngle(Ship, ShipAngle#)
    
    Move# = GetRawKeyState(38) - GetRawKeyState(40)
    
    If Move# <> 0.0 then SetSpritePositionByOffset(Ship, GetSpriteXByOffset(Ship) + SIN (ShipAngle#)* Move#, GetSpriteYByOffset(Ship) - COS(ShipAngle#)*Move# )
    
    //Position Cannon1 @ 0, -30, relative to ship center
    CX# = GetWorldXFromSprite(Ship,0.0,-30.0)        :    CY# = GetWorldYFromSprite(Ship,0.0,-30.0)
    SetSpritePositionByOffset(Cannon1,CX#, CY#)    :    SetSpriteAngle(Cannon1,ShipAngle#)

    Print( ScreenFPS() )
    Sync()
loop


code copied from discord
Posted: 1st Jan 2021 5:23
using a memblock to grayscale
+ Code Snippet
SetWindowSize( 1024, 768, 0 )
SetVirtualResolution( 1024, 768 )
 LoadImage(1,"youimage.png") 

createShader()
CreateSprite(1,1)
MakeGreyscale(1)
do
    sync()  
loop

function MakeGreyscale(spr)
//Gray = 0.2126?Red + 0.7152?Green + 0.0722?Blue
    img = GetSpriteImageID(spr)
    mb = CreateMemblockFromImage(img)
    size = GetMemblockSize(mb)
    for k = 12 to size-4 step 4
        r = GetMemblockByte(mb, k)
        g = GetMemblockByte(mb, k+1)
        b = GetMemblockByte(mb, k+2)
        Gray = 0.2126*r + 0.7152*g + 0.0722*b
        SetMemblockByte(mb, k, Gray)
        SetMemblockByte(mb, k+1, Gray)
        SetMemblockByte(mb, k+2, Gray)
    next k
    CreateImageFromMemblock(img, mb)
    DeleteMemblock(mb)
endfunction


the same using a shader

+ Code Snippet
SetWindowSize( 1024, 768, 0 )
SetVirtualResolution( 1024, 768 )
LoadImage(1,"yourspriteimge.png")

createShader()
CreateSprite(1, 1)
SetSpriteTransparency(1,1)
LoadSpriteShader(1, "bw.ps")
SetSpriteShader(1, 1)

//the next line is only there to show transparency with a background
bg=createsprite(LoadImage("anybackgroundimage.png")):SetSpriteDepth(bg,100)

SetSpritePosition(2, 100.0, 100.0)

resetTimer()
SetShaderConstantByName(1, "factor", 0, 0, 0, 0) //factor red blue green alpha

do

SetShaderConstantByName(1, "factor", 1, 1, 1, 1) //red green blue alpha set rgn to 1 like this for gray
//SetShaderConstantByName(1, "factor", 0.5, 0.6, 1.0, 1) //red green blue alpha
sync()

loop


function createShader()
file = OpenToWrite("bw.ps")
WriteLine(file,"uniform sampler2D texture0;")
//WriteLine(file,"uniform float agk_time;")
WriteLine(file,"varying mediump vec2 uvVarying;")
WriteLine(file,"uniform vec3 factor;")
WriteLine(file,"void main()")
WriteLine(file,"{")
WriteLine(file,"vec4 color = texture2D(texture0, uvVarying).rgba;")
WriteLine(file,"float grey = 0.21 * color.r + 0.71 * color.g + 0.07 * color.b;")
WriteLine(file,"vec4 color2 = vec4(color.rgb * (1.0 - factor) + (grey * factor), 1.0);")
WriteLine(file,"gl_FragColor = vec4(color2.r,color2.g,color2.b,color.a);")

WriteLine(file,"}")
CloseFile(file)
endfunction
Posted: 14th Jan 2021 0:44
Map generator using the Random Walk Algorithm
1>Makes a two dimensional map of walls
2>Chooses a random starting point on the map
3>While the number of tunnels is not zero
3>Chooses a random length from maximum allowed length
4>Chooses a random direction to turn to (right, left, up, down)
5>Draws a tunnel in that direction while avoiding the edges of the map
6>Decrements the number of tunnels and repeats the while loop
7>Returns the map with the changes

Note: the larger the maxTurn is compared to the dimensions, the denser the map will be.
The larger the maxLength is compared to the dimensions, the more ?tunnel-y? it will look.
Its a commonly known and used algorithym and has known issues that are commonly known
try it copy paste (run repeat) give it a go. There is also a simple character/monster movement in documented
source below.

+ Code Snippet
// Project: Walking procedural map generator  
// Created: 2021-01-13

// show all errors
SetErrorMode(2)

// set window properties
SetWindowTitle( "map generator" )
SetWindowSize( 769, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window

// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts

//Map generator using the Random Walk Algorithm
//1>Makes a two dimensional map of walls
//2>Chooses a random starting point on the map
//3>While the number of tunnels is not zero
//3>Chooses a random length from maximum allowed length
//4>Chooses a random direction to turn to (right, left, up, down)
//5>Draws a tunnel in that direction while avoiding the edges of the map
//6>Decrements the number of tunnels and repeats the while loop
//7>Returns the map with the changes

//Note: the larger the maxTurn is compared to the dimensions, the denser the map will be. 
//The larger the maxLength is compared to the dimensions, the more ?tunnel-y? it will look.


#constant maxlength 512
#constant maxY 48 ///multiplied by tileY for pixels
#constant maxX 48
#constant tileX 16
#constant tileY 16
#constant maxItems 5
#constant maxMonsters 2


type _character
	ID as integer
	x as integer //the x position in relation to the grid
	y as integer //the y position in relation to the grid
	items as integer //the number of items picked up
	realX as integer //the actual x location of the sprite 
	realY as integer //the actual y location of the sprite
	diagFlag as integer //a state if true a monster may move diagonally
endtype
monster as _character[maxMonsters] 
player as _character

imgBG=1
CreateRenderImage(imgBG,1024,768,0,0)
sprBG=createSprite(imgBG) //the background renering image note its set to the furthest depth
SetSpriteDepth(sprBG,100)

sprWhite=createSprite(0)    //white tile used for areaes that are both dug and can walk
SetSpriteColor(sprWhite,255,255,255,255)
SetSpriteSize(sprWhite,tileX,tileY)

sprBlack=createSprite(0)   //black tiles cannot be moved on
SetSpriteColor(sprBlack,0,0,0,255)
SetSpriteSize(sprBlack,tileX,tileY)
global levelArray 	as integer [maxX,maxY]

x=random(0,maxX):y=random(0,maxY)
SetrenderToImage(imgBG,0)
for y = 0 to maxY
    for x = 0 to maxX
        SetSpritePosition(sprBlack,x*tileX,y*tileY)
        levelArray[x,y]=1
        drawSprite(sprBlack)
    next x
next y
//SetRenderToScreen()

//tunnel starting point1
SetSpriteVisible(sprBlack,0)
//SetRenderToImage(imgBG,0)
x=random(0,maxX):y=random(0,maxY)
SetSpritePosition(sprWhite,x,y):levelArray[x,y]=0
drawSprite(sprWhite)

//BELOW IS THE BEGININNING OF PROCEDURAL WALK THROUGH DUNGEON CREATION ALGORiTHYM
///first digging pass
//random length less than max length
length=random(0,maxlength)
for num=0 to length //repeat process of digging algorithym lenghth set
	//random direction
	direction=random(1,4)
	//SetRenderToImage(imgBG,0)
	Select direction
		case 1:
			//north
			if y >0 then y = y -1
		endcase
		case 2:
			//south
			if y<maxY-1 then y = y +1
		endcase
		case 3:
			//west
			if x>0 then x=x-1
		endcase
		case 4:
			if x<maxX-1 then x=x+1
		endcase
	endselect
	SetSpritePosition(sprWhite,x*tileX,y*tileY):levelArray[x,y]=0
	drawSprite(sprWhite)
next num
SetSpriteVisible(sprWhite,0)
//SetRenderToScreen()

//second pass tunnels
//create more tunnels these have to be dug through in game
sprRed=createSprite(0)
SetSpriteColor(sprRed,255,0,0,255)
SetSpriteSize(sprRed,tileX,tileY)

for num=1 to length
	//random direction
	direction=random(1,4)
	//SetRenderToImage(imgBG,0)
	if random(1,2)=1
		Select direction
			case 1:
				//north
				if y > 1 then y = y -1
			endcase
			case 2:

				//south
				if y<maxY-1 then y = y +1
			endcase
			case 3:
				//west
				if x>1 then x=x-1
			endcase
			case 4:
				//east
				if x<maxX-1 then x=x+1
			endcase
		endselect

		if levelArray[x,y]=1
			SetSpritePosition(sprRed,x*tileX,y*tiley):levelArray[x,y]=2
			drawSprite(sprRed) //only draw and update for valid valid tiles
			endif
		endif
next num
deleteSprite(sprRed) //red prite is no longer needed delete it
//SetRenderToScreen()

//third pass place items
sprYellow=createSprite(0)
SetSpriteColor(sprYellow,255,255,0,255)
SetSpriteSize(sprYellow,tileX,tileY)
SetSpriteDepth(sprYellow,0)
//SetRenderToImage(imgBG,0)
num=1
repeat

	x=random(1,maxX):y=random(1,maxY)
	if levelArray[x,y]=0 //check if can place here
		levelArray[x,y]=3:SetSpritePosition(sprYellow,x*tileX,y*tileY):num=num+1:DrawSprite(sprYellow)
	endif		
until num>maxItems
deleteSprite(sprYellow) //yellow sprite(items) no longer needed

sprPlayer=createSprite(0) //create a green playing sprite
SetSpriteColor(sprPlayer,0,255,0,255)
SetSpriteSize(sprPlayer,tileX,tileY)
SetSpriteDepth(sprPlayer,0)
repeat
	x=random(1,maxX):y=random(1,maxY) //randomly position on map within the array area
until levelArray[x,y]<>1 //repeat until a valid location has been chosen which is not black repeat implies it must be done once
player.x=x*tileX:player.y=y*tileY //multipley but the tile size to display correctly on screen
SetSpritePosition(sprPlayer,player.x,player.y)	

//fourth pass place monsters
DeleteSprite(sprYellow)
for num =0 to monster.length-1
	monster[num].ID=createSprite(0)
		SetSpriteColor(monster[num].ID,0,0,255,255)
		SetSpriteSize(monster[num].ID,tileX,tileY)
		SetSpriteDepth(monster[num].ID,0)
		repeat
		x=random(1,maxX):y=random(1,maxY) //placing a monnster is same as player process
	until levelArray[x,y]<>1 //repeat until a valid placement
	SetSpritePosition(monster[num].ID,x*tileX,y*tileY) ///:DrawSprite(monster.ID)	
	//DeleteSprite(monster.ID)
	monster[num].x=x:monster[num].y=y //monster variables updated
	monster[num].realX=monster[num].x*tileX:monster[num].realY=monster[num].y*tileY //multiply by tile dimension for correct positioning
	if num <=1
		monster[num].diagFlag=num
	endif	
next num
SetRenderToScreen()

do
	
	player.x = GetPointerX() / tileX //calculate the x array/grid location
	player.y = GetPointerY() / tileY //calculate the y array/grid location
	
	player.realX=player.x*tileX:player.realY=player.y*tileY //update actual sprite location variable this is only need to do the following calculations
	if player.x>=0 and player.x<=maxX and player.y>=0 and player.y<=maxY //ensure player is within grid
	arrayLoc=levelArray[player.x,player.y]                               //store the array variable of the player location for calculations
	if arrayLoc<>1                                                       //check if player sprite is on a valid grid  
	SetSpritePosition(sprPlayer,player.realX,Player.realY)               //position player sprite
	if arrayLoc=2 or arrayLoc=3 
		if arrayLoc=3 then player.items = player.items +1
		levelArray[player.x,player.y]=0 								 //an item has been picked up draw a white tile there
		SetSpriteVisible(sprWhite,1)
		SetRenderToImage(imgBG,0)										 //set rendering to the image so white/mapped tile can be drawn	
		SetSpritePosition(sprWhite,player.realX,player.realY)            //position player sprite  
		drawSprite(sprWhite)
		SetRenderToScreen()
		SetSpriteVisible(sprWhite,0)
	endif
	endif 
	endif
	Print("Player has "+str(player.items)+ " items")
	Print(" ")	

	for num = 0 to monster.length-1
		moveMonster(levelArray,monster[num], player)                                              //pass the level array and allow diagonal movement
		monster[num].realX=monster[num].x*tileX:monster[num].realY=monster[num].Y*tileY
		SetSpritePosition(monster[num].ID,monster[num].realX,monster[num].realY)             //position the sprite on grid
		arrayLoc=levelArray[monster[num].x,monster[num].y]
		if arrayLoc>1                                                         //check if tile either needs to be mapped/2 or an item/yellow             
			if arrayLoc=3 then monster[num].items = monster[num].items +1
			levelArray[monster[num].x,monster[num].y]=0
			SetSpriteVisible(sprWhite,1)                                 //the location now has been mapped and has no other items 
			SetRenderToImage(imgBG,0)
			SetSpritePosition(sprWhite,monster[num].realX,monster[num].realY) //the white tile needs to be drawn to the background and then rendering set to normal/screen
			drawSprite(sprWhite)
			SetRenderToScreen()
			setSpriteVisible(sprWhite,0)
		endif
		Print("Monster "+str(num)+" diagonalMovement="+str(monster[num].diagFlag)+" has "+str(monster[num].items)+" items")
	next num
	sync()
loop

function moveMonster(levelArray as integer[][],monster ref as _character,player ref as _character)
// diag flag is true if that creature may move diagonally

	x as integer
	y as integer

    x = (player.x - monster.x)
    
    if x <> 0
    	x = x / abs(x)
    endif
    
    y = (player.y - monster.y)
    
    if y <> 0
    	y = y / abs(y)
    endif

	if monster.x<1 or monster.x>maxX-1 then exitfunction
	if monster.y<1 or monster.y>maxY-1 then exitfunction
	
	//add some more realism to movement without diagonal
	realism=random(0,1) //when 1 is given it is more likely to move horizontally 0=vertically
	
    if levelArray[ monster.x + x,monster.y + y] <> 1 and monster.diagFlag=1
        inc monster.x, x
        inc monster.y, y
    elseif levelArray[monster.x,monster.y + y] <> 1 and realism=0
        inc monster.y, y
    elseif levelArray[monster.x + x,monster.y] <> 1 and realism=0
        inc monster.x, x
	elseif levelArray[monster.x + x,monster.y] <> 1 
        inc monster.x, x
    elseif levelArray[monster.x,monster.y + y] <> 1
        inc monster.y, y
    endif
    
endfunction
	


Map integration
1>black tiles cant do anything here
0>white tiles area to move
2>red tiles area to discover
3>yellow tiles items
4>green tile you as player
4>blue tiles monsters
Posted: 26th Jan 2021 18:17
SOME MATH FUNCTIONS (without using built in vector commands)

2D distance calculation function
+ Code Snippet
function getDistance2D(x1 as integer,y1 as integer,x2 as integer,y2 as integer)
	d as integer
	rem using the formula d=sqrt((x2-x1)2 +(y2-y1)2)
	d=ABS(SQRT(POW((x2-x1),2) + POW((y2-y1),2)))
endfunction d

3D distance calculation
+ Code Snippet
function getDistance3D(x1 as integer,y1 as integer,z1 as integer ,x2 as integer,y2 as integer ,z2 as integer)
	d as integer
    d=ABS(SQRT(POW((x2-x1),2) + POW((y2-y1),2)+POW((z2-z1),2)))
endfunction	d

4D distance calculation a time derivative (but i use for in/out)
+ Code Snippet
function getDistance4D(x1 as integer,y1 as integer,z1 as integer ,t1 as integer,x2 as integer,y2 as integer ,z2 as integer, t2 as integer)
	d as integer
    d=ABS(SQRT(POW((x2-x1),2) + POW((y2-y1),2)+POW((z2-z1),2)+POW((t2-t1),2)))
endfunction d
Posted: 27th Jan 2021 10:11
For such a small amount of code, there are quite a few things wrong with (or could be improved within) your distance function.

Firstly: you shouldn't restrict the input/output to integers. Even if you're working with a fixed 2D grid that can only have integer inputs, the output should be a float.
For example, take the inputs 0, 0, and 1, 2. The distance between those two coordinates is 2.36. Which is definitely not the same as 2 even in a fixed grid system.
Restricting the output to an integer means that the values (0, 0, 1, 2) and (0, 0, 0, 2) would both return 2 and therefore give the same resulting distance, which is clearly not the case.

Secondly: the POW() function is a recursive function and therefore slower than calling the multiplication twice.
2*2 is faster than POW(2, 2)

Thirdly: calling ABS() is a wasted function call. ABS() removes the negation of a value (eg, -2.36 becomes 2.36). However, the calculation of the distance function will always return a positive value, so you can eliminate that step entirely.

A faster and more accurate distance function would be:
+ Code Snippet
function GetDistance2( x1#, y1#, x2#, y2# )
	x# = x2# - x1#
	y# = y2# - y1#
	d# = sqrt( (x#*x#) + (y#*y#) )
endfunction d#


You can even improve that further by removing the sqrt() function and instead check for distance squared.
+ Code Snippet
function GetDistance2Squared( x1#, y1#, x2#, y2# )
	x# = x2# - x1#
	y# = y2# - y1#
	d# = (x#*x#) + (y#*y#) 
endfunction d#

If you use the second variant, then instead of searching for a distance of say 5, you would search for 5 squared or (5 * 5) or 25. Which is a lot quicker than square rooting the distance.
In a one-off call you might think "so what?". But if you are checking the distance of 1000's of items every frame it soon adds up and every little helps.
Posted: 27th Jan 2021 12:42
Thanks scraggle somehow i knew you would be the one to know the simplified math
with your distance squared algorithym does that mean in relation of an object being inside a 10 by 10 grid would it return 100
Posted: 27th Jan 2021 12:53
Not necessarily but if it was exactly 10.0 units away then it would return 100.0 which is why I said you should check your distance against a squared value instead.

If you are in a fixed 2D grid and can only travel vertically or horizontally then you should use the [size=large]Manhattan Distance[/size] (or Taxi-Cab Distance) check instead.
+ Code Snippet
function GetManhattanDistance( x1, y1, x2, y2 )
	d = abs(x1-x2) + abs(y1-y2)
endfunction d

Manhattan distance is so called because it is the distance you would have to travel on roads in Manhattan which are all horizontal or vertical and you obviously can't travel in a straight line because ... buildings.


Using the example coordinates from the previous post: (0, 0, 1, 2)
GetDistance2D(0, 0, 1, 2)
returns 2.36

GetManhattanDistance(0, 0, 1, 2)
returns 3 because you have to traverse 3 squares (Two vertically plus one horizontally)

There is also the [size=large]Chebeshev Distance[/size] which returns the maximum distance on any axis in a 2D grid.
Because of how it works I prefer to think of it as the MaxGridDistance
+ Code Snippet
function MaxGridDistance( x1, y1, x2, y2 )
	x = abs(x1-x2)
	y = abs(y1-y2)
	if x > y then exitfunction x
endfunction y

Posted: 29th Jan 2021 22:22
Thanks Scraggle very handy,

Something thats very handy for coders i feel and worth a mention if youve overwritten your source file
doesnt always work tho unfortunately

Step 1. Open Windows Explorer and find the folder where the file was located in.

Step 2. Right-click anywhere inside this folder and select "Properties".

Step 3. Select the "Previous Versions" tab. Look for an earlier version of the overwritten file and restore from it.
Posted: 6th Feb 2021 21:02
To determine if you are running in debug (Windows only but there's probably a similar structure in mac i would imagine)
+ Code Snippet
debug as string
debug = lower(mid(GetStringToken(GetWritePath(), "/", CountStringTokens(GetWritePath(),"/")-1), 1, 6))
if debug = "window"
   // do debug stuff
endif
Posted: 11th Feb 2021 1:35
"


I think you have to have enabled backups for this.

Better yet, use git, preferably with a remote on a separate device and/or location
Posted: 24th Mar 2021 17:14
Another terrain creator
This one may be suitable for those that want a low poly retro feel to a game
No media required
1> w a s d/shift move camera (camera needs work)
2> space saves
the file will save to a location of your choice but you meed a file that exists there first ie dummy.obj
the program will then save dummy.obj and dummy.mtl at that location
3> you may wish to bring into a program like blender to weld close verts etc effectively shrinking the file size
USE AT OWN RISK

+ Code Snippet
// Project: heights 
// Created: 2019-01-01
   
// show all errors
SetErrorMode(2)
   
#constant screenwidth=1024
#constant screenheight=768
#constant fullscreen=0
#constant screenrate=0
   
// set window properties
SetWindowTitle( "heights" )
SetWindowSize( screenwidth, screenheight, fullscreen )
SetWindowAllowResize( 1 ) // allow the user to resize the window
   
// set display properties
SetVirtualResolution( screenwidth, screenheight ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( screenrate, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts
Create3DPhysicsWorld()  
#constant sizex=21 // change this to extend the map
#constant sizez=21 // change this to exeend the map
global angx#, angy#,startx#,starty#
startx#=screenwidth/2
starty#=screenheight/2
 
size=5
 
type _map
    id
    x#
    height#
    z#
    colorred
    colorgreen
    colorblue
    texture
endtype
  
global map as _map[sizex,sizez]
 
 
global vertexnumber

//textimages as integer[10]
//for loops=0 to 10
//   textimages[loops]= createtexture(64,64,MakeColor(0,255,0),255)
//next
textimages as integer[10]
textimages[0]= createtexture(64,64,MakeColor(0,255,0),255)
textimages[1]= createtexture(64,64,MakeColor(255,255,255),255)

land = CreateObjectBox(.01,.01,.01)
colorgreen=150
for x=1 to sizex
    for z=1 to sizez
        map[x,z].id = CreateObjectBox(9,9,9)
        map[x,z].x# = x * GetObjectSizeMaxX(map[x,z].id)*2 // Remove the * 2 to join the cubes together
        map[x,z].height#=random(0,0)
        map[x,z].z# = z * GetObjectSizeMaxZ(map[x,z].id)*2 // Remove the * 2 to join the cubes together

        //map[x,z].colorgreen = random(150,200)
		//SetObjectImage(map[x,z].id,textimages[0],0)
		if colorgreen=150
			colorgreen=200
		else
			colorgreen=150
		endif
				
		map[x,z].colorgreen =colorGreen	
		SetObjectImage(map[x,z].id,textimages[0],0)
		
        Create3DPhysicsStaticBody(map[x,z].id)   
        SetObjectColor(map[x,z].id,0,map[x,z].colorgreen,0,255)
        SetObjectPosition(map[x,z].id,map[x,z].x#,0,map[x,z].z#)
        FixObjectToObject(map[x,z].id,land)
        		
    next
next
 
RotateObjectLocalY(land,-30)
prepareheights()
  
camerax#=20
cameray#=30
cameraz#=0
 
  
// frameImg=LoadImage("\media\frame2.png")
//FrameSpr=createSprite(frameImg) 
collisioner=CreateObjectBox(10,10,10)
do
  
  //  SetSpriteDepth(frameSpr,100) //set the frame to behind all tiles to allow clicking to work
 
    unit_x#=Get3DVectorXFromScreen(getpointerx(),getpointery())
    unit_y#=Get3DVectorYFromScreen(getpointerx(),getpointery())
    unit_z#=Get3DVectorZFromScreen(getpointerx(),getpointery()) 
    // calculate the start of the ray cast, which is the unit vector + the camera position
        start_x# = unit_x# + camerax#
        start_y# = unit_y# + cameray#
        start_z# = unit_z# - cameraz#
 
        // calculate the end of the vector, which is the unit vector multiplied by the length of the ray cast and then add the camera position to it
        end_x# = 800*unit_x# + camerax#
        end_y# = 800*unit_y# + cameray#
        end_z# = 800*unit_z# - cameraz#
 
        // determine which object has been hit
        object_hit = ObjectRayCast(0,start_x#,start_y#,start_z#,end_x#,end_y#,end_z#)
 
        // if an object has been hit then turn it red
        if object_hit <> 0
 
            x=getobjectx(object_hit)/9
            z=getobjectz(object_hit)/9
             
        else
        endif
 
 
     
    if GetRawKeyState(13)
        RotateObjectLocalY(land,.05)
    endif
    if GetRawMouseLeftState()
        flag=1
        if x<2 or x>sizex-1 then flag=0
        if z<2 or z>sizez-1 then flag=0
        if flag=1
            inc map[x,z].height#,.01
            SetObjectPosition(map[x,z].id,map[x,z].x#,map[x,z].height#,map[x,z].z#)
            changeverts(x,z,.01)
            Delete3DPhysicsBody(map[x,z].id) 
            Create3DPhysicsStaticBody(map[x,z].id)   
        endif
    endif
 
 
    if GetRawMouseRightState()
        flag=1
        if x<2 or x>sizex-1 then flag=0
        if z<2 or z>sizez-1 then flag=0
        if flag=1 and map[x,z].height#>0
            dec map[x,z].height#,.01
            SetObjectPosition(map[x,z].id,map[x,z].x#,map[x,z].height#,map[x,z].z#)
            changeverts(x,z,-.01)
            Delete3DPhysicsBody(map[x,z].id) 
            Create3DPhysicsStaticBody(map[x,z].id)   
        endif
    endif
     
    if GetRawMouseMiddlePressed() 
        flag=1
        if x<2 or x>sizex-1 then flag=0
        if z<2 or z>sizez-1 then flag=0
        if flag=1 
			//if map[x,z].height#>0
				dec map[x,z].height#,10
				SetObjectPosition(map[x,z].id,map[x,z].x#,map[x,z].height#,map[x,z].z#)
				changeverts(x,z,-10.01)
				Delete3DPhysicsBody(map[x,z].id) 
				Create3DPhysicsStaticBody(map[x,z].id)
            //endif   
			//SetObjectColor(map[x,z].id,GetObjectColorRed(map[x,z].id)-50,GetObjectColorGreen(map[x,z].id)-50,GetObjectColorBlue(map[x,z].id)-50,255)  
			//SetObjectColor(map[x+1,z+1].id,GetObjectColorRed(map[x+1,z+1].id)-50,GetObjectColorGreen(map[x+1,z+1].id)-50,GetObjectColorBlue(map[x+1,z+1].id)-50,255)  
			//SetObjectColor(map[x-1,z+1].id,GetObjectColorRed(map[x-1,z+1].id)-50,GetObjectColorGreen(map[x-1,z+1].id)-50,GetObjectColorBlue(map[x-1,z+1].id)-50,255)  
			//SetObjectColor(map[x-1,z-1].id,GetObjectColorRed(map[x-1,z-1].id)-50,GetObjectColorGreen(map[x-1,z-1].id)-50,GetObjectColorBlue(map[x-1,z-1].id)-50,255)  
			//SetObjectColor(map[x+1,z].id,GetObjectColorRed(map[x+1,z].id)-50,GetObjectColorGreen(map[x+1,z].id)-50,GetObjectColorBlue(map[x+1,z].id)-50,255)  
			//SetObjectColor(map[x-1,z].id,GetObjectColorRed(map[x-1,z].id)-50,GetObjectColorGreen(map[x-1,z].id)-50,GetObjectColorBlue(map[x-1,z].id)-50,255)  
			//SetObjectColor(map[x,z+1].id,GetObjectColorRed(map[x,z+1].id)-50,GetObjectColorGreen(map[x,z+1].id)-50,GetObjectColorBlue(map[x,z+1].id)-50,255)  
			//SetObjectColor(map[x,z-1].id,GetObjectColorRed(map[x,z-1].id)-50,GetObjectColorGreen(map[x,z-1].id)-50,GetObjectColorBlue(map[x,z-1].id)-50,255)  
			SetObjectColor(map[x,z].id,100,100,100,255):SetObjectImage(map[x,z].id,textImages[1],0)  
			SetObjectColor(map[x+1,z+1].id,100,100,100,255):SetObjectImage(map[x+1,z+1].id,textImages[1],0) 
			SetObjectColor(map[x-1,z+1].id,100,100,100,255):SetObjectImage(map[x-1,z+1].id,textImages[1],0) 
			SetObjectColor(map[x-1,z-1].id,100,100,100,255):SetObjectImage(map[x-1,z-1].id,textImages[1],0) 
			SetObjectColor(map[x+1,z].id,100,100,100,255):SetObjectImage(map[x+1,z].id,textImages[1],0) 
			SetObjectColor(map[x-1,z].id,100,100,100,255):SetObjectImage(map[x-1,z].id,textImages[1],0) 
			SetObjectColor(map[x,z+1].id,100,100,100,255):SetObjectImage(map[x,z+1].id,textImages[1],0) 
			SetObjectColor(map[x,z-1].id,100,100,100,255):SetObjectImage(map[x,z-1].id,textImages[1],0) 
			
		endif
        
    endif  
 
    if GetRawKeyState(68) then inc camerax#,.1
    if GetRawKeyState(65) then dec camerax#,.1
    if GetRawKeyState(83) then inc cameray#,.1
    if GetRawKeyState(87) then dec cameray#,.1
      
    movecamera()
	if GetRawKeyPressed(32)
		SetObjectRotation(land,0,0,0)
        ret$=ChooseRawFile("*.obj;*.mtl",1)
        if ret$<>""
        		print("Saving"):sync()
            	AGM_SaveObject("raw:"+left(ret$,len(ret$)-4)+".obj","raw:"+left(ret$,len(ret$)-4)+".mtl")
	    endif
    endif	
	SetCameraPosition(1,camerax#,cameray#,cameraz#)
    Print( ScreenFPS() )
    Sync()
loop
 
function movecamera()
    if GetRawKeyState(32)
    fDiffX# = (GetPointerX() - startx#)/4.0
    fDiffY# = (GetPointerY() - starty#)/4.0
    newX# = angx# + fDiffY#
    if ( newX# > 89 ) then newX# = 89
    if ( newX# < -89 ) then newX# = -89
    SetCameraRotation(1, newX#, angy# + fDiffX#, 0 )
    endif
endfunction
   
function prepareheights()
    for x=2 to sizex-1
        for z=2 to sizez-1
            changeverts(x,z,map[x,z].height#)
        next
    next
endfunction
   
function changeverts(x,z,slope#)
      
            CreateMemblockFromObjectMesh(2,map[x+1,z-1].id,1) // bottom right corner
            CreateMemblockFromObjectMesh(4,map[x+1,z+1].id,1) // top right corner
            CreateMemblockFromObjectMesh(5,map[x-1,z+1].id,1) // top left corner
            CreateMemblockFromObjectMesh(6,map[x-1,z-1].id,1) // bottom left corner
    
            CreateMemblockFromObjectMesh(3,map[x+1,z].id,1) // right edges
  
            CreateMemblockFromObjectMesh(7,map[x-1,z].id,1) // left cube edges
           CreateMemblockFromObjectMesh(8,map[x,z-1].id,1) // bottom cube edges
           CreateMemblockFromObjectMesh(9,map[x,z+1].id,1) // top cube edges
  
              
    for i=0 to 23
          
// bottom rightcorner
        if i=8 then SetMeshMemblockVertexPosition(2,i,GetMeshMemblockVertexX(2,i),GetMeshMemblockVertexY(2,i)+slope#,GetMeshMemblockVertexZ(2,i))
        if i=16 then SetMeshMemblockVertexPosition(2,i,GetMeshMemblockVertexX(2,i),GetMeshMemblockVertexY(2,i)+slope#,GetMeshMemblockVertexZ(2,i))
        if i=14 then SetMeshMemblockVertexPosition(2,i,GetMeshMemblockVertexX(2,i),GetMeshMemblockVertexY(2,i)+slope#,GetMeshMemblockVertexZ(2,i))
  
// top rightcorner
        if i=9 then SetMeshMemblockVertexPosition(4,i,GetMeshMemblockVertexX(4,i),GetMeshMemblockVertexY(4,i)+slope#,GetMeshMemblockVertexZ(4,i))
        if i=0 then SetMeshMemblockVertexPosition(4,i,GetMeshMemblockVertexX(4,i),GetMeshMemblockVertexY(4,i)+slope#,GetMeshMemblockVertexZ(4,i))
        if i=18 then SetMeshMemblockVertexPosition(4,i,GetMeshMemblockVertexX(4,i),GetMeshMemblockVertexY(4,i)+slope#,GetMeshMemblockVertexZ(4,i))
  
// top leftcorner
        if i=11 then SetMeshMemblockVertexPosition(5,i,GetMeshMemblockVertexX(5,i),GetMeshMemblockVertexY(5,i)+slope#,GetMeshMemblockVertexZ(5,i))
        if i=2 then SetMeshMemblockVertexPosition(5,i,GetMeshMemblockVertexX(5,i),GetMeshMemblockVertexY(5,i)+slope#,GetMeshMemblockVertexZ(5,i))
       if i=4 then SetMeshMemblockVertexPosition(5,i,GetMeshMemblockVertexX(5,i),GetMeshMemblockVertexY(5,i)+slope#,GetMeshMemblockVertexZ(5,i))
   
  
// tbottom leftcorner
        if i=10 then SetMeshMemblockVertexPosition(6,i,GetMeshMemblockVertexX(6,i),GetMeshMemblockVertexY(6,i)+slope#,GetMeshMemblockVertexZ(6,i))
        if i=6 then SetMeshMemblockVertexPosition(6,i,GetMeshMemblockVertexX(6,i),GetMeshMemblockVertexY(6,i)+slope#,GetMeshMemblockVertexZ(6,i))
        if i=12 then SetMeshMemblockVertexPosition(6,i,GetMeshMemblockVertexX(6,i),GetMeshMemblockVertexY(6,i)+slope#,GetMeshMemblockVertexZ(6,i))
  
  
// right cube
        if i=8 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=9 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=16 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=18 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=0 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=14 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
  
// left cube
        if i=10 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=11 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=4 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=6 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=2 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=12 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
         
// bottom cube
        if i=8 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=10 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=6 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=12 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=14 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=16 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
  
// top cube
        if i=9 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=11 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=0 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=2 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=4 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=18 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
  
    next
      
    SetObjectMeshFromMemblock(map[x+1,z-1].id,1,2)   
    SetObjectMeshFromMemblock(map[x+1,z].id,1,3)   
    SetObjectMeshFromMemblock(map[x+1,z+1].id,1,4)   
    SetObjectMeshFromMemblock(map[x-1,z+1].id,1,5)   
    SetObjectMeshFromMemblock(map[x-1,z-1].id,1,6)   
    SetObjectMeshFromMemblock(map[x-1,z].id,1,7)   
    SetObjectMeshFromMemblock(map[x,z-1].id,1,8)   
    SetObjectMeshFromMemblock(map[x,z+1].id,1,9)   
  
  
    DeleteMemblock(2)
    DeleteMemblock(3)
    DeleteMemblock(4)
    DeleteMemblock(5)
    DeleteMemblock(6)
    DeleteMemblock(7)
    DeleteMemblock(8)
    DeleteMemblock(9)
   
   
endfunction

// Function to create a texture
//
// Inputs - Sizex - size of the texture to create - width
//          Sizey - size of the texture to create - height
//          Color - is the main color of the image
//          Denisity - is a the depth of the texture - the lower the value, the more detail. higher value = no detail
// 
// Returns the image for the resulting texture
//
// EG. CreateTexture ( 100, 100,  makecolor(0,0,255), 100)
//          This could create a DEEP water effect texture?
  
function createtexture(sizex# as float, sizey# as float, color, density as integer)
  
      
    swap()
    drawbox(0,0,sizex#, sizey#, color, color,color,color, 1)
    render()
    img = getimage(0,0,sizex#, sizey#)
      
    memblockid = CreateMemblockFromImage (img)
    imgwidth = GetMemblockInt(memblockid, 0)
    imgheight = GetMemblockInt(memblockid, 4)
      
      
        size=GetMemblockSize(memblockid)
  
        for offset=12 to size-4 step 4
        
            r=GetMemblockByte(memblockid, offset)
            g=GetMemblockByte(memblockid, offset+1)
            b=GetMemblockByte(memblockid, offset+2)
            a=GetMemblockByte(memblockid, offset+3)
              
          
            strength=random(1,density)
  
            SetMemblockByte (memblockid, offset, r-strength)
            SetMemblockByte (memblockid, offset+1, g-strength)
            SetMemblockByte (memblockid, offset+2, b-strength )
            SetMemblockByte (memblockid, offset+3, a-strength)
               
          
    next
      
    deleteimage (img)
      
    img = CreateImageFromMemblock(memblockid)
    DeleteMemblock(memblockid)
  
  
endfunction img

Function AGM_SaveObject(filename$ as string,material$ as string)

fw = OpenToWrite(filename$) 
   
WriteLine(fw,"#AGM Object - " + filename$)
WriteLine(fw,"#Exported with AppGameKit")
WriteLine(fw,"")
WriteLine(fw,"mtllib " + trimPath(material$))
incrementalcounter=0
    
`number of material
m=0

size=abs(sizex*sizez)
for x = 1 to sizex
  for z = 1 to sizez
    if GetObjectExists(map[x,z].id) 
    	
        mesh = CreateMemblockFromObjectMesh(map[x,z].id,1)
`       get object vertex quantity 
        verts= GetMemblockInt( mesh, 0 )
        writeline(fw,"g ") //GROUP
    
        `VERTEX
        for i= 0 to verts -1
            x#=GetMeshMemblockVertexX(mesh,i)
            y#=GetMeshMemblockVertexy(mesh,i)
            z#=GetMeshMemblockVertexz(mesh,i)
            //ox#=(size-1)-GetObjectWorldX(map[x,z].id)
            ox#=GetObjectWorldX(map[x,z].id)
            oy#=GetObjectWorldY(map[x,z].id)
            oz#=GetObjectWorldZ(map[x,z].id)
            
            Writeline ( fw, " v " + str(x#+ox#)+ " "+str(y#+oy#)+ " "+str(z#+oz#))
        next i
    
    `TEXTURE VEERTICES
    for i= 1 to verts
        uu#=GetMeshMemblockVertexU( mesh, i )
        vv#=GetMeshMemblockVertexV( mesh, i )
        writeline(fw, " vt "+str(uu#)+" "+str(vv#))
    next
     
  `     NORMALS
    for i= 0 to verts -1
        x#=GetMeshMemblockVertexnormalX(mesh,i)
        y#=GetMeshMemblockVertexnormaly(mesh,i)
        z#=GetMeshMemblockVertexnormalz(mesh,i)
   
        Writeline ( fw, " vn " + str(x#)+ " "+str(y#)+ " "+str(z#))
    next i
      
     
    `FACES
    
    inc m,1
    //Writeline ( fw,"usemtl Material.00"+str(m))
    Writeline ( fw,"usemtl Material.00")
     
    s=0 `reseting variable s
   
   for i= 1 to verts-4
          
    inc s,1
      if s=3
        n=n+1
        nor=nor+4
        writeline (fw, " f "+ str(n+1)+"/"+str(n+1)+"/"+str(nor)    +" "+str(n) +"/"+str(n+2)+"/"+str(nor)     +" "+str(n+2)+"/"+str(n)+"/"+str(nor)      +" "+str(n+3)+"/"+str(n+3)+"/"+str(nor))
        s=0
        n=n+3
      endif
   next
   DeleteMemblock(mesh)
endif
next z
next x
CloseFile ( fw )  

fw=OpenToWrite(material$)
for z = 1 to sizex
  for x = 1 to sizez 
  	if GetObjectExists(map[x,z].id) 
        //Writeline ( fw,"newmtl Material.00"+str(t))
        Writeline ( fw,"newmtl Material.00")
         
        WriteLine(fw,"Kd " + str(GetObjectColorRed(map[x,z].id)/255.0) + " " + str(GetObjectColorGreen(map[x,z].id)/255.0) + " " + str(GetObjectColorBlue(map[x,z].id)/255.0))
        //DeleteObject(map[x,z].id)
        //DeleteMemblock(map[x,z].memID)
        //map.remove(x,z)
    endif
next x
next z
CloseFile(fw)

   
//DeleteAllObjects()
endfunction
 
function trimPath(str$ as string)
num=len(str$)
if num<1 then exitfunction ""
repeat
    dec num
until mid(str$,num,1)="\"
for num2=(num+1) to len(Str$)   
    trimStr$=trimStr$+mid(str$,num2,1) 
next
endfunction trimStr$
Posted: 24th Mar 2021 17:14
Another terrain creator
This one may be suitable for those that want a low poly retro feel to a game
No media required
1> w a s d/shift move camera (camera needs work)
2> space saves
the file will save to a location of your choice but you meed a file that exists there first ie dummy.obj
the program will then save dummy.obj and dummy.mtl at that location
3> you may wish to bring into a program like blender to weld close verts etc effectively shrinking the file size
USE AT OWN RISK

+ Code Snippet
// Project: heights 
// Created: 2019-01-01
   
// show all errors
SetErrorMode(2)
   
#constant screenwidth=1024
#constant screenheight=768
#constant fullscreen=0
#constant screenrate=0
   
// set window properties
SetWindowTitle( "heights" )
SetWindowSize( screenwidth, screenheight, fullscreen )
SetWindowAllowResize( 1 ) // allow the user to resize the window
   
// set display properties
SetVirtualResolution( screenwidth, screenheight ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( screenrate, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts
Create3DPhysicsWorld()  
#constant sizex=21 // change this to extend the map
#constant sizez=21 // change this to exeend the map
global angx#, angy#,startx#,starty#
startx#=screenwidth/2
starty#=screenheight/2
 
size=5
 
type _map
    id
    x#
    height#
    z#
    colorred
    colorgreen
    colorblue
    texture
endtype
  
global map as _map[sizex,sizez]
 
 
global vertexnumber

//textimages as integer[10]
//for loops=0 to 10
//   textimages[loops]= createtexture(64,64,MakeColor(0,255,0),255)
//next
textimages as integer[10]
textimages[0]= createtexture(64,64,MakeColor(0,255,0),255)
textimages[1]= createtexture(64,64,MakeColor(255,255,255),255)

land = CreateObjectBox(.01,.01,.01)
colorgreen=150
for x=1 to sizex
    for z=1 to sizez
        map[x,z].id = CreateObjectBox(9,9,9)
        map[x,z].x# = x * GetObjectSizeMaxX(map[x,z].id)*2 // Remove the * 2 to join the cubes together
        map[x,z].height#=random(0,0)
        map[x,z].z# = z * GetObjectSizeMaxZ(map[x,z].id)*2 // Remove the * 2 to join the cubes together

        //map[x,z].colorgreen = random(150,200)
		//SetObjectImage(map[x,z].id,textimages[0],0)
		if colorgreen=150
			colorgreen=200
		else
			colorgreen=150
		endif
				
		map[x,z].colorgreen =colorGreen	
		SetObjectImage(map[x,z].id,textimages[0],0)
		
        Create3DPhysicsStaticBody(map[x,z].id)   
        SetObjectColor(map[x,z].id,0,map[x,z].colorgreen,0,255)
        SetObjectPosition(map[x,z].id,map[x,z].x#,0,map[x,z].z#)
        FixObjectToObject(map[x,z].id,land)
        		
    next
next
 
RotateObjectLocalY(land,-30)
prepareheights()
  
camerax#=20
cameray#=30
cameraz#=0
 
  
// frameImg=LoadImage("\media\frame2.png")
//FrameSpr=createSprite(frameImg) 
collisioner=CreateObjectBox(10,10,10)
do
  
  //  SetSpriteDepth(frameSpr,100) //set the frame to behind all tiles to allow clicking to work
 
    unit_x#=Get3DVectorXFromScreen(getpointerx(),getpointery())
    unit_y#=Get3DVectorYFromScreen(getpointerx(),getpointery())
    unit_z#=Get3DVectorZFromScreen(getpointerx(),getpointery()) 
    // calculate the start of the ray cast, which is the unit vector + the camera position
        start_x# = unit_x# + camerax#
        start_y# = unit_y# + cameray#
        start_z# = unit_z# - cameraz#
 
        // calculate the end of the vector, which is the unit vector multiplied by the length of the ray cast and then add the camera position to it
        end_x# = 800*unit_x# + camerax#
        end_y# = 800*unit_y# + cameray#
        end_z# = 800*unit_z# - cameraz#
 
        // determine which object has been hit
        object_hit = ObjectRayCast(0,start_x#,start_y#,start_z#,end_x#,end_y#,end_z#)
 
        // if an object has been hit then turn it red
        if object_hit <> 0
 
            x=getobjectx(object_hit)/9
            z=getobjectz(object_hit)/9
             
        else
        endif
 
 
     
    if GetRawKeyState(13)
        RotateObjectLocalY(land,.05)
    endif
    if GetRawMouseLeftState()
        flag=1
        if x<2 or x>sizex-1 then flag=0
        if z<2 or z>sizez-1 then flag=0
        if flag=1
            inc map[x,z].height#,.01
            SetObjectPosition(map[x,z].id,map[x,z].x#,map[x,z].height#,map[x,z].z#)
            changeverts(x,z,.01)
            Delete3DPhysicsBody(map[x,z].id) 
            Create3DPhysicsStaticBody(map[x,z].id)   
        endif
    endif
 
 
    if GetRawMouseRightState()
        flag=1
        if x<2 or x>sizex-1 then flag=0
        if z<2 or z>sizez-1 then flag=0
        if flag=1 and map[x,z].height#>0
            dec map[x,z].height#,.01
            SetObjectPosition(map[x,z].id,map[x,z].x#,map[x,z].height#,map[x,z].z#)
            changeverts(x,z,-.01)
            Delete3DPhysicsBody(map[x,z].id) 
            Create3DPhysicsStaticBody(map[x,z].id)   
        endif
    endif
     
    if GetRawMouseMiddlePressed() 
        flag=1
        if x<2 or x>sizex-1 then flag=0
        if z<2 or z>sizez-1 then flag=0
        if flag=1 
			//if map[x,z].height#>0
				dec map[x,z].height#,10
				SetObjectPosition(map[x,z].id,map[x,z].x#,map[x,z].height#,map[x,z].z#)
				changeverts(x,z,-10.01)
				Delete3DPhysicsBody(map[x,z].id) 
				Create3DPhysicsStaticBody(map[x,z].id)
            //endif   
			//SetObjectColor(map[x,z].id,GetObjectColorRed(map[x,z].id)-50,GetObjectColorGreen(map[x,z].id)-50,GetObjectColorBlue(map[x,z].id)-50,255)  
			//SetObjectColor(map[x+1,z+1].id,GetObjectColorRed(map[x+1,z+1].id)-50,GetObjectColorGreen(map[x+1,z+1].id)-50,GetObjectColorBlue(map[x+1,z+1].id)-50,255)  
			//SetObjectColor(map[x-1,z+1].id,GetObjectColorRed(map[x-1,z+1].id)-50,GetObjectColorGreen(map[x-1,z+1].id)-50,GetObjectColorBlue(map[x-1,z+1].id)-50,255)  
			//SetObjectColor(map[x-1,z-1].id,GetObjectColorRed(map[x-1,z-1].id)-50,GetObjectColorGreen(map[x-1,z-1].id)-50,GetObjectColorBlue(map[x-1,z-1].id)-50,255)  
			//SetObjectColor(map[x+1,z].id,GetObjectColorRed(map[x+1,z].id)-50,GetObjectColorGreen(map[x+1,z].id)-50,GetObjectColorBlue(map[x+1,z].id)-50,255)  
			//SetObjectColor(map[x-1,z].id,GetObjectColorRed(map[x-1,z].id)-50,GetObjectColorGreen(map[x-1,z].id)-50,GetObjectColorBlue(map[x-1,z].id)-50,255)  
			//SetObjectColor(map[x,z+1].id,GetObjectColorRed(map[x,z+1].id)-50,GetObjectColorGreen(map[x,z+1].id)-50,GetObjectColorBlue(map[x,z+1].id)-50,255)  
			//SetObjectColor(map[x,z-1].id,GetObjectColorRed(map[x,z-1].id)-50,GetObjectColorGreen(map[x,z-1].id)-50,GetObjectColorBlue(map[x,z-1].id)-50,255)  
			SetObjectColor(map[x,z].id,100,100,100,255):SetObjectImage(map[x,z].id,textImages[1],0)  
			SetObjectColor(map[x+1,z+1].id,100,100,100,255):SetObjectImage(map[x+1,z+1].id,textImages[1],0) 
			SetObjectColor(map[x-1,z+1].id,100,100,100,255):SetObjectImage(map[x-1,z+1].id,textImages[1],0) 
			SetObjectColor(map[x-1,z-1].id,100,100,100,255):SetObjectImage(map[x-1,z-1].id,textImages[1],0) 
			SetObjectColor(map[x+1,z].id,100,100,100,255):SetObjectImage(map[x+1,z].id,textImages[1],0) 
			SetObjectColor(map[x-1,z].id,100,100,100,255):SetObjectImage(map[x-1,z].id,textImages[1],0) 
			SetObjectColor(map[x,z+1].id,100,100,100,255):SetObjectImage(map[x,z+1].id,textImages[1],0) 
			SetObjectColor(map[x,z-1].id,100,100,100,255):SetObjectImage(map[x,z-1].id,textImages[1],0) 
			
		endif
        
    endif  
 
    if GetRawKeyState(68) then inc camerax#,.1
    if GetRawKeyState(65) then dec camerax#,.1
    if GetRawKeyState(83) then inc cameray#,.1
    if GetRawKeyState(87) then dec cameray#,.1
      
    movecamera()
	if GetRawKeyPressed(32)
		SetObjectRotation(land,0,0,0)
        ret$=ChooseRawFile("*.obj;*.mtl",1)
        if ret$<>""
        		print("Saving"):sync()
            	AGM_SaveObject("raw:"+left(ret$,len(ret$)-4)+".obj","raw:"+left(ret$,len(ret$)-4)+".mtl")
	    endif
    endif	
	SetCameraPosition(1,camerax#,cameray#,cameraz#)
    Print( ScreenFPS() )
    Sync()
loop
 
function movecamera()
    if GetRawKeyState(32)
    fDiffX# = (GetPointerX() - startx#)/4.0
    fDiffY# = (GetPointerY() - starty#)/4.0
    newX# = angx# + fDiffY#
    if ( newX# > 89 ) then newX# = 89
    if ( newX# < -89 ) then newX# = -89
    SetCameraRotation(1, newX#, angy# + fDiffX#, 0 )
    endif
endfunction
   
function prepareheights()
    for x=2 to sizex-1
        for z=2 to sizez-1
            changeverts(x,z,map[x,z].height#)
        next
    next
endfunction
   
function changeverts(x,z,slope#)
      
            CreateMemblockFromObjectMesh(2,map[x+1,z-1].id,1) // bottom right corner
            CreateMemblockFromObjectMesh(4,map[x+1,z+1].id,1) // top right corner
            CreateMemblockFromObjectMesh(5,map[x-1,z+1].id,1) // top left corner
            CreateMemblockFromObjectMesh(6,map[x-1,z-1].id,1) // bottom left corner
    
            CreateMemblockFromObjectMesh(3,map[x+1,z].id,1) // right edges
  
            CreateMemblockFromObjectMesh(7,map[x-1,z].id,1) // left cube edges
           CreateMemblockFromObjectMesh(8,map[x,z-1].id,1) // bottom cube edges
           CreateMemblockFromObjectMesh(9,map[x,z+1].id,1) // top cube edges
  
              
    for i=0 to 23
          
// bottom rightcorner
        if i=8 then SetMeshMemblockVertexPosition(2,i,GetMeshMemblockVertexX(2,i),GetMeshMemblockVertexY(2,i)+slope#,GetMeshMemblockVertexZ(2,i))
        if i=16 then SetMeshMemblockVertexPosition(2,i,GetMeshMemblockVertexX(2,i),GetMeshMemblockVertexY(2,i)+slope#,GetMeshMemblockVertexZ(2,i))
        if i=14 then SetMeshMemblockVertexPosition(2,i,GetMeshMemblockVertexX(2,i),GetMeshMemblockVertexY(2,i)+slope#,GetMeshMemblockVertexZ(2,i))
  
// top rightcorner
        if i=9 then SetMeshMemblockVertexPosition(4,i,GetMeshMemblockVertexX(4,i),GetMeshMemblockVertexY(4,i)+slope#,GetMeshMemblockVertexZ(4,i))
        if i=0 then SetMeshMemblockVertexPosition(4,i,GetMeshMemblockVertexX(4,i),GetMeshMemblockVertexY(4,i)+slope#,GetMeshMemblockVertexZ(4,i))
        if i=18 then SetMeshMemblockVertexPosition(4,i,GetMeshMemblockVertexX(4,i),GetMeshMemblockVertexY(4,i)+slope#,GetMeshMemblockVertexZ(4,i))
  
// top leftcorner
        if i=11 then SetMeshMemblockVertexPosition(5,i,GetMeshMemblockVertexX(5,i),GetMeshMemblockVertexY(5,i)+slope#,GetMeshMemblockVertexZ(5,i))
        if i=2 then SetMeshMemblockVertexPosition(5,i,GetMeshMemblockVertexX(5,i),GetMeshMemblockVertexY(5,i)+slope#,GetMeshMemblockVertexZ(5,i))
       if i=4 then SetMeshMemblockVertexPosition(5,i,GetMeshMemblockVertexX(5,i),GetMeshMemblockVertexY(5,i)+slope#,GetMeshMemblockVertexZ(5,i))
   
  
// tbottom leftcorner
        if i=10 then SetMeshMemblockVertexPosition(6,i,GetMeshMemblockVertexX(6,i),GetMeshMemblockVertexY(6,i)+slope#,GetMeshMemblockVertexZ(6,i))
        if i=6 then SetMeshMemblockVertexPosition(6,i,GetMeshMemblockVertexX(6,i),GetMeshMemblockVertexY(6,i)+slope#,GetMeshMemblockVertexZ(6,i))
        if i=12 then SetMeshMemblockVertexPosition(6,i,GetMeshMemblockVertexX(6,i),GetMeshMemblockVertexY(6,i)+slope#,GetMeshMemblockVertexZ(6,i))
  
  
// right cube
        if i=8 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=9 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=16 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=18 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=0 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
        if i=14 then SetMeshMemblockVertexPosition(3,i,GetMeshMemblockVertexX(3,i),GetMeshMemblockVertexY(3,i)+slope#,GetMeshMemblockVertexZ(3,i))
  
// left cube
        if i=10 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=11 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=4 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=6 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=2 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
        if i=12 then SetMeshMemblockVertexPosition(7,i,GetMeshMemblockVertexX(7,i),GetMeshMemblockVertexY(7,i)+slope#,GetMeshMemblockVertexZ(7,i))
         
// bottom cube
        if i=8 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=10 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=6 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=12 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=14 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
        if i=16 then SetMeshMemblockVertexPosition(8,i,GetMeshMemblockVertexX(8,i),GetMeshMemblockVertexY(8,i)+slope#,GetMeshMemblockVertexZ(8,i))
  
// top cube
        if i=9 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=11 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=0 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=2 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=4 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
        if i=18 then SetMeshMemblockVertexPosition(9,i,GetMeshMemblockVertexX(9,i),GetMeshMemblockVertexY(9,i)+slope#,GetMeshMemblockVertexZ(9,i))
  
    next
      
    SetObjectMeshFromMemblock(map[x+1,z-1].id,1,2)   
    SetObjectMeshFromMemblock(map[x+1,z].id,1,3)   
    SetObjectMeshFromMemblock(map[x+1,z+1].id,1,4)   
    SetObjectMeshFromMemblock(map[x-1,z+1].id,1,5)   
    SetObjectMeshFromMemblock(map[x-1,z-1].id,1,6)   
    SetObjectMeshFromMemblock(map[x-1,z].id,1,7)   
    SetObjectMeshFromMemblock(map[x,z-1].id,1,8)   
    SetObjectMeshFromMemblock(map[x,z+1].id,1,9)   
  
  
    DeleteMemblock(2)
    DeleteMemblock(3)
    DeleteMemblock(4)
    DeleteMemblock(5)
    DeleteMemblock(6)
    DeleteMemblock(7)
    DeleteMemblock(8)
    DeleteMemblock(9)
   
   
endfunction

// Function to create a texture
//
// Inputs - Sizex - size of the texture to create - width
//          Sizey - size of the texture to create - height
//          Color - is the main color of the image
//          Denisity - is a the depth of the texture - the lower the value, the more detail. higher value = no detail
// 
// Returns the image for the resulting texture
//
// EG. CreateTexture ( 100, 100,  makecolor(0,0,255), 100)
//          This could create a DEEP water effect texture?
  
function createtexture(sizex# as float, sizey# as float, color, density as integer)
  
      
    swap()
    drawbox(0,0,sizex#, sizey#, color, color,color,color, 1)
    render()
    img = getimage(0,0,sizex#, sizey#)
      
    memblockid = CreateMemblockFromImage (img)
    imgwidth = GetMemblockInt(memblockid, 0)
    imgheight = GetMemblockInt(memblockid, 4)
      
      
        size=GetMemblockSize(memblockid)
  
        for offset=12 to size-4 step 4
        
            r=GetMemblockByte(memblockid, offset)
            g=GetMemblockByte(memblockid, offset+1)
            b=GetMemblockByte(memblockid, offset+2)
            a=GetMemblockByte(memblockid, offset+3)
              
          
            strength=random(1,density)
  
            SetMemblockByte (memblockid, offset, r-strength)
            SetMemblockByte (memblockid, offset+1, g-strength)
            SetMemblockByte (memblockid, offset+2, b-strength )
            SetMemblockByte (memblockid, offset+3, a-strength)
               
          
    next
      
    deleteimage (img)
      
    img = CreateImageFromMemblock(memblockid)
    DeleteMemblock(memblockid)
  
  
endfunction img

Function AGM_SaveObject(filename$ as string,material$ as string)

fw = OpenToWrite(filename$) 
   
WriteLine(fw,"#AGM Object - " + filename$)
WriteLine(fw,"#Exported with AppGameKit")
WriteLine(fw,"")
WriteLine(fw,"mtllib " + trimPath(material$))
incrementalcounter=0
    
`number of material
m=0

size=abs(sizex*sizez)
for x = 1 to sizex
  for z = 1 to sizez
    if GetObjectExists(map[x,z].id) 
    	
        mesh = CreateMemblockFromObjectMesh(map[x,z].id,1)
`       get object vertex quantity 
        verts= GetMemblockInt( mesh, 0 )
        writeline(fw,"g ") //GROUP
    
        `VERTEX
        for i= 0 to verts -1
            x#=GetMeshMemblockVertexX(mesh,i)
            y#=GetMeshMemblockVertexy(mesh,i)
            z#=GetMeshMemblockVertexz(mesh,i)
            //ox#=(size-1)-GetObjectWorldX(map[x,z].id)
            ox#=GetObjectWorldX(map[x,z].id)
            oy#=GetObjectWorldY(map[x,z].id)
            oz#=GetObjectWorldZ(map[x,z].id)
            
            Writeline ( fw, " v " + str(x#+ox#)+ " "+str(y#+oy#)+ " "+str(z#+oz#))
        next i
    
    `TEXTURE VEERTICES
    for i= 1 to verts
        uu#=GetMeshMemblockVertexU( mesh, i )
        vv#=GetMeshMemblockVertexV( mesh, i )
        writeline(fw, " vt "+str(uu#)+" "+str(vv#))
    next
     
  `     NORMALS
    for i= 0 to verts -1
        x#=GetMeshMemblockVertexnormalX(mesh,i)
        y#=GetMeshMemblockVertexnormaly(mesh,i)
        z#=GetMeshMemblockVertexnormalz(mesh,i)
   
        Writeline ( fw, " vn " + str(x#)+ " "+str(y#)+ " "+str(z#))
    next i
      
     
    `FACES
    
    inc m,1
    //Writeline ( fw,"usemtl Material.00"+str(m))
    Writeline ( fw,"usemtl Material.00")
     
    s=0 `reseting variable s
   
   for i= 1 to verts-4
          
    inc s,1
      if s=3
        n=n+1
        nor=nor+4
        writeline (fw, " f "+ str(n+1)+"/"+str(n+1)+"/"+str(nor)    +" "+str(n) +"/"+str(n+2)+"/"+str(nor)     +" "+str(n+2)+"/"+str(n)+"/"+str(nor)      +" "+str(n+3)+"/"+str(n+3)+"/"+str(nor))
        s=0
        n=n+3
      endif
   next
   DeleteMemblock(mesh)
endif
next z
next x
CloseFile ( fw )  

fw=OpenToWrite(material$)
for z = 1 to sizex
  for x = 1 to sizez 
  	if GetObjectExists(map[x,z].id) 
        //Writeline ( fw,"newmtl Material.00"+str(t))
        Writeline ( fw,"newmtl Material.00")
         
        WriteLine(fw,"Kd " + str(GetObjectColorRed(map[x,z].id)/255.0) + " " + str(GetObjectColorGreen(map[x,z].id)/255.0) + " " + str(GetObjectColorBlue(map[x,z].id)/255.0))
        //DeleteObject(map[x,z].id)
        //DeleteMemblock(map[x,z].memID)
        //map.remove(x,z)
    endif
next x
next z
CloseFile(fw)

   
//DeleteAllObjects()
endfunction
 
function trimPath(str$ as string)
num=len(str$)
if num<1 then exitfunction ""
repeat
    dec num
until mid(str$,num,1)="\"
for num2=(num+1) to len(Str$)   
    trimStr$=trimStr$+mid(str$,num2,1) 
next
endfunction trimStr$
Posted: 11th Apr 2021 11:36
some test images for the above
Posted: 11th Apr 2021 11:36
This program may be used display paintball splats/bullets on an object etc

+ Code Snippet
// set window properties
SetWindowTitle( "Paintball example" )
SetWindowSize( 800, 600, 0 )
SetWindowAllowResize( 0 ) // dont allow the user to resize the window
SetClearColor(100,200,100)

global xw = 256
global yw = 256
global brush as integer

target=CreateObjectPlane(50,50)
//SetObjectTransparency(target,0)
SetGenerateMipmaps(1)

defaultImg=LoadImage("white.png") // no need for alpha with this one
bulletHole=LoadImage("splash.png") // with alpha ;)
//SetImageTransparentColor(bulletHole,0,0,0)
Brush = CreateSprite(bulletHole)
SetSpriteSize(brush,16,16)
SetSpritevisible(brush,0)

#constant renderImg = 1
CreateRenderImage( renderImg,GetVirtualWidth(), GetVirtualHeight(), 0, 0 )


LoadShader(3, "blend2.vs", "blend2.ps")
SetObjectShader(target,3)
SetObjectImage(target,defaultImg,0)
SetObjectImage(target,renderImg,1)

SetCameraPosition(1,0,0,-50)
setcameralookat(1,0,0,0,0)
//SetCameraPosition(1,0,5,-10)
do

    if GetPointerState() 
        // get the position of the pointer (mouse)
        pointer_x = GetPointerX()
        pointer_y = GetPointerY()

        // get the x, y and z unit vectors based on the pointer position
        unit_x# = Get3DVectorXFromScreen(pointer_x,pointer_y)
        unit_y# = Get3DVectorYFromScreen(pointer_x,pointer_y)
        unit_z# = Get3DVectorZFromScreen(pointer_x,pointer_y)

        // calculate the start of the ray cast, which is the unit vector + the camera position
        start_x# = unit_x#
        start_y# = unit_y#
        start_z# = unit_z#-100

        // calculate the end of the vector, which is the unit vector multiplied by the length of the ray cast and then add the camera position to it
        end_x# = 800*unit_x#
        end_y# = 800*unit_y#
        end_z# = 800*unit_z#+100


                // only ray cast against the sphere
        if ObjectRayCast(0,start_x#,start_y#,start_z#,end_x#,end_y#,end_z#) <>0

                        // get the coordinates of the intersect
                        intersect_x# = GetObjectRayCastX(0)
                        intersect_y# = GetObjectRayCastY(0)
                        intersect_z# = GetObjectRayCastZ(0)

                    // translate the object 3D coordinates to 2D screen coordinate
					screen_x# = GetScreenXFrom3D( intersect_x#, intersect_y#, intersect_z#)
					screen_y# = GetScreenYFrom3D( intersect_x#, intersect_y#, intersect_z#)
					print(screen_x#):print(getpointerx())
                    // if the ray cast intersects paint the brush
					SetSpriteColor(brush,random(100,255),random(100,255),random(100,255),255)
					paint(screen_x#,screen_y#)
					SetObjectImage(target,renderImg,1)
					SetSpriteVisible(brush,0)
			endif
	endif
    sync()

loop

function Paint(x,y)
	SetRenderToImage(renderImg, 0 )
	SetSpritePositionByOffset(Brush,x,y)
	SetSpriteAngle(Brush,random(0,360))
	SetSpriteVisible(brush,1)
	DrawSprite(Brush)
	SetRenderToScreen()  
endfunction


ps shader
+ Code Snippet
// constant values sent through from AGK code.
uniform sampler2D texture0; 
uniform sampler2D texture1; 

// Anything that the vertex shader passes as output needs to 
// be defined here as input. The vertex shader is passing the 
// texture coordinate, so it is defined again here.
varying vec2 uv0Varying;
varying vec2 uv1Varying;

void main()
{
  // copy the textures coords
  vec2 texCoord0 = uv0Varying;
  vec2 texCoord1 = uv1Varying;
  
  vec4 colorResult0  = texture2D(texture0, texCoord0);
  vec4 colorResult1  = texture2D(texture1, texCoord0); // you can change here the second uvlayer by texture2D(texture1, texCoord1) if you use different uvchanel for each texture
  
  gl_FragColor = mix(colorResult0, colorResult1, colorResult1.a); // mix with the alpha of the second texture. You can mix with a third texture if you want to use seamless texture and repeat it.
}


vs shader
+ Code Snippet
attribute vec3 position;
attribute vec2 uv;
 
varying vec2 uv0Varying;
uniform vec4 uvBounds0;
 
uniform mat4 agk_World;
uniform mat4 agk_ViewProj;

void main()
{
    vec4 pos = agk_World * vec4(position,1);
    gl_Position = agk_ViewProj * pos;
    uv0Varying = uv * uvBounds0.xy + uvBounds0.zw;
}
Posted: 28th Apr 2021 10:49
I just finished going through all of these. Absolutely amazing library of resources, mate, thank you for sharing them!