lua utils

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: lua utils

Post by ivan »

Code: Select all

local x, y = aspect.ratio(800, 600)
print("aspect ratio is: " .. x .. " : " .. y)
User avatar
Snuux
Prole
Posts: 49
Joined: Sun Dec 15, 2013 10:43 am
Location: Russia, Moskow
Contact:

Re: lua utils

Post by Snuux »

))

Oh, sorry. I mean this question: how can I use information about aspect ratio, to properly zoom game (for different screens)?
My library for easy saving Slib! Try this! Now you can encrypt your save!
- Drop of light LD#30
- OUTRANGE LD#31
(Sorry for my english. I learn it myself, and I don't have enough experience)
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: lua utils

Post by ivan »

The aspect ratio function simply rounds the resolution to the nearest aspect ratio format.

I'm not 100% sure how the transformations work in Love2D but take a look at "Coordinate System" on this wiki page:
http://love2d.org/wiki/love.graphics#co ... e%20system
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: lua utils

Post by ivan »

Tutorial on platformers and finite state machines:
http://2dengine.com/doc_1_3_10/gs_fsm.html

Attached is a love2d version of the tutorial.

Image
Attachments
platform.love
(11.35 KiB) Downloaded 263 times
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

line/ray/segment casting

Post by ivan »

I was inspired by Taehl and davisdude to write a small raycasting lib:

Code: Select all

--
-- Segment, ray and line casts
-- ===========================
-- Based on "Real-Time Collision Detection" by Christer Ericson
--

-- Definitions
-- ===========
-- This module works with three different types:
-- "segment" has two endpoints
-- "ray" has one endpoint
-- "line" has no endpoints

-- Results
-- =======
-- Each test, returns either one or two points.
-- The order of returned points is determined by
-- the direction of the segment, ray or line (a-b).
--
-- After each returned intersection point,
-- the module also returns the "intersection value".
-- The "intersection value" can be defined as the ratio:
-- R = |a-q|/|a-b|
-- if a-b is a segment: R is from 0 to 1
-- if a-b is a rays: R is 0 or greater
-- if a-b is a line: R could be any number

-- Example
-- =======
-- -- one intersection point:
-- qx,qy,q = line.segment(-1,0,1,0, 0,-1,0,1, "segment", "segment")
-- assert(qx == 0 and qy == 0 and q == 0.5)
--
-- -- two intersection points:
-- qx,qy,q, qx2,qy2,q2 = line.circle(-1,0,1,0, 0,0,0.5, "segment")
-- assert(qx == -0.5 and qy == 0 and q == 0.25)
-- assert(qx2 == 0.5 and qy2 == 0 and q2 == 0.75)

-- Limitations
-- ===========
-- "line.segment" does not work with "collinear" segments, rays or lines
-- None of the functions work with "degenerate" segments, rays or lines
-- Triangles are not supported :(

-- License
-- =======
-- MIT License

local sqrt = math.sqrt

local line = {}

function line.is_degenerate(ax, ay, bx, by)
  --return dist2(ax, ay, bx, by) == 0
  local dx, dy = ax - bx, ay - by
  return dx*dx + dy*dy == 0
end


--  (a)
--    \  (b2)
--     \ / 
--     (q)
--     / \
--   (a2) \
--        (b)

--- Segment
-- @param ax,ay,bx,by segment, ray or line
-- @param ax2,ay2,bx2,by2 segment, ray or line
-- @param lt defines a-b as either: "segment", "ray" or "line" (optional)
-- @param lt2 defines a2-b2 as either: "segment", "ray" or "line" (optional)
-- @return intersection point and ratio or nil
function line.segment(x1, y1, x2, y2, x3, y3, x4, y4, lt1, lt2)
  lt1 = lt1 or "segment"
  lt2 = lt2 or "segment"
  local dx1, dy1 = x2 - x1, y2 - y1
  local dx2, dy2 = x4 - x3, y4 - y3

  local d = dx1*dy2 - dy1*dx2
  if d == 0 then
    return -- collinear
  end
  local dx3, dy3 = x1 - x3, y1 - y3
  local t1 = (dx2*dy3 - dy2*dx3)/d
  if (lt1 ~= "line" and t1 < 0) or (lt1 == "segment" and t1 > 1) then
    return -- non-intersecting segment or ray
  end
  local t2 = (dx1*dy3 - dy1*dx3)/d
  if (lt2 ~= "line" and t2 < 0) or (lt2 == "segment" and t2 > 1) then
    return -- non-intersecting segment or ray
  end
  return x1 + t1*dx1, y1 + t1*dy1, t1, t2
end

-- (a)
--   \ .-'''-.
--   (q)      \
--   | \ (c)   |
--    \ \     /
--     `(q2)-'
--        \   
--        (b)  

--- Circle
-- @param ax,ay,bx,by segment, ray or line
-- @param cx,cy circle center
-- @param cr circle radius
-- @param lt defines a-b as either: "segment", "ray" or "line" (optional)
-- @return intersection point(s) and ratio(s) or nil
function line.circle(ax, ay, bx, by, cx, cy, cr, lt)
  lt = lt or "segment"
  local dx, dy = bx - ax, by - ay
  local d = sqrt(dx*dx + dy*dy) -- len(dx, dy)
  if d == 0 then
    return -- degenerate
  end
  local nx, ny = dx/d, dy/d
  local mx, my = ax - cx, ay - cy
  local b = mx*nx + my*ny -- dot(mx, my, nx, ny)
  local c = mx*mx + my*my - cr*cr -- dot(mx, my, mx, my) - cr*cr
  if lt ~= "line" and c > 0 and b > 0 then
    return -- non-intersecting
  end
  local discr = b*b - c
  if discr < 0 then
    return -- non-intersecting
  end
  discr = sqrt(discr)
  local tmin = -b - discr
  if lt ~= "line" and tmin < 0 then
    tmin = 0
  end
  if lt == "segment" and tmin > d then
    return -- non-intersecting
  end
  local tmax = discr - b
  if lt == "segment" and tmax > d then
    tmax = d
  end
  local qx, qy = ax + tmin*nx, ay + tmin*ny, tmin
  if tmax == tmin then
    return qx, qy, tmin/d
  end
  return qx, qy, tmin/d, ax + tmax*nx, ay + tmax*ny, tmax/d
end

-- (a)
--   \ --------
--    \|      |
--    (q)     |
--     |\     |
--     -(q2)---
--        \   
--        (b)

--- Axis-aligned rectangle (l,t,r,b)
-- @param ax,ay,bx,by segment, ray or line
-- @param l,t left/top corner of the rectangle
-- @param r,b right/bottom corner of the rectangle
-- @param lt defines a-b as either: "segment", "ray" or "line" (optional)
-- @return intersection point(s) and ratio(s) or nil
function line.aabb(ax, ay, bx, by, l, t, r, b, lt)
  lt = lt or "segment"
  -- misaligned aabb?
  if l > r then
    l, r = r, l
  end
  if t > b then
    t, b = b, t
  end
  local dx, dy = bx - ax, by - ay
  local d = sqrt(dx*dx + dy*dy) -- len(dx, dy)
  if d == 0 then
    return -- degenerate
  end
  local nx, ny = dx/d, dy/d
  local tmin, tmax
  if lt == "segment" then
    tmin = 0
    tmax = d
  elseif lt == "ray" then
    tmin = 0
  end
  --if abs(dx) < EPSILON then
  if dx == 0 then
    if ax < l or ax > r then
      return -- non-intersecting
    end
  else
    local ood = 1/nx
    local t1, t2 = (l - ax)*ood, (r - ax)*ood
    if t1 > t2 then
      t1, t2 = t2, t1
    end
    if tmin == nil or tmin < t1 then
      tmin = t1
    end
    if tmax == nil or tmax > t2 then
      tmax = t2
    end
    if tmin > tmax then
      return -- non-intersecting
    end
  end
  --if abs(dy) < EPSILON then
  if dy == 0 then
    if ay < t or ay > b then
      return -- non-intersectings
    end
  else
    local ood = 1/ny
    local t1, t2 = (t - ay)*ood, (b - ay)*ood
    if t1 > t2 then
      t1, t2 = t2, t1
    end
    if tmin == nil or tmin < t1 then
      tmin = t1
    end
    if tmax == nil or tmax > t2 then
      tmax = t2
    end
    if tmin > tmax then
      return -- non-intersecting
    end
  end
  local qx, qy = ax + nx*tmin, ay + ny*tmin, tmin
  if tmin == tmax then
    return qx, qy, tmin
  end
  return qx, qy, tmin/d, ax + nx*tmax, ay + ny*tmax, tmax/d
end

--- Axis-aligned rectangle (second representation)
-- @param ax,ay,bx,by segment, ray or line
-- @param l,t left/top corner of the rectangle
-- @param w,h width and height of the rectangle
-- @param lt defines a-b as either: "segment", "ray" or "line" (optional)
-- @return intersection point(s) and ratio(s) or nil
function line.rect(ax, ay, bx, by, l, t, w, h, lt)
  return line.aabb(ax, ay, bx, by, l, t, l + w, t + h, lt)
end

--- Axis-aligned rectangle (third representation)
-- @param ax,ay,bx,by segment, ray or line
-- @param x,y center point of the rectangle
-- @param hw,hh half-width and half-height extents of the rectangle
-- @param lt defines a-b as either: "segment", "ray" or "line" (optional)
-- @return intersection point(s) and ratio(s) or nil
function line.box(ax, ay, bx, by, x, y, hw, hh, lt)
  return line.aabb(ax, ay, bx, by, x - hw, y - hh, x + hw, y + hh, lt)
end

return line
It's still WIP and some things could be refactored/improved.
A lot of the code is based on Christer Ericson's book.

For the latest code I would advise to visit this repository under math/line.lua

Edit: improved segment vs segment, getting closer to a solution for collinear segments
Last edited by ivan on Thu Jan 22, 2015 2:22 pm, edited 1 time in total.
User avatar
Ref
Party member
Posts: 702
Joined: Wed May 02, 2012 11:05 pm

Re: lua utils

Post by Ref »

FYI Ivan!
Following does not function as advertised:

Code: Select all

--- Splits a path into directory, filename and extension
--- Assumes the path is a filename, if it does not end with a slash
--- Adapted from Paul Kulchenko
-- @param fn Filename
-- @return Directory path, filename and extension
function io.split(fn)
  return string.match(fn, "(.-)([^\\/]-%.?([^%.\\/]*))$")
end
Returns the filename with extension.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: lua utils

Post by ivan »

Hey Ref, thanks for taking a look. :)
Yep, I agree - that lib needs some revisions too.
You're right - "split" is not the right word in this case.
Can you please give some example input that doesn't work.
Seems to return three captures:

Code: Select all

function io.split(fn)
  return string.match(fn, "(.-)([^\\/]-%.?([^%.\\/]*))$")
end
a,b,c = io.split("c:/dev/games/oops.lua")
print("path:".. (a or "nil"))
print("file:".. (b or "nil"))
print("ext:".. (c or "nil"))
Output:

Code: Select all

path:c:/dev/games/
file:oops.lua
ext:lua
User avatar
Ref
Party member
Posts: 702
Joined: Wed May 02, 2012 11:05 pm

Re: lua utils

Post by Ref »

I have a warped sense of what 'filename' means.
Expected 'filename' would be the name without extension.
Your function returns path, filename.ext and ext.
Lot of neat stuff in your library.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

SVG

Post by ivan »

I noticed a few people asking if SVG files can be used/loaded in Love2D/Lua.
After a lot of testing with the AGen engine I have to say, yes, it's possible but it's slow and not very practical.
Check out the attached SVG demo.
It's only a demo though so don't treat this as a complete library.
All done in Lua, no external libs. Love2D is used purely for rendering.

What "utils.svg" supports:
-parses svg files (parses xml using "utils.io.table")
-filled paths with holes (triangulates using "utils.math.poly")
-bezier curves (level of detail is defined in "utils.math.curves")
-filled shapes
-elliptic arcs

What's not supported:
-stroke (requires polygon offsetting)
-self-intersecting paths, fill-rules, etc (requires polygon difference/union)
-textures/images
-gradients
-type and fonts
-styles

How to use:
Use the left/right arrow keys to change examples.
So ya, don't expect this to work for every type of SVG file, but as long as it doesn't use "stroke" it would probably work.
Extract svg.love and drop your SVG files into "svg/tests/" to try it out.
Attachments
svg.love
svg demos
(214.64 KiB) Downloaded 312 times
User avatar
arampl
Party member
Posts: 248
Joined: Mon Oct 20, 2014 3:26 pm

Re: lua utils

Post by arampl »

Check my post in the "What's everyone working on? (tigsource inspired)" section (page 110).
May be you find this interesting. Self-intersecting beziers (it's only the beginning of full paths support).
SVG import is planned. I'm thinking about full-scale vector editor and new lua+vector graphics file format.

About slowliness: vector graphics can be prepared beforehand using canvases, and drawn as plain images in love.draw() later. Something like precaching svgs' in Qt.

Vector graphics can be extremely useful for procedural content generation. Just invaluable tool for that. Plus different shaders for amazing effects.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest