Posted: 30th Jan 2021 17:25
Is there a way to let's say raycast onto the heightmap and then raise the height at that position?

I guess you have to use memblocks, but then again, is this fast enough in real time?

Perhaps this forum has some examples?!
Posted: 30th Jan 2021 19:05
Sort of, check here: https://forum.thegamecreators.com/thread/222027?page=3#msg2639070
Posted: 31st Jan 2021 13:00
Dont forget that you will have to recalculate the normals after every change if you want the lighting to be correct.

There is some code in this thread that seems to do the very thing you are asking about. https://forum.thegamecreators.com/thread/222992
Posted: 3rd Feb 2021 4:07
This was possible in realtime in DBP, I'm certain AppGameKit is fast enough.
Posted: 3rd Feb 2021 4:56
I reckon you could do this in real time with a shader
Posted: 3rd Feb 2021 5:58
example 1 (modifying a mesh in real time)
+ Code Snippet
// Project: coordinate 
// Created: 2018-04-06

// show all errors
SetErrorMode(2)
#constant screenWidth=1024
#constant screenHeight=768
#constant perlinw = 200
#constant perlinh = 200
#constant perlinz = 200  
#constant mapX=2048
#constant mapY=50
#constant mapZ=1024

  
SetWindowSize(screenWidth,screenHeight,0)
Setvirtualresolution(screenWidth,screenHeight)
SetScissor(0,0,0,0)
SetCameraRange( 1, 0.1, 900000 )
SetGlobal3DDepth(10000)

type _heights
	meshposition
	height
endtype
global heights as _heights[]

 
global TerrainImageID
  
  
// start perlin map data
NoiseInit()
TerrainImageID=generatePerlinImages()
mapsprite = CreateSprite(TerrainImageID)
SetSpriteSize(mapsprite,100,100)
SetSpritePosition(mapsprite,screenWidth-100,0)
HeightMapTextureMemblock = CreateMemblockFromImage(TerrainImageID)
HeightMapTextureWidthMemblock = GetMemblockInt(HeightMapTextureMemblock, 0)
HeightMapTextureHeightMemblock = GetMemblockInt(HeightMapTextureMemblock, 4)
TerrainImageID =CreateImageFromMemblock(HeightMapTextureMemblock)
  
  
//the following three lines only used if not updating on fly
//HeightImageMemblock=CreateMemblockFromImage(HeightImage)
//HeightImageWidthMemblock=GetMemblockInt(HeightImageMemblock, 0)
//HeightImageHeightMemblock=GetMemblockInt(HeightImageMemblock, 4)
  
global TerrainObjectID
  
// create the terrain object from a height map
TerrainObjectID=CreateObjectFromHeightMap( "height.png", mapX,mapY, mapZ, 0, 0 )
SetObjectCollisionMode( TerrainObjectID, 1 ) //On needed for object raycasting
SetObjectImage( TerrainObjectID, TerrainImageID, 0 )
SetObjectTransparency(TerrainObjectID,0)
TerrainMemblock=createMapMemblock(TerrainObjectID)
//DeleteObject(TerrainObjectID)
//createObjectFromMeshMemblock(TerrainObjectID,TerrainMemblock)
//SetObjectPosition(TerrainObjectID,x,y,z) 
//SetObjectCollisionMode( TerrainObjectID, 1 ) 
//SetObjectImage( TerrainObjectID, TerrainImageID, 0 )
//SetObjectTransparency(TerrainObjectID,0)
  
  
//SetCameraRange(1,1,2000 ) 
SetCameraPosition(1, 805, 378, -41)
  
//SetObjectMeshNormalMapScale( TerrainObjectID, 0, 1.0, 1.0 ) 
  
