local love = assert( love ) local ffi = require( "ffi" ) local sideLength = 128 --VERTICES in a side local vertexCount = sideLength * sideLength local vertices = love.data.newByteData( 4 * 2 * vertexCount ) local heightMap = love.image.newImageData( "tex/terrain.jpg" ) local heightTex = love.graphics.newImage( heightMap, {linear = true} ) heightTex:setWrap( "repeat", "repeat" ) local mesh = love.graphics.newMesh( {{"VertexPosition", "float", 2 }}, vertexCount, "triangles", "static" ) --set vertices do local p = vertices:getFFIPointer() local ptr = ffi.cast( "float*", p ) local i = 0 for x = 0, sideLength-1 do for y = 0, sideLength-1 do ptr[i],ptr[i+1] = x - sideLength / 2 ,y - sideLength / 2 i=i+2 end end mesh:setVertices( vertices ) do local _ = p end end --set vertex map do local ptr = {} local n = 1 local s = sideLength for x = 1, sideLength - 1 do for y = 0, sideLength - 2 do local i = y*s+x --print( x, y, i, i+1, i+s, i+s+1 ) ptr[n],ptr[n+1],ptr[n+2] = i,i+1,i+s n=n+3 ptr[n],ptr[n+1],ptr[n+2] = i+1,s+i+1,i+s n=n+3 end end mesh:setVertexMap( ptr ) end local shader = love.graphics.newShader[[ #define fog vec4( 0.6, 0.6, 0.7, 1.0 ) #define fogHigh vec4( 1.0, 1.0, 0.9, 1.0 ) #define fogFalloff 0.03 varying vec2 uv; varying vec3 world; varying vec3 normal; varying float depth; #ifdef VERTEX uniform sampler2D height; uniform mat4 view; uniform mat4 proj; float sigmoid( float x ){ return 1.0 / ( 1.0 + exp( -x ) ); } vec4 position( mat4 _, vec4 pos ){ pos = pos.xzyw; float y = Texel( height, pos.xz / 256.0 ).r - 0.5; uv = 0.25 * (pos.xz + vec2(y, sin( y ) )); float r = dot( pos.xz, pos.xz ); pos.y = sigmoid( r / 50.0 - 20.0 ) * ( 1.0 + y ) * 0.05 * r / (sqrt( r ) + 1) - 0.01; world = pos.xyz; vec4 eye = view*pos; depth = clamp( -eye.z * fogFalloff, 0.0, 1.0 ); normal = vec3( 0.0, 1.0, 0.0 ) + 1.5 * pos.y ; return proj*eye; } #endif #ifdef PIXEL uniform vec3 light; vec4 effect( vec4 color, Image tex, vec2 texuv, vec2 scruv) { vec3 albedo = 0.2 * Texel( tex, uv ).rgb; //diffuse light vec3 norm = normalize( normal ); vec3 toLight = normalize( light - world.xyz ); float diff = max( dot( norm, light ), 0.1 ); vec4 d = vec4( diff * albedo, 1.0 ); return mix( color * d , fog, depth ); } #endif ]] --set texture do local tex = love.graphics.newImage( "tex/rock.png", {mipmaps = true} ) tex:setWrap( "repeat", "repeat" ) mesh:setTexture( tex ) end shader:send( "height", heightTex ) local obj = {} local function worldSpaceToTexCoord( x, z ) return x, z end function obj.getHeight( x, z ) return heightMap:getPixel( worldSpaceToTexCoord(x,z) )[1] end function obj.draw( view, proj, light ) shader:send( "view", "column", view ) shader:send( "proj", "column", proj ) shader:send( "light", light ) love.graphics.setShader( shader ) love.graphics.draw( mesh ) end return obj