Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

push v1.0 #44

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Visual Studio Code
.vscode/*
178 changes: 57 additions & 121 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,180 +1,116 @@
**⚠️ Looking for maintainer:** as I am not working with LÖVE anymore, this repository is not actively maintained, except for critical fixes. Please do reach out if you're interested in maintaining this repository.
# push
**push** is a simple resolution-handling library for LÖVE that allows you to focus on making your game with a fixed resolution.

push
==============
![Screenshot](images/screenshot.png)

push is a simple resolution-handling library that allows you to focus on making your game with a fixed resolution.

![image](https://media.giphy.com/media/xTb1RycLHeAOPDownu/giphy.gif)

Setup
----------------
Fullscreen
## Demo
This demo creates a 1280x720 resizable window and sets push to an upscaled 800x600 resolution. Under the "Draw stuff here!" comment, add some drawing functions to see push in action!
```lua
local push = require "push"
push = require "push"

local gameWidth, gameHeight = 1080, 720 --fixed game resolution
local windowWidth, windowHeight = love.window.getDesktopDimensions()
love.window.setMode(1280, 720, {resizable = true}) -- Resizable 1280x720 window
push.setupScreen(800, 600, {upscale = "normal"}) -- 800x600 game resolution, upscaled

push:setupScreen(gameWidth, gameHeight, windowWidth, windowHeight, {fullscreen = true})

function love.draw()
push:start()

--draw here

push:finish()
-- Make sure push follows LÖVE's resizes
function love.resize(width, height)
push.resize(width, height)
end
```

Windowed
```lua
local push = require "push"

local gameWidth, gameHeight = 1080, 720 --fixed game resolution
local windowWidth, windowHeight = love.window.getDesktopDimensions()
windowWidth, windowHeight = windowWidth*.7, windowHeight*.7 --make the window a bit smaller than the screen itself

push:setupScreen(gameWidth, gameHeight, windowWidth, windowHeight, {fullscreen = false})

function love.draw()
push:start()

--draw here

push:finish()
push.start()
-- Draw stuff here!
push.finish()
end
```

Usage
----------------

Init push
```lua
push:setupScreen(gameWidth, gameHeight, windowWidth, windowHeight, {fullscreen, resizable, canvas, pixelperfect})
```
**gameWidth**, **gameHeight** represent the game's fixed resolution. **windowWidth** and **windowHeight** are the dimensions of the window you need to adapt the game to.

The last argument is a table containing:
- **fullscreen** (bool): turns fullscreen mode on or off
- **resizable** (bool): allows resizing the window
- **canvas** (bool): uses canvas
- **pixelperfect** (bool): enables pixel-perfect mode (integer scaling 1x, 2x, 3x, ...)
- **highdpi** (bool): enables high-dpi mode on supported screens (e.g. Retina)
- **stretched** (bool): stretches the game to window dimensions

Apply **push** transforms
## Usage
After applying changes to LÖVE's window using `love.window.setMode()`, init **push**:
```lua
push:start()
--draw here
push:finish()

--alias
push:apply(operation)
push.setupScreen(pushWidth, pushHeight, {upscale = ..., canvas = ...})
```
**operation** should be equal to "start" or "end", meaning "before" or "after" your main drawing logic

Mobile support
----------------
`pushWidth` and `pushHeight` represent **push's** fixed resolution.

**push** does *not* have built-in support for mobile platforms, but it is trivial to handle mobile screens correctly.
The last argument is a table containing settings for **push**:
* `upscale` (string): upscale **push's** resolution to the current window size
* `"normal"`: fit to the current window size, preserving aspect ratio
* `"pixel-perfect"`: pixel-perfect scaling using integer scaling (for values ≥1, otherwise uses normal scaling)
* `"stretched"`: stretch to the current window size
* `canvas` (bool): use and upscale canvas set to **push's** resolution

A possible solution is to initialize **push** in fullscreen mode:
Hook **push** into the `love.resize()` function so that it follows LÖVE's resizes:
```lua
local screenWidth, screenHeight = love.window.getDesktopDimensions()
push:setupScreen(gameWidth, gameHeight, screenWidth, screenHeight, { fullscreen = true, resizable = false, ... })
function love.resize(width, height)
push.resize(width, height)
end
```

And listen to screen orientation changes:
Finally, apply **push** transforms:
```lua
function love.resize(w, h)
return push:resize(w, h)
function love.draw()
push.start()
-- Draw stuff here!
push.finish()
end
```

Multiple shaders
----------------

## Multiple shaders
Any method that takes a shader as an argument can also take a *table* of shaders instead. The shaders will be applied in the order they're provided.

Set multiple global shaders
```lua
push:setShader({ shader1, shader2 })
push.setShader({ shader1, shader2 })
```

Set multiple canvas-specific shaders
```lua
push:setupCanvas({ { name = "multiple_shaders", shader = { shader1, shader2 } } })
push.setupCanvas({{name = "multiple_shaders", shader = {shader1, shader2}}})
```

Advanced canvases/shaders
----------------

**push** provides basic canvas and shader functionality through the *canvas* flag in push:setupScreen() and push:setShader(), but you can also create additional canvases, name them for later use and apply multiple shaders to them.
## Advanced canvases/shaders
**push** provides basic canvas and shader functionality through the `canvas` flag in push:setupScreen() and push:setShader(), but you can also create additional canvases, name them for later use and apply multiple shaders to them.

Set up custom canvases
Set up custom canvases:
```lua
push:setupCanvas(canvasList)
push.setupCanvas(canvasList)

--e.g. push:setupCanvas({ { name = "foreground", shader = foregroundShader }, { name = "background" } })
-- e.g. push.setupCanvas({{name = "foreground", shader = foregroundShader}, {name = "background"}})
```

Shaders can be passed to canvases directly through push:setupCanvas(), or you can choose to set them later.
```lua
push:setShader(canvasName, shader)
push.setShader(canvasName, shader)
```

Then, you just need to draw your game on different canvases like you'd do with love.graphics.setCanvas():
```lua
push:setCanvas(canvasName)
push.setCanvas(canvasName)
```

Resizing the window
----------------

In order for push to take in account window resizing (if you have set {resizable = true} in push:setupScreen()), you need to call push:resize() like so:

## Misc
Update settings:
```lua
function love.resize(w, h)
push:resize(w, h)
end
push.updateSettings({settings})
```

Misc
----------------

Switch fullscreen
Set a post-processing shader (will apply to the whole screen):
```lua
push:switchFullscreen(w, h)
push.setShader([canvasName], shader)
```
**w** and **h** are optional parameters that are used in case the game switches to windowed mode
You don't need to call this every frame. Simply call it once, and it will be stored into **push** until you change it back to something else. If no `canvasName` is passed, shader will apply to the final render. Use it at your advantage to combine shader effects.

Set a post-processing shader (will apply to the whole screen)
Convert coordinates:
```lua
push:setShader([canvasName], shader)
```
You don't need to call this every frame. Simply call it once, and it will be stored into **push** until you change it back to something else.
If no canvasName is passed, shader will apply to the final render. Use it at your advantage to combine shader effects.

Convert coordinates
```lua
push:toGame(x, y) --convert coordinates from screen to game (useful for mouse position)
--push:toGame will return nil for the values that are outside the game - be sure to check that before using them
push.toGame(x, y) -- Convert coordinates from screen to game (useful for mouse position)
-- push.toGame will return false for values that are outside the game, be sure to check that before using them!

push:toReal(x, y) --convert coordinates from game to screen
push.toReal(x, y) -- Convert coordinates from game to screen
```

Get game dimensions
Get game dimensions:
```lua
push:getDimensions() --returns push:getWidth(), push:getHeight()
push.getWidth() -- Returns game width

push:getWidth() --returns game width
push.getHeight() -- Returns game height

push:getHeight() --returns game height
push.getDimensions() -- Returns push.getWidth(), push.getHeight()
```

Set border color
```lua
push:setBorderColor(r, g, b, a) --also accepts a table
```

Binary file removed examples/low-res/background.png
Binary file not shown.
Binary file added examples/low-res/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 48 additions & 69 deletions examples/low-res/init.lua
Original file line number Diff line number Diff line change
@@ -1,77 +1,56 @@
--[[ Low resolution ]]--

return function()

love.graphics.setDefaultFilter("nearest", "nearest") --disable blurry scaling

local gameWidth, gameHeight = 64, 64

local windowWidth, windowHeight = love.window.getDesktopDimensions()
windowWidth, windowHeight = windowWidth*.5, windowHeight*.5
love.graphics.setDefaultFilter("nearest", "nearest") -- Disable blurry scaling

push:setupScreen(gameWidth, gameHeight, windowWidth, windowHeight, {
fullscreen = false,
resizable = true,
pixelperfect = true
})
push:setBorderColor{0, 0, 0} --default value

--

time = 0
love.window.setMode(640, 480, {resizable = true}) -- LÖVE resolution 640x480, resizable
push.setupScreen(64, 64, {upscale = "pixel-perfect", canvas = true}) -- push resolution 64x64, pixel perfect scaling, drawn to a canvas

function love.load()
mario = love.graphics.newImage("examples/low-res/mario.png")
background = love.graphics.newImage("examples/low-res/background.png")

love.graphics.setNewFont(16)
end

function love.update(dt)

time = (time + dt) % 1

end
--

function love.draw()
push:apply("start")

local mouseX, mouseY = love.mouse.getPosition()
mouseX, mouseY = push:toGame(mouseX, mouseY)
--if nil is returned, that means the mouse is outside the game screen

local abs = math.abs(time-.5)
local pi = math.cos(math.pi*2*time)
local pi2 = math.cos(math.pi*8*time)
local w = push:getWidth()
--for animating basic stuff

love.graphics.draw(background, 0, 0)

love.graphics.setScissor(0, 0, push:getWidth(), push:getHeight()-16)
love.graphics.setColor(0, 0, 0, 100)
love.graphics.draw(mario, 27, 33)
love.graphics.setScissor()
love.graphics.setColor(255, 255, 255)
love.graphics.draw(mario, 26, 32)

love.graphics.setColor(0, 0, 0, 100)
love.graphics.printf("Hi!", 34+1, 22-pi*2+1, w, "center", -.15+.5*abs, abs*.25+1, abs*.25+1, w*.5, 12)
love.graphics.setColor(255, 255, 255)
love.graphics.printf("Hi!", 34, 22-pi*2, w, "center", -.15+.5*abs, abs*.25+1, abs*.25+1, w*.5, 12)
time = 0

love.graphics.setColor(255, 255, 255)
if mouseX and mouseY then --cursor
love.graphics.points(
mouseX, mouseY-1,
mouseX-1, mouseY,
mouseX, mouseY,
mouseX+1, mouseY,
mouseX, mouseY+1
)
end

push:apply("end")
end

end
function love.load()
image = love.graphics.newImage("examples/low-res/image.png")

love.graphics.setNewFont(16)
end

function love.update(dt)

time = (time + dt) % 1

end

function love.draw()
push.start()
local mouseX, mouseY = love.mouse.getPosition()
mouseX, mouseY = push.toGame(mouseX, mouseY)
-- If false is returned, that means the mouse is outside the game screen

local abs = math.abs(time-.5)
local pi = math.cos(math.pi*2*time)
local w = push:getWidth()
--for animating basic stuff

love.graphics.draw(image, 0, 0)

love.graphics.setColor(0, 0, 0, 0.5)
love.graphics.printf("Hi!", 31, 23-pi*2, w, "center", -.15+.5*abs, abs*.25+1, abs*.25+1, w*.5, 12)
love.graphics.setColor(1, 1, 1)
love.graphics.printf("Hi!", 30, 22-pi*2, w, "center", -.15+.5*abs, abs*.25+1, abs*.25+1, w*.5, 12)

love.graphics.setColor(1, 1, 1)
if mouseX and mouseY then --cursor
love.graphics.points(
mouseX, mouseY-1,
mouseX-1, mouseY,
mouseX, mouseY,
mouseX+1, mouseY,
mouseX, mouseY+1
)
end
push.finish()
end
end
Binary file removed examples/low-res/mario.png
Binary file not shown.
Loading