do
    checkCameraMovement()
      
    pointerState=GetRawMouseLeftState() 
    if pointerState = 1
  
        pointer_x = GetPointerX()
        pointer_y = GetPointerY()
        //pointer_y2 =screenHeight-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# + GetCameraX(1)
        start_y# = unit_y# + GetCameraY(1)
        start_z# = unit_z# - GetCameraZ(1)
  
        // 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# = 1000*unit_x# + GetCameraX(1)
        end_y# = 1000*unit_y# + GetCameraY(1)
        end_z# = 1000*unit_z# - GetCameraZ(1)
  
  
        // determine which object has been hit
        object_hit = ObjectRayCast(0,start_x#,start_y#,start_z#,end_x#,end_y#,end_z#)
        Print ("objhit" + str(object_hit)+"="+str(TerrainObjectID))
          
        if object_hit = TerrainObjectID
            xPixel# = GetObjectRayCastX(0)
        
    yPixel# = GetObjectRayCastZ(0) 
            for y = -5 to 5 step 1
                for x = -5 to 5 step 1
                    writePixelMemblock(HeightMapTextureMemblock,HeightMapTextureWidthMemblock,HeightMapTextureHeightMemblock,xPixel#+x,yPixel#+y,1,1,1,255)     
                    //i=xpixel#+x
                    //SetMeshMemblockVertexPosition(TerrainMemblock,i,GetMeshMemblockVertexX(TerrainMemblock,i),GetMeshMemblockVertexY(TerrainMemblock,i)+1,GetMeshMemblockVertexZ(TerrainMemblock,i)) //make it flat
                    //i=i+ypixel#+y
                    //SetMeshMemblockVertexPosition(TerrainMemblock,i,GetMeshMemblockVertexX(TerrainMemblock,i),GetMeshMemblockVertexY(TerrainMemblock,i)+1,GetMeshMemblockVertexZ(TerrainMemblock,i)) //make it flat

               next x      
            next y

					
          // index of this vertex is (Vertices start back left and go right  then down to next line etc....
          yPixel#=screenHeight-yPixel#/1.2
          maxX=(SQRT(GetMemblockInt(TerrainMemblock,0)))*1.5
          maxZ=(SQRT(GetMemblockInt(TerrainMemblock,0)))*.95
          x=xPixel#/(mapX/maxX):z=(yPixel#)/(mapZ/MaxZ)
          x=xPixel#/(mapX/perlinw):z=(yPixel#)/(mapZ/perlinz)
          i=floor((x) + (z*maxX))
          if i>0 and i<=GetMemblockInt(terrainMemblock,0)  
           
         //  i = floor(xPixel# + (yPixel#*MapX)*GetMemblockInt(TerrainMemblock,0))
           print (i)
			posy=1
//			for posy=-1 to 1
			for posx=-1 to 1 
				if (i+posx)*posy >0 or (i+posx) * posy<GetMemblockSize(TerrainMemBlock)
            SetMeshMemblockVertexPosition(TerrainMemblock,heights[(i+posx) * posy].meshposition,GetMeshMemblockVertexX(TerrainMemblock,(i+posx)*posy),GetMeshMemblockVertexY(TerrainMemblock,(i+posx)*posy)+heights[i].height/10,GetMeshMemblockVertexZ(TerrainMemblock,(i+posx)*posy))
            dec heights[(i+posx) * posy].height,1
			endif
  //         next
           
           next
            SetObjectMeshFromMemblock(TerrainObjectID,1,TerrainMemblock) 

         endif 


       endif
              
        // update the image from the memblock
        CreateImageFromMemblock(TerrainImageID,HeightMapTextureMemblock)
          
    endif
    if GetRawMouseRightPressed()
        resetTerrain(TerrainMemblock)
    endif
      
    // show some information
    Print( "FPS: " + str(ScreenFPS(),1) )
    Print("MsxX="+str(GetObjectSizeMaxX(terrainObjectID)))
    Print( "Polygons: " + str(GetPolygonsDrawn()))
    print( "CameraPos: " + str(GetCameraX(1)) + ", " + str(GetCameraY(1)) +", " + str(GetCameraZ(1)))
    print("vertices="+str(GetMemblockInt(terrainMemblock,0)))
    print("maxX="+str(maxX))
  print("maxZ="+str(maxZ))
    print("X="+str(X))
    print("Z="+str(z))
    print("i ="+str(i))
      
      
          
    sync()
      
loop
  
function createMapMemblock(newobj as integer)
    chk = CreateMemblockFromObjectMesh(newobj,1)
endfunction chk
  
function checkCameraMovement()
  
if GetRawKeyState(37) then MoveCameraLocalX(1,-5) //Left
if GetRawKeyState(39) then MoveCameraLocalX(1,5) //Right
if GetRawKeyState(38) then MoveCameraLocalZ(1,5) //Forward
if GetRawKeyState(40) then MoveCameraLocalZ(1,-5) //Backward
if GetRawKeyState(87) then MoveCameraLocalY(1,-5) //87 W
if GetRawKeyState(83) then MoveCameraLocalY(1,5) //87 S
//if GetRawKeyState(65) then RotateCameraLocalY(1,1)
//if GetRawKeyState(68) then RotateCameraLocalY(1,-1)
  
// if cameray#<(blocksizey*10) then cameray#=(blocksizey*10)
if GetRawKeyPressed(27) then end
/*
        // rotate the camera
if ( GetPointerPressed()=1 )
    startMouseX# = GetPointerX()
    startMouseY# = GetPointerY()
    angx# = GetCameraAngleX(1)
    angy# = GetCameraAngleY(1)
  
endif
if ( GetPointerState() = 1 )
    fDiffX# = (GetPointerX() - startMouseX#)/4.0
    fDiffY# = (GetPointerY() - startMouseY#)/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 writePixelMemblock(memblockId as integer,memblockWidth,memblockHeight,x as integer,y as integer,R as integer, G as integer, B as integer, A as integer)
    if (mapX/perlinw)>1 and (mapZ/perlinz)>1
        x=x/(mapX/perlinw):y=y/(mapZ/perlinz)
    else 
        x=x/perlinw:y=y/perlinz
    endif
         
    if x<0 then exitfunction
    if y<0 then exitfunction
    R =R+ GetMemblockByte(memblockId,12+(x*4)+((memblockHeight-y)*4*memblockWidth))
    G =G+ GetMemblockByte(memblockId,13+(x*4)+((memblockHeight-y)*4*memblockWidth))
    B =B+ GetMemblockByte(memblockId,14+(x*4)+((memblockHeight-y)*4*memblockWidth))
    A =A+ GetMemblockByte(memblockId,15+(x*4)+((memblockHeight-y)*4*memblockWidth))
      
    if R>255 then R=255
    if G>255 then G=255
    if B>255 then B=255
    if A>255 then A=255
      
    SetMemblockByte(memblockId,12+(x*4)+((memblockHeight-y)*4*memblockWidth),R) // Write Red 
    SetMemblockByte(memblockId,13+(x*4)+((memblockHeight-y)*4*memblockWidth),G) // Write Green 
    SetMemblockByte(memblockId,14+(x*4)+((memblockHeight-y)*4*memblockWidth),B) // Write Blue 
    SetMemblockByte(memblockId,15+(x*4)+((memblockHeight-y)*4*memblockWidth),A) // Write Alpha full opaque (255)
      
endfunction
  
function resetTerrain (msblk as integer) 
  
    count = GetMemblockInt( msblk ,0 )
    for i = 0 to count  
        SetMeshMemblockVertexPosition(msblk,i,GetMeshMemblockVertexX(msblk,i),0,GetMeshMemblockVertexZ(msblk,i)) //make it flat
    next
    SetObjectMeshFromMemblock(TerrainObjectID,1,msblk)
Endfunction
  
   
function generatePerlinImages()
// Generate image from memblock
  
size = perlinw * perlinh * 4 + 12
mem = CreateMemblock(size) //the colour texture image
SetMemblockInt(mem,0,perlinw)
SetMemblockInt(mem,4,perlinh)
SetMemblockInt(mem,8,32)
mem2 = CreateMemblock(size) //the black and white height image
SetMemblockInt(mem2,0,perlinw)
SetMemblockInt(mem2,4,perlinh)
SetMemblockInt(mem2,8,32)
     
offset as integer = 12
a as float, b as float
a = 5.0
b = 2.0
     
meshposition=0
for y = 0 to perlinh - 1
    for x = 0 to perlinw - 1
        a = a + 0.0001
        b = b + 0.002
             
        // Try out these two noise methods
        //noise = 255.0*Noise2D(x/10.0,y/10.0)
        noise = 255.0*Noise2D(x/255.0,y/255.0)
             
        noise = abs(noise)
		
		// add to array
		height as _heights
		height.meshposition=meshposition
		height.height = noise
		heights.insert(height)
		// end of adding to array
		
		inc meshposition
        //clouds
        if noise>255
            SetMemblockByte(mem, offset, noise)
            SetMemblockByte(mem, offset+1, noise)
            SetMemblockByte(mem, offset+2, noise)
            SetMemblockByte(mem, offset+3, 255)
        endif
            
     
         //greenary
        if noise>100 and noise<=255
            SetMemblockByte(mem, offset, 0)
            SetMemblockByte(mem, offset+1, noise)
            SetMemblockByte(mem, offset+2, 0)
            SetMemblockByte(mem, offset+3, 255)
        endif
        //sand
        if noise>50 and noise<=100  
            SetMemblockByte(mem, offset, noise)
            SetMemblockByte(mem, offset+1, noise)
            SetMemblockByte(mem, offset+2, 0)
            SetMemblockByte(mem, offset+3, 255)
        endif
        // water
        if noise<=50 
            SetMemblockByte(mem, offset, noise/2)
            SetMemblockByte(mem, offset+1, 0)
            SetMemblockByte(mem, offset+2, noise)
            SetMemblockByte(mem, offset+3, 255)
        endif
        //mem2 is the black and white image
        SetMemblockByte(mem2, offset, noise)
        SetMemblockByte(mem2, offset+1, noise)
        SetMemblockByte(mem2, offset+2, noise)
        SetMemblockByte(mem2, offset+3, 255)
        offset = offset + 4
    next
next
     
map=CreateImageFromMemblock(mem)
//heightImage=CreateImageFromMemblock(heightImage)
saveImage(mem,"height.png")
DeleteObject(mem):DeleteObject(mem2)
endfunction map
  
// ***************************************************************************************************
// Ken Perlin's Simplex Noise 2D. AGK Version.
// Ported from Stefan Gustavson's Java implementation
// (http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf)
// 2015.02.03
// AGK reference https://forum.thegamecreators.com/thread/213532
// Thank you Thank you 
    
#constant PN3DF2 = 0.5*(sqrt(3.0)-1.0)
#constant PN3DG2 = (3.0-sqrt(3.0))/6.0
    
Type sPNVECTOR
    x as float
    y as float
    z as float
endtype
    
Global PNHash as integer[512]
Global PNGrad3 as sPNVECTOR[256]
    
    
Function NoiseInit()
    Local n as integer, rn as integer
    For n=0 To 255
        PNHash[n] = n
    Next n 
    For n=0 To 255
        rn=Random(0, 255) 
        PNHash.swap(n,rn)
    Next n
    For n=0 To 255
        PNHash[256 + n] = PNHash[n]
    Next n
    PNHash[511] = PNHash[0]
    
    For n=0 To 15
        PNGrad3[n * 16 + 0].x = 1 : PNGrad3[n * 16 + 0].y = 1 : PNGrad3[n * 16 + 0].z = 0
        PNGrad3[n * 16 + 1].x = -1 : PNGrad3[n * 16 + 1].y = 1 : PNGrad3[n * 16 + 1].z = 0
        PNGrad3[n * 16 + 2].x = 1 : PNGrad3[n * 16 + 2].y = -1 : PNGrad3[n * 16 + 2].z = 0
        PNGrad3[n * 16 + 3].x = -1 : PNGrad3[n * 16 + 3].y = -1 : PNGrad3[n * 16 + 3].z = 0
    
        PNGrad3[n * 16 + 4].x = 1 : PNGrad3[n * 16 + 4].y = 0 : PNGrad3[n * 16 + 4].z = 1
        PNGrad3[n * 16 + 5].x = -1 : PNGrad3[n * 16 + 5].y = 0 : PNGrad3[n * 16 + 5].z = 1
        PNGrad3[n * 16 + 6].x = 1 : PNGrad3[n * 16 + 6].y = 0 : PNGrad3[n * 16 + 6].z = -1
        PNGrad3[n * 16 + 7].x = -1 : PNGrad3[n * 16 + 7].y = 0 : PNGrad3[n * 16 + 7].z = -1
    
        PNGrad3[n * 16 + 8].x = 0 : PNGrad3[n * 16 + 8].y = 1 : PNGrad3[n * 16 + 8].z = 1
        PNGrad3[n * 16 + 9].x = 0 : PNGrad3[n * 16 + 9].y = -1 : PNGrad3[n * 16 + 9].z = 1
        PNGrad3[n * 16 + 10].x = 0 : PNGrad3[n * 16 + 10].y = 1 : PNGrad3[n * 16 + 10].z = -1
        PNGrad3[n * 16 + 11].x = 0 : PNGrad3[n * 16 + 11].y = -1 : PNGrad3[n * 16 + 11].z = -1
    
        PNGrad3[n * 16 + 12].x = 1 : PNGrad3[n * 16 + 12].y = 1 : PNGrad3[n * 16 + 12].z = 0
        PNGrad3[n * 16 + 13].x = -1 : PNGrad3[n * 16 + 13].y = 1 : PNGrad3[n * 16 + 13].z = 0
        PNGrad3[n * 16 + 14].x = 0 : PNGrad3[n * 16 + 14].y = -1 : PNGrad3[n * 16 + 14].z = 1
        PNGrad3[n * 16 + 15].x = 0 : PNGrad3[n * 16 + 15].y = -1 : PNGrad3[n * 16 + 15].z = -1
    Next n 
endfunction
    
function Noise2D(xin as float, yin as float)
    local n0 as float, n1 as float, n2 as float, s as float, t as float, x0 as float, y0 as float, xs as float, ys as float
    local i as integer, j as integer, i1 as integer, j1 as integer, i2 as integer, j2 as integer, gi0 as integer, gi1 as integer, gi2 as integer
    local x1 as float, y1 as float, x2 as float, y2 as float, x3 as float, y3 as float, t0 as float, t1 as float, t2 as float
        
    s = (xin + yin) * PN3DF2
    xs = xin + s
    i = floor(xs)
    ys = yin + s
    j = floor(ys)
    t = (i + j) * PN3DG2
    x0 = xin - (i - t)
    y0 = yin - (j - t)
    if x0>y0
        i1=1
        j1=0
    else
        i1=0
        j1=1
    endif
    x1 = x0 - i1 + PN3DG2
    y1 = y0 - j1 + PN3DG2
    x2 = x0 - 1.0 + 2.0 * PN3DG2
    y2 = y0 - 1.0 + 2.0 * PN3DG2
    i = i && 255
    j = j && 255
    gi0 =  PNHash[i + PNHash[j]] && 15
    gi1 = PNHash[i + i1 + PNHash[j + j1]] && 15
    gi2 = PNHash[i + 1 + PNHash[j+ 1]] && 15
    t0 = 0.5 - x0*x0-y0*y0
    if t0<0
        n0 = 0.0
    else
        t0 = t0 * t0
        n0 = t0 * t0 * (PNGrad3[gi0].x * x0 + PNGrad3[gi0].y * y0)
    endif
    t1 = 0.5 - x1*x1-y1*y1
    if t1<0
        n1 = 0.0
    else
        t1 = t1 * t1
        n1 = t1 * t1 * (PNGrad3[gi1].x * x1 + PNGrad3[gi1].y * y1)
    endif
    t2 = 0.5 - x2*x2-y2*y2
    if t2<0
        n2 = 0.0
    else
        t2 = t2 * t2
        n2 = t2 * t2 * (PNGrad3[gi2].x * x2 + PNGrad3[gi2].y * y2)
    endif  
endfunction  70.0 * (n0 + n1 + n2)


example 2 slightly easier method

+ Code Snippet
//3D Modifying a mesh height by modifying texture and re loading

// Project: coordinate 
// Created: 2018-04-06

// show all errors
SetErrorMode(2)
#constant screenWidth=1024
#constant screenHeight=768
#constant perlinw = 200
#constant perlinh = 200
#constant perlinz = 200  
#constant mapX=2048
#constant mapY=100
#constant mapZ=1024

  
SetWindowSize(screenWidth,screenHeight,0)
Setvirtualresolution(screenWidth,screenHeight)
SetScissor(0,0,0,0)
SetCameraRange( 1, 0.1, 900000 )
SetGlobal3DDepth(10000)

type _heights
	meshposition
	height
endtype
global heights as _heights[]

global TerrainImageID
  
// start perlin map data
NoiseInit()
TerrainImageID=generatePerlinImages()
mapsprite = CreateSprite(TerrainImageID)
SetSpriteSize(mapsprite,100,100)
SetSpritePosition(mapsprite,screenWidth-100,0)
HeightMapTextureMemblock = CreateMemblockFromImage(TerrainImageID)
HeightMapTextureWidthMemblock = GetMemblockInt(HeightMapTextureMemblock, 0)
HeightMapTextureHeightMemblock = GetMemblockInt(HeightMapTextureMemblock, 4)
TerrainImageID =CreateImageFromMemblock(HeightMapTextureMemblock)
  
  
//the following three lines only used if not updating on fly
//createBlankTexture(heightImage,200,200,makecolor(0,0,0))
HeightImage=loadImage("height.png")
HeightImageMemblock=CreateMemblockFromImage(HeightImage)
HeightImageWidthMemblock=GetMemblockInt(HeightImageMemblock, 0)
HeightImageHeightMemblock=GetMemblockInt(HeightImageMemblock, 4)
  
Local TerrainObjectID
  
// create the terrain object from a height map
TerrainObjectID=CreateObjectFromHeightMap( "height.png", mapX,mapY, mapZ, 0, 0 )
SetObjectCollisionMode( TerrainObjectID, 1 ) //On needed for object raycasting
SetObjectImage( TerrainObjectID, TerrainImageID, 0 )
SetObjectTransparency(TerrainObjectID,0)
//TerrainMemblock=CreateMemblockFromObjectMesh(TerrainObjectID,1)

//SetCameraRange(1,1,2000 ) 
SetCameraPosition(1, 805, 378, -41)
  
  
do
    checkCameraMovement()
      
    if GetPointerState()=1
  
        pointer_x = GetPointerX()
        pointer_y = GetPointerY()
        //pointer_y2 =screenHeight-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# + GetCameraX(1)
        start_y# = unit_y# + GetCameraY(1)
        start_z# = unit_z# - GetCameraZ(1)
  
        // 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# = 1000*unit_x# + GetCameraX(1)
        end_y# = 1000*unit_y# + GetCameraY(1)
        end_z# = 1000*unit_z# - GetCameraZ(1)
  

        // determine which object has been hit
        object_hit = ObjectRayCast(0,start_x#,start_y#,start_z#,end_x#,end_y#,end_z#)
        Print ("objhit=" + str(object_hit))
          
        if object_hit = TerrainObjectID
            xPixel# = GetObjectRayCastX(0)
 			yPixel# = GetObjectRayCastZ(0) 
            for y = -5 to 5 step 1
                for x = -5 to 5 step 1
                    writePixelMemblock(HeightImageMemblock,HeightImageWidthMemblock,HeightImageHeightMemblock,xPixel#+x,yPixel#+y,1,1,1,255)     
                next x      
            next y
			DeleteImage(HeightImage)
			HeightImage=CreateImageFromMemblock(HeightImageMemblock)
			saveImage(HeightImage,"height.png")
			DeleteObject(TerrainObjectID)
			TerrainObjectID=CreateObjectFromHeightMap( "height.png", mapX,mapY, mapZ, 0, 0 )
			SetObjectCollisionMode( TerrainObjectID, 1 )
			SetObjectImage( TerrainObjectID, TerrainImageID, 0 )
		endif
    endif
    sync()      
loop
  
  
function checkCameraMovement()
  
if GetRawKeyState(37) then MoveCameraLocalX(1,-5) //Left
if GetRawKeyState(39) then MoveCameraLocalX(1,5) //Right
if GetRawKeyState(38) then MoveCameraLocalZ(1,5) //Forward
if GetRawKeyState(40) then MoveCameraLocalZ(1,-5) //Backward
if GetRawKeyState(87) then MoveCameraLocalY(1,-5) //87 W
if GetRawKeyState(83) then MoveCameraLocalY(1,5) //87 S

if GetRawKeyPressed(27) then end

endfunction
  
  
  
function writePixelMemblock(memblockId as integer,memblockWidth,memblockHeight,x as integer,y as integer,R as integer, G as integer, B as integer, A as integer)
    if (mapX/perlinw)>1 and (mapZ/perlinz)>1
        x=x/(mapX/perlinw):y=y/(mapZ/perlinz)
    else 
        x=x/perlinw:y=y/perlinz
    endif
         
    if x<0 then exitfunction
    if y<0 then exitfunction
    R =R+ GetMemblockByte(memblockId,12+(x*4)+((memblockHeight-y)*4*memblockWidth))
    G =G+ GetMemblockByte(memblockId,13+(x*4)+((memblockHeight-y)*4*memblockWidth))
    B =B+ GetMemblockByte(memblockId,14+(x*4)+((memblockHeight-y)*4*memblockWidth))
    A =A+ GetMemblockByte(memblockId,15+(x*4)+((memblockHeight-y)*4*memblockWidth))
      
    if R>255 then R=255
    if G>255 then G=255
    if B>255 then B=255
    if A>255 then A=255
      
    SetMemblockByte(memblockId,12+(x*4)+((memblockHeight-y)*4*memblockWidth),R) // Write Red 
    SetMemblockByte(memblockId,13+(x*4)+((memblockHeight-y)*4*memblockWidth),G) // Write Green 
    SetMemblockByte(memblockId,14+(x*4)+((memblockHeight-y)*4*memblockWidth),B) // Write Blue 
    SetMemblockByte(memblockId,15+(x*4)+((memblockHeight-y)*4*memblockWidth),A) // Write Alpha full opaque (255)
      
endfunction
  
   
function generatePerlinImages()
// Generate image from memblock
  
size = perlinw * perlinh * 4 + 12
mem = CreateMemblock(size) //the colour texture image
SetMemblockInt(mem,0,perlinw)
SetMemblockInt(mem,4,perlinh)
SetMemblockInt(mem,8,32)
mem2 = CreateMemblock(size) //the black and white height image
SetMemblockInt(mem2,0,perlinw)
SetMemblockInt(mem2,4,perlinh)
SetMemblockInt(mem2,8,32)
     
offset as integer = 12
a as float, b as float
a = 5.0
b = 2.0
     
meshposition=0
for y = 0 to perlinh - 1
    for x = 0 to perlinw - 1
        a = a + 0.0001
        b = b + 0.002
             
        // Try out these two noise methods
        //noise = 255.0*Noise2D(x/10.0,y/10.0)
        noise = 255.0*Noise2D(x/255.0,y/255.0)
             
        noise = abs(noise)
		
		// add to array
		height as _heights
		height.meshposition=meshposition
		height.height = noise
		heights.insert(height)
		// end of adding to array
		
		inc meshposition
        //clouds
        if noise>255
            SetMemblockByte(mem, offset, noise)
            SetMemblockByte(mem, offset+1, noise)
            SetMemblockByte(mem, offset+2, noise)
            SetMemblockByte(mem, offset+3, 255)
        endif
            
     
         //greenary
        if noise>100 and noise<=255
            SetMemblockByte(mem, offset, 0)
            SetMemblockByte(mem, offset+1, noise)
            SetMemblockByte(mem, offset+2, 0)
            SetMemblockByte(mem, offset+3, 255)
        endif
        //sand
        if noise>50 and noise<=100  
            SetMemblockByte(mem, offset, noise)
            SetMemblockByte(mem, offset+1, noise)
            SetMemblockByte(mem, offset+2, 0)
            SetMemblockByte(mem, offset+3, 255)
        endif
        // water
        if noise<=50 
            SetMemblockByte(mem, offset, noise/2)
            SetMemblockByte(mem, offset+1, 0)
            SetMemblockByte(mem, offset+2, noise)
            SetMemblockByte(mem, offset+3, 255)
        endif
        //mem2 is the black and white image
        SetMemblockByte(mem2, offset, noise)
        SetMemblockByte(mem2, offset+1, noise)
        SetMemblockByte(mem2, offset+2, noise)
        SetMemblockByte(mem2, offset+3, 255)
        offset = offset + 4
    next
next
     
map=CreateImageFromMemblock(mem)
heightImg=CreateImageFromMemblock(mem2)
saveImage(heightImg,"height.png")
DeleteObject(mem):DeleteObject(mem2)
endfunction map
  
// ***************************************************************************************************
// Ken Perlin's Simplex Noise 2D. AGK Version.
// Ported from Stefan Gustavson's Java implementation
// (http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf)
// 2015.02.03
// AGK reference https://forum.thegamecreators.com/thread/213532
// Thank you Thank you 
    
#constant PN3DF2 = 0.5*(sqrt(3.0)-1.0)
#constant PN3DG2 = (3.0-sqrt(3.0))/6.0
    
Type sPNVECTOR
    x as float
    y as float
    z as float
endtype
    
Global PNHash as integer[512]
Global PNGrad3 as sPNVECTOR[256]
    
    
Function NoiseInit()
    Local n as integer, rn as integer
    For n=0 To 255
        PNHash[n] = n
    Next n 
    For n=0 To 255
        rn=Random(0, 255) 
        PNHash.swap(n,rn)
    Next n
    For n=0 To 255
        PNHash[256 + n] = PNHash[n]
    Next n
    PNHash[511] = PNHash[0]
    
    For n=0 To 15
        PNGrad3[n * 16 + 0].x = 1 : PNGrad3[n * 16 + 0].y = 1 : PNGrad3[n * 16 + 0].z = 0
        PNGrad3[n * 16 + 1].x = -1 : PNGrad3[n * 16 + 1].y = 1 : PNGrad3[n * 16 + 1].z = 0
        PNGrad3[n * 16 + 2].x = 1 : PNGrad3[n * 16 + 2].y = -1 : PNGrad3[n * 16 + 2].z = 0
        PNGrad3[n * 16 + 3].x = -1 : PNGrad3[n * 16 + 3].y = -1 : PNGrad3[n * 16 + 3].z = 0
    
        PNGrad3[n * 16 + 4].x = 1 : PNGrad3[n * 16 + 4].y = 0 : PNGrad3[n * 16 + 4].z = 1
        PNGrad3[n * 16 + 5].x = -1 : PNGrad3[n * 16 + 5].y = 0 : PNGrad3[n * 16 + 5].z = 1
        PNGrad3[n * 16 + 6].x = 1 : PNGrad3[n * 16 + 6].y = 0 : PNGrad3[n * 16 + 6].z = -1
        PNGrad3[n * 16 + 7].x = -1 : PNGrad3[n * 16 + 7].y = 0 : PNGrad3[n * 16 + 7].z = -1
    
        PNGrad3[n * 16 + 8].x = 0 : PNGrad3[n * 16 + 8].y = 1 : PNGrad3[n * 16 + 8].z = 1
        PNGrad3[n * 16 + 9].x = 0 : PNGrad3[n * 16 + 9].y = -1 : PNGrad3[n * 16 + 9].z = 1
        PNGrad3[n * 16 + 10].x = 0 : PNGrad3[n * 16 + 10].y = 1 : PNGrad3[n * 16 + 10].z = -1
        PNGrad3[n * 16 + 11].x = 0 : PNGrad3[n * 16 + 11].y = -1 : PNGrad3[n * 16 + 11].z = -1
    
        PNGrad3[n * 16 + 12].x = 1 : PNGrad3[n * 16 + 12].y = 1 : PNGrad3[n * 16 + 12].z = 0
        PNGrad3[n * 16 + 13].x = -1 : PNGrad3[n * 16 + 13].y = 1 : PNGrad3[n * 16 + 13].z = 0
        PNGrad3[n * 16 + 14].x = 0 : PNGrad3[n * 16 + 14].y = -1 : PNGrad3[n * 16 + 14].z = 1
        PNGrad3[n * 16 + 15].x = 0 : PNGrad3[n * 16 + 15].y = -1 : PNGrad3[n * 16 + 15].z = -1
    Next n 
endfunction
    
function Noise2D(xin as float, yin as float)
    local n0 as float, n1 as float, n2 as float, s as float, t as float, x0 as float, y0 as float, xs as float, ys as float
    local i as integer, j as integer, i1 as integer, j1 as integer, i2 as integer, j2 as integer, gi0 as integer, gi1 as integer, gi2 as integer
    local x1 as float, y1 as float, x2 as float, y2 as float, x3 as float, y3 as float, t0 as float, t1 as float, t2 as float
        
    s = (xin + yin) * PN3DF2
    xs = xin + s
    i = floor(xs)
    ys = yin + s
    j = floor(ys)
    t = (i + j) * PN3DG2
    x0 = xin - (i - t)
    y0 = yin - (j - t)
    if x0>y0
        i1=1
        j1=0
    else
        i1=0
        j1=1
    endif
    x1 = x0 - i1 + PN3DG2
    y1 = y0 - j1 + PN3DG2
    x2 = x0 - 1.0 + 2.0 * PN3DG2
    y2 = y0 - 1.0 + 2.0 * PN3DG2
    i = i && 255
    j = j && 255
    gi0 =  PNHash[i + PNHash[j]] && 15
    gi1 = PNHash[i + i1 + PNHash[j + j1]] && 15
    gi2 = PNHash[i + 1 + PNHash[j+ 1]] && 15
    t0 = 0.5 - x0*x0-y0*y0
    if t0<0
        n0 = 0.0
    else
        t0 = t0 * t0
        n0 = t0 * t0 * (PNGrad3[gi0].x * x0 + PNGrad3[gi0].y * y0)
    endif
    t1 = 0.5 - x1*x1-y1*y1
    if t1<0
        n1 = 0.0
    else
        t1 = t1 * t1
        n1 = t1 * t1 * (PNGrad3[gi1].x * x1 + PNGrad3[gi1].y * y1)
    endif
    t2 = 0.5 - x2*x2-y2*y2
    if t2<0
        n2 = 0.0
    else
        t2 = t2 * t2
        n2 = t2 * t2 * (PNGrad3[gi2].x * x2 + PNGrad3[gi2].y * y2)
    endif  
endfunction  70.0 * (n0 + n1 + n2)

function createBlankTexture(ImgId as integer,sizex as integer, sizey as integer, color)
    SetClearColor(0,0,0)
    ClearScreen()
    Render()
    drawbox(0,0,sizex-1, sizey-1, color, color,color,color, 0)
    Render()
    //img = getimage(0,0,sizex, sizey)
    getimage(ImgId,0,0,sizex, sizey)
    Swap()
    saveImage(imgId,"height.png")
 endfunction 


Ideally a shader would be fastest
Posted: 3rd Feb 2021 6:09
the way i understand there are mainly two methods that can be used
you can modify the vertex data directly as as any object created from a heightmap is a mesh
secondly as heightmaps themselves are just black and white images you can modify the image used
to create your land mesh. both of these approaches can be done with memblocks or a shader.

best of luck with it

ps i did have another vertex data approach just cant find t sorry
Posted: 15th Jul 2023 18:51
deally a shader would be fastest


Heyhey, long time no see! This works pretty well and easy, but there is just something strange about it, when I use your example in the AppGameKit the modification are pretty fast.

When I use my own code there is stuttering when the new heightmap is created. Basically the createobjectfromheightmap is pretty slow, albeit I dont seem to do anything different.