Modifying a mesh in real time with memblocks
// 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)
fubar