Draw pixels correctly

Hello,
I’m trying to draw pixels to positon of mouse only, but in my code are pixels drawed next to mouse postion. I suspect the mistake is somewhere here and I would like to understand it.

local index = (y * self.width * 4) + (x * 4) + 1

Can someone explain it to me please?
I’ll send you the whole code to be sure.

local function draw_pixel(self, x, y, r, g, b, a)

		-- draw the pixel at the correct index in the buffer stream
		local index = (y * self.width * 4) + (x * 4) + 1
		print(index)
		self.stream[index + 0] = r
		self.stream[index + 1] = g
		self.stream[index + 2] = b
		self.stream[index + 3] = a or 0xff
	end

	function init(self)
		msg.post(".", "acquire_input_focus")

		-- size of texture when scaled to nearest power of two
		self.width = 960
		self.height = 640

		-- create RGBA buffer and get the stream so we can manipulate it using Lua
		self.buffer = buffer.create(self.width * self.height, { {name=hash("rgba"), type=buffer.VALUE_TYPE_UINT8, count=4} } )
		self.stream = buffer.get_stream(self.buffer, hash("rgba"))
		-- drawing params
		self.color = vmath.vector4(1, 1, 1, 1)
	end

	function update(self, dt)
		local resource_path = go.get("#sprite", "texture0")
		local header = { width = self.width, height = self.height, type = resource.TEXTURE_TYPE_2D, format = resource.TEXTURE_FORMAT_RGBA, num_mip_maps = 1 }
		resource.set_texture( resource_path, header, self.buffer )
	end

	function on_input(self, action_id, action)
		local pos = vmath.vector3(action.x, action.y, 0)
		local x = math.floor(pos.x)
		local y = math.floor(pos.y)

		r = math.floor(self.color.x * 255)
		g = math.floor(self.color.y * 255)
		b = math.floor(self.color.z * 255)
		a = math.floor(self.color.w * 255)

		draw_pixel(self, x, y, r, g, b, a)
	end

Are you sure the screen coordinates of the mouse align with the sprite and buffer? Did you compare to the example in the DrawPixels extension?

I found that I had a smaller canvas size than an atlas. Could it be the mistake? When I change it in Draw pixels example, it makes a similar mistake.

Yes, sounds likely. The buffer you create must be of the same size as the atlas (not the image inside the atlas).

Thank you, but whenever I try to put an image of the same or similar size to the atlas than the atlas, the atlas resizes to twice what I would like. Do you know how to do it?

I just switched on how to set the atlas size correctly. I must change Extrude Borders to 0. Maybe it will work.

Thank you very much @britzl ! It really works now.

Indeed! Extrude borders will duplicate the border pixels the image which in turn will cause the atlas to grow if the image has a size that is a power of two.

1 Like

Trying similar to @anon64925349 's example, however the alpha channel is not working. All pixels are fully opaque regardless. Wondering what the problem could be?

local function create_canvas()
	canvas = buffer.create(canvas_size * canvas_size, { { name = hash("rgba"), type = buffer.VALUE_TYPE_UINT8, count = 4 } })
	stream = buffer.get_stream(canvas, hash("rgba"))
	for y = 1, canvas_size do
		for x = 1, canvas_size do
			local index = (y - 1) * canvas_size * 4 + (x - 1) * 4 + 1
			stream[index] = math.random(0, 255)
			stream[index + 1] = math.random(0, 255)
			stream[index + 2] = math.random(0, 255)
			stream[index + 3] = math.random(0, 255)
		end
	end
	local canvas_path = go.get(msg.url(nil, "/canvas", "sprite"), "texture0")
	resource.set_texture(canvas_path, { width = canvas_size, height = canvas_size, type = resource.TEXTURE_TYPE_2D, format = resource.TEXTURE_FORMAT_RGBA, num_mip_maps = 1 }, canvas)
end

Hmm, only thing I can think of is that we use premultiplied alpha :thinking:

Thank you, premultiplied and is now working as expected. Strange that applying a value to that fourth pixel buffer index doesn’t do anything by itself.

1 Like