Code Doodles!

General discussion about LÖVE, Lua, game development, puns, and unicorns.
PGUp
Citizen
Posts: 72
Joined: Fri Apr 21, 2017 9:17 am

Re: Code Doodles!

Post by PGUp » Sun Jul 01, 2018 5:52 am

frac.png
frac.png (26.3 KiB) Viewed 1882 times
generating fractal, one pixel at a time

Code: Select all

function getDist(x1, y1, x2, y2)
return math.sqrt(math.pow(x2 - x1, 2) + math.pow(y2 - y1, 2))
end

function getPos(x, y, rot, dist)
return x - math.sin(rot) * dist, y + math.cos(rot) * dist
end

function getAngle(x1, y1, x2, y2)
return math.atan2(x1 - x2, y2 - y1)
end

function love.load()
math.randomseed(os.time())
lg = love.graphics
lw = love.window
lw.setMode(500, 500)
poly = {}
for i=1, 3, 1 do
local p = {}
p.x = 250 - math.sin(math.rad(60) + i*math.rad(360)/3)*200
p.y = 250 + math.cos(math.rad(60) + i*math.rad(360)/3)*200
table.insert(poly, p)
end
points = {}
local r1 = math.random()
local r2 = math.random()
local p = {}
p.x = (1 - math.sqrt(r1)) * poly[1].x + (math.sqrt(r1) * (1 - r2)) * poly[2].x + (math.sqrt(r1) * r2) * poly[3].x 
p.y = (1 - math.sqrt(r1)) * poly[1].y + (math.sqrt(r1) * (1 - r2)) * poly[2].y + (math.sqrt(r1) * r2) * poly[3].y
table.insert(points, p)
--MAX POINTS
spawn = 10000
end

