Page 15 of 20

Re: Code Doodles!

Posted: Thu Jan 25, 2018 1:05 pm
by Tst_
creeper9207 wrote: Sun Mar 26, 2017 3:18 pm I sadly don't have the code for this, as it was made by mistake when trying to draw a circle.

-snip-
I managed to do something like that once, I was making a radial menu and I found that if you drew polygons as lines instead of filled they do funky stuff.
Image

Never really finished this project but I might do something out of the code I wrote for it some day.

Re: Code Doodles!

Posted: Thu Feb 01, 2018 2:08 pm
by grump
A simple, quick, and dirty implementation of a depth-search "genetic" algorithm that tries to recreate a reference image using random primitives (noise, lines, circles) and fitness testing.

The reference image I used for testing:
Image

A series of progress images, taken every 250 generations:
Image

3,000 generations took about 15 minutes on my laptop (i7-7700HQ, 2.8 GHz, GTX 1050, using a single core). The last image is made of 158 primitives.

Code: Select all

local rnd = love.math.random

local function randColor()
	return {
		math.floor(rnd(0, 256)),
		math.floor(rnd(0, 256)),
		math.floor(rnd(0, 256)),
		math.floor(rnd(0, 256)),
	}
end

local Line = function(w, h)
	return {
		x1 = rnd(0, w),
		y1 = rnd(0, h),
		x2 = rnd(0, w),
		y2 = rnd(0, h),
		color = randColor(),
		w = rnd(1, 30),

		draw = function(self)
			love.graphics.setColor(self.color)
			love.graphics.setLineWidth(self.w)
			love.graphics.line(self.x1, self.y1, self.x2, self.y2)
		end
	}
end

local Circle = function(w, h)
	return {
		x = rnd(0, w),
		y = rnd(0, h),
		w = rnd(1, 30),
		color = randColor(),
		radius = rnd(0, .5 * math.min(w, h)),
		filled = rnd() < .5,

		draw = function(self)
			love.graphics.setColor(self.color)
			if not self.filled then
				love.graphics.setLineWidth(self.w)
			end
			love.graphics.circle(self.filled and "fill" or "line", self.x, self.y, self.radius)
		end
	}
end

local noise = nil

local Noise = function(w, h)
	if not noise then
		local img = love.image.newImageData(w, h)
		img:mapPixel(function(x, y, r, g, b, a)
			local n = love.math.noise(x + rnd(), y + rnd())
			return 255, 255, 255, 255 * n
		end)
		noise = love.graphics.newImage(img)
	end

	return {
		x = rnd(0, w),
		y = rnd(0, h),
		angle = rnd(0, math.pi * 2),
		sx = rnd(0.1, 10),
		sy = rnd(0.1, 10),
		color = randColor(),

		draw = function(self)
			love.graphics.setColor(self.color)
			love.graphics.draw(noise, self.x, self.y, self.angle, self.sx, self.sy)
		end
	}
end

local shapes = { Noise, Line, Circle, }

local rimg = love.image.newImageData("reference.jpg")
love.window.setMode(rimg:getWidth(), rimg:getHeight() * 3)

local reference = love.graphics.newImage(rimg)
local state = { }
local canvas = love.graphics.newCanvas(reference:getWidth(), reference:getHeight())
local diff = love.graphics.newCanvas(reference:getWidth(), reference:getHeight())
local best = canvas:newImageData()
local bestImage = love.graphics.newImage(best)
local bestFitness = 1e9
local generation = 1
local nochange = 0

local diffShader = love.graphics.newShader([[
	extern Image reference;

	vec4 effect(vec4 color, Image texture, vec2 uv, vec2 fc) {
		vec3 c = abs(Texel(texture, uv).rgb - Texel(reference, uv).rgb);
		return vec4(c.rgb, 1.0);
	}
]])

function fitness()
	local img = diff:newImageData()
	local result = 0
	img:mapPixel(function(x, y, r, g, b, a)
		result = result + r + g + b
		return r, g, b, a
	end)
	return result, img
end

