Post-0.10.0 feature wishlist

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
HugoBDesigner
Party member
Posts: 403
Joined: Mon Feb 24, 2014 6:54 pm
Location: Above the Pocket Dimension
Contact:

Re: Post-0.10.0 feature wishlist

Post by HugoBDesigner »

So, I've been working with stencils quite a lot lately, and I was thinking: would it be possible for stencils to have some sort of "smoothness"? I mean, they're basically a "pixel map". If a value meets this "map", it'll be drawn full alpha (or whatever alpha value for that pixel is). But, would it be possible that the alpha would be "decreased" if that pixel isn't of value 1? I'm sucking at giving a proper explanation, but in summary: it'd make the edges of stencils smoother, rather than super sharp like they currently are.

On that note, is it already possible to add a stencil mode where you can detect if the stencil value is between two numbers, instead of greater or smaller or equal to a single value?
@HugoBDesigner - Twitter
HugoBDesigner - Blog
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: Post-0.10.0 feature wishlist

Post by Positive07 »

You could draw to a larger canvas with a stencil, then draw that canvas to string scaling it down, I guess the inverse is also true.

Stencils are a mask, basically true or false, draw or don't draw and is something GPU come with so LÖVE doesn't do much on top of that I guess
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
slime
Solid Snayke
Posts: 3131
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Post-0.10.0 feature wishlist

Post by slime »

You can also use MSAA to make things a bit smoother (this affects stenciling too), but yeah, the stencil test is still fundamentally a binary yes/no operation.
HugoBDesigner wrote:On that note, is it already possible to add a stencil mode where you can detect if the stencil value is between two numbers, instead of greater or smaller or equal to a single value?
I don't think GPUs / graphics APIs support that natively, unfortunately.
Last edited by slime on Mon Sep 12, 2016 1:12 am, edited 2 times in total.
User avatar
HugoBDesigner
Party member
Posts: 403
Joined: Mon Feb 24, 2014 6:54 pm
Location: Above the Pocket Dimension
Contact:

Re: Post-0.10.0 feature wishlist

Post by HugoBDesigner »

So basically the only way of doing the smoothing out would be to draw the same thing several times, one for each alpha value?

EDIT: Slime beat me on posting that faster. Oh well, I could give the stencil+canvas trick a go, I guess. Thanks for the reply! It's a bit unfortunate that the GPU APIs are limited in that manner, would make things a lot easier :P
@HugoBDesigner - Twitter
HugoBDesigner - Blog
MachineCode
Citizen
Posts: 70
Joined: Fri Jun 20, 2014 1:33 pm

Re: Post-0.10.0 feature wishlist

Post by MachineCode »

Hi

Love2d with ZeroBrane has become my favourite programming tool and it gets better each release.

I wrote some code that uses the threads and channels to communicate. The ImageData object is very useful as it lets you efficiently do work on the bitmap and then handle the update to screen in the main Draw thread - you pass a reference to it. What I was thinking was it would be very nice if there was a general purpose object similar to ImageData, but more like an array of 32 bit words that could be accessed as bytes, shorts, ints. ArrayData might be a reasonable name for this. I would think this new data object would be quite similar code to ImageData, but maybe a little simpler. Maybe it could be part of the thread system or a new Data section?

The reasoning behind this is that if you want to process large blocks of data and pass them to different threads, Lua is not efficient with strings or tables being passed via channels. Suppose we have 64K blocks of data coming from a network port or USB device. We create a string and then pass it to another thread which might be a VM that is implimenting a draw engine. that will exercise the garbage collector a lot and does not scale well. On the other hand, if incoming data is put in an ArrayData object, then this can be passed by reference to another thread which can process it. In fact, using multiple threads in a pipeline becomes possible. I think there would be lots of applications for this object as a thread friendly way to share data efficiently. Obviously it would be the programmers responsibility to manage ownership of the object, but that is the same with ImageData.


love.data.newArrayData(size) - size is in 32 bit words, so multiples of 4 bytes

The ArrayData object allows r,w as 8, 16, 32 values aligned to natural boundaries. In each case the index is in multiples of the data size.

number = ArrayData:read8(byte_index)
number = ArrayData:read16(short_index)
number = ArrayData:read32(int_index)

ArrayData:write8(byte_index, number)
ArrayData:write16(short_index, number)
ArrayData:write32(int_index, number)

The ability to insert or retrieve strings from anywhere in the ArrayData object would be very nice. This would mean a byte index and string length for the Get and just a byte index and string for the put.

string = ArrayData:getstr(byte_index, str_size)
ArrayData:putstr(byte_index, string)

Since strings are most likely what you get from any data source, this put/get gives a really simple way of getting the string into an efficient mutable array object which can then be processed by some other thread. Easy to do BitOps on the data - like you might want for CPU emulators etc. Think about a string representing a 6502 program that you feed to an emulator process - this makes it easy.

Those few functions would be pretty much all you need for this to be useful. The only other nice feature might be a "fill" to set all the array to a known pattern, but not essential. This object would be a much better version of ByteArray.
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Post-0.10.0 feature wishlist

