How would I go about this?

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
ForeverDevv
Prole
Posts: 9
Joined: Sat Sep 13, 2014 10:20 pm

How would I go about this?

Post by ForeverDevv »

I'm working on a Mandelbrot fractal generator. It generates a certain number of pixels on the screen, then iterates through a function to produce color. Once the whole screen is filled with pixels, I use the screenshot function and create an image of that screenshot. Next, I stop drawing each pixel to the screen, and I draw the screenshot, to stop the lag. This is what it looks like:

https://love2d.org/imgmirrur/blJRoQu.png

I added the ability to zoom in using your mouse wheel, and to pan using WASD. However, when you zoom in, the fractal gets blurry. How would I go about re-rendering the fractal when you zoom in, so it appears high quality? I only want to re-render the pixels visible on the screen, to prevent lag.
User avatar
artofwork
Citizen
Posts: 91
Joined: Mon Sep 15, 2014 1:17 am
Location: East Coast USA

Re: How would I go about this?

Post by artofwork »

Upload your love file and we can help you.

We can make all the suggestions in the world but without the source its a waste of time.
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: How would I go about this?

Post by zorg »

From what you wrote, i believe you want something like this:
when zooming in, you probably have a set scale that you use; you can use that, and the panning values to calculate the area you would need to re-render that one "view".

Problem is, you're trying to draw an infinitely detailed... thing, so you can't store that in its entirety.

What you can do, is to cache (save) separate parts of it at different detail levels, and if you are at a place rendered previously, it can display that without the need to calculate every pixel again, but sooner or later, this will eat up your ram, and even your hdd if you decide to utilize that as well.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
ForeverDevv
Prole
Posts: 9
Joined: Sat Sep 13, 2014 10:20 pm

Re: How would I go about this?

Post by ForeverDevv »

artofwork wrote:Upload your love file and we can help you.

We can make all the suggestions in the world but without the source its a waste of time.
Here is my code. It's kind of messy considering I did a lot of playing around with it

Code: Select all


--[[

	Mandelbrot set:  Iterate through the following function

	fc(z) z^2 + c



	Case1, blows up:

	c = 1
	f1(0) 0^2 + 1 --> 1
	f1(1) 1^2 + 1 --> 2
	f1(2) 2^2 + 1 --> 5
	f1(5) 5^2 + 1 --> 26


	Case2, is always <= 2:

	c = -1
	f-1(0) 0^2 - 1 --> -1
	f-1(-1) -1^2 - 1 --> 0
	f-1(0) 0^2 - 1 --> -1

]]

function love.load()

	maxIter = 1000
	gridSize = 50

	default = 10
	default2 = 5
	box = 1

	colorScale = 8

	scale = 1
	transX = 0
	transY = 0

	power = 2

	iterationCount = 0
	pixelCount = 0


	love.graphics.setBackgroundColor(255, 255, 255)
	screenshot = nil
	points = {}
	loops = 0
	width, height = love.graphics.getWidth(), love.graphics.getHeight()
	processing = true
	zoomCol = width / 2
	zoomRow = height / 2
	nowH, nowW = 10, 10

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

	function love.mousepressed(x, y, button)
		if button == "wu" and not processing then
			scale = scale + (scale / 4)
		elseif button == "wd" and not processing then
			scale = scale - (scale / 4)
		end
	end

	--i = root(-1), so by squaring i, you get a real number to graph (-1)
	function toRealNumber(imaginary)
		return imaginary ^ 2
	end

	function f(z, c)
		return z ^ power + c
	end

	function comma(number)
		repeat number, count = tostring(number):gsub("^(%d+)(%d%d%d)", "%1,%2") until count == 0
		return number
	end

	function redraw(zoom)

	end
end

function love.draw()
	love.graphics.scale(scale, scale)
	love.graphics.translate(transX, transY)
	if loops == 0 then
		for _, point in ipairs(points) do
			love.graphics.setColor(point[3] == "white" and {point[4] * colorScale, point[4] * colorScale, point[4] * colorScale} or {0, 0, 0})
			love.graphics.rectangle("fill", point[1], point[2], default, default)
		end
	elseif loops == 1 or loops == 2 then
		love.graphics.draw(screenshot, 0, 0)
		for _, point in ipairs(points) do
			love.graphics.setColor(point[3] == "white" and {point[4] * colorScale, point[4] * colorScale, point[4] * colorScale} or {0, 0, 0})
			love.graphics.rectangle("fill", point[1], point[2], default, default)
		end
	else
		love.graphics.draw(screenshot, 0, 0)
	end
	love.graphics.setColor(255, 255, 255)
	love.graphics.rectangle("line", nowW - gridSize, nowH - gridSize, gridSize, gridSize)
	if loops < 3 then
		love.graphics.printf("Iterations: " .. comma(iterationCount), 25, 25, 500, "left")
		love.graphics.printf("Pixels: " .. comma(pixelCount), 25, 50, 500, "left")
	end
end

function love.update()
	if processing then
		for row = nowH - gridSize, nowH, default do
			for col = nowW - gridSize, nowW, default do
				pixelCount = pixelCount + 1
				local real = (col - zoomCol) * 4 / width --- (love.mouse.getX() / width)--x axis (real numbers)
				local imaginary = (row - zoomRow) * 4 / width --- (love.mouse.getY() / width)--y axis (imaginary numbers) (i = root(-1))
				local z, c, iter = 0, 0, 0
				while (f(z, toRealNumber(c)) <= 4 and iter < maxIter) do --f(x, z) z^2 + c
					iterationCount = iterationCount + 1
					local zNew = z^2 - toRealNumber(c) + real
					c = 2*z*c + imaginary
					z = zNew
					iter = iter + 1
				end
				if iter < maxIter then
					table.insert(points, {col, row, "white", iter})
				else
					table.insert(points, {col, row, "black"})
				end
			end
		end
		nowW = nowW + gridSize
		if nowW >= width + (gridSize * 3) then
			nowW = 1
			nowH = nowH + gridSize
		end
		if nowH - gridSize >= height then
			nowW = 1
			nowH = 1
			screenshot = love.graphics.newImage(love.graphics.newScreenshot(true))
			points = {}
			loops = loops + 1
			if loops == 1 then
				pixelCount = 0
				iterationCount = 0
				processing = true
				default = default2
			elseif loops == 2 then
				pixelCount = 0
				iterationCount = 0
				default = box
			else
				processing = false
			end
		end
	else
		if love.keyboard.isDown("w") then
			transY = transY + (5*(1/scale))
		end
		if love.keyboard.isDown("s") then
			transY = transY - (5*(1/scale))
		end
		if love.keyboard.isDown("d") then
			transX = transX - (5*(1/scale))
		end
		if love.keyboard.isDown("a") then
			transX = transX + (5*(1/scale))
		end
	end
end


User avatar
artofwork
Citizen
Posts: 91
Joined: Mon Sep 15, 2014 1:17 am
Location: East Coast USA

Re: How would I go about this?

Post by artofwork »

I went over the code and didn't find a solution, although it was late when i read the initial thread.

The problem you said your having is when you zoom the image becomes pixelated, there are a few reasons for this, your not actually drawing out the image in terms of pixels example below

Code: Select all

love.graphics.rectangle("fill", point[1], point[2], default, default)
What you are doing however is drawing out rectangles in specific dimensions which are a series of pixels so when you zoom in your stretching the rectangles increasing the pixel count which creates a blurred image.

The next issue is your taking a screenshot of the screen which is saved into memory as a raster image which sets you up for failure when you want to zoom in.

You need to find a way to draw out your rectangles using a grid system, where they are saved into memory and then can be rebuilt as a vector, this will allow you to easily rebuild the image when you zoom in.

That is just my thoughts on this, hope it was a little helpful.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 99 guests