News : The level of daily SPAM has reached insane proportions, all registrations are now manual.
I ask you to send me an e-mail (john (at) murga (dot) org), to confirm that you want me to create an account for you.
when trying some transparent images.
Johns globe example is working fine, tiling weird, but loads.
A lot of my png files are not working. But others are.
The ones that are not working have been run through
a PNG optimizer. I wonder what the difference is?
This post was last modified: 02-25-2008 08:15 PM by iGame3D.
image1 = Fl_Shared_Image.get(fileName,ts*tc,ts*tc)
is the problem
image1 = Fl_Shared_Image.get(fileName)
stops the segmentation fault.
Well that really sucks. I was counting on the ability to resize the image automatically so you don't need to manually resize all your images to specific dimensions. I've tried image=Fl_Shared_Image.get(fileName) followed by image1=image:copy(ts*tc,ts*tc), but that also segfaults. I haven't tried image1:h(ts*tc); image1:w(ts*tc)
Considering getTiles() seems to work only for RGB images, I could try replacing Fl_Shared_Image.get() with Fl_PNG_Image() and others specific to the selected file's type. Perhaps it would do a better job of handling the image, but I'm just speculating.
Quote:
I get attempt to index field '?' (a nil value) at
Code:
tile[key-1]:image(value)
tile[key-1]:redraw()
when trying some transparent images.
It seems one or more transparent tiles aren't being added to the table? Another possibility is that removing the image resizing creates a gap between the number of tiles in the interface and the number of tiles in the image.
I wonder if it's possible to dynamically remove transparency from a PNG before resizing it in FLTK. That might solve the whole thing.
I found a partial solution to the segfault. Using the data() method that John demonstrated in imageDecodingTest.lua, I was able to limit the image depth to 3, which messes up the look of transparent images but at least prevents the crash.
So apparently there is a problem with getTiles() reading an alpha channel on a resized image?
EDIT: Made some minor changes to the preview behavior, added bmp to the filename filter and more comments
Code:
#!/home/dsl/bin/murgaLua-0.6.4
-- slide puzzle for MurgaLua 0.6.4+
-- 2008 mikshaw
-- window and image size are determined by these variables
ts=64 -- tile size
--ts=48 -- tile size
tc=4 -- number of tiles in one line
fr=5 -- frame size
if not Fl_Image.getTiles then
fltk.fl_alert("This program requires murgaLua 0.6.4 or newer.\n\n"..
"http://www.murga-projects.com/murgaLua/index.html")
os.exit(1)
end
function reset_hidden()
tile[hidden]:box(fltk.FL_UP_BOX)
tile[hidden]:labeltype(fltk.FL_NORMAL_LABEL)
end
function load_callback(object)
-- mod of a function (and a piece) written by John Murga
fileName = fltk.fl_file_chooser("Choose an RGB image", "Image Files (*.{jpg,png,bmp})", nil, nil)
if fileName then
if image1 then image1:uncache() end -- don't know if this is needed
image1 = Fl_Shared_Image.get(fileName,ts*tc,ts*tc)
prev_img:image(image1); prev_img:redraw() -- load the preview
test = image1:data()
-- force d(3) to prevent problems with alpha channel
image2 = fltk:Fl_RGB_Image(test[1], test["w"], test["h"], 3, test["ld"])
myImages = image2:getTiles(ts,ts)
for key,value in ipairs(myImages) do
tile[key-1]:image(value)
-- tile[key-1]:redraw()
end
scramble()
scrambutt:label("load an image")
end
end
function move_tile(t)
if Fl:event_button() >1 then prev_butt:do_callback() elseif image2 then
local my_x,my_y,movex,movey=t:x(),t:y()
-- tile must be adjacent to the missing piece
if (my_x == tile[hidden]:x() and math.abs(my_y-tile[hidden]:y()) == ts)
or (my_y == tile[hidden]:y() and math.abs(my_x-tile[hidden]:x()) == ts)
then
-- swap selected tile with the hidden one
movex=tile[hidden]:x()
movey=tile[hidden]:y()
tile[hidden]:position(my_x,my_y)
t:position(movex,movey)
w:redraw()
end
-- check to see if puzzle is solved
-- "ok" is incremented each time a tile is found in its proper place
if start==0 then -- don't check puzzle during scramble
local ok=0
for i=0,tc*tc-1 do
if tile[i]:x()==pos[i].col and tile[i]:y()==pos[i].row then
ok=ok+1
if ok==tc*tc then -- if ok == total number of tiles
reset_hidden() -- reset the hidden tile
fltk.fl_beep()
scrambutt:label(plize[math.random(1,table.getn(plize))])
for i=0,tc*tc-1 do tile[i]:set_output() end -- disable the buttons
break
end
end
end
end
end
end
function scramble()
-- this picks a random tile to attempt to move and
-- repeats the process many times. Simply placing
-- tiles in random locations could potentially make
-- the puzzle impossible to solve
for i=0,tc*tc-1 do tile[i]:clear_output() end -- enable the buttons
if hidden then reset_hidden() end
-- turn a random tile into the missing piece
hidden=math.random(0,tc*tc-1)
tile[hidden]:labeltype(fltk.FL_NO_LABEL)
tile[hidden]:box(fltk.FL_DOWN_BOX)
start=1
local scram=0
while scram < 10000 do
move_tile(tile[math.random(0,tc*tc-1)])
scram=scram+1
end
start=0
w:redraw()
end
fltk.fl_register_images()
math.randomseed(os.time())
Fl:visible_focus(0) -- get rid of the ants
Fl:set_boxtype(fltk.FL_UP_BOX,fltk.FL_THIN_UP_BOX) -- looks a little more like tiles
Fl:set_boxtype(fltk.FL_DOWN_BOX,fltk.FL_THIN_DOWN_BOX)
w=fltk:Fl_Double_Window(ts*tc+fr*2,ts*(tc+0.5)+fr*3,"slide puzzle")
scrambutt=fltk:Fl_Button(fr,ts*tc+fr*2,ts*tc,ts/2,"load an image")
scrambutt:callback(load_callback)
-- array of tiles, top left to right, then move down
tile={}; pos={}
-- allow space for the frame
row=fr; col=fr
-- subtract one is used because the number of tiles starts at one
-- but the table starts at zero (easier to position them from zero)
for i=0,tc*tc-1 do
tile[i]=fltk:Fl_Button(col,row,ts,ts)
tile[i]:align(80)
tile[i]:callback(move_tile)
pos[i]={col=col,row=row}
-- next piece is ts pixels to the right
col=col+ts
-- start the next row
if col == ts*tc+fr then col=fr;row=row+ts end
end
-- offscreen button to call the preview window with a hotkey
prev_butt=fltk:Fl_Button(0,0,0,0,"&p")
prev_butt:callback(function() preview:show() end)
fltk:Fl_End() -- end of main window
I'm assuming that's from the extra channel, but I don't want to say for sure. All I know is that is a result of forcing a color depth of 3 on images that would normally be 4. (i guess maybe those numbers would be bytes, so a depth of 4 would be an image with 32-bit color?). I'm hoping to find a way to avoid having to do this....maybe I'll just not allow any 32-bit images to be loaded.
Another potential segfault can be seen when increasing the size and number of tiles. This is another mystery to me.
I'm assuming that's from the extra channel, but I don't want to say for sure. All I know is that is a result of forcing a color depth of 3 on images that would normally be 4. (i guess maybe those numbers would be bytes, so a depth of 4 would be an image with 32-bit color?). I'm hoping to find a way to avoid having to do this....maybe I'll just not allow any 32-bit images to be loaded.
I think that the PNG (and maybe also JPG) support needs some fixing. I haven't looked into the code but I guess the Fl_Shared_Image.get method returns (obviously) an RGBA image (when the loaded image contains an alpha channel). It might work better when you use Fl_PNG_Image() instead. It is supposed to "handle color- and alpha-based transparency". (Whatever that means)
The problem is that PNG has a few different color modes:
1) indexed with 1,2,4,8 bits per pixel
2) grey with 1,2,4,8,16 bit per pixel
3) grey with alpha: 16 or 32 bit per pixel (with 8 or 16 bit alpha channel)
4) RGB with 8 or 16 bits per channel this makes 24 or 48 bits per pixel
5) RGBA with 8 or 16 bits per channel this makes 32 or 64 bits per pixel
When this raw RGB(A) data is handled the pixel and channel size has to taken into account, when the memeroy is reserved and also (obviously) when the individual pixels accessed. I haven't looked into the sources, but I guess that gettiles() just assumes a pixel size of 3 bytes. Then you would get ecactly the effect that you can see. When gettiles scans the RGBA values you can see that alternating one of the RGB values is blanked out, because in memory it looks like RGB0RGB0RGB0RGB0.... which is then scanned as RGB,0RG,B0R,GB0,RGB,....
mikshaw Wrote:
Another potential segfault can be seen when increasing the size and number of tiles. This is another mystery to me.
If the C/C++ code makes wrong assumptions about the pixel size, most likely it tries to access a memory location which is not backed by physical memory, which will result in a segmentation fault. Even if the program accessed a wrong address it is not necessary that a segmentation fault occures. There are up to 4095 bytes after the last valid address it can access, before a segfault occures. It is even possible that valid addresses, used by other objects follow, so even if something goes wrong, it may go unnoticed under some conditions and under some others not.
(If you want, I can elaborate it a little more.)
I guess the Fl_Shared_Image.get method returns (obviously) an RGBA image (when the loaded image contains an alpha channel). It might work better when you use Fl_PNG_Image() instead. It is supposed to "handle color- and alpha-based transparency". (Whatever that means)
That makes sense. It's something that crossed my mind but I haven't done any tests yet. Still, I don't see that explaining why an RGBA file loaded with Fl_Shared_Image.get() would tile properly if it's not resized.
Quote:
When gettiles scans the RGBA values you can see that alternating one of the RGB values is blanked out, because in memory it looks like RGB0RGB0RGB0RGB0.... which is then scanned as RGB,0RG,B0R,GB0,RGB,...
...
If the C/C++ code makes wrong assumptions about the pixel size, most likely it tries to access a memory location which is not backed by physical memory, which will result in a segmentation fault.
You see, this is exactly the sort of thing that amazes me. I wouldn't have a clue to even begin speculating what the prblems are, but your explanations makes complete sense =o)
Quote:
If you want, I can elaborate it a little more.
I wouldn't mind at all, if you don't mind. I might not be able to follow it, but at the least I might have a little better understanding of how images are handled and about why I have to tweak things so often to prevent crashes.
I noticed two more things that "puzzle" me, one about getTile() and one about my script. The first is that getTile() seems to vertically compress the tiles slightly (maybe by a pixel?). This creates a shift in the tiled image and a small line along the bottom of the image:
The other is the fact that the scrambling occasionally results in teh unsolvable puzzle that I had consciously tried to avoid by not simply choosing random locations for the tiles:
puzzle.jpg (Size: 25.15 KB / Downloads: 31)
The two tiles in the bottom right are apparently impossible to swap. Maybe I haven't thought it through completely yet, but it seems like this should never happen if the scramble is done in a loop that checks to make sure a tile is adjacent only to the "hidden" tile before doing a swap.
Then again, it could be an issue of changing images before the puzzle is solved. If that's the case then maybe the hidden tile is in an inappropriate place to start with. If so I think I'll need to force the tile postitions to reset with every image change.
myImages = image1:getTiles(ts,ts)
prevented the destruction of the the image as posted previously.
Yes, that's how I had it originally, but was the cause of my original problem...crashing with resized 32-bit images. I'm still considering simply refusing 32-bit fr the time being.
Quote:
also note I changed
image1 = Fl_Shared_Image.get(fileName,ts*tc,ts*tc)
to
image1 = Fl_Shared_Image.get(fileName)
image1:h(ts*tc); image1:w(ts*tc)
But that didn't seem to make a world of difference.
I tried that too, but w() and h() of images are protected methods. I never quite understood the definition of protected as it relates to FLTK, but it seems that you cannot use it to directly set the dimensions of an image. That's why I specify height and width in Fl_Shared_Image.get().
I also tried image2=image1:copy(ts*tc,ts*tc), which results in the same behavior.