Post by pgimeno »

You can do that already with FFI. The only problem is that there doesn't seem to be a way to produce pure Data objects. But you can use for example SoundData, so you can do:

Code: Select all

local ffi = require 'ffi'
local rawdata = love.sound.newSoundData(ArrayLength, 44100, 16, 2) -- 16 bits * 2 channels = 32 bits per entry
local array = ffi.cast('uint32_t *', rawdata:getPointer())
for i = 0, ArrayLength-1 do
  array[i] = love.math.random(0, 999999)
end
You can now pass rawdata through a channel, and an identical call to ffi.cast will let you retrieve the values on the other side through the variable array.

[Edit: But you have to be careful. These FFI objects are raw pointers. They won't give you nil for non-existing elements, and they will let you write out of bounds, which is almost assured to cause a disaster.]

I guess that adding creation of generic Data objects would be nice, though.
User avatar
slime
Solid Snayke
Posts: 3131
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Post-0.10.0 feature wishlist

Post by slime »

pgimeno wrote:I guess that adding creation of generic Data objects would be nice, though.
MachineCode wrote: number = ArrayData:read8(byte_index)
number = ArrayData:read16(short_index)
number = ArrayData:read32(int_index)

ArrayData:write8(byte_index, number)
ArrayData:write16(short_index, number)
ArrayData:write32(int_index, number)
Something like both of these would be useful I think - although as pgimeno mentioned you can already do the latter via the FFI, [wiki]Data:getPointer[/wiki], and ffi.cast.

A generic Data object is easier to design and implement than a more specific set of APIs, so that'll probably happen first. :)
MachineCode
Citizen
Posts: 70
Joined: Fri Jun 20, 2014 1:33 pm

Re: Post-0.10.0 feature wishlist

Post by MachineCode »

I was think some more about how you could use a data object like this, and it occurred to me that the ability to insert and extract data via strings -

string = ArrayData:getstr(byte_index, str_size)
ArrayData:putstr(byte_index, string)

is an extremely useful tool for managing data coherence across multiple threads - providing the operation is atomic, which I suspect would be an inherent property. This would let you set up a data object with mailboxes of arbitrary data size which would always be coherent provided the read/write used the atomic string insert/extract method.

The current channel mechanism is an excellent feature and works very well, however in some cases a shared data object is better. The problem with shared data objects is that unless you only use single values, a lock is needed to prevent other threads accessing multi value sets during update. The ability to insert/extract via strings actually negates the need for locks and gives a very simple thread safe shared data object. A simple robust mechanism like this can make it a lot easier for people to effectively use threads, and the use of strings is very natural for Lua.


Here is an example of how you might practically use this data object and how it would compare to using channels. You have a game where there are 128 short (<80 char)text strings that can be presented to the user depending on what they do in game, however the contents of the text strings is being modified by an AI component(s) running in one or more threads.

Using channels, the AI processes might keep a list of clients who use the strings and send new ones as produced. The client(s) would then maintain their own private table of strings. If you start a new client process that wants to use these strings you have a problem, because the table state is only stored in existing clients. So, you now need a master client that only exists to accumulate the latest version of the string table. Anyone else who wants a particular string might as well send a request to this thread and get the string back via a channel. All up there is quite a bit of design and management in constructing the channels to achieve all this.

Using the shared data object, this is how it could work. A data object is created with a size of 128 x 84 (10,752 bytes or 2,688 words). This is effectively 128 "slots" which consist of a string length followed by up to 80 bytes which includes the text string. AI threads and any client threads are given a reference to this data object. Anyone can update a text entry by making a string with the length in the first 4 bytes and the new text appended and then using the atomic string insert to the data object. A client reads a text slot by doing a full 84 byte string extract (atomic) on the slot, then recovers the text by pulling out the length in the 4th byte of the string and then grabbing the appropriate data using lua str library. Simple and not network of channels required.

I think that for many applications the coherent data object is a much simpler way of sharing data across threads - a sort of swiss army knife. PingPong buffers between threads, mailboxes, data flow - lots of interesting ways to use this.
User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Post-0.10.0 feature wishlist

Post by raidho36 »

LUA is by design not multithreaded, the threads are implemented as separate LUA states (hence LUA threads can share absolutely nothing) and the only means of communication between these is copying around data packets. What the framework does is a workaround and is pretty much the best you get, your suggestion is the same except requires lower level access and thus extra work for no good reason. Of course string operations are not atomic, too.
User avatar
slime
Solid Snayke
Posts: 3131
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Post-0.10.0 feature wishlist

Post by slime »

As raidho says, strings (and any other Lua-owned value) cannot be shared between love threads, since each thread is a completely independent Lua instance.

The string example you gave would need to perform a mutex lock and copy the string's bytes, every time it's read or written. You can already accomplish this using the FFI as pgimeno described (the thread safety would be in the form of Channels if you need - there's a mutex abstraction for Channels here, if you prefer: https://github.com/slime73/love-mutex/b ... /mutex.lua )
Post Reply

Who is online

Users browsing this forum: No registered users and 53 guests