function love.update()
if spawn > 0 then
--MODIFY THIS FOR LOOP TO CHANGE THE SPEED OF THE GENERATOR
for i=1, 10, 1 do
local p = {}
local pick = math.random(1, 3)
local distance = getDist(points[#points].x, points[#points].y, poly[pick].x, poly[pick].y)
local angle = getAngle(points[#points].x, points[#points].y, poly[pick].x, poly[pick].y)
p.x, p.y = getPos(points[#points].x, points[#points].y, angle, distance/2)
table.insert(points, p)
spawn = spawn - 1
end
end
end

function love.draw()
for i,v in pairs(poly) do
lg.setColor(1,1,1)
lg.circle("fill", v.x, v.y, 5)
end
lg.setColor(1,0,0)
for i,v in pairs(points) do
lg.circle("fill", v.x, v.y, 1)
end
end
-

User avatar
rmcode
Party member
Posts: 453
Joined: Tue Jul 15, 2014 12:04 pm
Location: Germany
Contact:

Re: Code Doodles!

Post by rmcode » Tue Oct 02, 2018 8:48 pm


User avatar
veethree
Inner party member
Posts: 800
Joined: Sat Dec 10, 2011 7:18 pm

Re: Code Doodles!

Post by veethree » Thu Nov 08, 2018 5:53 pm

Wrote a function that extracts colors from an image. It does this in a very naive way so it only works good sometimes.
1541699302.png
1541699302.png (432.87 KiB) Viewed 1103 times
The attachment 1541699312.png is no longer available
The attachment 1541699302.png is no longer available

Code: Select all

function love.load()
	http = require("socket.http")
	s = ""
	love.window.setMode(640, 480)
	love.graphics.setLineStyle("rough")

	local img = getImage()
	image = love.graphics.newImage(img)

	color = scanImage(img)
	sprint("Total pixels: "..(640 * 480))
	sprint("Extracted colors: "..#color)
	sprint("Hold space to show colors")
end

function sprint(t)
	s = s..t.."\n"
end

function scanImage(data, skip, distance)
	skip = skip or 10
	distance = distance or 1

	local colors = {}
	for y=0, data:getHeight()-1, skip do
		for x=0, data:getWidth()-1, skip do
			local r, g, b, a = data:getPixel(x, y)

			local add = true
			for i,v in ipairs(colors) do
				if colorDistance(v, {r, g, b, a}) < distance then
					add = false
				end
			end

			if add then
				colors[#colors + 1] = {r, g, b, a}
			end
		end
	end

	return colors
end

function love.update(dt)

end

function love.draw()
	if image then love.graphics.draw(image) end

	for i,v in ipairs(color) do
		love.graphics.setColor(v)
		love.graphics.rectangle("fill", (love.graphics.getWidth() / #color) * (i - 1), love.graphics.getHeight() - 64, love.graphics.getWidth() / #color, 64)
	end

	love.graphics.setColor(1, 1, 1)
	love.graphics.print(s, 12, 12)
end

function love.keypressed(key)
	if key == "escape" then love.event.push("quit") end
	if key == "r" then
		love.load()
	end

	if key == "1" then
		love.graphics.captureScreenshot(os.time()..".png")
	end
end

function colorDistance(a, b)
	return math.abs(a[1] - b[1]) + math.abs(a[2] - b[2]) + math.abs(a[3] - b[3])
end

function getImage()
	local body, code = http.request("https://picsum.photos/640/480/?random")
	local data = false
	if body then
		love.filesystem.write("tmp.jpg", body)
		data = love.image.newImageData("tmp.jpg")
		love.filesystem.remove("tmp.jpg")
	else
		error(code)
	end


	return data
end

User avatar
pgimeno
Party member
Posts: 1366
Joined: Sun Oct 18, 2015 2:58 pm

Re: Code Doodles!

Post by pgimeno » Wed Dec 05, 2018 3:33 pm

I made this to visualize the bias in formulas for picking random points from the surface of a unit sphere, using four different methods. It rotates the sphere (in orthographic projection) so it can be seen from several angles. It looked nice so I thought I'd add it to this thread too:

Code: Select all

local rng
local sin, cos, sqrt, pi = math.sin, math.cos, math.sqrt, math.pi

local tf = love.math.newTransform()
local tf2 = love.math.newTransform()
local pts = {}

local npts = 80000

local function randvec3d_1()
  local x = rng:random() * 2 * pi
  local y = rng:random() * 2 * pi
  local z = sin(y)
  return { x = cos(x) * z, y = sin(x) * z, z = cos(y) }
end

local function randvec3d_2()
  local x = rng:random() * 2 - 1
  local y = rng:random() * 2 - 1
  local z = rng:random() * 2 - 1
  local r = sqrt(x*x+y*y+z*z)
  return {x = x/r, y = y/r, z = z/r}
end

local function randvec3d_3()
  local x, y, z, r
  repeat
    x = rng:random() * 2 - 1
    y = rng:random() * 2 - 1
    z = rng:random() * 2 - 1
    r = sqrt(x*x+y*y+z*z)
  until r >= 0.0001 and r < 1
  return {x = x/r, y = y/r, z = z/r}
end

local function randvec3d_4()
  local z = rng:random()*2 - 1
  local a = rng:random()*(2*pi)
  local r = sqrt(1 - z*z)
  return { x = r*cos(a), y = r*sin(a), z = z }
end

local randvec_3d = randvec3d_1

local function regen()
  local len = 0
  for i = 1, npts do
    v = randvec_3d()
    len = len + 3
    pts[len - 2] = v.x
    pts[len - 1] = v.y
    pts[len] = v.z
  end
end

function love.load()
  rng = love.math.newRandomGenerator(love.timer.getTime()*1000000)
  regen()
end

local pt2d = {}

function love.update(dt)
  for i = 1, npts do
    local x, y, z = pts[i*3 - 2], tf:transformPoint(pts[i*3 - 1], pts[i*3])
    pt2d[i*2 - 1], pt2d[i*2] = tf2:transformPoint(x, y), z
  end
  tf:rotate(dt/pi)
  tf2:rotate(dt/3)
end

function love.draw()
  love.graphics.translate(400, 300)
  love.graphics.scale(290, 290)
  love.graphics.points(pt2d)
end

function love.keypressed(_, k)
  if k == "escape" then return love.event.quit() end
  if k == "1" then randvec_3d = randvec3d_1 regen() end
  if k == "2" then randvec_3d = randvec3d_2 regen() end
  if k == "3" then randvec_3d = randvec3d_3 regen() end
  if k == "4" then randvec_3d = randvec3d_4 regen() end
end
The method is chosen with the numbers 1 to 4 in the regular keyboard.

Method 1 picks two random angles and uses them as the spherical coordinates of a point in the sphere. This results in a clear clustering near the poles:
Image

Method 2 picks three random numbers in [-1, 1] and normalizes the resulting vector. This causes clustering in the projection of the edges and vertices of the cube that circumscribes the sphere:
Image

Method 3 is like method 2, but if the length of the vector is > 1 or < 0.0001, it's rejected and another one is picked until one within range is found. The time to obtain a valid vector is unbound, but in practice it doesn't take too many iterations to get a valid one. This results in a good uniform distribution no matter the angle:
Image

Method 4 picks a random point in the curved side of a cylinder with radius 1 that circumscribes the sphere, and then projects the cylinder on the sphere horizontally. This results in a uniform distribution too, essentially equal to method 3, so I haven't taken a snapshot for it.

We can modify the code to prevent projecting the cylinder, by forcing the radius to 1:

Code: Select all

--  local r = sqrt(1 - z*z)
  local r = 1 
and this is the result:

Image

I chose the number of points (npts) so that they can be calculated in a single frame in my computer; you may need to adjust that depending on the required frame rate and how fast your computer is.
Attachments
random-vector-visualize.love
(808 Bytes) Downloaded 7 times
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests