├── oh eye tee ├── README.md ├── dude.png ├── lut.png ├── bubble.png ├── shader.glsl ├── conf.lua └── main.lua ├── voxter ├── C1W.png ├── D1.png ├── vt.glsl ├── main.lua └── conf.lua ├── dungeon ├── ceil.png ├── floor.png ├── wall.png ├── cell.lua ├── R3helper.lua ├── conf.lua └── main.lua ├── painter's worst nightmare ├── README.md ├── lut.png ├── shader.glsl ├── main.lua └── conf.lua ├── deferred ├── house.png ├── n_house.png ├── player.png ├── n_player.png ├── geometry_pass.glsl ├── lighting_pass.glsl └── main.lua ├── filmgrain ├── arch.jpg ├── glass.jpg ├── stairs.jpg ├── grain.glsl ├── main.lua └── conf.lua ├── palette ├── p_dark.png ├── p_light.png ├── sprite.png ├── shader.glsl └── main.lua ├── big squares ├── screen.png ├── main.lua └── conf.lua ├── subpixel art ├── derp.png ├── main.lua └── conf.lua ├── where is zalgo ├── dude.png ├── shader.glsl ├── main.lua └── conf.lua ├── enlarge your pixel ├── screen.png ├── main.lua └── conf.lua ├── r3helper examples ├── textures │ ├── brick.png │ ├── main.lua │ ├── ciwb.lua │ ├── R3helper.lua │ └── conf.lua ├── instancing │ ├── icube.glsl │ ├── ciwb.lua │ ├── main.lua │ ├── R3helper.lua │ └── conf.lua ├── depth_peeling │ ├── icube.glsl │ ├── ciwb.lua │ ├── R3helper.lua │ ├── main.lua │ └── conf.lua ├── camera │ ├── ciwb.lua │ ├── R3helper.lua │ ├── main.lua │ └── conf.lua ├── shadows │ ├── ciwb.lua │ ├── scene.lua │ ├── sm.glsl │ ├── main.lua │ ├── R3helper.lua │ └── conf.lua └── spinning_cube │ ├── ciwb.lua │ ├── main.lua │ ├── R3helper.lua │ └── conf.lua ├── shady grass ├── vs.glsl ├── vbs.glsl ├── gs.glsl └── main.lua ├── glowybits ├── shader.glsl ├── main.lua └── conf.lua ├── blood sample ├── main.lua ├── shader.glsl └── conf.lua ├── codenames ├── main.lua ├── words.lua ├── conf.lua ├── field.lua └── menu.lua ├── bit umbra ├── shadow_map.glsl ├── light_shader.glsl ├── lights.lua └── conf.lua ├── move along ├── main.lua ├── catmull_rom.lua └── conf.lua ├── pong ├── main.lua └── conf.lua ├── README.md ├── ad astra ├── conf.lua └── main.lua ├── voronoi ├── conf.lua └── main.lua ├── boolit heck └── conf.lua └── ponger └── conf.lua /oh eye tee/README.md: -------------------------------------------------------------------------------- 1 | # requires gl4 feature level 2 | # will only run in LOVE 12 3 | -------------------------------------------------------------------------------- /voxter/C1W.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/voxter/C1W.png -------------------------------------------------------------------------------- /voxter/D1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/voxter/D1.png -------------------------------------------------------------------------------- /dungeon/ceil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/dungeon/ceil.png -------------------------------------------------------------------------------- /dungeon/floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/dungeon/floor.png -------------------------------------------------------------------------------- /dungeon/wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/dungeon/wall.png -------------------------------------------------------------------------------- /painter's worst nightmare/README.md: -------------------------------------------------------------------------------- 1 | # requires gl4 feature level 2 | # will only run in LOVE 12 3 | -------------------------------------------------------------------------------- /deferred/house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/deferred/house.png -------------------------------------------------------------------------------- /deferred/n_house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/deferred/n_house.png -------------------------------------------------------------------------------- /deferred/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/deferred/player.png -------------------------------------------------------------------------------- /filmgrain/arch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/filmgrain/arch.jpg -------------------------------------------------------------------------------- /filmgrain/glass.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/filmgrain/glass.jpg -------------------------------------------------------------------------------- /filmgrain/stairs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/filmgrain/stairs.jpg -------------------------------------------------------------------------------- /oh eye tee/dude.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/oh eye tee/dude.png -------------------------------------------------------------------------------- /oh eye tee/lut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/oh eye tee/lut.png -------------------------------------------------------------------------------- /palette/p_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/palette/p_dark.png -------------------------------------------------------------------------------- /palette/p_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/palette/p_light.png -------------------------------------------------------------------------------- /palette/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/palette/sprite.png -------------------------------------------------------------------------------- /big squares/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/big squares/screen.png -------------------------------------------------------------------------------- /deferred/n_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/deferred/n_player.png -------------------------------------------------------------------------------- /oh eye tee/bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/oh eye tee/bubble.png -------------------------------------------------------------------------------- /subpixel art/derp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/subpixel art/derp.png -------------------------------------------------------------------------------- /where is zalgo/dude.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/where is zalgo/dude.png -------------------------------------------------------------------------------- /enlarge your pixel/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/enlarge your pixel/screen.png -------------------------------------------------------------------------------- /painter's worst nightmare/lut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/painter's worst nightmare/lut.png -------------------------------------------------------------------------------- /r3helper examples/textures/brick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a13X-B/lovely-little-experiments/HEAD/r3helper examples/textures/brick.png -------------------------------------------------------------------------------- /shady grass/vs.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | uniform vec2 vel; 3 | 4 | vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords ){ 5 | return vec4(vel,0.,1.); 6 | } -------------------------------------------------------------------------------- /r3helper examples/instancing/icube.glsl: -------------------------------------------------------------------------------- 1 | #ifdef VERTEX 2 | attribute vec3 pos; 3 | 4 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 5 | vertex_position.xyz += pos; 6 | return transform_projection * vertex_position; 7 | } 8 | #endif 9 | -------------------------------------------------------------------------------- /palette/shader.glsl: -------------------------------------------------------------------------------- 1 | uniform sampler2D pal; 2 | 3 | vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords){ 4 | vec4 c = Texel(tex, texture_coords); 5 | if(c.x == c.y && c.x == c.z){ 6 | float id = c.x * 255. / 32.; 7 | c = Texel(pal, vec2(id, 0.)); 8 | } 9 | return c * color; 10 | } -------------------------------------------------------------------------------- /glowybits/shader.glsl: -------------------------------------------------------------------------------- 1 | uniform float scale; 2 | 3 | vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords ){ 4 | float c = Texel(tex, texture_coords).r; 5 | vec2 sc = floor(screen_coords*scale); 6 | 7 | c = (mod(sc.x+sc.y, 2.) + float(c > .45)) * float(c > 0.); 8 | return vec4(clamp(c, 0., 1.), 0., 0., 1.) * color; 9 | } 10 | -------------------------------------------------------------------------------- /blood sample/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local quad = g.newCanvas(1,1) 4 | 5 | local shader = g.newShader("shader.glsl") 6 | local w,h = g.getDimensions() 7 | local t = love.timer.getTime 8 | 9 | function love.draw() 10 | g.setShader(shader) 11 | shader:send("iTime", t()) 12 | g.draw(quad, 0,0, 0, w,h) 13 | end 14 | 15 | function love.keypressed(k,s,r) 16 | if k == "escape" then love.event.quit(0) end 17 | end 18 | -------------------------------------------------------------------------------- /shady grass/vbs.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | //uniform float dt; 3 | 4 | vec4 effect( vec4 color, Image tex, vec2 uv, vec2 screen_coords ){ 5 | vec2 uvo = fwidth(uv); 6 | vec4 c = vec4(.0); 7 | for(int y = -1; y < 2; y ++) 8 | for(int x = -1; x < 2; x ++){ 9 | vec2 p = vec2(x,y); 10 | float q = .25; 11 | if(x!=0) q*=.5; 12 | if(y!=0) q*=.5; 13 | c += texture(tex,uv+uvo*vec2(x,y))*q; 14 | } 15 | c*=.991; 16 | 17 | return c * color; 18 | } -------------------------------------------------------------------------------- /deferred/geometry_pass.glsl: -------------------------------------------------------------------------------- 1 | varying vec4 world_pos; 2 | 3 | #ifdef VERTEX 4 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 5 | world_pos = TransformMatrix * vertex_position; 6 | return transform_projection * vertex_position; 7 | } 8 | #endif 9 | 10 | #ifdef PIXEL 11 | uniform ArrayImage MainTex; 12 | void effect(){ 13 | vec4 n = Texel(MainTex, vec3(VaryingTexCoord.xy, 1.)); 14 | vec4 c = Texel(MainTex, vec3(VaryingTexCoord.xy, 0.)); 15 | if(c.a == 0.) discard; 16 | love_Canvases[0] = c; 17 | love_Canvases[1] = n; 18 | } 19 | #endif -------------------------------------------------------------------------------- /r3helper examples/depth_peeling/icube.glsl: -------------------------------------------------------------------------------- 1 | #ifdef VERTEX 2 | attribute vec3 pos; 3 | 4 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 5 | vertex_position.xyz += pos; 6 | return transform_projection * vertex_position; 7 | } 8 | #endif 9 | 10 | #ifdef PIXEL 11 | uniform sampler2D d; 12 | 13 | vec4 effect( vec4 color, Image tex, vec2 uv, vec2 sc){ 14 | float depth = Texel(d, sc/love_ScreenSize.xy).x; 15 | if(depth >= gl_FragCoord.z) discard; 16 | vec4 texcolor = Texel(tex, uv); 17 | return texcolor * color; 18 | } 19 | #endif 20 | 21 | -------------------------------------------------------------------------------- /where is zalgo/shader.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | #ifdef VERTEX 3 | uniform float depth_scale; 4 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 5 | int v_id = gl_VertexID%2; 6 | vertex_position.z = (vertex_position.y-32.*float(v_id))/depth_scale; 7 | return transform_projection * vertex_position; 8 | } 9 | #endif 10 | #ifdef PIXEL 11 | vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords){ 12 | vec4 texturecolor = Texel(tex, texture_coords); 13 | if (texturecolor.a < 1.) discard; 14 | return texturecolor * color; 15 | } 16 | #endif -------------------------------------------------------------------------------- /filmgrain/grain.glsl: -------------------------------------------------------------------------------- 1 | uniform Image noise_texture; 2 | uniform vec2 random_offset; 3 | 4 | vec4 effect( vec4 color, Image tex, vec2 uv, vec2 sc ){ 5 | vec4 c = Texel(tex, uv); 6 | // noise sampling coordinates, scale down for bigger grains 7 | // 128 in this case is the size of a noise texture 8 | vec2 nuv = sc/128.*.5 + random_offset; 9 | vec3 n = Texel(noise_texture, nuv).xyz; 10 | float l = dot(c.xyz, vec3(.2, .7, .1)); //luma to attenuate the noise 11 | 12 | // mix has highest and lowest possible noise intensity 13 | // third parameter is a curve, can be linear with just l 14 | return vec4(c.xyz + n*mix(.08, .02, sqrt(l)), 1.); 15 | } 16 | -------------------------------------------------------------------------------- /r3helper examples/camera/ciwb.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local vcf = {{"VertexPosition", "float", 3}} 4 | local vtf = {{"VertexColor", "float", 3}} 5 | local vc = { 6 | {-1,-1,-1}, {1,-1,-1}, {-1,-1,1}, {1,-1,1}, 7 | {-1,1,-1}, {1,1,-1}, {-1,1,1}, {1,1,1} 8 | } 9 | local vt = { 10 | {0,0,0}, {1,0,0}, {0,0,1}, {1,0,1}, 11 | {0,1,0}, {1,1,0}, {0,1,1}, {1,1,1} 12 | } 13 | 14 | local vm = { 15 | 1,3,2, 2,3,4, 16 | 5,6,7, 6,8,7, 17 | 3,7,8, 3,8,4, 18 | 1,6,5, 1,2,6, 19 | 3,5,7, 1,5,3, 20 | 4,8,6, 2,4,6, 21 | } 22 | 23 | local cube = g.newMesh(vcf, vc, "triangles", "static") 24 | local tex = g.newMesh(vtf, vt, "triangles", "static") 25 | cube:setVertexMap(vm) 26 | 27 | cube:attachAttribute("VertexColor", tex) 28 | 29 | return cube -------------------------------------------------------------------------------- /r3helper examples/shadows/ciwb.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local vcf = {{"VertexPosition", "float", 3}} 4 | local vtf = {{"VertexColor", "float", 3}} 5 | local vc = { 6 | {-1,-1,-1}, {1,-1,-1}, {-1,-1,1}, {1,-1,1}, 7 | {-1,1,-1}, {1,1,-1}, {-1,1,1}, {1,1,1} 8 | } 9 | local vt = { 10 | {0,0,0}, {1,0,0}, {0,0,1}, {1,0,1}, 11 | {0,1,0}, {1,1,0}, {0,1,1}, {1,1,1} 12 | } 13 | 14 | local vm = { 15 | 1,3,2, 2,3,4, 16 | 5,6,7, 6,8,7, 17 | 3,7,8, 3,8,4, 18 | 1,6,5, 1,2,6, 19 | 3,5,7, 1,5,3, 20 | 4,8,6, 2,4,6, 21 | } 22 | 23 | local cube = g.newMesh(vcf, vc, "triangles", "static") 24 | local tex = g.newMesh(vtf, vt, "triangles", "static") 25 | cube:setVertexMap(vm) 26 | 27 | cube:attachAttribute("VertexColor", tex) 28 | 29 | return cube -------------------------------------------------------------------------------- /r3helper examples/depth_peeling/ciwb.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local vcf = {{"VertexPosition", "float", 3}} 4 | local vtf = {{"VertexColor", "float", 3}} 5 | local vc = { 6 | {-1,-1,-1}, {1,-1,-1}, {-1,-1,1}, {1,-1,1}, 7 | {-1,1,-1}, {1,1,-1}, {-1,1,1}, {1,1,1} 8 | } 9 | local vt = { 10 | {0,0,0}, {1,0,0}, {0,0,1}, {1,0,1}, 11 | {0,1,0}, {1,1,0}, {0,1,1}, {1,1,1} 12 | } 13 | 14 | local vm = { 15 | 1,3,2, 2,3,4, 16 | 5,6,7, 6,8,7, 17 | 3,7,8, 3,8,4, 18 | 1,6,5, 1,2,6, 19 | 3,5,7, 1,5,3, 20 | 4,8,6, 2,4,6, 21 | } 22 | 23 | local cube = g.newMesh(vcf, vc, "triangles", "static") 24 | local tex = g.newMesh(vtf, vt, "triangles", "static") 25 | cube:setVertexMap(vm) 26 | 27 | cube:attachAttribute("VertexColor", tex) 28 | 29 | return cube -------------------------------------------------------------------------------- /r3helper examples/instancing/ciwb.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local vcf = {{"VertexPosition", "float", 3}} 4 | local vtf = {{"VertexColor", "float", 3}} 5 | local vc = { 6 | {-1,-1,-1}, {1,-1,-1}, {-1,-1,1}, {1,-1,1}, 7 | {-1,1,-1}, {1,1,-1}, {-1,1,1}, {1,1,1} 8 | } 9 | local vt = { 10 | {0,0,0}, {1,0,0}, {0,0,1}, {1,0,1}, 11 | {0,1,0}, {1,1,0}, {0,1,1}, {1,1,1} 12 | } 13 | 14 | local vm = { 15 | 1,3,2, 2,3,4, 16 | 5,6,7, 6,8,7, 17 | 3,7,8, 3,8,4, 18 | 1,6,5, 1,2,6, 19 | 3,5,7, 1,5,3, 20 | 4,8,6, 2,4,6, 21 | } 22 | 23 | local cube = g.newMesh(vcf, vc, "triangles", "static") 24 | local tex = g.newMesh(vtf, vt, "triangles", "static") 25 | cube:setVertexMap(vm) 26 | 27 | cube:attachAttribute("VertexColor", tex) 28 | 29 | return cube -------------------------------------------------------------------------------- /r3helper examples/spinning_cube/ciwb.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local vcf = {{"VertexPosition", "float", 3}} 4 | local vtf = {{"VertexColor", "float", 3}} 5 | local vc = { 6 | {-1,-1,-1}, {1,-1,-1}, {-1,-1,1}, {1,-1,1}, 7 | {-1,1,-1}, {1,1,-1}, {-1,1,1}, {1,1,1} 8 | } 9 | local vt = { 10 | {0,0,0}, {1,0,0}, {0,0,1}, {1,0,1}, 11 | {0,1,0}, {1,1,0}, {0,1,1}, {1,1,1} 12 | } 13 | 14 | local vm = { 15 | 1,3,2, 2,3,4, 16 | 5,6,7, 6,8,7, 17 | 3,7,8, 3,8,4, 18 | 1,6,5, 1,2,6, 19 | 3,5,7, 1,5,3, 20 | 4,8,6, 2,4,6, 21 | } 22 | 23 | local cube = g.newMesh(vcf, vc, "triangles", "static") 24 | local tex = g.newMesh(vtf, vt, "triangles", "static") 25 | cube:setVertexMap(vm) 26 | 27 | cube:attachAttribute("VertexColor", tex) 28 | 29 | return cube -------------------------------------------------------------------------------- /codenames/main.lua: -------------------------------------------------------------------------------- 1 | --read the rules 2 | --research possibility of copying a picture 3 | --pictures 4 | --consider bg change instead of markers 5 | 6 | local field = require("field") 7 | local menu = require("menu") 8 | 9 | local game = false 10 | 11 | function love.mousepressed(x, y, b, t) 12 | if menu.start() then 13 | field.click(x, y) 14 | else 15 | menu.click(x,y) 16 | game = menu.start() 17 | end 18 | end 19 | 20 | function love.update(dt) 21 | if game then 22 | game = false 23 | field.new_field(menu.options()) 24 | end 25 | love.timer.sleep(0.0333) 26 | end 27 | 28 | function love.draw() 29 | if menu.start() then 30 | field.draw() 31 | else 32 | menu.draw() 33 | end 34 | end 35 | 36 | function love.keypressed(k,s,r) 37 | if k == "escape" then love.event.quit(0) end 38 | if k == "space" then menu.reset() end 39 | end -------------------------------------------------------------------------------- /r3helper examples/shadows/scene.lua: -------------------------------------------------------------------------------- 1 | local scene = {} 2 | local R3 = require("R3helper") 3 | local cube = require("ciwb") 4 | 5 | local g = love.graphics 6 | 7 | local rng = love.math.newRandomGenerator() 8 | function scene.draw() 9 | g.push() 10 | g.applyTransform( 11 | R3.translate(0,-2,0)* --move the ground 12 | R3.scale(10,1,10) --scale the ground 13 | ) 14 | g.draw(cube) --draw the ground 15 | g.pop() 16 | 17 | rng:setSeed(31337) 18 | for i=1,33 do 19 | g.push() 20 | g.applyTransform( 21 | R3.translate(-8+16*rng:random(),-rng:random(),-8+16*rng:random()) * --move a cube 22 | R3.rotate(R3.aa_to_quat(0,1,0,rng:random()*math.pi*2)) * --rotate the cube 23 | R3.scale(.3+rng:random()*.3,1,.3+rng:random()*.5) --scale the cube 24 | ) 25 | g.draw(cube) --draw the cube 26 | g.pop() 27 | end 28 | end 29 | 30 | return scene -------------------------------------------------------------------------------- /bit umbra/shadow_map.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | 3 | flat varying int light_id; 4 | 5 | #ifdef VERTEX 6 | // perinstance attributes 7 | attribute vec4 lpos; 8 | 9 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 10 | light_id = gl_InstanceID; 11 | if (vertex_position.z > 0.) { 12 | vertex_position.xy += normalize(vertex_position.xy-lpos.xy)*99999999999.; 13 | } 14 | vertex_position.z = float(gl_InstanceID)/100.; 15 | return transform_projection * vertex_position; 16 | } 17 | #endif 18 | 19 | #ifdef PIXEL 20 | void effect(){ 21 | vec2 shadow_id[2]; 22 | shadow_id[0] = vec2(0.); 23 | shadow_id[1] = vec2(0.); 24 | int light_bit = light_id; 25 | shadow_id[light_id/32][(light_id/16)&1] = float(1<<(light_id%16)) / 65535.; 26 | 27 | love_Canvases[0] = vec4(shadow_id[0], 0., 1.); 28 | love_Canvases[1] = vec4(shadow_id[1], 0., 1.); 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /r3helper examples/spinning_cube/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local R3 = require("R3helper") 3 | 4 | g.setMeshCullMode("back") 5 | g.setFrontFaceWinding("ccw") 6 | g.setDepthMode("less", true) 7 | 8 | local cube = require("ciwb") 9 | 10 | local origin = R3.new_origin(true, g.getDimensions()) 11 | 12 | function love.draw() 13 | local t = love.timer.getTime() 14 | g.setDepthMode("less", true) 15 | g.replaceTransform( 16 | origin * 17 | R3.translate(0,0,2.5) * --step away a little bit 18 | R3.rotate(R3.aa_to_quat(math.cos(t), math.sin(t), 0, t%(math.pi*2))) --rotate the cube 19 | ) 20 | 21 | g.draw(cube) 22 | g.origin() 23 | g.setDepthMode("always", false) 24 | g.print(love.timer.getDelta()) 25 | g.print(g.getStats().drawcalls, 0, 20) 26 | g.print(love.timer.getFPS(), 0, 40) 27 | end 28 | 29 | function love.keypressed(k,s,r) 30 | if k == "escape" then love.event.quit(0) end 31 | end 32 | -------------------------------------------------------------------------------- /r3helper examples/textures/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local R3 = require("R3helper") 3 | 4 | g.setMeshCullMode("back") 5 | g.setFrontFaceWinding("ccw") 6 | 7 | local texture = g.newImage("brick.png", {mipmaps=true}) 8 | local cube = require("ciwb") 9 | cube:setTexture(texture) 10 | 11 | local origin = R3.new_origin(true, g.getDimensions()) 12 | 13 | function love.draw() 14 | local t = love.timer.getTime() 15 | g.setDepthMode("less", true) 16 | g.replaceTransform( 17 | origin * 18 | R3.translate(0,0,2.5) * --step away a little bit 19 | R3.rotate(R3.aa_to_quat(math.cos(t), math.sin(t), 0, t%(math.pi*2))) --rotate the cube 20 | ) 21 | 22 | g.draw(cube) 23 | g.origin() 24 | g.setDepthMode("always", false) 25 | g.print(love.timer.getDelta()) 26 | g.print(g.getStats().drawcalls, 0, 20) 27 | g.print(love.timer.getFPS(), 0, 40) 28 | end 29 | 30 | function love.keypressed(k,s,r) 31 | if k == "escape" then love.event.quit(0) end 32 | end 33 | -------------------------------------------------------------------------------- /big squares/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local w, h = g.getDimensions() 3 | 4 | local screen = g.newImage("screen.png") 5 | screen:setFilter("nearest") 6 | local sw, sh = screen:getDimensions() 7 | local smesh = g.newMesh(sw*sh*6, "triangles", "static") 8 | for y = 0, sh-1 do 9 | for x = 0, sw-1 do 10 | local i = (sw*y+x)*6 11 | local hpu,hpv = .5/sw, .5/sh 12 | local u,v = x/(sw-1), y/(sh-1) 13 | smesh:setVertex(i+1, x, y, u,v) 14 | smesh:setVertex(i+2, x, y+1, u,v) 15 | smesh:setVertex(i+3, x+1, y, u,v) 16 | smesh:setVertex(i+4, x, y+1, u,v) 17 | smesh:setVertex(i+5, x+1, y+1, u,v) 18 | smesh:setVertex(i+6, x+1, y, u,v) 19 | end 20 | end 21 | smesh:setTexture(screen) 22 | 23 | local s = math.min(w/sw, h/sh) 24 | 25 | function love.draw() 26 | g.scale(s) 27 | g.draw(smesh) 28 | g.origin() 29 | g.print(love.timer.getFPS()) 30 | end 31 | 32 | function love.keypressed(k,s,r) 33 | if k == "escape" then love.event.quit(0) end 34 | end 35 | -------------------------------------------------------------------------------- /voxter/vt.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | uniform vec3 pos; 3 | uniform vec2 dir; 4 | uniform sampler2D dm; 5 | 6 | varying vec2 uv; 7 | 8 | #ifdef VERTEX 9 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 10 | int instance = gl_VertexID/4; 11 | int top = gl_VertexID%2; 12 | int v_id = gl_VertexID%4; 13 | 14 | float col = float(instance%400); 15 | float row = float(instance/400); 16 | 17 | uv = vec2(.5) + (pos.xy + vec2(-dir.y,dir.x)*((col-200.)/400.)*(1.+row) + dir*row) / 1024.; 18 | 19 | float d = textureLod(dm, uv, 0.).x; 20 | 21 | float x = col*2. + float(v_id/2)*2.; 22 | float y = (pos.z-d*255.)*400./(1.+row)+300. + float(top)*250.; 23 | float z = -row/1024.; 24 | 25 | vertex_position = vec4(x,y,z,1.); 26 | return transform_projection * vertex_position; 27 | } 28 | #endif 29 | 30 | #ifdef PIXEL 31 | vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords ){ 32 | color = vec4(1.); 33 | vec4 texcolor = textureLod(tex, uv, 0.); 34 | return texcolor * color; 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /bit umbra/light_shader.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | 3 | varying vec3 w_p; // world position 4 | varying float scale; // lightsource size 5 | varying vec3 diff; // diffuse color 6 | flat varying int light_id; 7 | 8 | #ifdef VERTEX 9 | // perinstance attributes 10 | attribute vec4 lpos; 11 | attribute vec3 diffuse; 12 | 13 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 14 | // pass all the stuff to pixel shader 15 | scale = lpos.w; 16 | diff = diffuse; 17 | w_p = lpos.xyz; 18 | light_id = gl_InstanceID; 19 | 20 | // transform light vertex for rendering 21 | return transform_projection * (vec4(vertex_position.xyz*lpos.w, vertex_position.w) + vec4(lpos.xy, 0., 0.)); 22 | } 23 | #endif 24 | 25 | #ifdef PIXEL 26 | uniform ArrayImage shadowmap; 27 | 28 | vec4 effect(vec4 col, Image tex, vec2 uv, vec2 sc){ 29 | vec2 shadow = Texel(shadowmap, vec3(sc/love_ScreenSize.xy,float(light_id/32))).xy; 30 | if((int(shadow[(light_id/16)&1]*65535.) & (1<<(light_id%16))) != 0) discard; 31 | vec3 c = diff * (1.-clamp(dot(sc - w_p.xy, sc - w_p.xy)/(scale*scale),0.,1.)); 32 | return vec4(c, 1.); 33 | } 34 | #endif -------------------------------------------------------------------------------- /painter's worst nightmare/shader.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl4 2 | #extension GL_ARB_sample_shading : enable 3 | #ifdef VERTEX 4 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 5 | int v_id = 1-((gl_VertexID%4)/2); // make things overlap procedurally 6 | vertex_position.z = float(v_id); 7 | return transform_projection * vertex_position; 8 | } 9 | #endif 10 | #ifdef PIXEL 11 | float hash( vec2 v ) { 12 | return fract( 1.0e4 * sin( 17.0*v.x + 0.1*v.y ) * ( 0.1 + abs( sin( 13.0*v.y + v.x )))); 13 | } 14 | 15 | uniform sampler2D lut; 16 | uniform float alpha_offset; 17 | vec4 effect (vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { 18 | vec4 col = Texel(tex, texture_coords)*color; 19 | float alpha = col.a; 20 | alpha += .1*(hash(gl_FragCoord.xy)-.5); // this could be better for lower alpha values 21 | 22 | // here we add that random alpha offset to get a different bitmask each time 23 | vec2 mask_sample=vec2(hash(vec2(gl_FragCoord.z, alpha_offset)),alpha); 24 | int mask = int(255.*Texel(lut, mask_sample).r); 25 | 26 | gl_SampleMask[0] = mask; 27 | return vec4(col.xyz, 1.); 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /oh eye tee/shader.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl4 2 | #extension GL_ARB_sample_shading : enable 3 | #ifdef VERTEX 4 | uniform float depth_scale; 5 | uniform float depth_offset; 6 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 7 | int v_id = 1-(gl_VertexID%2); 8 | vertex_position.z = (vertex_position.y+depth_offset*float(v_id))/depth_scale; 9 | return transform_projection * vertex_position; 10 | } 11 | #endif 12 | #ifdef PIXEL 13 | float hash( vec2 v ) { 14 | return fract( 1.0e4 * sin( 17.0*v.x + 0.1*v.y ) * ( 0.1 + abs( sin( 13.0*v.y + v.x )))); 15 | } 16 | 17 | uniform sampler2D lut; 18 | uniform float mask_offset; 19 | vec4 effect (vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { 20 | vec4 col = Texel(tex, texture_coords)*color; 21 | float alpha = col.a; 22 | alpha += .1*(hash(gl_FragCoord.xy+vec2(mask_offset, 0.)) -.5); 23 | if (alpha < 1./9.) discard; 24 | 25 | alpha -= 1./9.; 26 | alpha /=.7/.9; 27 | 28 | int mask = int(255.*Texel(lut, vec2(hash(vec2(mask_offset,gl_FragCoord.z)), alpha)).r); 29 | if (alpha > 1.) 30 | mask = 0xff; 31 | gl_SampleMask[0] = mask; 32 | return vec4(col.xyz, 1.); 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /r3helper examples/shadows/sm.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | varying vec4 worldpos; 3 | 4 | #ifdef VERTEX 5 | uniform mat4 proj; 6 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 7 | // save world position for shadow sampling later 8 | worldpos = TransformMatrix * vertex_position; 9 | return proj * worldpos; 10 | } 11 | #endif 12 | 13 | #ifdef PIXEL 14 | uniform mat4 shadow_view; 15 | uniform sampler2DShadow sm; 16 | 17 | vec4 effect( vec4 color, Image tex, vec2 uv, vec2 sc){ 18 | // surface normal 19 | vec3 n = -normalize(cross(dFdx(worldpos.xyz), dFdy(worldpos.xyz))); 20 | // surface normal in lightview 21 | vec3 ln = normalize((shadow_view * vec4(n, 1.)).xyz); 22 | // shadow sample point 23 | vec3 ssp = (shadow_view * worldpos).xyz*vec3(.5); 24 | ssp.y*=-1.; 25 | ssp += vec3(.5); 26 | 27 | vec2 step = vec2(1.)/textureSize(sm, 0); 28 | 29 | float db = dot(vec3(.0,.0,-1.), ln); 30 | // sample shadow 31 | float s = texture(sm, ssp+vec3(step*-1.7*ln.xy,-ln.z*.001)); 32 | // also shade anything not facing light to hide most of the artefacts 33 | s = min(s, float(db>.0)); 34 | // color is simply world coordinate + light 35 | return vec4(vec3(s)*.9 + worldpos.xyz*.1, 1.); 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /r3helper examples/textures/ciwb.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local vpf = {{"VertexPosition", "float", 3}} 4 | local vtf = {{"VertexTexCoord", "float", 2}} 5 | 6 | local vp = { 7 | {-1,-1,-1}, {-1,-1,1}, {1,-1,-1}, {1,-1,-1}, {-1,-1,1}, {1,-1,1}, 8 | {-1,1,-1}, {1,1,-1}, {-1,1,1}, {1,1,-1}, {1,1,1}, {-1,1,1}, 9 | {-1,-1,1}, {-1,1,1}, {1,1,1}, {-1,-1,1}, {1,1,1}, {1,-1,1}, 10 | {-1,-1,-1}, {1,1,-1}, {-1,1,-1}, {-1,-1,-1}, {1,-1,-1}, {1,1,-1}, 11 | {-1,-1,1}, {-1,1,-1}, {-1,1,1}, {-1,-1,-1}, {-1,1,-1}, {-1,-1,1}, 12 | {1,-1,1}, {1,1,1}, {1,1,-1}, {1,-1,-1}, {1,-1,1}, {1,1,-1}, 13 | } 14 | 15 | local vt = { 16 | {0,0}, {0,1}, {1,0}, {1,0}, {0,1}, {1,1}, 17 | {1,0}, {0,0}, {1,1}, {0,0}, {0,1}, {1,1}, 18 | {0,0}, {0,1}, {1,1}, {0,0}, {1,1}, {1,0}, 19 | {0,0}, {1,1}, {0,1}, {0,0}, {1,0}, {1,1}, 20 | {1,1}, {0,0}, {0,1}, {1,0}, {0,0}, {1,1}, 21 | {0,1}, {1,1}, {1,0}, {0,0}, {0,1}, {1,0}, 22 | } 23 | 24 | local vm = { 25 | 1,3,2, 2,3,4, 26 | 5,6,7, 6,8,7, 27 | 3,7,8, 3,8,4, 28 | 1,6,5, 1,2,6, 29 | 3,5,7, 1,5,3, 30 | 4,8,6, 2,4,6, 31 | } 32 | 33 | local cube = g.newMesh(vpf, vp, "triangles", "static") 34 | local tex = g.newMesh(vtf, vt, "triangles", "static") 35 | 36 | cube:attachAttribute("VertexTexCoord", tex) 37 | 38 | return cube -------------------------------------------------------------------------------- /palette/main.lua: -------------------------------------------------------------------------------- 1 | local sprite = love.graphics.newImage("sprite.png") 2 | sprite:setFilter("nearest") 3 | 4 | local pl = love.graphics.newImage("p_light.png") 5 | pl:setFilter("nearest") 6 | 7 | local pd = love.graphics.newImage("p_dark.png") 8 | pd:setFilter("nearest") 9 | 10 | local masterpalette = love.graphics.newCanvas(32,1) 11 | masterpalette:setFilter("nearest") 12 | 13 | local shader = love.graphics.newShader("shader.glsl") 14 | 15 | function love.draw() 16 | love.graphics.setCanvas(masterpalette) 17 | 18 | local offset = 0 19 | --offset = math.fmod(love.timer.getTime(),1)*20 --seizure warning 20 | 21 | love.graphics.draw(pl,offset,0) 22 | love.graphics.draw(pl,offset-20,0) 23 | 24 | --love.graphics.setColor(math.abs(math.sin(love.timer.getTime()*2)), 0.7, 0.7, 1) --hair color change by rendering a rectangle to a palette 25 | --love.graphics.rectangle("fill", 2,0,1,1) 26 | 27 | love.graphics.setColor(1,1,1,1) 28 | love.graphics.setCanvas() 29 | 30 | love.graphics.scale(10,10) 31 | love.graphics.setShader(shader) 32 | shader:send("pal", masterpalette) 33 | 34 | love.graphics.draw(sprite,0,0) 35 | love.graphics.setShader() 36 | love.graphics.draw(masterpalette, 0, 0) 37 | end 38 | 39 | function love.keypressed(k,s,r) 40 | if s == "escape" then love.event.quit(0) end 41 | end 42 | -------------------------------------------------------------------------------- /bit umbra/lights.lua: -------------------------------------------------------------------------------- 1 | local max_lights = 64 2 | local current_lights = 64 3 | 4 | --math.randomseed() 5 | local random = math.random 6 | 7 | local lvfp = {{"lpos", "float", 4}} -- pos.xyz, scale 8 | local lvfd = {{"diffuse", "float", 3}} -- color 9 | local r = {math.cos(math.pi/32), math.sin(math.pi/32)} 10 | 11 | local v = {{0,0, 0,0, 0,0,0,1}, {0,1, 0,0, 1,1,1,1}} 12 | for i = 1, 64 do 13 | local t = v[#v] 14 | v[#v+1] = {t[1]*r[1] - t[2]*r[2], t[1]*r[2] + t[2]*r[1], 0,0, 1,1,1,1} 15 | end 16 | 17 | local pointlight = love.graphics.newMesh( v, nil, "static") 18 | local pl_position = love.graphics.newMesh(lvfp, max_lights) 19 | local pl_diffuse = love.graphics.newMesh(lvfd, max_lights) 20 | 21 | local w,h = love.graphics.getDimensions() 22 | 23 | pl_position:setVertex(1, {w/2,h/2,0,66.6}) 24 | pl_diffuse:setVertex(1, {.5, .5, .5}) 25 | for i = 2, current_lights do 26 | pl_position:setVertex(i, {random(0, w),random(0, h),0,random(50, 350)}) 27 | pl_diffuse:setVertex(i, {random()*.1, random()*.1, random()*.1}) 28 | end 29 | pointlight:attachAttribute("lpos", pl_position, "perinstance") 30 | pointlight:attachAttribute("diffuse", pl_diffuse, "perinstance") 31 | 32 | return { 33 | light = pointlight, 34 | pos = pl_position, 35 | diffuse = pl_diffuse, 36 | max_lights = max_lights, 37 | current_lights = current_lights 38 | } 39 | -------------------------------------------------------------------------------- /filmgrain/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | --load a bunch of pictures 4 | local arch = g.newImage("arch.jpg", {mipmaps = true}) 5 | local glass = g.newImage("glass.jpg", {mipmaps = true}) 6 | local stairs = g.newImage("stairs.jpg", {mipmaps = true}) 7 | 8 | local screen = g.newCanvas() --screen sized canvas for post effect(s) 9 | local grain = g.newShader("grain.glsl") 10 | 11 | --noise generation 12 | local noise_size = 128 13 | local noise_data = love.image.newImageData(noise_size, noise_size) 14 | local function noise_f(x,y,r,g,b,a) 15 | return love.math.noise(x,y), love.math.noise(x+noise_size,y), love.math.noise(x,y+noise_size), 1 16 | end 17 | 18 | noise_data:mapPixel(noise_f) 19 | 20 | local noise = g.newImage(noise_data) 21 | noise:setWrap("repeat") 22 | 23 | local random_offset = {} 24 | 25 | function love.draw() 26 | g.setCanvas(screen) 27 | g.draw(arch, 0, 0, 0, 0.35, 0.35) 28 | g.draw(glass, 600, 0, 0, 0.3, 0.3) 29 | g.draw(stairs, 1200, 0, 0, 0.19, 0.19) 30 | g.setCanvas() 31 | g.setShader(grain) 32 | grain:send("noise_texture", noise) 33 | --we will send a random offset vector to alternate the noise each frame 34 | random_offset[1] = love.math.random() 35 | random_offset[2] = love.math.random() 36 | grain:send("random_offset", random_offset) 37 | g.draw(screen) 38 | g.setShader() 39 | --love.timer.sleep(1/24) --cinematic mode 40 | end 41 | 42 | function love.keypressed(k,s,r) 43 | if k == "escape" then love.event.quit(0) end 44 | end 45 | -------------------------------------------------------------------------------- /blood sample/shader.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | #define R(p,a) p=p*cos(a)+vec2(-p.y,p.x)*sin(a); 3 | 4 | uniform float iTime; 5 | 6 | float sphere(vec3 p, float r){ 7 | return dot(p,p)-r; 8 | } 9 | 10 | float box(vec3 p, vec3 r){ 11 | vec3 di = abs(p)-r; 12 | return min( max(di.x,max(di.y,di.z)), length(max(di,0.0)) ); 13 | } 14 | 15 | float scene(vec3 p){ 16 | float h = sphere(mod(p,0.25)-0.125,0.011); 17 | float a = iTime+max(abs(cos(mod(iTime,acos(-1.0)))),0.0); 18 | float b1 = sphere(p-vec3(0.4*cos(iTime),0.0,-0.17),0.02); 19 | float b2 = sphere(p-vec3(0.0,0.17*cos(iTime+1.01),-0.17),0.02); 20 | R(p.xy,a*1.3); 21 | R(p.yz,a*0.7); 22 | float t = sphere(mod(p,0.25)-0.125,0.005); 23 | float c = max(box(p,vec3(0.25)),-h); 24 | float m = 1.0/(b1 + 0.021) + 1.0/(b2 + 0.021) + 1.0/(c + 0.026); 25 | float s = 1.0/m - 0.02; 26 | 27 | return max(max(s,-s-0.0018),-t); 28 | } 29 | 30 | vec4 effect(vec4 color, Image tex, vec2 uv, vec2 sc){ 31 | vec2 pos = (sc-0.5*love_ScreenSize.xy) / min(love_ScreenSize.x,love_ScreenSize.y); 32 | vec3 o = vec3(0.0,0.0,-min(love_ScreenSize.x,love_ScreenSize.y)/max(love_ScreenSize.x,love_ScreenSize.y)); 33 | vec3 d = vec3(pos,0.0)-o; 34 | vec3 p = o; 35 | float l; 36 | float e = 0.001; 37 | vec3 c = vec3(0.0005,0.0,.002); 38 | float t = 0.0; 39 | for(int i = 0; i<256; i++){ 40 | l=scene(p); 41 | if(abs(l) 2 then 56 | g.draw(front) 57 | end 58 | end 59 | } 60 | -------------------------------------------------------------------------------- /glowybits/main.lua: -------------------------------------------------------------------------------- 1 | local scale = 1/5 --smaller scale == bigger pixels 2 | local max_offset = 3 --how far will smoky thing offset randomly 3 | local fdt = 1/120 --fixed delta for the fixed tickrate 4 | local fade_rate = 1/60 --how much to fade per tick 5 | 6 | local g = love.graphics 7 | local w,h = g.getDimensions() 8 | 9 | local fadebuffer = g.newCanvas(w*scale, h*scale, {format = "r8", msaa = 0}) 10 | fadebuffer:setFilter("nearest", "nearest") 11 | local shader = g.newShader("shader.glsl") 12 | shader:send("scale", scale) 13 | 14 | local function get_offset() 15 | return love.math.random(-max_offset,max_offset) 16 | end 17 | 18 | local function tick() 19 | g.origin() 20 | g.setCanvas(fadebuffer) 21 | 22 | g.scale(scale, scale) 23 | g.translate(love.mouse.getPosition()) 24 | g.setBlendMode("lighten", "premultiplied") 25 | local offset_x, offset_y = get_offset(), get_offset() 26 | for i = 1, 10 do 27 | g.setColor(i/10, 1, 1, 1) 28 | g.circle("fill", offset_x*5, offset_y*5, 55-(35/9)*i) 29 | end 30 | 31 | g.setBlendMode("subtract", "alphamultiply") 32 | g.setColor(fade_rate, 1, 1, 1) 33 | g.origin() 34 | g.rectangle("fill", 0, 0, w, h) 35 | g.reset() 36 | end 37 | 38 | local t = 0 39 | function love.update(dt) 40 | t = t + dt 41 | while t > fdt do 42 | tick() 43 | t = t - fdt 44 | end 45 | end 46 | 47 | function love.draw() 48 | g.setShader(shader) 49 | g.draw(fadebuffer, 0, 0, 0, 1/scale, 1/scale) 50 | g.setShader() 51 | g.translate(love.mouse.getPosition()) 52 | g.circle("fill", 0, 0, 50) 53 | end 54 | 55 | function love.keypressed(k,s,r) 56 | if k == "escape" then love.event.quit(0) end 57 | end 58 | -------------------------------------------------------------------------------- /enlarge your pixel/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local img = g.newImage("screen.png") 4 | local max_scale = 7 -- arbitrary number 5 | 6 | local w,h = img:getDimensions() 7 | local can = g.newCanvas(w*max_scale, h*max_scale) 8 | 9 | local shader = g.newShader([[#pragma language glsl3 10 | #ifdef PIXEL 11 | vec4 texture2DAA(sampler2D tex, vec2 uv) { 12 | vec2 texsize = vec2(textureSize(tex,0)); 13 | vec2 uv_texspace = uv*texsize; 14 | vec2 seam = floor(uv_texspace+.5); 15 | uv_texspace = (uv_texspace-seam)/fwidth(uv_texspace)+seam; 16 | uv_texspace = clamp(uv_texspace, seam-.5, seam+.5); 17 | return Texel(tex, uv_texspace/texsize); 18 | } 19 | vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords ){ 20 | vec4 texcolor = texture2DAA(tex, texture_coords); 21 | return texcolor * color; 22 | } 23 | #endif 24 | ]]) 25 | 26 | function love.draw() 27 | local x,y = love.mouse.getPosition() 28 | local w,h = img:getDimensions() 29 | x,y = x,y 30 | s = math.max(x/w, y/h) 31 | s = math.max(2,s) 32 | s = math.min(s,max_scale) 33 | g.setShader(shader) 34 | img:setFilter("linear") 35 | g.draw(img,0,0,0,s,s) 36 | g.setShader() 37 | g.setCanvas(can) 38 | g.scale(math.ceil(s)) 39 | g.clear() 40 | img:setFilter("nearest") 41 | g.draw(img) 42 | g.origin() 43 | g.setCanvas() 44 | g.scale(s/(math.ceil(s))) 45 | if love.keyboard.isScancodeDown("1") then 46 | g.setBlendMode("subtract") 47 | end 48 | if love.keyboard.isScancodeDown("space") then 49 | g.draw(can) 50 | end 51 | g.origin() 52 | g.setBlendMode("alpha") 53 | g.print(s, x,y-20) 54 | end 55 | 56 | function love.keypressed(k,s,r) 57 | if k == "escape" then love.event.quit(0) end 58 | end 59 | -------------------------------------------------------------------------------- /move along/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local w, h = g.getDimensions() 3 | local cr = require"catmull_rom" 4 | local derp = cr.newSpline({100,100,200,100,150,300}) 5 | 6 | local b2cp = {w*.55, h*.45, w*.75, h*.05, w*.95, h*.45} 7 | local b3cp = {w*.55, h*.95, w*.55, h*.05, w*.95, h*1.5, w*.95, h*.55} 8 | local crcp = { 9 | w*.2, h*.5, 10 | w*.1, h*.1, 11 | w*.4, h*.1, 12 | w*.3, h*.4, 13 | w*.4, h*.9, 14 | w*.1, h*.7, 15 | w*.2, h*.6, 16 | } 17 | 18 | local function lerp(a,b,t) 19 | return a*(1-t)+b*t 20 | end 21 | 22 | local b2 = love.math.newBezierCurve(b2cp) 23 | local b3 = love.math.newBezierCurve(b3cp) 24 | local cat = cr.newSpline(crcp) 25 | 26 | local lines = {b2:render(), b3:render(), cat:render(1)} 27 | local len = {} 28 | 29 | for j,v in ipairs(lines) do 30 | local l = {} 31 | for i=1,#v-3,2 do 32 | local dx,dy = v[i], v[i+1] 33 | dx,dy = v[i+2]-dx,v[i+3]-dy 34 | l[#l+1] = math.sqrt(dx*dx+dy*dy) 35 | end 36 | len[j] = l 37 | end 38 | 39 | local p = {{s=1, dr=0},{s=1, dr=0},{s=1, dr=0}} -- current segment, distance remainder 40 | 41 | function love.update(dt) 42 | for i,v in ipairs(p) do 43 | v.dr = v.dr + 100*dt 44 | while v.dr > len[i][v.s] do 45 | v.dr = v.dr - len[i][v.s] 46 | if v.s + 1 > #len[i] then v.s = 1 else v.s = v.s + 1 end 47 | end 48 | end 49 | end 50 | 51 | 52 | function love.draw() 53 | for i,v in ipairs(p) do 54 | g.line(lines[i]) 55 | end 56 | for i,v in ipairs(p) do 57 | local sx, sy = lines[i][v.s*2-1], lines[i][v.s*2] 58 | local ex, ey = lines[i][v.s*2+1], lines[i][v.s*2+2] 59 | local t = v.dr/len[i][v.s] 60 | x = lerp(sx, ex, t) 61 | y = lerp(sy, ey, t) 62 | g.circle("line",x,y, 10) 63 | end 64 | end 65 | 66 | function love.keypressed(k,s,r) 67 | if k == "escape" then love.event.quit(0) end 68 | end 69 | -------------------------------------------------------------------------------- /r3helper examples/instancing/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local R3 = require("R3helper") 4 | 5 | g.setMeshCullMode("back") 6 | g.setFrontFaceWinding("ccw") 7 | g.setDepthMode("less", true) 8 | 9 | local cube = require("ciwb") 10 | 11 | local origin = R3.new_origin(true, g.getDimensions()) 12 | 13 | local pf = {{"pos", "float", 3}} 14 | local cubes = g.newMesh(pf, 32*32*32, nil, "dynamic") 15 | 16 | local spread = 7 17 | local id = 1 18 | for i = 1,32 do 19 | for j = 1,32 do 20 | for k = 1,32 do 21 | cubes:setVertex(id, {spread*(i-16), spread*(k-16), spread*(j-16)}) 22 | id = id+1 23 | end 24 | end 25 | end 26 | 27 | cube:attachAttribute("pos", cubes, "perinstance") 28 | 29 | local icube = g.newShader("icube.glsl") 30 | 31 | function love.draw() 32 | local t = love.timer.getTime() 33 | g.setDepthMode("less", true) 34 | g.replaceTransform( 35 | origin * 36 | R3.translate(0,0,2.5) * 37 | R3.rotate(R3.aa_to_quat(0, 1, 0, .1*t%(math.pi*2))) 38 | ) 39 | --[[ run this code if you want to compare the speed with rendering one by one 40 | for i = 1,32 do 41 | for j = 1,32 do 42 | for k = 1,32 do 43 | g.push() 44 | g.applyTransform( 45 | R3.scale(.01,.01,.01) * 46 | R3.translate(spread*(i-16), spread*(k-16), spread*(j-16)) 47 | ) 48 | g.draw(cube) 49 | g.pop() 50 | end 51 | end 52 | end 53 | --]] 54 | g.setShader(icube) 55 | local s = .011 - .001*math.cos(t*.0001) 56 | g.applyTransform(R3.scale(s, s, s)) 57 | g.drawInstanced(cube, 32*32*32) 58 | g.setShader() 59 | g.origin() 60 | g.setDepthMode("always", false) 61 | g.print(love.timer.getDelta()) 62 | g.print(g.getStats().drawcalls, 0, 20) 63 | g.print(love.timer.getFPS(), 0, 40) 64 | end 65 | 66 | function love.keypressed(k,s,r) 67 | if k == "escape" then love.event.quit(0) end 68 | end 69 | -------------------------------------------------------------------------------- /deferred/lighting_pass.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 ndc_p; // normalized display coordinate light position 2 | varying vec3 w_p; // world position 3 | varying float scale; // lightsource size 4 | varying vec3 diff; // diffuse color 5 | varying vec3 dir; // light direction 6 | varying float angle; // cosine of light cone angle 7 | 8 | #ifdef VERTEX 9 | // perinstance attributes 10 | attribute vec4 lpos; 11 | attribute vec4 ldir; 12 | attribute vec3 diffuse; 13 | 14 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 15 | vec2 lp = (transform_projection * vec4(lpos.xyz, 1.)).xy; // light position to screenspace 16 | ndc_p = vec2(lp.x, -lp.y); // screenspace to ndc 17 | 18 | // pass all the other stuff to pixel shader 19 | scale = lpos.w; 20 | diff = diffuse; 21 | dir = normalize(ldir.xyz); 22 | angle = ldir.w; 23 | w_p = lpos.xyz; 24 | 25 | // transform light vertex for rendering 26 | return transform_projection * (vec4(vertex_position.xyz*lpos.w, vertex_position.w) + vec4(lpos.xy, 0., 0.)); 27 | } 28 | #endif 29 | 30 | #ifdef PIXEL 31 | uniform Image cb; 32 | uniform Image nb; 33 | 34 | vec4 effect(vec4 col, Image tex, vec2 uv, vec2 sc){ 35 | sc /= love_ScreenSize.xy; 36 | vec2 ndc = (sc - vec2(.5)) * 2.; // ndc of a current pixel 37 | 38 | // color and normal of a to be lit pixel 39 | vec3 c = Texel(cb, sc).xyz; 40 | vec3 n = normalize(Texel(nb, sc).xyz - vec3(.5)); 41 | n.y = -n.y; 42 | 43 | vec3 tl = vec3(normalize(ndc_p-ndc) * col.x, w_p.z / scale); //vector towards the light 44 | float ld = length(tl); 45 | vec3 l = normalize(tl); 46 | 47 | // discard if pixel is beyond the bounding sphere or cone 48 | if((length(tl)/scale > 1.) || (dot(-l, dir) < angle)) discard; 49 | 50 | // compute lambertian term, distance dissipation, and multiply by diffuse 51 | c = c * dot(n,l) * max(1.-ld*ld, 0.) * diff; 52 | return vec4(c, 1.); 53 | } 54 | #endif -------------------------------------------------------------------------------- /r3helper examples/shadows/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local R3 = require("R3helper") 3 | local scene = require("scene") 4 | 5 | local res = 1024 6 | local shadow_inv = R3.new_inverse(res,res) 7 | 8 | --shadow ortho projection 9 | --this preferably should be computed to cover as much frustum as possible 10 | local shadow_proj = R3.new_ortho(26,26, -11.7, 11.7) 11 | shadow_proj:apply( 12 | R3.rotate(R3.aa_to_quat(1,0,0,.3)) * 13 | R3.rotate(R3.aa_to_quat(0,1,0,.3)) 14 | ) 15 | 16 | --shadow map settings 17 | local shadow_map = {} 18 | do 19 | shadow_map.depthstencil = g.newCanvas(res, res, {type="2d", format="depth32f", readable=true}) 20 | shadow_map.depthstencil:setDepthSampleMode("gequal") 21 | end 22 | local shadow_shader = g.newShader("sm.glsl") 23 | 24 | --perspective projection 25 | local w,h = g.getDimensions() 26 | local proj = R3.new_perspective(w,h, .1, math.pi/3) 27 | 28 | function love.draw() 29 | local t = love.timer.getTime() 30 | g.setDepthMode("less", true) 31 | g.setMeshCullMode("front") 32 | 33 | --draw depth buffer for shadowmap 34 | g.setCanvas(shadow_map) 35 | g.clear(0,0,0,0,false,true) 36 | g.replaceTransform(shadow_inv*shadow_proj) 37 | scene.draw() 38 | 39 | --draw scene with shadows 40 | g.setCanvas() 41 | g.setMeshCullMode("back") 42 | g.setShader(shadow_shader) 43 | shadow_shader:send("sm", shadow_map.depthstencil) 44 | shadow_shader:send("shadow_view", shadow_proj) 45 | shadow_shader:send("proj", proj * 46 | R3.rotate(R3.aa_to_quat(1,0,0,.3)) * --rotate the camera 47 | R3.translate(0,-4,14) * --move the camera 48 | R3.rotate(R3.aa_to_quat(0,1,0,love.timer.getTime()%(math.pi*2))) --rotate the camera 49 | ) 50 | g.origin() 51 | scene.draw() 52 | 53 | g.setShader() 54 | g.origin() 55 | g.setDepthMode("always", false) 56 | g.print(love.timer.getDelta()) 57 | g.print(g.getStats().drawcalls, 0, 20) 58 | g.print(love.timer.getFPS(), 0, 40) 59 | end 60 | 61 | function love.keypressed(k,s,r) 62 | if k == "escape" then love.event.quit(0) end 63 | end 64 | -------------------------------------------------------------------------------- /painter's worst nightmare/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local w,h = love.graphics.getDimensions() 3 | 4 | local rnd = love.math.newRandomGenerator() 5 | local rnd_state = rnd:getState() 6 | 7 | local alpha_shader = g.newShader("shader.glsl") 8 | 9 | local coverage_lut = g.newImage("lut.png", {linear=true}) 10 | coverage_lut:setFilter("nearest") -- absolutely don't wanna interpolate bitmasks 11 | coverage_lut:setWrap("repeat","clamp") 12 | 13 | local rgb = { 14 | {1,0,0,.7}, 15 | {0,1,0,.7}, 16 | {0,0,1,.7}, 17 | } 18 | 19 | local pic = g.newCanvas(1,1) 20 | g.setCanvas(pic); g.rectangle("fill",0,0,1,1); g.setCanvas() 21 | 22 | local thing = g.newSpriteBatch(pic,3) 23 | for i=1,3 do 24 | thing:setColor(rgb[i]) 25 | thing:add(0,0,(1-i)*math.pi*2/3,w/3,h/13,.5,-.4) 26 | end 27 | 28 | function love.update(dt) 29 | end 30 | 31 | local superscale = 2 -- more than two requires a different downsampling method 32 | local iter = 4 -- number of iterations, 33 | -- final calculation is average of superscale squared by iter of msaa graded alpha 34 | 35 | local screen = g.newCanvas(w*superscale,h*superscale,{msaa=8}) 36 | local screen_set = {screen, depth=true} 37 | local function draw_scene() 38 | g.setCanvas(screen_set) 39 | g.clear() 40 | alpha_shader:send("lut", coverage_lut) 41 | -- random offset so iterations don't repeat the same pattern 42 | alpha_shader:send("alpha_offset", rnd:random()) 43 | g.setShader(alpha_shader) 44 | g.setDepthMode("less", true) 45 | g.draw(thing, w/2*superscale, h/2*superscale, 0, superscale, superscale) 46 | g.setDepthMode() 47 | g.setShader() 48 | g.setCanvas() 49 | end 50 | 51 | function love.draw() 52 | local avg = 1/iter 53 | rnd:setState(rnd_state) 54 | for i = 1, iter do 55 | draw_scene() 56 | g.setColor(love.math.linearToGamma(avg,avg,avg,1)) 57 | g.setBlendMode("add", "premultiplied") 58 | g.draw(screen,0,0,0, 1/superscale, 1/superscale) 59 | g.setColor(1,1,1,1) 60 | g.setBlendMode("alpha") 61 | end 62 | g.setColor(0,0,0) 63 | g.rectangle("fill",0,0,200,40) 64 | g.setColor(1,1,1) 65 | g.print(love.timer.getDelta()) 66 | g.print(love.timer.getFPS(),0,20) 67 | end 68 | 69 | function love.keypressed(k,s,r) 70 | if k == "escape" then love.event.quit(0) end 71 | end 72 | -------------------------------------------------------------------------------- /dungeon/R3helper.lua: -------------------------------------------------------------------------------- 1 | local m = love.math 2 | local g = love.graphics 3 | 4 | local tmp = m.newTransform() 5 | local bak = m.newTransform() 6 | local R3 = {} 7 | 8 | function R3.new_inverse(width, height) 9 | return m.newTransform():setMatrix( 10 | 2/width,0,0,-1, 11 | 0,-2/height,0,1, 12 | 0,0,-1/10,0, 13 | 0,0,0,1 14 | ):inverse() 15 | end 16 | 17 | function R3.new_perspective(width, height, near, hfov) 18 | local n = near or .1 19 | hfov = hfov or math.pi*.5 20 | local f = 1/math.tan(hfov*.5) 21 | local ar = width/height 22 | return m.newTransform():setMatrix( 23 | f/ar, 0, 0, 0, 24 | 0, f, 0, 0, 25 | 0, 0, 1, -2*n, 26 | 0, 0, 1, 0 27 | ) 28 | end 29 | 30 | function R3.new_ortho(width, height, near, far) 31 | return m.newTransform():setMatrix( 32 | 2/width, 0, 0, 0, 33 | 0, 2/height, 0, 0, 34 | 0, 0, 2/(far-near), -(far+near)/(far-near), 35 | 0, 0, 0, 1 36 | ) 37 | end 38 | 39 | function R3.new_origin(perspective, width, height, near, hfov) 40 | if perspective then 41 | return R3.new_inverse(width, height):apply(R3.new_perspective(width, height, near, hfov)) 42 | else 43 | return R3.new_inverse(width, height):apply(R3.new_ortho(2, 2, near, hfov)) 44 | end 45 | end 46 | 47 | function R3.translate(x,y,z) 48 | tmp:setMatrix( 49 | 1,0,0,x, 50 | 0,1,0,y, 51 | 0,0,1,z, 52 | 0,0,0,1 53 | ) 54 | tmp, bak = bak, tmp 55 | return bak 56 | end 57 | 58 | function R3.scale(x,y,z) 59 | tmp:setMatrix( 60 | x,0,0,0, 61 | 0,y,0,0, 62 | 0,0,z,0, 63 | 0,0,0,1 64 | ) 65 | tmp, bak = bak, tmp 66 | return bak 67 | end 68 | 69 | function R3.rotate(i,j,k,w) 70 | tmp:setMatrix( 71 | 1-2*j*j-2*k*k, 2*i*j+2*w*k, 2*i*k-2*w*j, 0, 72 | 2*i*j-2*w*k, 1-2*i*i-2*k*k, 2*j*k+2*w*i, 0, 73 | 2*i*k+2*w*j, 2*j*k-2*w*i, 1-2*i*i-2*j*j, 0, 74 | 0, 0, 0, 1 75 | ) 76 | tmp, bak = bak, tmp 77 | return bak 78 | end 79 | 80 | function R3.aa_to_quat(x,y,z,a) 81 | --let's turn axis angle into a quaternion 82 | local l = math.sqrt(x*x+y*y+z*z) 83 | x,y,z = x/l, y/l, z/l --normalize imaginary part 84 | local w, s = math.cos(a/2), math.sin(a/2) --the real part is a COsine of half an angle 85 | --the imaginary part will get multiplied by sine of half an angle 86 | return x*s, y*s, z*s, w 87 | end 88 | 89 | return R3 90 | -------------------------------------------------------------------------------- /r3helper examples/camera/R3helper.lua: -------------------------------------------------------------------------------- 1 | local m = love.math 2 | local g = love.graphics 3 | 4 | local tmp = m.newTransform() 5 | local bak = m.newTransform() 6 | local R3 = {} 7 | 8 | function R3.new_inverse(width, height) 9 | return m.newTransform():setMatrix( 10 | 2/width,0,0,-1, 11 | 0,-2/height,0,1, 12 | 0,0,-1/10,0, 13 | 0,0,0,1 14 | ):inverse() 15 | end 16 | 17 | function R3.new_perspective(width, height, near, hfov) 18 | local n = near or .1 19 | hfov = hfov or math.pi*.5 20 | local f = 1/math.tan(hfov*.5) 21 | local ar = width/height 22 | return m.newTransform():setMatrix( 23 | f/ar, 0, 0, 0, 24 | 0, f, 0, 0, 25 | 0, 0, 1, -2*n, 26 | 0, 0, 1, 0 27 | ) 28 | end 29 | 30 | function R3.new_ortho(width, height, near, far) 31 | return m.newTransform():setMatrix( 32 | 2/width, 0, 0, 0, 33 | 0, 2/height, 0, 0, 34 | 0, 0, 2/(far-near), -(far+near)/(far-near), 35 | 0, 0, 0, 1 36 | ) 37 | end 38 | 39 | function R3.new_origin(perspective, width, height, near, hfov) 40 | if perspective then 41 | return R3.new_inverse(width, height):apply(R3.new_perspective(width, height, near, hfov)) 42 | else 43 | return R3.new_inverse(width, height):apply(R3.new_ortho(2, 2, near, hfov)) 44 | end 45 | end 46 | 47 | function R3.translate(x,y,z) 48 | tmp:setMatrix( 49 | 1,0,0,x, 50 | 0,1,0,y, 51 | 0,0,1,z, 52 | 0,0,0,1 53 | ) 54 | tmp, bak = bak, tmp 55 | return bak 56 | end 57 | 58 | function R3.scale(x,y,z) 59 | tmp:setMatrix( 60 | x,0,0,0, 61 | 0,y,0,0, 62 | 0,0,z,0, 63 | 0,0,0,1 64 | ) 65 | tmp, bak = bak, tmp 66 | return bak 67 | end 68 | 69 | function R3.rotate(i,j,k,w) 70 | tmp:setMatrix( 71 | 1-2*j*j-2*k*k, 2*i*j+2*w*k, 2*i*k-2*w*j, 0, 72 | 2*i*j-2*w*k, 1-2*i*i-2*k*k, 2*j*k+2*w*i, 0, 73 | 2*i*k+2*w*j, 2*j*k-2*w*i, 1-2*i*i-2*j*j, 0, 74 | 0, 0, 0, 1 75 | ) 76 | tmp, bak = bak, tmp 77 | return bak 78 | end 79 | 80 | function R3.aa_to_quat(x,y,z,a) 81 | --let's turn axis angle into a quaternion 82 | local l = math.sqrt(x*x+y*y+z*z) 83 | x,y,z = x/l, y/l, z/l --normalize imaginary part 84 | local w, s = math.cos(a/2), math.sin(a/2) --the real part is a COsine of half an angle 85 | --the imaginary part will get multiplied by sine of half an angle 86 | return x*s, y*s, z*s, w 87 | end 88 | 89 | return R3 90 | -------------------------------------------------------------------------------- /r3helper examples/shadows/R3helper.lua: -------------------------------------------------------------------------------- 1 | local m = love.math 2 | local g = love.graphics 3 | 4 | local tmp = m.newTransform() 5 | local bak = m.newTransform() 6 | local R3 = {} 7 | 8 | function R3.new_inverse(width, height) 9 | return m.newTransform():setMatrix( 10 | 2/width,0,0,-1, 11 | 0,-2/height,0,1, 12 | 0,0,-1/10,0, 13 | 0,0,0,1 14 | ):inverse() 15 | end 16 | 17 | function R3.new_perspective(width, height, near, hfov) 18 | local n = near or .1 19 | hfov = hfov or math.pi*.5 20 | local f = 1/math.tan(hfov*.5) 21 | local ar = width/height 22 | return m.newTransform():setMatrix( 23 | f/ar, 0, 0, 0, 24 | 0, f, 0, 0, 25 | 0, 0, 1, -2*n, 26 | 0, 0, 1, 0 27 | ) 28 | end 29 | 30 | function R3.new_ortho(width, height, near, far) 31 | return m.newTransform():setMatrix( 32 | 2/width, 0, 0, 0, 33 | 0, 2/height, 0, 0, 34 | 0, 0, 2/(far-near), -(far+near)/(far-near), 35 | 0, 0, 0, 1 36 | ) 37 | end 38 | 39 | function R3.new_origin(perspective, width, height, near, hfov) 40 | if perspective then 41 | return R3.new_inverse(width, height):apply(R3.new_perspective(width, height, near, hfov)) 42 | else 43 | return R3.new_inverse(width, height):apply(R3.new_ortho(2, 2, near, hfov)) 44 | end 45 | end 46 | 47 | function R3.translate(x,y,z) 48 | tmp:setMatrix( 49 | 1,0,0,x, 50 | 0,1,0,y, 51 | 0,0,1,z, 52 | 0,0,0,1 53 | ) 54 | tmp, bak = bak, tmp 55 | return bak 56 | end 57 | 58 | function R3.scale(x,y,z) 59 | tmp:setMatrix( 60 | x,0,0,0, 61 | 0,y,0,0, 62 | 0,0,z,0, 63 | 0,0,0,1 64 | ) 65 | tmp, bak = bak, tmp 66 | return bak 67 | end 68 | 69 | function R3.rotate(i,j,k,w) 70 | tmp:setMatrix( 71 | 1-2*j*j-2*k*k, 2*i*j+2*w*k, 2*i*k-2*w*j, 0, 72 | 2*i*j-2*w*k, 1-2*i*i-2*k*k, 2*j*k+2*w*i, 0, 73 | 2*i*k+2*w*j, 2*j*k-2*w*i, 1-2*i*i-2*j*j, 0, 74 | 0, 0, 0, 1 75 | ) 76 | tmp, bak = bak, tmp 77 | return bak 78 | end 79 | 80 | function R3.aa_to_quat(x,y,z,a) 81 | --let's turn axis angle into a quaternion 82 | local l = math.sqrt(x*x+y*y+z*z) 83 | x,y,z = x/l, y/l, z/l --normalize imaginary part 84 | local w, s = math.cos(a/2), math.sin(a/2) --the real part is a COsine of half an angle 85 | --the imaginary part will get multiplied by sine of half an angle 86 | return x*s, y*s, z*s, w 87 | end 88 | 89 | return R3 90 | -------------------------------------------------------------------------------- /r3helper examples/textures/R3helper.lua: -------------------------------------------------------------------------------- 1 | local m = love.math 2 | local g = love.graphics 3 | 4 | local tmp = m.newTransform() 5 | local bak = m.newTransform() 6 | local R3 = {} 7 | 8 | function R3.new_inverse(width, height) 9 | return m.newTransform():setMatrix( 10 | 2/width,0,0,-1, 11 | 0,-2/height,0,1, 12 | 0,0,-1/10,0, 13 | 0,0,0,1 14 | ):inverse() 15 | end 16 | 17 | function R3.new_perspective(width, height, near, hfov) 18 | local n = near or .1 19 | hfov = hfov or math.pi*.5 20 | local f = 1/math.tan(hfov*.5) 21 | local ar = width/height 22 | return m.newTransform():setMatrix( 23 | f/ar, 0, 0, 0, 24 | 0, f, 0, 0, 25 | 0, 0, 1, -2*n, 26 | 0, 0, 1, 0 27 | ) 28 | end 29 | 30 | function R3.new_ortho(width, height, near, far) 31 | return m.newTransform():setMatrix( 32 | 2/width, 0, 0, 0, 33 | 0, 2/height, 0, 0, 34 | 0, 0, 2/(far-near), -(far+near)/(far-near), 35 | 0, 0, 0, 1 36 | ) 37 | end 38 | 39 | function R3.new_origin(perspective, width, height, near, hfov) 40 | if perspective then 41 | return R3.new_inverse(width, height):apply(R3.new_perspective(width, height, near, hfov)) 42 | else 43 | return R3.new_inverse(width, height):apply(R3.new_ortho(2, 2, near, hfov)) 44 | end 45 | end 46 | 47 | function R3.translate(x,y,z) 48 | tmp:setMatrix( 49 | 1,0,0,x, 50 | 0,1,0,y, 51 | 0,0,1,z, 52 | 0,0,0,1 53 | ) 54 | tmp, bak = bak, tmp 55 | return bak 56 | end 57 | 58 | function R3.scale(x,y,z) 59 | tmp:setMatrix( 60 | x,0,0,0, 61 | 0,y,0,0, 62 | 0,0,z,0, 63 | 0,0,0,1 64 | ) 65 | tmp, bak = bak, tmp 66 | return bak 67 | end 68 | 69 | function R3.rotate(i,j,k,w) 70 | tmp:setMatrix( 71 | 1-2*j*j-2*k*k, 2*i*j+2*w*k, 2*i*k-2*w*j, 0, 72 | 2*i*j-2*w*k, 1-2*i*i-2*k*k, 2*j*k+2*w*i, 0, 73 | 2*i*k+2*w*j, 2*j*k-2*w*i, 1-2*i*i-2*j*j, 0, 74 | 0, 0, 0, 1 75 | ) 76 | tmp, bak = bak, tmp 77 | return bak 78 | end 79 | 80 | function R3.aa_to_quat(x,y,z,a) 81 | --let's turn axis angle into a quaternion 82 | local l = math.sqrt(x*x+y*y+z*z) 83 | x,y,z = x/l, y/l, z/l --normalize imaginary part 84 | local w, s = math.cos(a/2), math.sin(a/2) --the real part is a COsine of half an angle 85 | --the imaginary part will get multiplied by sine of half an angle 86 | return x*s, y*s, z*s, w 87 | end 88 | 89 | return R3 90 | -------------------------------------------------------------------------------- /r3helper examples/depth_peeling/R3helper.lua: -------------------------------------------------------------------------------- 1 | local m = love.math 2 | local g = love.graphics 3 | 4 | local tmp = m.newTransform() 5 | local bak = m.newTransform() 6 | local R3 = {} 7 | 8 | function R3.new_inverse(width, height) 9 | return m.newTransform():setMatrix( 10 | 2/width,0,0,-1, 11 | 0,-2/height,0,1, 12 | 0,0,-1/10,0, 13 | 0,0,0,1 14 | ):inverse() 15 | end 16 | 17 | function R3.new_perspective(width, height, near, hfov) 18 | local n = near or .1 19 | hfov = hfov or math.pi*.5 20 | local f = 1/math.tan(hfov*.5) 21 | local ar = width/height 22 | return m.newTransform():setMatrix( 23 | f/ar, 0, 0, 0, 24 | 0, f, 0, 0, 25 | 0, 0, 1, -2*n, 26 | 0, 0, 1, 0 27 | ) 28 | end 29 | 30 | function R3.new_ortho(width, height, near, far) 31 | return m.newTransform():setMatrix( 32 | 2/width, 0, 0, 0, 33 | 0, 2/height, 0, 0, 34 | 0, 0, 2/(far-near), -(far+near)/(far-near), 35 | 0, 0, 0, 1 36 | ) 37 | end 38 | 39 | function R3.new_origin(perspective, width, height, near, hfov) 40 | if perspective then 41 | return R3.new_inverse(width, height):apply(R3.new_perspective(width, height, near, hfov)) 42 | else 43 | return R3.new_inverse(width, height):apply(R3.new_ortho(2, 2, near, hfov)) 44 | end 45 | end 46 | 47 | function R3.translate(x,y,z) 48 | tmp:setMatrix( 49 | 1,0,0,x, 50 | 0,1,0,y, 51 | 0,0,1,z, 52 | 0,0,0,1 53 | ) 54 | tmp, bak = bak, tmp 55 | return bak 56 | end 57 | 58 | function R3.scale(x,y,z) 59 | tmp:setMatrix( 60 | x,0,0,0, 61 | 0,y,0,0, 62 | 0,0,z,0, 63 | 0,0,0,1 64 | ) 65 | tmp, bak = bak, tmp 66 | return bak 67 | end 68 | 69 | function R3.rotate(i,j,k,w) 70 | tmp:setMatrix( 71 | 1-2*j*j-2*k*k, 2*i*j+2*w*k, 2*i*k-2*w*j, 0, 72 | 2*i*j-2*w*k, 1-2*i*i-2*k*k, 2*j*k+2*w*i, 0, 73 | 2*i*k+2*w*j, 2*j*k-2*w*i, 1-2*i*i-2*j*j, 0, 74 | 0, 0, 0, 1 75 | ) 76 | tmp, bak = bak, tmp 77 | return bak 78 | end 79 | 80 | function R3.aa_to_quat(x,y,z,a) 81 | --let's turn axis angle into a quaternion 82 | local l = math.sqrt(x*x+y*y+z*z) 83 | x,y,z = x/l, y/l, z/l --normalize imaginary part 84 | local w, s = math.cos(a/2), math.sin(a/2) --the real part is a COsine of half an angle 85 | --the imaginary part will get multiplied by sine of half an angle 86 | return x*s, y*s, z*s, w 87 | end 88 | 89 | return R3 90 | -------------------------------------------------------------------------------- /r3helper examples/instancing/R3helper.lua: -------------------------------------------------------------------------------- 1 | local m = love.math 2 | local g = love.graphics 3 | 4 | local tmp = m.newTransform() 5 | local bak = m.newTransform() 6 | local R3 = {} 7 | 8 | function R3.new_inverse(width, height) 9 | return m.newTransform():setMatrix( 10 | 2/width,0,0,-1, 11 | 0,-2/height,0,1, 12 | 0,0,-1/10,0, 13 | 0,0,0,1 14 | ):inverse() 15 | end 16 | 17 | function R3.new_perspective(width, height, near, hfov) 18 | local n = near or .1 19 | hfov = hfov or math.pi*.5 20 | local f = 1/math.tan(hfov*.5) 21 | local ar = width/height 22 | return m.newTransform():setMatrix( 23 | f/ar, 0, 0, 0, 24 | 0, f, 0, 0, 25 | 0, 0, 1, -2*n, 26 | 0, 0, 1, 0 27 | ) 28 | end 29 | 30 | function R3.new_ortho(width, height, near, far) 31 | return m.newTransform():setMatrix( 32 | 2/width, 0, 0, 0, 33 | 0, 2/height, 0, 0, 34 | 0, 0, 2/(far-near), -(far+near)/(far-near), 35 | 0, 0, 0, 1 36 | ) 37 | end 38 | 39 | function R3.new_origin(perspective, width, height, near, hfov) 40 | if perspective then 41 | return R3.new_inverse(width, height):apply(R3.new_perspective(width, height, near, hfov)) 42 | else 43 | return R3.new_inverse(width, height):apply(R3.new_ortho(2, 2, near, hfov)) 44 | end 45 | end 46 | 47 | function R3.translate(x,y,z) 48 | tmp:setMatrix( 49 | 1,0,0,x, 50 | 0,1,0,y, 51 | 0,0,1,z, 52 | 0,0,0,1 53 | ) 54 | tmp, bak = bak, tmp 55 | return bak 56 | end 57 | 58 | function R3.scale(x,y,z) 59 | tmp:setMatrix( 60 | x,0,0,0, 61 | 0,y,0,0, 62 | 0,0,z,0, 63 | 0,0,0,1 64 | ) 65 | tmp, bak = bak, tmp 66 | return bak 67 | end 68 | 69 | function R3.rotate(i,j,k,w) 70 | tmp:setMatrix( 71 | 1-2*j*j-2*k*k, 2*i*j+2*w*k, 2*i*k-2*w*j, 0, 72 | 2*i*j-2*w*k, 1-2*i*i-2*k*k, 2*j*k+2*w*i, 0, 73 | 2*i*k+2*w*j, 2*j*k-2*w*i, 1-2*i*i-2*j*j, 0, 74 | 0, 0, 0, 1 75 | ) 76 | tmp, bak = bak, tmp 77 | return bak 78 | end 79 | 80 | function R3.aa_to_quat(x,y,z,a) 81 | --let's turn axis angle into a quaternion 82 | local l = math.sqrt(x*x+y*y+z*z) 83 | x,y,z = x/l, y/l, z/l --normalize imaginary part 84 | local w, s = math.cos(a/2), math.sin(a/2) --the real part is a COsine of half an angle 85 | --the imaginary part will get multiplied by sine of half an angle 86 | return x*s, y*s, z*s, w 87 | end 88 | 89 | return R3 90 | -------------------------------------------------------------------------------- /r3helper examples/spinning_cube/R3helper.lua: -------------------------------------------------------------------------------- 1 | local m = love.math 2 | local g = love.graphics 3 | 4 | local tmp = m.newTransform() 5 | local bak = m.newTransform() 6 | local R3 = {} 7 | 8 | function R3.new_inverse(width, height) 9 | return m.newTransform():setMatrix( 10 | 2/width,0,0,-1, 11 | 0,-2/height,0,1, 12 | 0,0,-1/10,0, 13 | 0,0,0,1 14 | ):inverse() 15 | end 16 | 17 | function R3.new_perspective(width, height, near, hfov) 18 | local n = near or .1 19 | hfov = hfov or math.pi*.5 20 | local f = 1/math.tan(hfov*.5) 21 | local ar = width/height 22 | return m.newTransform():setMatrix( 23 | f/ar, 0, 0, 0, 24 | 0, f, 0, 0, 25 | 0, 0, 1, -2*n, 26 | 0, 0, 1, 0 27 | ) 28 | end 29 | 30 | function R3.new_ortho(width, height, near, far) 31 | return m.newTransform():setMatrix( 32 | 2/width, 0, 0, 0, 33 | 0, 2/height, 0, 0, 34 | 0, 0, 2/(far-near), -(far+near)/(far-near), 35 | 0, 0, 0, 1 36 | ) 37 | end 38 | 39 | function R3.new_origin(perspective, width, height, near, hfov) 40 | if perspective then 41 | return R3.new_inverse(width, height):apply(R3.new_perspective(width, height, near, hfov)) 42 | else 43 | return R3.new_inverse(width, height):apply(R3.new_ortho(2, 2, near, hfov)) 44 | end 45 | end 46 | 47 | function R3.translate(x,y,z) 48 | tmp:setMatrix( 49 | 1,0,0,x, 50 | 0,1,0,y, 51 | 0,0,1,z, 52 | 0,0,0,1 53 | ) 54 | tmp, bak = bak, tmp 55 | return bak 56 | end 57 | 58 | function R3.scale(x,y,z) 59 | tmp:setMatrix( 60 | x,0,0,0, 61 | 0,y,0,0, 62 | 0,0,z,0, 63 | 0,0,0,1 64 | ) 65 | tmp, bak = bak, tmp 66 | return bak 67 | end 68 | 69 | function R3.rotate(i,j,k,w) 70 | tmp:setMatrix( 71 | 1-2*j*j-2*k*k, 2*i*j+2*w*k, 2*i*k-2*w*j, 0, 72 | 2*i*j-2*w*k, 1-2*i*i-2*k*k, 2*j*k+2*w*i, 0, 73 | 2*i*k+2*w*j, 2*j*k-2*w*i, 1-2*i*i-2*j*j, 0, 74 | 0, 0, 0, 1 75 | ) 76 | tmp, bak = bak, tmp 77 | return bak 78 | end 79 | 80 | function R3.aa_to_quat(x,y,z,a) 81 | --let's turn axis angle into a quaternion 82 | local l = math.sqrt(x*x+y*y+z*z) 83 | x,y,z = x/l, y/l, z/l --normalize imaginary part 84 | local w, s = math.cos(a/2), math.sin(a/2) --the real part is a COsine of half an angle 85 | --the imaginary part will get multiplied by sine of half an angle 86 | return x*s, y*s, z*s, w 87 | end 88 | 89 | return R3 90 | -------------------------------------------------------------------------------- /pong/main.lua: -------------------------------------------------------------------------------- 1 | local paddle = { 2 | {x = 50, y = 300, v = 320, h = 90}, 3 | {x = 750, y = 300, v = 400, h = 90} 4 | } 5 | local ball = {x = 400, y = 300, vx = 1, vy = 0, v = 420} 6 | local control = { 7 | {up = false, down = false}, 8 | {up = false, down = false} 9 | } 10 | local score = {0,0} 11 | local m = {1,-1} 12 | 13 | local fdt = 1/125 14 | local t = 0 15 | 16 | local function goal(s) 17 | score[s] = score[s] + 1 18 | ball.x, ball.y, ball.vx, ball.vy, ball.v = 400, 300, m[s], 0, 320 19 | end 20 | 21 | local function fupdate() 22 | control[1].up, control[1].down = love.keyboard.isDown("up"), love.keyboard.isDown("down") 23 | control[2].up, control[2].down = ball.y < paddle[2].y-30, ball.y > paddle[2].y+30 24 | 25 | for i,v in ipairs(paddle) do 26 | paddle[i].y = paddle[i].y + paddle[i].v * fdt * ((control[i].up and -1) or (control[i].down and 1) or 0) 27 | end 28 | 29 | ball.x, ball.y = ball.x + ball.vx * fdt * ball.v, ball.y + ball.vy * fdt * ball.v 30 | 31 | for i,v in ipairs(paddle) do 32 | if (math.abs(ball.x - paddle[i].x) < 20) and 33 | (math.abs(ball.y - paddle[i].y) < 10 + paddle[i].h*0.5) 34 | then 35 | local nx, ny = (ball.x - paddle[i].x), (ball.y - paddle[i].y) 36 | local l = math.sqrt(nx*nx+ny*ny) 37 | nx, ny = nx/l, ny/l 38 | nx = m[i]*math.abs(ball.vx) + nx 39 | ny = ball.vy + ny 40 | l = math.sqrt(nx*nx+ny*ny) 41 | ball.vx = nx/l 42 | ball.vy = ny/l 43 | ball.v = math.min(ball.v*1.1, 1666) 44 | end 45 | end 46 | 47 | if ball.y < 10 then ball.vy = math.abs(ball.vy) end 48 | if ball.y > 590 then ball.vy = -math.abs(ball.vy) end 49 | 50 | _ = (ball.x < 0) and goal(2) 51 | _ = (ball.x > 800) and goal(1) 52 | end 53 | 54 | function love.update(dt) 55 | t = t + dt 56 | if t > fdt then 57 | t = t - fdt 58 | fupdate() 59 | end 60 | end 61 | 62 | function love.draw() 63 | for i, v in ipairs(paddle) do 64 | love.graphics.rectangle("fill", paddle[i].x-10, paddle[i].y-paddle[i].h*0.5, 20, paddle[i].h) 65 | end 66 | love.graphics.circle("fill", ball.x, ball.y, 10) 67 | love.graphics.print(score[1]..":"..score[2], 400-13, 20) 68 | end 69 | 70 | function love.keypressed(k,s,r) 71 | if k == "escape" then love.event.quit(0) end 72 | end -------------------------------------------------------------------------------- /subpixel art/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local m = love.math 3 | g.setDefaultFilter("nearest") 4 | local img = g.newImage("derp.png") 5 | local w,h = g.getDimensions() 6 | local q = m.linearToGamma(1/4,0,0) 7 | local s = 4 -- upscale value 8 | local bleed, hint = false, true 9 | 10 | local color = {4,4,4} 11 | 12 | local pixel = g.newCanvas(s,s) 13 | pixel:setWrap("repeat","repeat") 14 | 15 | local stq = g.newQuad(0,0,w,h,pixel) 16 | 17 | function love.draw() 18 | local sw,sh = g.getDimensions() 19 | -- add up the same picture with offsets to get light bleeding effect if needed 20 | g.setBlendMode("add", "premultiplied") 21 | if bleed then 22 | g.setColor(q,q,q) 23 | g.draw(img,1,0,0,s,s) 24 | g.draw(img,0,1,0,s,s) 25 | g.draw(img,1,1,0,s,s) 26 | end 27 | g.draw(img,0,0,0,s,s) 28 | 29 | -- multiply the entire screen by pixel pattern 30 | g.setColor(1,1,1) 31 | g.setBlendMode("multiply", "premultiplied") 32 | g.draw(pixel, stq) 33 | 34 | -- ui stuff, you shouldn't care about it, I sure didn't 35 | g.setBlendMode("replace", "premultiplied") 36 | g.draw(pixel, w-20*s,0,0,20,20) 37 | g.setBlendMode("alpha") 38 | g.setColor(0,0,0) 39 | g.rectangle("fill", w-20*s, 20*s, 20*s, 60) 40 | g.setColor(1,1,1) 41 | g.rectangle("line", w-20*s,0,20*s,20*s) 42 | g.print("r: "..(color[1]/4),w-20*s,20*s) 43 | g.print("g: "..(color[2]/4),w-20*s,20*s+20) 44 | g.print("b: "..(color[3]/4),w-20*s,20*s+40) 45 | if hint then 46 | g.print("press h to hide this hint", 300, 20) 47 | g.print("press space to toggle light bleeding", 300, 40) 48 | g.print("left click to add and right click to subtract the color from the top right minicanvas", 300, 60) 49 | g.print("press 1,2,3 to cycle r,g, and b components of the color", 300, 80) 50 | end 51 | end 52 | 53 | local modes = {"add", "subtract"} 54 | function love.mousepressed(x,y,b) 55 | g.setCanvas(pixel) 56 | g.setBlendMode(modes[b] or "add", "premultiplied") 57 | local cr,cg,cb = m.linearToGamma(color[1]/4,color[2]/4,color[3]/4) 58 | g.setColor(m.linearToGamma(color[1]/4,color[2]/4,color[3]/4)) 59 | local cx, cy = math.floor((x - (w-20*s))/20), math.floor(y/20) 60 | g.rectangle("fill",cx,cy,1,1) 61 | g.setCanvas() 62 | end 63 | 64 | function love.keypressed(k,s,r) 65 | if k == "escape" then love.event.quit(0) end 66 | local id = tonumber(k) 67 | if color[id] then color[id] = (color[id]+1)%5 end 68 | if k == "h" then hint = not hint end 69 | if k == "space" then bleed = not bleed end 70 | end 71 | -------------------------------------------------------------------------------- /codenames/words.lua: -------------------------------------------------------------------------------- 1 | local words = [[ 2 | africa 3 | agent 4 | air 5 | alien 6 | amazon 7 | angel 8 | antarctica 9 | apple 10 | arm 11 | back 12 | band 13 | bank 14 | bark 15 | beach 16 | belt 17 | berlin 18 | berry 19 | board 20 | bond 21 | boom 22 | bow 23 | box 24 | bug 25 | canada 26 | capital 27 | cell 28 | center 29 | china 30 | chocolate 31 | circle 32 | club 33 | compound 34 | copper 35 | crash 36 | cricket 37 | cross 38 | death 39 | dice 40 | dinosaur 41 | doctor 42 | dog 43 | dress 44 | dwarf 45 | eagle 46 | egypt 47 | engine 48 | england 49 | europe 50 | eye 51 | fair 52 | fall 53 | fan 54 | field 55 | file 56 | film 57 | fish 58 | flute 59 | fly 60 | forest 61 | fork 62 | france 63 | gas 64 | ghost 65 | giant 66 | glass 67 | glove 68 | gold 69 | grass 70 | greece 71 | green 72 | ham 73 | head 74 | himalaya 75 | hole 76 | hood 77 | hook 78 | human 79 | horseshoe 80 | hospital 81 | hotel 82 | ice 83 | ice cream 84 | india 85 | iron 86 | ivory 87 | jam 88 | jet 89 | jupiter 90 | kangaroo 91 | ketchup 92 | kid 93 | king 94 | kiwi 95 | knife 96 | knight 97 | lab 98 | lap 99 | laser 100 | lawyer 101 | lead 102 | lemon 103 | limousine 104 | leadlock 105 | log 106 | mammoth 107 | maple 108 | march 109 | mass 110 | mercury 111 | millionaire 112 | model 113 | mole 114 | moscow 115 | mouth 116 | mug 117 | needle 118 | net 119 | new york 120 | night 121 | note 122 | novel 123 | nurse 124 | nut 125 | oil 126 | olive 127 | olympus 128 | opera 129 | orange 130 | paper 131 | park 132 | part 133 | paste 134 | phoenix 135 | piano 136 | telescope 137 | teacher 138 | switch 139 | swing 140 | sub 141 | stick 142 | staff 143 | stadium 144 | sprint 145 | spike 146 | snowman 147 | slip 148 | shot 149 | shadow 150 | server 151 | ruler 152 | row 153 | rose 154 | root 155 | rome 156 | rock 157 | robot 158 | robin 159 | revolution 160 | rat 161 | racket 162 | queen 163 | press 164 | port 165 | pilot 166 | time 167 | tooth 168 | tower 169 | truck 170 | triangle 171 | trip 172 | turkey 173 | undertaker 174 | unicorn 175 | vacuum 176 | van 177 | wake 178 | wall 179 | war 180 | washer 181 | washington 182 | water 183 | wave 184 | well 185 | whale 186 | whip 187 | worm 188 | yard 189 | ]] 190 | 191 | local w = {} 192 | 193 | local _start = 0 194 | local _end = 0 195 | 196 | while _end do 197 | _start, _end = _end+1, string.find(words, "\n", _end+1) 198 | w[#w+1] = string.sub(string.sub(words, _start, _end or _start+1), 1, -2) 199 | end 200 | w[#w] = nil 201 | 202 | return w -------------------------------------------------------------------------------- /shady grass/gs.glsl: -------------------------------------------------------------------------------- 1 | #pragma language glsl3 2 | varying float n; 3 | varying vec3 col; 4 | uniform vec2 size; 5 | uniform sampler2D vb; 6 | uniform float dt; 7 | 8 | //iq noise function 9 | float hash(vec2 p){ // replace this by something better 10 | p = 50.0*fract( p*0.3183099 + vec2(0.71,0.113)); 11 | return -1.0+2.0*fract( p.x*p.y*(p.x+p.y) ); 12 | } 13 | float noise( in vec2 p ){ 14 | vec2 i = floor( p ); 15 | vec2 f = fract( p ); 16 | vec2 u = f*f*(3.0-2.0*f); 17 | return mix( mix( hash( i + vec2(0.0,0.0) ), 18 | hash( i + vec2(1.0,0.0) ), u.x), 19 | mix( hash( i + vec2(0.0,1.0) ), 20 | hash( i + vec2(1.0,1.0) ), u.x), u.y); 21 | } 22 | vec3 hsv(float h,float s,float v) { 23 | return mix(vec3(1.),clamp((abs(fract(h+vec3(3.,2.,1.)/3.)*6.-3.)-1.),0.,1.),s)*v; 24 | } 25 | #ifdef VERTEX 26 | vec4 position( mat4 transform_projection, vec4 vertex_position ){ 27 | n = noise(vec2(gl_InstanceID*0.23156464)); //there is definitely a better way to get random number, this one is just a drop in solution 28 | float h = 0.857*n-7.295; 29 | float d = dt/17.; 30 | ivec2 id = ivec2(gl_VertexID%2, gl_VertexID/2); 31 | vec2 p[8]; 32 | float l[7]; 33 | for(int i=0; i<8; i++) p[i] = vec2(mod(1.7*gl_InstanceID+n, size.x) + abs(n)*n*(i*2), h*i + size.y*0.69 - 1.); //initial grass blade position 34 | for(int i=0; i<7; i++) l[i] = length(p[i+1]-p[i]); 35 | for(int j=0; j<5; j++){ //five iterations of our verlet-like solver 36 | for(int i=1; i<8; i++){ //root stays at the same place hence starting with offset of 1 37 | vec2 vel = textureLod(vb, p[i]/size, 0).xy; 38 | p[i] += vel*d*i*i*(.5+n*n); 39 | } 40 | for(int i=6; i>0; i--) p[i] = p[i+1] + normalize(p[i]-p[i+1])*l[i]; 41 | for(int i=1; i<8; i++) p[i] = p[i-1] + normalize(p[i]-p[i-1])*l[i-1]; 42 | } 43 | vec2 offset = id.y!=0 ? normalize(p[id.y-1]-p[id.y]) : vec2(.0, 1.); 44 | offset = vec2(-offset.y, offset.x); 45 | col = vec3(.0,.5-(abs(n))*0.2,.0); 46 | if(id.y == 7 && mod(1.-n*n, .37) < 0.018){ 47 | offset *= 13.+(gl_InstanceID%3+2)*(1.-n); 48 | col = hsv(gl_InstanceID*n,1.-abs(n),1.); 49 | } 50 | 51 | p[id.y] += offset*(1.-(id.x)*2.)/(sqrt(float(id.y))+1.); 52 | vertex_position.xy = p[id.y]; 53 | return transform_projection * vertex_position; 54 | } 55 | #endif 56 | 57 | #ifdef PIXEL 58 | vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords ){ 59 | color = vec4(col,1.); 60 | vec4 texcolor = Texel(tex, texture_coords); 61 | return texcolor * color; 62 | } 63 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lovely little experiments 2 | is a collection of small projects you can run with [löve](https://love2d.org/) 3 | 4 | ## ad astra 5 | simple starfield rendering exploration 6 | - uv scrolling 7 | - 2d points mesh scrolling 8 | - 3d mesh dome rotation 9 | 10 | ## big squares 11 | proof of concept for "pixelart" upscaling using huge mesh and MSAA, plaese don't take it seriously 12 | 13 | ## bit umbra 14 | an experiment with *sort of* stencil 2d shadows/visibility that draws 64 shadowcasting 2D lights 15 | 16 | ## blood sample 17 | port of my old SDF raymarching shadertoy demo 18 | 19 | ## codenames 20 | codenames implementation for playing on streams 21 | 22 | ## deferred 23 | deferred lighting example, assets provided by @flamendless 24 | 25 | ## filmgrain 26 | a simplistic decent looking film grain post-processing effect in five lines of shader code 27 | 28 | ## glowybits 29 | blending/postprocessing effect for banded dithered lights 30 | 31 | ## palette 32 | palette rendering example 33 | 34 | ## pong 35 | simple pong game that features pretty much everything a pong game needs 36 | 37 | ## ponger 38 | same pong with interpolation, extrapolation, fixed/relaxed timestep, and adjustable tickrate and framerate 39 | - space to pause the game and bring up simulation settings 40 | - there are four gamestates you can color differently 41 | - use fixed to toggle beetwen fixed/relaxed timestep 42 | - use slow to toggle slow mode to truly appreciat that 10 tickrate interpolation 43 | - tickrate defines physics updates per second for a fixed timestep 44 | - frametime sets a minimum time for a frame to update + render in ms to simulate lower framerates, affects relaxed timestep simulation 45 | - fluctuation adds random time in ms to each frame rendered to simulate unstable framerate 46 | 47 | ## R3helper examples 48 | a set of 3d rendering programs using R3helper functions to simplify 3d transformations in löve 49 | in ascending complexity 50 | - ### spinning_cube 51 | you would not believe what it does! 52 | - ### textures 53 | adds textures to a cube 54 | - ### instancing 55 | renders lots of cubes fast 56 | - ### depth peeling 57 | order independent transparency with 16 layers 58 | - ### camera 59 | it's almost like you're there! 60 | - ### shadows 61 | renders shadowmap with HW PCF 62 | 63 | ## shady grass 64 | instanced grass generated and animated in a shader 65 | 66 | ## voronoi 67 | exploration of voronoi diagrams rendering using gpu thech 68 | 69 | ## voxter 70 | voxel space algorithm that runs in a shader 71 | -------------------------------------------------------------------------------- /r3helper examples/depth_peeling/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | 3 | local R3 = require("R3helper") 4 | 5 | g.setMeshCullMode("back") 6 | g.setFrontFaceWinding("ccw") 7 | g.setDepthMode("less", true) 8 | 9 | local cube = require("ciwb") 10 | 11 | local n = 16 --number of layers 12 | local div = 1 --render at 1/div resolution 13 | local w,h = g.getDimensions() 14 | w,h = w/div,h/div 15 | 16 | local layers = g.newCanvas(w,h,n,{type="array"}) 17 | 18 | local d = g.newCanvas(w,h, {format = "depth24", readable = true}) 19 | local pd = g.newCanvas(w,h, {format = "depth24", readable = true}) 20 | local dd = g.newCanvas(1,1, {format = "r8"}) --dummy depth sampler for the first layer 21 | 22 | --instanced ciwbiau 23 | local pf = {{"pos", "float", 3}} 24 | local cubes = g.newMesh(pf, 32*32*32, nil, "dynamic") 25 | 26 | local spread = 3 27 | local id = 1 28 | for i = 1,32 do 29 | for j = 1,32 do 30 | for k = 1,32 do 31 | cubes:setVertex(id, {spread*(i-16), spread*(k-16), spread*(j-16)}) 32 | id = id+1 33 | end 34 | end 35 | end 36 | 37 | cube:attachAttribute("pos", cubes, "perinstance") 38 | 39 | local oit_instanced = g.newShader("icube.glsl") 40 | 41 | local origin = R3.new_origin(true, w,h) 42 | 43 | local setup = {{}} 44 | 45 | function love.draw() 46 | local t = love.timer.getTime() 47 | g.setDepthMode("less", true) 48 | g.replaceTransform(origin) 49 | g.applyTransform( 50 | R3.translate(0,0,2.5) * 51 | R3.rotate(R3.aa_to_quat(0, 1, 0, .1*t%(math.pi*2))) * 52 | R3.scale(.024, .024, .024) 53 | ) 54 | g.setShader(oit_instanced) 55 | 56 | --first layer with dummy depth sampler 57 | --pretty much the same as the loop later 58 | setup[1][1] = layers 59 | setup[1].layer = 1 60 | setup.depthstencil = d 61 | g.setCanvas(setup) 62 | g.clear() 63 | oit_instanced:send("d", dd) 64 | g.drawInstanced(cube, 32*32*32) 65 | for i = 2, n do --already have the first layer 66 | d,pd = pd,d --swap previous and current depthbuffer 67 | setup[1].layer = i -- render to the next layer 68 | setup.depthstencil = d -- with the empty depthbuffer(cleared later) 69 | oit_instanced:send("d", pd) --prev depth will be sampled to discard already rendered layers 70 | g.setCanvas(setup) 71 | g.clear() --clear canvas and depth 72 | g.drawInstanced(cube, 32*32*32) 73 | end 74 | 75 | g.setShader() 76 | g.setCanvas() 77 | g.origin() 78 | g.setDepthMode("always", false) 79 | g.setColor(1,1,1,.1) -- transparent layers 80 | for i = n,1,-1 do -- in reverse order 81 | g.drawLayer(layers,i,0,0,0,div,div) 82 | end 83 | g.setColor(1,1,1,1) 84 | g.print(love.timer.getDelta()) 85 | g.print(g.getStats().drawcalls, 0, 20) 86 | g.print(love.timer.getFPS(), 0, 40) 87 | end 88 | 89 | function love.keypressed(k,s,r) 90 | if k == "escape" then love.event.quit(0) end 91 | end 92 | -------------------------------------------------------------------------------- /where is zalgo/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local rnd = love.math.newRandomGenerator() 3 | local w,h = love.graphics.getDimensions() 4 | 5 | local sort_en = true 6 | local number_of_dudes = 5000 7 | local dude_velocity = 60 8 | 9 | local function sort(a,b) return a.y dude.x and 1 or -1 32 | dudes[i] = dude 33 | batch_of_dudes:add(0,0) 34 | end 35 | 36 | function love.update(dt) 37 | --move dudes 38 | for _, dude in ipairs(dudes) do 39 | local dx, dy = dude.dest_x - dude.x, dude.dest_y - dude.y 40 | local d = math.sqrt(dx*dx+dy*dy) 41 | if dude.t > 0 then -- idle 42 | dude.t = dude.t - dt*10 43 | elseif d < dude_velocity*dt then -- change direction and wait a bit 44 | dude.x, dude.y = dude.dest_x, dude.dest_y 45 | dude.t = rnd:random(10,105) 46 | dude.dest_x = rnd:random(-100, w+100) 47 | dude.dest_y = rnd:random(-100, h+100) 48 | dude.dir = dude.dest_x > dude.x and 1 or -1 49 | else -- walk around 50 | dude.x = dude.x + dude_velocity*dt*dx/d 51 | dude.y = dude.y + dude_velocity*dt*dy/d 52 | dude.d_walked = (dude.d_walked + dude_velocity*dt)%20 53 | end 54 | end 55 | if sort_en then 56 | table.sort(dudes,sort) 57 | end 58 | for i, dude in ipairs(dudes) do 59 | local quad 60 | if dude.t > 0 then 61 | local idle_index = math.floor((dude.t%3)/1.5) -- 0 or 1 in idle 62 | quad = dude_frames[1+idle_index] 63 | else 64 | local walk_index = math.floor(dude.d_walked/10) -- 0 ir 1 in walking 65 | quad = dude_frames[3+walk_index] 66 | end 67 | batch_of_dudes:set(i,quad,math.floor(dude.x),math.floor(dude.y),0,dude.dir,1,16,32,0,0) 68 | end 69 | end 70 | 71 | function love.draw() 72 | if not sort_en then 73 | g.setShader(depth_shader) 74 | depth_shader:send("depth_scale", h*2) 75 | g.setDepthMode("less", true) 76 | end 77 | g.draw(batch_of_dudes) 78 | g.setDepthMode() 79 | g.setShader() 80 | g.setColor(0,0,0) 81 | g.rectangle("fill",0,0,200,60) 82 | g.setColor(1,1,1) 83 | g.print(love.timer.getDelta()) 84 | g.print(love.timer.getFPS(),0,20) 85 | g.print("sort: "..tostring(sort_en).." (space to change)",0,40) 86 | end 87 | 88 | function love.keypressed(k,s,r) 89 | if k == "space" then sort_en = not sort_en end 90 | if k == "escape" then love.event.quit(0) end 91 | end 92 | -------------------------------------------------------------------------------- /r3helper examples/camera/main.lua: -------------------------------------------------------------------------------- 1 | local g = love.graphics 2 | local R3 = require("R3helper") 3 | 4 | g.setMeshCullMode("back") 5 | g.setFrontFaceWinding("ccw") 6 | g.setDepthMode("less", true) 7 | 8 | local cube = require("ciwb") 9 | 10 | local origin = R3.new_origin(true, g.getDimensions()) 11 | 12 | love.mouse.setRelativeMode(true) 13 | love.mouse.setGrabbed(true) 14 | 15 | local player = { 16 | x = 0, 17 | y = 0, 18 | z = 0, 19 | hor = 0, 20 | ver = 0, 21 | } 22 | 23 | local max_ver_angle = math.pi*.25 24 | local sens = .01 25 | local function rotate_camera(dx,dy) 26 | player.hor = (player.hor+dx*sens)%(2*math.pi) 27 | player.ver = math.max(-max_ver_angle, math.min(max_ver_angle, player.ver + dy*sens)) 28 | end 29 | 30 | function love.mousemoved(x, y, dx, dy) 31 | rotate_camera(dx, dy) 32 | end 33 | 34 | local velocity = 7 35 | function love.update(dt) 36 | local forward, sideways = 0, 0 37 | if love.keyboard.isScancodeDown("w") then 38 | forward = 1 39 | end 40 | if love.keyboard.isScancodeDown("s") then 41 | forward = forward - 1 42 | end 43 | if love.keyboard.isScancodeDown("a") then 44 | sideways = -1 45 | end 46 | if love.keyboard.isScancodeDown("d") then 47 | sideways = sideways + 1 48 | end 49 | do 50 | local l = math.sqrt(forward*forward + sideways*sideways) 51 | if l ~= 0 then 52 | forward, sideways = forward/l, sideways/l 53 | end 54 | end 55 | player.z = player.z + ( forward*math.cos(player.hor) - sideways*math.sin(player.hor) )*dt*velocity 56 | player.x = player.x + ( sideways*math.cos(player.hor) + forward*math.sin(player.hor) )*dt*velocity 57 | end 58 | 59 | local rng = love.math.newRandomGenerator() 60 | function love.draw() 61 | local t = love.timer.getTime() 62 | g.setDepthMode("less", true) 63 | g.replaceTransform(origin) 64 | g.applyTransform( 65 | R3.rotate(R3.aa_to_quat(1,0,0,player.ver)) * --rotate the camera 66 | R3.rotate(R3.aa_to_quat(0,1,0,player.hor)) * --rotate the camera 67 | R3.translate(-player.x, -player.y, -player.z) --move the camera 68 | ) 69 | 70 | g.push() 71 | g.applyTransform( 72 | R3.translate(0,-2,0) * --move the ground 73 | R3.scale(10,1,10) --scale the ground 74 | ) 75 | g.draw(cube) --draw the ground 76 | g.pop() 77 | 78 | rng:setSeed(31337) 79 | for i=1,33 do 80 | g.push() 81 | g.applyTransform( 82 | R3.translate(-8+16*rng:random(),-rng:random(),-8+16*rng:random()) * --move a cube 83 | R3.rotate(R3.aa_to_quat(0,1,0,rng:random()*math.pi*2)) * --rotate the cube 84 | R3.scale(.3+rng:random()*.3,1,.3+rng:random()*.5) --scale the cube 85 | ) 86 | g.draw(cube) --draw the cube 87 | g.pop() 88 | end 89 | 90 | g.origin() 91 | g.setDepthMode("always", false) 92 | g.print(love.timer.getDelta()) 93 | g.print(g.getStats().drawcalls, 0, 20) 94 | g.print(love.timer.getFPS(), 0, 40) 95 | end 96 | 97 | function love.keypressed(k,s,r) 98 | if k == "escape" then love.event.quit(0) end 99 | end 100 | -------------------------------------------------------------------------------- /shady grass/main.lua: -------------------------------------------------------------------------------- 1 | local w,h = love.graphics.getDimensions() 2 | love.window.setMode(w, h, {msaa=8}) --smooth like fine wine 3 | 4 | local s = 1/8 5 | 6 | local p = {x=w*(1-0.69), y=0, vx = 0, vy = 0, l = false} --player 7 | local pp = {} 8 | local g = 1337 --gravity 9 | local gr = h*0.69 --ground plane 10 | local _dt 11 | 12 | --graphics related stuff, mesh, shader, velocity buffers 13 | local grass_blade_mesh = love.graphics.newMesh(16, "strip", "static") --we will generate geometry in the shader 14 | local vb = {} 15 | for i=1,2 do 16 | vb[i] = love.graphics.newCanvas(w*s, h*s, {type="2d", format="rg32f", readable=true, msaa=0, mipmaps="none"}) 17 | end 18 | local gs = love.graphics.newShader("gs.glsl") --grass rendering shader 19 | local vs = love.graphics.newShader("vs.glsl") --velocity shader 20 | local vbs = love.graphics.newShader("vbs.glsl") --liquid dynamics shader 21 | 22 | love.update = function(dt) 23 | _dt = dt 24 | pp.x, pp.y = p.x, p.y --I might need it 25 | local d = (love.keyboard.isDown("left") and -1 or 0) + (love.keyboard.isDown("right") and 1 or 0) --move direction 26 | 27 | p.vx = d* (love.keyboard.isDown("lshift") and 123 or 321) 28 | p.x = p.x + p.vx*dt 29 | 30 | p.vy = (love.keyboard.isDown("up") and p.y >= gr-2) and -456.7 or p.vy + g*dt 31 | p.y = p.y + p.vy*dt 32 | if p.y > gr-1 then 33 | if p.vy > 200 then p.l = true end 34 | p.y, p.vy = gr-1, 0 35 | end 36 | end 37 | 38 | love.draw = function() 39 | love.graphics.draw(vb[1],0,0,0,8,8) 40 | love.graphics.setColor(0.7,0.2,0.2,1) 41 | love.graphics.rectangle("fill", p.x-15, p.y-69, 30, 69) 42 | 43 | love.graphics.setColor(1,1,1,1) 44 | 45 | love.graphics.setCanvas(vb[1]) 46 | love.graphics.setShader(vs) 47 | love.graphics.setBlendMode("add") 48 | vs:send("vel",{p.vx,math.max(p.vy,0)}) 49 | love.graphics.rectangle("fill", (p.x-5)*s, (p.y-69)*s, 10*s, 60*s) 50 | if p.l then 51 | p.l = false 52 | vs:send("vel",{p.vx+22222, 2222}) 53 | love.graphics.rectangle("fill", (p.x+15)*s, (p.y-69)*s, 30*s, 50*s) 54 | vs:send("vel",{p.vx-22222, 2222}) 55 | love.graphics.rectangle("fill", (p.x-45)*s, (p.y-69)*s, 30*s, 50*s) 56 | --draw landing 57 | end 58 | 59 | love.graphics.setBlendMode("replace") 60 | love.graphics.setCanvas(vb[2]) 61 | love.graphics.setShader(vbs) 62 | --vbs:send("dt", _dt) 63 | love.graphics.draw(vb[1]) 64 | vb[1], vb[2] = vb[2], vb[1] --swap buffers 65 | 66 | love.graphics.setCanvas() 67 | love.graphics.setShader(gs) 68 | gs:send("size", {w,h}) 69 | gs:send("vb", vb[1]) 70 | gs:send("dt", _dt) 71 | love.graphics.drawInstanced(grass_blade_mesh, math.floor(w/1.7*2)) 72 | love.graphics.setShader() 73 | love.graphics.print("left/right to move\nup to jump\nleft shift to walk",10,30) 74 | love.graphics.print(love.timer.getFPS(),10,10) 75 | love.graphics.setColor(0,0,0,1) 76 | love.graphics.rectangle("fill",0,gr,w,100) 77 | love.graphics.setColor(1,1,1,1) 78 | love.graphics.line(-10, gr, w+20, gr) 79 | end 80 | 81 | love.keypressed = function(k,s,r) 82 | if s=='escape' then love.event.quit(0) end 83 | end 84 | -------------------------------------------------------------------------------- /voxter/main.lua: -------------------------------------------------------------------------------- 1 | local fl = {mipmaps = true} 2 | local cm = love.graphics.newImage("C1W.png", fl) 3 | local dm = love.graphics.newImage("D1.png", fl) 4 | local mr = "mirroredrepeat" 5 | cm:setWrap(mr,mr) 6 | dm:setWrap(mr,mr) 7 | cm:setFilter("nearest") 8 | dm:setFilter("nearest") 9 | 10 | local rows = 1024 11 | local vt_shader = love.graphics.newShader("vt.glsl") 12 | local vt_mesh = love.graphics.newMesh(4*400*rows, "triangles","static") 13 | --we're doing merege instancing because hw instancing for quads is suboptimal 14 | --*when* null vertex buffers are implemented in love we won't need no mesh at all 15 | 16 | local vert_map = {} 17 | 18 | for i=1,400*rows do 19 | local o = i*4-4 20 | vert_map[#vert_map+1] = 1+o 21 | vert_map[#vert_map+1] = 2+o 22 | vert_map[#vert_map+1] = 3+o 23 | vert_map[#vert_map+1] = 3+o 24 | vert_map[#vert_map+1] = 2+o 25 | vert_map[#vert_map+1] = 4+o 26 | end 27 | vt_mesh:setVertexMap(vert_map) --this index buffer is there to make things simpler in vs 28 | vt_mesh:setTexture(cm) 29 | 30 | local map = love.graphics.newQuad(0,0,1024,1024,1024,1024) 31 | 32 | local controls = {fwd=0, bwd=0, stl=0, str=0, ll=0, lr=0, uwd=0, dwd=0,} 33 | local bindings = {w="fwd", a="stl", s="bwd", d="str", q="ll", e="lr", space = "uwd", lshift = "dwd"} 34 | local sens = 0.002 35 | 36 | local px,py,pz, dx,dy = 0,0,120,1,0 37 | local v = 100 38 | 39 | love.mouse.setRelativeMode(true) 40 | 41 | function cam_rotate(a) 42 | local c, s = math.cos(a), math.sin(a) 43 | dx,dy = dx*c-dy*s, dx*s+dy*c 44 | local l = math.sqrt(dx*dx+dy*dy) 45 | dx, dy = dx/l, dy/l 46 | end 47 | 48 | function love.update(dt) 49 | local forward = controls.fwd - controls.bwd 50 | local rightward = controls.stl - controls.str 51 | local upward = controls.uwd - controls.dwd 52 | local vx, vy, vz = (forward*dx + rightward*dy)*v*dt, (forward*dy - rightward*dx)*v*dt, upward*v*dt*0.75 53 | local a = controls.lr - controls.ll 54 | cam_rotate(a * math.pi*0.5 * dt) 55 | px, py, pz = (px + vx)%2048, (py + vy)%2048, math.max(25, math.min(pz+vz, 166)) 56 | end 57 | 58 | function love.draw() 59 | love.graphics.setDepthMode("less", true) 60 | vt_shader:send("dm", dm) 61 | vt_shader:send("dir", {dx, dy}) 62 | vt_shader:send("pos", {px, py, pz}) 63 | love.graphics.setShader(vt_shader) 64 | love.graphics.draw(vt_mesh)--this line is the raycasting part :D 65 | love.graphics.reset() 66 | map:setViewport(0+px, 0+py, 1024, 1024) 67 | love.graphics.scale(1/8,1/8) 68 | love.graphics.draw(cm,map,0,0) 69 | love.graphics.reset() 70 | love.graphics.setColor(0,1,0,1) 71 | love.graphics.polygon("fill",64+dx*16,64+dy*16, 64-dy*2,64+dx*2, 64+dy*2,64-dx*2) 72 | love.graphics.reset() 73 | love.graphics.print("WASD+shift+space to move\nQE and/or mouse to look\nFPS:"..love.timer.getFPS(), 600, 10) 74 | end 75 | 76 | function love.mousemoved(x,y,ox,oy) 77 | cam_rotate(ox*sens) 78 | end 79 | 80 | function love.keypressed(k,s,r) 81 | if s == "escape" then love.event.quit(0) end 82 | if bindings[s] then controls[bindings[s]] = 1 end 83 | end 84 | 85 | function love.keyreleased(k,s) 86 | if bindings[s] then controls[bindings[s]] = 0 end 87 | end -------------------------------------------------------------------------------- /move along/catmull_rom.lua: -------------------------------------------------------------------------------- 1 | local spline = {} 2 | 3 | local function knot(t,a, ax,ay, bx,by) 4 | return t + ((bx-ax)*(bx-ax) + (by-ay)*(by-ay))^(.5*a) 5 | end 6 | 7 | function spline:evaluate(i, t, alpha, loop) 8 | local np = self:getControlPointCount() 9 | local x0,y0,x1,y1,x2,y2,x3,y3 10 | if loop then 11 | assert(np >= 3, "need at least 3 control points for looping spline") 12 | x0,y0 = self:getControlPoint(1+((i-2)%np)) 13 | x1,y1 = self:getControlPoint(1+((i-1)%np)) 14 | x2,y2 = self:getControlPoint(1+((i)%np)) 15 | x3,y3 = self:getControlPoint(1+((i+1)%np)) 16 | else 17 | assert(np>3, "need at least 4 control points") 18 | assert(i>1, "first segment can't be evaluated in non-looping mode") 19 | assert(i