[Lua] Palette Based Graphics Programming

Started by Scavenger, Wed 27/11/2013 15:35:39

Previous topic - Next topic

Scavenger

Thank you so much Calin! I never dreamed I'd get my module running fullspeed! Now I can use translucent images in my next game without losing any speed!

Now all I have to do is fiddle with it a bit to get it to work all across the spectrum, and possibly convert all the other parts of the module to Lua as well! I am so excited about the possibilities!
(And the CLUT generator definitely, that thing takes like an hour on this computer to render a CLUT.)

Though, now I'm getting this error:

Quote---------------------------
Adventure Game Studio
---------------------------
An internal error has occurred. Please note down the following information.
If the problem persists, post the details on the AGS Technical Forum.
(ACI version 3.3.0.1148)

Error: [Lua] [string "local select = select;local error = error;l..."]:1: bad argument #2 to 'setter' (number expected, got nil)

This happens every time there's an unclean crash in the AGS engine or editor. The project is thereafter ruined, even if the code is okay.

Calin Leafshade

No, I'm using Wine.

I loaded the 3.2.1 project in the version of AGS I happen to have on my laptop which is:

AGS Editor .NET (Build 3.3.0.1132) ** BETA VERSION **
v3.3.0, April 2013


Calin Leafshade

Quote from: Scavenger on Fri 29/11/2013 22:36:26
Though, now I'm getting this error:

Quote---------------------------
Adventure Game Studio
---------------------------
An internal error has occurred. Please note down the following information.
If the problem persists, post the details on the AGS Technical Forum.
(ACI version 3.3.0.1148)

Error: [Lua] [string "local select = select;local error = error;l..."]:1: bad argument #2 to 'setter' (number expected, got nil)

This happens every time there's an unclean crash in the AGS engine or editor. The project is thereafter ruined, even if the code is okay.

I have seen that error before but never found out what causes it. Maybe a Rebuild All Files might fix it, i'm not sure.

Crimson Wizard

