britzl / template-lowres

Defold template project for lowres/pixel-art games.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Turn into general purpose pixel art template

subsoap opened this issue · comments

commented

Only real changes needed I think would be to include a SIZE_HEIGHT and SIZE_WIDTH in the render script.

Another thing could add would be to produce non-square pixels. Here is an example

local SIZE = 64
local SIZE_WIDTH = 64 * 1.143


local IDENTITY = vmath.matrix4()
local LOWREZ_PROJECTION = vmath.matrix4_orthographic(0, SIZE, 0, SIZE, -1, 1)

function init(self)
	self.tile_pred = render.predicate({"tile"})
	self.gui_pred = render.predicate({"gui"})
	self.text_pred = render.predicate({"text"})
	self.particle_pred = render.predicate({"particle"})
	self.lowrez_pred = render.predicate({"lowrez"})
	self.controls_pred = render.predicate({"controls"})

	self.view = IDENTITY

	-- render target buffer parameters
	local color_params = {
		format = render.FORMAT_RGBA,
		width = SIZE,
		height = SIZE,
		min_filter = render.FILTER_NEAREST,
		mag_filter = render.FILTER_NEAREST,
		u_wrap = render.WRAP_CLAMP_TO_EDGE,
		v_wrap = render.WRAP_CLAMP_TO_EDGE
	}
	local depth_params = {
		format = render.FORMAT_DEPTH,
		width = SIZE,
		height = SIZE,
		u_wrap = render.WRAP_CLAMP_TO_EDGE,
		v_wrap = render.WRAP_CLAMP_TO_EDGE
	}
	self.rt = render.render_target("lowrez", { [render.BUFFER_COLOR_BIT] = color_params, [render.BUFFER_DEPTH_BIT] = depth_params })

	local clear_color = vmath.vector4(0, 0, 0, 0)
	clear_color.x = sys.get_config("render.clear_color_red", 0)
	clear_color.y = sys.get_config("render.clear_color_green", 0)
	clear_color.z = sys.get_config("render.clear_color_blue", 0)
	clear_color.w = sys.get_config("render.clear_color_alpha", 0)
	self.clear_buffers = {
		[render.BUFFER_COLOR_BIT] = clear_color,
		[render.BUFFER_DEPTH_BIT] = 1,
		[render.BUFFER_STENCIL_BIT] = 0
	}
end


local function clear(self, w, h)
	-- clear
	render.set_view(IDENTITY)
	render.set_projection(vmath.matrix4_orthographic(0, w, 0, h, -1, 1))
	render.set_depth_mask(true)
	render.set_stencil_mask(0xff)
	render.clear(self.clear_buffers)
end


local function draw_game(self)
	clear(self, render.get_window_width(), render.get_window_height())
	
	render.set_viewport(0, 0, SIZE, SIZE)

	-- draw world (sprites, tiles, pfx etc)
	render.set_depth_mask(false)
	render.disable_state(render.STATE_DEPTH_TEST)
	render.disable_state(render.STATE_STENCIL_TEST)
	render.disable_state(render.STATE_CULL_FACE)
	render.enable_state(render.STATE_BLEND)
	render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
	render.set_view(self.view)
	render.set_projection(LOWREZ_PROJECTION)
	render.draw(self.tile_pred)
	render.draw(self.particle_pred)
	render.draw_debug3d()
	
	-- draw screen space gui
	render.set_view(vmath.matrix4())
	render.set_projection(LOWREZ_PROJECTION)
	render.enable_state(render.STATE_STENCIL_TEST)
	render.draw(self.gui_pred)
	render.draw(self.text_pred)
	render.disable_state(render.STATE_STENCIL_TEST)
end


local function draw_upscaled(self)
	-- calculate zoom
	local window_width = render.get_window_width()
	local window_height = render.get_window_height()
	local zoom = math.min(window_width / SIZE_WIDTH, window_height / SIZE)
	zoom = math.max(1, math.floor(zoom))

	-- positioning
	local width = SIZE_WIDTH * zoom
	local height = SIZE * zoom
	local width_halved = width / 2
	local height_halved = height / 2
	local offsetx = (window_width - width) / 2
	local offsety = (window_height - height) / 2

	-- draw!
	render.set_viewport(offsetx, offsety, width, height)
	render.set_view(IDENTITY)
	render.set_projection(IDENTITY)
	render.enable_texture(0, self.rt, render.BUFFER_COLOR_BIT)
	render.draw(self.lowrez_pred)
	render.disable_texture(0, self.rt)
end


local function draw_controls(self)
	render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())
	render.set_view(IDENTITY)
	render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0, render.get_window_height(), -1, 1))

	render.enable_state(render.STATE_STENCIL_TEST)
	render.draw(self.controls_pred)
	--render.draw(self.text_pred)
	render.disable_state(render.STATE_STENCIL_TEST)
end

function update(self)
	clear(self,	render.get_window_width(), render.get_window_height())
	render.enable_render_target(self.rt)
	draw_game(self)
	render.disable_render_target(self.rt)
	draw_upscaled(self)
	draw_controls(self)
end

function on_message(self, message_id, message)
	if message_id == hash("clear_color") then
		self.clear_buffers[render.BUFFER_COLOR_BIT] = message.color
	elseif message_id == hash("set_view_projection") then
		self.view = message.view
	end
end


Which produces thicc pixels useful in NES projects although may not be best way to achieve the effect that NES emulators can produce to give proper NES look, other game systems use non-square pixels too

2018-08-11 14_03_23-lowrezjam

Could maybe merge this with Orthographic or make it an extension of that somehow.

commented

Should also add an upscaling shader, one of the pixel art to "vector" graphics shaders common with emulators. http://filthypants.blogspot.com/search/label/xBR

I think maybe the shader stuff, crt and scanline filters are better suited for a separate repo. You started something similar recently? I've many tims thought of trying to find a way to modularize the render script and make it really easy for people to create full screen effects using shaders.

As for setting WIDTH and HEIGHT individually: Good idea and a simple change. I'll keep the default values to 64x64.

commented

Yes, it could be an a stand alone example (I could make some too, if they don't exist at some point I will). It's something people who want to make pixel art games will eventually ask for always.

I made a rendertarget helper which makes using full screen render targets for post processing and other full screen effects really easy. Will release it sometime soon. It somewhat makes full screen effects easy although you still have to manually include and setup unitquads and materials, require the module, and then set whatever you want rendered to the rendertarget listed there instead of being rendered normally. At least it's all easier now than it was before!

commented

Mind if I make a pixel art template as a fork of this project with post processing enabled or do you want to do it?

Please go ahead! I haven't had time to do it yet.

Closing in favor of #6