function mutateState()
	local index = rnd(1, #state)
	local rand = rnd()
	if #state == 0 or nochange > 1000 or rand < 1 / #state then
		nochange = 0
		table.insert(state, rnd(1, #state), shapes[rnd(1, #shapes)](reference:getWidth(), reference:getHeight()))
	elseif rand < .25 then
		table.remove(state, index)
	elseif rand < .5 then
		local index2 = rnd(1, #state)
		local temp = state[index]
		state[index] = state[index2]
		state[index2] = temp
	else
		state[index] = shapes[rnd(1, #shapes)](reference:getWidth(), reference:getHeight())
	end
end

function copyState()
	local r = {}
	for i = 1, #state do
		r[i] = state[i]
	end
	return r
end

function love.draw()
	for loop = 1, 256 do
		local old = copyState()
		mutateState()

		canvas:renderTo(function()
			love.graphics.clear(0, 0, 0, 255)
			for i = 1, #state do
				state[i]:draw()
			end
		end)

		love.graphics.setColor(255, 255, 255)

		diff:renderTo(function()
			love.graphics.clear(0, 0, 0, 255)
			love.graphics.setShader(diffShader)
			diffShader:send("reference", reference)
			love.graphics.draw(canvas)
			love.graphics.setShader()
		end)

		local fit, diffImage = fitness()
		if fit < bestFitness then
			best = canvas:newImageData()
			bestImage = love.graphics.newImage(best)
			bestFitness = fit
			generation = generation + 1
			nochange = 0
			if generation % 250 == 0 then
				bestImage:getData():encode("png", string.format("%03d.png", generation / 250))
			end
			break
		else
			nochange = nochange + 1
			state = old
		end
	end

	love.graphics.draw(reference)
	love.graphics.draw(canvas, 0, reference:getHeight())
	love.graphics.draw(bestImage, 0, reference:getHeight() * 2)
	love.graphics.print(bestFitness, 0, 0)
	love.graphics.print("Gen " .. generation .. " (" .. #state .. " primitives)", 0, reference:getHeight() * 2)
end

Re: Code Doodles!

Posted: Sat Feb 03, 2018 1:29 pm
by veethree
This is somewhat inspired by grump's thing, But significantly less interesting. It "evolves" the complete works of Shakespeare from a random string.

Code: Select all

function love.load()
	goal = "The complete works of Shakespeare."
	current = rndstring(#goal)
	gen = 0
	fit = fitness(current)
	finished = false
	run = false

	local f = love.graphics.newFont(18)
	love.graphics.setFont(f)
	love.graphics.setBackgroundColor(220, 220, 220)

	startTime = 0
	endTime = 0
end

function fitness(str)
	local f = 0
	for i=0, #current do
		local c = str:sub(i)
		local g = goal:sub(i)
		local d = dist(c, g)
		f = f + d
	end
	return f
end

function rndstring(length)
	local s = ""
	local alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 '
	for i=1, length do
		local r = math.random(#alphabet)
		s = s..alphabet:sub(r, r)
	end
	return s
end

function mutatestring(str)
	local r = math.random(#str)
	local s = str:sub(0, r-1)
	local c = str:sub(r, r)
	local e = str:sub(r+1)

	local rd = math.random()

	local new = c
	if rd < 0.5 then
		new = string.char(string.byte(c) - 1)
	else
		new = string.char(string.byte(c) + 1)
	end

	return s..new..e
end

function evolve()
	gen = gen + 1

	local n = mutatestring(current)
	local f = fitness(n)
	if f < fit then
		current = n
		fit = f
	end

	if fit == 0 then
		finished = true
		endTime = love.timer.getTime()
	end
end

function love.update(dt)
	if not finished and run then
		evolve()
	end
end

function love.draw()
	if finished then
		love.graphics.setColor(10, 200, 50)
	else
		love.graphics.setColor(255, 10, 10)
	end
	love.graphics.printf("CURRENT\n"..current.."\n\nGOAL\n"..goal.."\n\nGeneration: "..gen.. " | Fitness: "..fit, 0, 12, 800, "center")

	if finished then
		love.graphics.printf("Finished!\nTime: "..(math.floor( (endTime - startTime) * 1000) / 1000).."\nGenerations: "..gen.."\nPress r to reset", 0, 300, 800, "center")
	end
end

function love.keypressed(key)
	if key == "escape" then love.event.push("quit") end
	if key == "space" then
		run = not run	
		if run then
			startTime = love.timer.getTime()
		end
	elseif key == "r" then
		love.load()
	end
end

function dist(a, b)
	return math.abs(string.byte(a) - string.byte(b))
end

Re: Code Doodles!

Posted: Sat Feb 03, 2018 7:03 pm
by jojomickymack
Rectangle mesh tilted back so it's like a chess board and made a waveform of the sketch shader from moonshine. This might be a good game ending animation?
explode.gif
explode.gif (430.94 KiB) Viewed 23340 times

Re: Code Doodles!

Posted: Fri Feb 09, 2018 3:49 pm
by SirRanjid
Flow field with some random squre fish things.

You can drag the background with left mouse and apply some movement like scrolling with your smartphone.

Image
flow_field.love
(3.22 KiB) Downloaded 625 times

Re: Code Doodles!

Posted: Sun Feb 11, 2018 2:17 am
by s-ol
spiral around a 3d torus very simply projected to 2d and rendered as many circles:
Image
(source)

This eventually led to an this 4d torus explorer program: https://github.com/s-ol/torus4d

Re: Code Doodles!

Posted: Thu Feb 15, 2018 2:53 am
by SirRanjid
Maybe not a doodle anymore but I've taken the fish to the next level.
Also cleaner and more commented code.

Image

Re: Code Doodles!

Posted: Sun Apr 29, 2018 7:51 pm
by veethree
Why? Eye don't know.
eyedontknow.gif
eyedontknow.gif (769.9 KiB) Viewed 22805 times

Code: Select all

---EYE STUFF
eye = {}
local em = {__index = eye}

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

local function distance(x1, y1, x2, y2)
	return ((x2-x1)^2+(y2-y1)^2)^0.5
end

local function normal(val, min, max)
	return (val - min) / (max - min)
end

function eye.new(x, y, radius, irisRadius, irisColor, pupilDialation)
	local e = {
		x = x,
		y = y,
		dx = x,
		dy = y,
		ix = x,
		iy = y,
		dix = x,
		diy = y,
		radius = radius,
		irisRadius = irisRadius,
		irisColor = irisColor,
		pupilDialation = pupilDialation,
		blinkProgress = 1
	}
	return setmetatable(e, em)
end

function eye:update(dt)
	self.dix = self.dix + (self.ix - self.dix) * 16 * dt
	self.diy = self.diy + (self.iy - self.diy) * 16 * dt

end

function eye:blink()
	self.blinkProgress = 0
end

function eye:draw()
	love.graphics.setColor(1, 1, 1, 1)
	love.graphics.circle("fill", self.x, self.y, self.radius)

	love.graphics.setColor(self.irisColor)
	love.graphics.circle("fill", self.dix, self.diy, self.irisRadius)

	love.graphics.setColor(0, 0, 0, 1)
	love.graphics.circle("fill", self.dix, self.diy, self.irisRadius * self.pupilDialation)

end

function eye:look(x, y)
	local a = angle(self.x, self.y, x, y)
	local d = distance(self.x, self.y, x, y)
	if d > self.radius then d = self.radius end

	self.ix = self.x + (self.radius - self.irisRadius) * (normal(d, 0, self.radius)) * math.cos(a)
	self.iy = self.y + (self.radius - self.irisRadius) * (normal(d, 0, self.radius)) * math.sin(a)
end

--Rest of the shit
function love.load()
	love.window.setMode(800, 600, {msaa = 8} )
	screen = {width = love.graphics.getWidth(), height = love.graphics.getHeight()}
	math.randomseed(os.time() + love.mouse.getX())
	love.graphics.setBackgroundColor(0.2, 0.2, 0.2)
	love.mouse.setVisible(false)
	space = 50
	radius = 32
	color = {math.random(), math.random(), math.random()}
	e = {
		eye.new( (screen.width / 2) - space, (screen.height / 2), radius, radius / 2, color, 0.4 ),
		eye.new( (screen.width / 2) + space, (screen.height / 2), radius, radius / 2, color, 0.4 )
	}
	mx = 0
	my = 0
	h = 0

	blink = 0
	blinkTick = 0
	blinkFrequency = {2, 10}
	nBlink = math.random(blinkFrequency[1], blinkFrequency[2])

	mood = "happy" --happy, concerned, sad

	dist = 0
end

function love.update(dt)
	h = h + 100 * dt
	if h > 255 then h = 0 end
	
	dist = distance(love.mouse.getX(), love.mouse.getY(), screen.width / 2, screen.height / 2)

	if dist > radius * 8 then
		mood = "happy"
	elseif dist > radius * 4 then
		mood = "concerned"
	else
		mood = "sad"
	end

	blinkTick = blinkTick + dt
	if blinkTick > nBlink then
		blinkTick = 0
		nBlink = math.random(blinkFrequency[1], blinkFrequency[2])
		blink = 1
	end

	blink = blink + (0 - blink) * 16 * dt

	mx = mx + (love.mouse.getX() - mx) * 16 * dt
	my = my + (love.mouse.getY() - my) * 16 * dt

	for i,v in ipairs(e) do
		v:update(dt)
		v:look(love.mouse.getX(), love.mouse.getY())
	end

end

function love.draw()
	love.graphics.setColor(232 / 255, 209 / 255, 171 / 255)
	love.graphics.circle("fill", screen.width / 2, screen.height / 2, radius * 4)

	love.graphics.setColor(0, 0, 0)
	if mood == "happy" then
		love.graphics.arc("fill", screen.width / 2, screen.height * 0.58, radius * 1.5, 0, math.pi )
	elseif mood == "concerned" then
		love.graphics.ellipse("fill", screen.width / 2, screen.height * 0.62, radius, radius / 2)
	elseif mood == "sad" then
		love.graphics.arc("fill", screen.width / 2, screen.height * 0.65, radius * 1.5, math.pi, math.pi * 2)
	end

	for i,v in ipairs(e) do
		v:draw()
	end

	--Eyelid
	love.graphics.setColor(232 / 255, 209 / 255, 171 / 255)
	love.graphics.rectangle("fill", (screen.width / 2) - space - radius, screen.height / 2 - radius, (radius * 2) + (space * 2), (radius * 3) * blink)

	love.graphics.setColor(hsl(h, 255, 126))
	love.graphics.circle("fill", mx, my, 8)

end

function love.touchmoved( id, x, y, dx, dy, pressure )
	for i,v in ipairs(e) do
		v:update(dt)
		v:look(x, y)
	end
end

function love.keypressed(key)
	if key == "escape" then love.event.push("quit") end
	if key == "space" then love.load() end
	if key == "f1" then
		love.graphics.captureScreenshot(os.time()..".png")
	end
	if key == "b" then blink = 1 end
end

function hsl(h, s, l, a)
	if s<=0 then return l,l,l,a end
	h, s, l = h/256*6, s/255, l/255
	local c = (1-math.abs(2*l-1))*s
	local x = (1-math.abs(h%2-1))*c
	local m,r,g,b = (l-.5*c), 0,0,0
	if h < 1     then r,g,b = c,x,0
	elseif h < 2 then r,g,b = x,c,0
	elseif h < 3 then r,g,b = 0,c,x
	elseif h < 4 then r,g,b = 0,x,c
	elseif h < 5 then r,g,b = x,0,c
	else              r,g,b = c,0,x
	end return (r+m),(g+m),(b+m),a
end

Re: Code Doodles!

Posted: Thu May 03, 2018 12:35 am
by Madeline Ladd
Woah these are so cool! :D

Re: Code Doodles!

Posted: Wed Jun 27, 2018 11:10 pm
by SirRanjid
First actual doodle. It's a bit psychedelic and plays seemlessly forever.

(No worries no fullscreen and console in case you can't close it directly for some reason like me. Maybe you could tell me what's wrong.)
DON'T disable the event module at least not in v0.10.2 .

Image