There's some mystery here.
3.2.1 crashes at loop count 100.
3.3.0 betas 1 - 9 do not crash, but I see no blending effect (just two opaque characters).
3.3.0 beta 10 crashes like 3.2.1.
:(

I'll check again tomorrow, maybe I am doing something wrong, or using older version of plugin or something.

Scavenger

Rebuild All Files didn't work. Hmm. I just wish it was a little more stable on my end. :P This makes it very hard to want to use it in a real game, if there's a danger of an editor or engine crash that messes everything up. Not all script errors quit neatly!

I'll upload the project file - It works, you can see the translucency, but on Loop 17 it falls dead.

https://dl.dropboxusercontent.com/u/50882197/Game/paltest_ruined.zip (3.3.0)

And the version of Lua for AGS I'm using is the one from here: http://lua-for-ags.wikispaces.com/Downloads

Calin Leafshade

My version works well into loop 500 with no issues.

I think this might be some issue with AGS itself. It does seem to be behaving oddly.

Posting your error into the Lua plugin thread might be helpful since I think the author monitors that thread.

Khris


Scavenger

Okay, I've moved all of the necessary files over to 3.2.1 and I'll just work on this module from there until it can be confirmed that Lua and 3.3.0 can work nicely together. (And I'll hit up the Lua plugin thread to give my bug reports.)

I'm now converting this code:

Code: AGS

static function PALgorithms::ProcessPalette (int palsiz, int palindex[])
{
  int paltemp [];
  paltemp = new int [palsiz];
  char i = 0;
  int i2 = 1;
  int upperboundary;
  while (i < palsiz)
  {
    paltemp [i] = (palette[palindex[i]].r +  // This algorithm produces an accurate, fast approximation of
                   palette[palindex[i]].r +  // The luminescence value of each of our palette slots.
                   palette[palindex[i]].r +  //
                   palette[palindex[i]].b +  // This ensures that when we colourise the final product, there 
                   palette[palindex[i]].g +  // will be little to no weird artifacts or lightness shifts.
                   palette[palindex[i]].g +  //
                   palette[palindex[i]].g +  // By using addition and bit shifts instead of multiplication, 
                   palette[palindex[i]].g    // the code will run a lot faster and more efficiently.
                   )>>3;
    i++;
  }
  i = 0;
  while (i < palsiz)
  {
      //Display ("%d , %d", i,  i+1);
      if (i > palsiz -2) upperboundary = 255;
      else upperboundary = (paltemp [i] + paltemp [i + 1])/2;
      //Display ("%d",upperboundary);

      while (i2 < upperboundary)
      {
        String output;
        _C8palgorithm [i2] = palindex[i];
        i2++;
      }
    i++;
    }
    
    i= 0;
    paltemp = new int [256];
    while (i < 255)
      {
       paltemp [i] = (palette[i].r +  // This algorithm produces an accurate, fast approximation of
                      palette[i].r +  // The luminescence value of each of our palette slots.
                      palette[i].r +  //
                      palette[i].b +  // This ensures that when we colourise the final product, there 
                      palette[i].g +  // will be little to no weird artifacts or lightness shifts.
                      palette[i].g +  //
                      palette[i].g +  // By using addition and bit shifts instead of multiplication, 
                      palette[i].g    // the code will run a lot faster and more efficiently.
                      )>>3;
                      i++;
      }
    i = 0;
    while (i < 255)
      {
       _C8PaletteMap [i] = _C8palgorithm [paltemp[i]];
       i++;
      }
  } 


But I'm not sure how to pass a dynamic array to Lua. The wiki doesn't seem much help. :( Everything else is fine, I can deal with that, but there isn't much documentation on transferring arrays between AGS and Lua.

Calin Leafshade

Make a new LuaValueList and add the values 1 by 1. It's not ideal but its probably the best you'll get.

(all code untested and done from memory)
Code: ags

    LuaValueList *list = Lua.NewValueList();
    int i = 0;
    while (i < arrayCount)
    {
        list.Add(Lua.IntValue(array[i]))
        i ++;
    }
    Lua.Call("func", list)


Code: lua

    function func(...) -- This means it has an arbitrary number of args
        local array = {...} -- This encapsulates those args into a table.
        --do shit with array
    end


If you want to have other values too you can do this:

Code: lua

    function func(valA, valB, ...)
        -- now you can use valA and valB as normal and still encap the ... args.
    end

Crimson Wizard

Quote from: Scavenger on Sat 30/11/2013 19:01:28
Okay, I've moved all of the necessary files over to 3.2.1 and I'll just work on this module from there until it can be confirmed that Lua and 3.3.0 can work nicely together.
Do you have a 3.2.1 project that works well for you? Having that will help to debug 3.3.0.

Scavenger

The 3.2.1 files are here: https://dl.dropboxusercontent.com/u/50882197/Game/paltest321.zip

Also, how do you access the palette array with Lua? I've tried ags.palette.r et al but it just returns:
Error: [Lua][string "ProcessTranslucency.lua"]:99 attempt to index field 'palette' (a nil value)

Code: Lua
function ProcessPalette (...)
  local palindex = {...}
  local paltemp = {...}
  local i = 0
  local i2 = 1
  local upperboundary
  C8Palgorithm = {}
  C8PaletteMap = {}
  while (i < table.getn(palindex))
  do
    paltemp [i] = ags.palette[i].r + ags.palette[i].r + ags.palette[i].r + ags.palette[i].b +  ags.palette[i].g + ags.palette[i].g + ags.palette[i].g + ags.palette[i].g
    paltemp [i] = bit.rshift(paltemp [i],3) 
    i = i + 1
  end
  i = 0
  C8palgorithm = {}
  while (i < palsiz)
  do
      if (i > palsiz -2) then upperboundary = 255
      else upperboundary = (paltemp [i] + paltemp [i + 1])/2; end
      
      while (i2 < upperboundary)
      do
        C8palgorithm [i2] = palindex[i]
        i2 = i2 + 1
      end
    i = i + 1
  end
    
   i= 0
   paltemp = {}
   while (i < 255)
      do
       paltemp [i] = ags.palette[i].r + ags.palette[i].r + ags.palette[i].r + ags.palette[i].b +  ags.palette[i].g + ags.palette[i].g + ags.palette[i].g + ags.palette[i].g
       paltemp [i] = bit.rshift(paltemp [i],3)
       i = i+ 1
      end
    i = 0
    while (i < 255)
      do
       C8PaletteMap [i] = C8palgorithm [paltemp[i]]
       i = i + 1
      end
  
end

Calin Leafshade

It doesn't look like there is a way to access the palette. I'd suggest posting that in the Lua Plugin thread to get it added.

You could just pass the palette to the plugin in the way I described in my last post though.

Crimson Wizard

Hmm, interesting.

First of all, the effect I see in this game is different, the Jacob (name is right?) character is not translucent, but he has some weird effect applied on it, looks like running vertical scanlines. Is this what is expected to happen?

Secondly, I made a copy of the project, opened it in 3.3.0.1148 (beta 10) and made full rebuild. The game runs fine with same effect. No crashes so far  (waited till loop 500).

Scavenger

I was testing the very edges of the translucency effect, since I only have 8 CLUTs at the moment, change the SetTransparency function in Room 1.asc to 50 to see a more spectacular effect.

And I'll do that, thanks Calin!

Crimson Wizard

Quote from: Scavenger on Sat 30/11/2013 21:48:08
I was testing the very edges of the translucency effect, since I only have 8 CLUTs at the moment, change the SetTransparency function in Room 1.asc to 50 to see a more spectacular effect.
Ah, I see now. Yes, that's nice, although his legs do not look translucent. Maybe because the background color is too close, or that table missing some colors?
Anyway still works well in 3.2.1 and 3.3.0. Maybe the previous errors was due "project corruption" you mentioned?
I'll keep an eye on how this progresses, I must make sure that 3.3.0 works well with plugins.

Scavenger

Yeah, there's probably not enough purples and purple-like colours in the palette for it to work properly. It DOES, however, work really nicely for a wide variety of effects - I'm not quite sure how to make characters translucent yet as that requires fiddling around with the ViewFrame functions and that is some deep stuff I don't want to mess around with.

I'm trying to code a workaround for passing the palette to Lua, but I don't think Lua likes having 256 parameters in it's functions.

Code: AGS
function GiveLuaPalette ()
{
  LuaValueList *r = Lua.NewValueList();
    int i = 0;
    while (i < 255)
    {
        r.Add(Lua.IntValue(palette[i].r));
        i ++;
    }
    Lua.Call("CatchPalette_R", r, eLuaUnprotectedMode);
    
    LuaValueList *b = Lua.NewValueList();
    i = 0;
    while (i < 255)
    {
        b.Add(Lua.IntValue(palette[i].b));
        i ++;
    }
    Lua.Call("CatchPalette_B", b, eLuaUnprotectedMode);
    
      LuaValueList *g = Lua.NewValueList();
    i = 0;
    while (i < 255)
    {
        g.Add(Lua.IntValue(palette[i].g));
        i ++;
    }
    Lua.Call("CatchPalette_G", g, eLuaUnprotectedMode);
}


function ProcessPaletteLua (int palsiz, int palindex [])
{
  GiveLuaPalette ();
  LuaValueList *list = Lua.NewValueList();
    int i = 0;
    while (i < palsiz)
    {
        list.Add(Lua.IntValue(palindex[i]));
        i ++;
    }
    Lua.Call("ProcessPalette", list, eLuaUnprotectedMode);
}

static function PALgorithms::ProcessPalette (int palsiz, int palindex[])
{
  /*
  int paltemp [];
  paltemp = new int [palsiz];
  char i = 0;
  int i2 = 1;
  int upperboundary;
  while (i < palsiz)
  {
    paltemp [i] = (palette[palindex[i]].r +  // This algorithm produces an accurate, fast approximation of
                   palette[palindex[i]].r +  // The luminescence value of each of our palette slots.
                   palette[palindex[i]].r +  //
                   palette[palindex[i]].b +  // This ensures that when we colourise the final product, there 
                   palette[palindex[i]].g +  // will be little to no weird artifacts or lightness shifts.
                   palette[palindex[i]].g +  //
                   palette[palindex[i]].g +  // By using addition and bit shifts instead of multiplication, 
                   palette[palindex[i]].g    // the code will run a lot faster and more efficiently.
                   )>>3;
    i++;
  }
  i = 0;
  while (i < palsiz)
  {
      //Display ("%d , %d", i,  i+1);
      if (i > palsiz -2) upperboundary = 255;
      else upperboundary = (paltemp [i] + paltemp [i + 1])/2;
      //Display ("%d",upperboundary);

      while (i2 < upperboundary)
      {
        String output;
        _C8palgorithm [i2] = palindex[i];
        i2++;
      }
    i++;
    }
    
    i= 0;
    paltemp = new int [256];
    while (i < 255)
      {
       paltemp [i] = (palette[i].r +  // This algorithm produces an accurate, fast approximation of
                      palette[i].r +  // The luminescence value of each of our palette slots.
                      palette[i].r +  //
                      palette[i].b +  // This ensures that when we colourise the final product, there 
                      palette[i].g +  // will be little to no weird artifacts or lightness shifts.
                      palette[i].g +  //
                      palette[i].g +  // By using addition and bit shifts instead of multiplication, 
                      palette[i].g    // the code will run a lot faster and more efficiently.
                      )>>3;
                      i++;
      }
    i = 0;
    while (i < 255)
      {
       _C8PaletteMap [i] = _C8palgorithm [paltemp[i]];
       i++;
      }
      */
      ProcessPaletteLua (palsiz, palindex);
  } 
  
function Colourise (DynamicSprite* sprite)
{
  LuaValueList *list = Lua.NewValueList();
  list.Add(sprite.AsLuaValue());
  Lua.Call("Colourise", list, eLuaUnprotectedMode);
}

function ColouriseArea (this DynamicSprite*, int x1,  int y1,  int w,  int h)
{
  DrawingSurface *Surface;
  DynamicSprite *Area;
  //Display ("Init C8");
  mouse.Visible = false;
  Wait (1);
  Area = DynamicSprite.CreateFromScreenShot (320, 200);
  //Display ("Screenshot created.");
  mouse.Visible = true;
  if (Area.ColorDepth != 8) AbortGame ("Error in COLOR8: Isn't an indexed image!");
  int realwidth = w;
  int realheight = h;
  if (x1 + w > 320) realwidth = 320 - x1;
  if (y1 + h > 200) realheight = 200 - y1;
  int realx = x1;
  int realy = y1;
  if (x1 == 320) 
  {
    realx = 319;
    realwidth = 1;
  }
  if (y1 == 200)
  {
    realy = 199;
    realheight = 1;
  }
  Area.Crop (realx, realy, realwidth, realheight);
  Colourise (Area);
  /*Surface = Area.GetDrawingSurface ();
  int i;
  int j;
  int cpixel;
  while (j < h)
  {
    while (i < w)
    {
      cpixel = Surface.GetPixel (i, j);
      //Display ("Coordinates: %d, %d. Colour: %d",i, j,  Surface.GetPixel (i, j));
      if (cpixel == COLOR_TRANSPARENT) Surface.DrawingColor = COLOR_TRANSPARENT;
      else Surface.DrawingColor = _C8PaletteMap [cpixel];
      Surface.DrawPixel (i, j);
      i++;
    }
    i = 0;
    j++;
  } 
  this.Crop (x1, y1, w, h);
  Surface.Release ();
  */
  this.Crop (realx, realy, realwidth, realheight);
  Surface = this.GetDrawingSurface ();
  Surface.DrawImage (0, 0, Area.Graphic);
  Surface.Release ();
  Area.Delete ();
  return this.Graphic;
}


Code: Lua

function CatchPalette_R (...)
  local i = 0
  local r = {...}
  palette_r = {}
  while (i < 255)
  do
      palette_r [i] = r[i]
      i = i + 1
  end
end

function CatchPalette_B (...)
  local i = 0
  local b = {...}
  palette_b = {}
  while (i < 255)
  do
      palette_b [i] = b[i]
      i = i + 1
  end
end

function CatchPalette_G (...)
  local i = 0
  local g = {...}
  palette_g = {}
  while (i < 255)
  do
      palette_g [i] = g[i]
      i = i + 1
  end
end


function ProcessPalette (...)
  local palindex = {...}
  local paltemp = {...}
  local i = 0
  local i2 = 1
  local upperboundary
  C8Palgorithm = {}
  C8PaletteMap = {}
  while (i < table.getn(palindex))
  do
    --paltemp [i] = ags.palette[i].r + ags.palette[i].r + ags.palette[i].r + ags.palette[i].b +  ags.palette[i].g + ags.palette[i].g + ags.palette[i].g + ags.palette[i].g
    paltemp [i] = palette_r [i] + palette_r [i] + palette_r [i] + palette_b [i] +  palette_g [i] + palette_g [i] + palette_g [i] + palette_g [i]
    paltemp [i] = bit.rshift(paltemp [i],3) 
    i = i + 1
  end
  i = 0
  C8palgorithm = {}
  while (i < palsiz)
  do
      if (i > palsiz -2) then upperboundary = 255
      else upperboundary = (paltemp [i] + paltemp [i + 1])/2; end
      
      while (i2 < upperboundary)
      do
        C8palgorithm [i2] = palindex[i]
        i2 = i2 + 1
      end
    i = i + 1
  end
    
   i= 0
   paltemp = {}
   while (i < 255)
      do
       --paltemp [i] = ags.palette[i].r + ags.palette[i].r + ags.palette[i].r + ags.palette[i].b +  ags.palette[i].g + ags.palette[i].g + ags.palette[i].g + ags.palette[i].g
       paltemp [i] = palette_r [i] + palette_r [i] + palette_r [i] + palette_b [i] +  palette_g [i] + palette_g [i] + palette_g [i] + palette_g [i]
       paltemp [i] = bit.rshift(paltemp [i],3)
       i = i+ 1
      end
    i = 0
    while (i < 255)
      do
       C8PaletteMap [i] = C8palgorithm [paltemp[i]]
       i = i + 1
      end
  
end

function Colourise (ds)
  local surface = ds:GetDrawingSurface ()
  local i;
  local j;
  local h = ds.Height
  local w = ds.Width
  local cpixel;
  while (j < h)
  do
    while (i < w)
    do
      cpixel = surface:GetPixel (i, j)
      if (cpixel == 0)
        then
          surface.DrawingColor = 0
      else 
          surface.DrawingColor = C8PaletteMap [cpixel]
        end
      surface:DrawPixel (i, j)
      i = j + 1
    end
    i = 0
    j = j + 1
  end
  surface:Release ()
end


It just quits with an unspecified error.

Calin Leafshade

Oh apparently you can pass arrays:

Code: ags

    LuaValueList *r = Lua.NewValueList();
    int i = 0;
    while (i < 255)
    {
        r.Add(Lua.IntValue(palette[i].r));
        i ++;
    }
    Lua.Call("CatchPalette_R", r.ToArray(), eLuaUnprotectedMode);


Code: lua

function CatchPalette_R (r)
  palette_r = r
end



Scavenger

I get:

Quotepal2.asc(569): Error (line 569): '.ToArray' is not a public member of 'LuaValueList'. Are you sure you spelt it correctly (remember, capital letters are important)?

Maybe it's in a newer version than what I've got? Where's the latest version of the plugin?

Calin Leafshade


Scavenger

Funny, I do have that version (LuaForAGS_v6_b), but it's not got ToArray in it. I'm not sure what's going on there. Perhaps it wasn't implemented yet?

SMF spam blocked by CleanTalk