Author Topic: Recoloring Script  (Read 16425 times)

Offline Yankes

  • Commander
  • *****
  • Posts: 3293
    • View Profile
Recoloring Script
« on: April 27, 2014, 06:23:46 pm »
This is mod tool (modified OpenXcom source) for recoloring unit sprites on runtime.
To use it you need compile exe using src from https://github.com/Yankes/OpenXcom/tree/ColorScript
Then you can alter ruleset to add scripts.

Some example in action:
https://www.youtube.com/watch?v=_G34PHMiBv0
https://www.youtube.com/watch?v=85A8eSGpO5Q

Features:
  • Reuse same graphic for multiple armors with altered colors
  • Alter look of unit based on stats (e.g. different color based on rank)
  • Special effects (e.g. show blood or fatal wounds on unit arm or leg)
  • Direct control on light shading

Syntax:
Every armor ruleset have new field "recolorScript" in "armors".
Code: [Select]
    recolorScript: |
      #this script is used to recolor solders hair/face colors based on nationality
      get_color r0 in;
      get_shade r1 in;
      test r0 color_hair;
      skip_eq hair;
      test r0 color_face;
      skip_eq face;
      ret in;
     
      hair:
      add r1 soldier_hair;
      ret r1;
     
      face:
      add r1 soldier_face;
      ret r1;
Syntax based on assembler, every line contains
Code: [Select]
label: op arg0 arg1 arg2 arg3;label is optional and number of args depends on op.
Code: [Select]
#"Reg" is one of: "r0", "r1", "r2", "r3", "in"
#"Data" can be Reg, const value (eg "-1", "0x1F"), data from unit
#"Label" is label defined somewhere in script
#"in" reg have value of current pixel

exit; #exit script, value retunded will be from reg "in"

ret Data; #exit with value
ret_gt Data; #exit with value if test is greater
ret_lt Data; #exit with value if test is less
ret_eq Data; #exit with value if test is equal
ret_neq Data; #exit with value if test is not equal

skip Label; #skip to label
skip_gt Label; #skip to label if test is greater
skip_lt Label; #skip to label if test is less
skip_eq Label; #skip to label if test is equal
skip_neq Label; #skip to label if test is not equal

set Reg Data; #set reg
set_gt Reg Data; #set reg if test is greater
set_lt Reg Data; #set reg if test is less
set_eq Reg Data; #set reg if test is equal
set_neq Reg Data; #set reg if test is not equal

Test Data Data; #test two values

swap Reg Reg;  #swap value of two regs
add Reg Data; #add value to reg
sub Reg Data; #subtract value from reg
mul Reg Data; #multiple value of reg

muladd Reg Data Data; #multiple and add in one opeartion
muladdmod Reg Data Data Data; # Reg = (Reg * D1 + D2) % D3

wavegen_rect Reg Data Data Data; #create repeating sequence, args: x, period, rect width, rect height
wavegen_saw Reg Data Data Data; #create repeating sequence, args: x, period, sawtooth width, sawtooth cut out height
wavegen_tri Reg Data Data Data; #create repeating sequence, args: x, period, triangle width, triangle cut out height

div Reg Data; #division reg by value
mod Reg Data; #modulo reg by value

shl Reg Data; #left shift reg by value
shr Reg Data; #right shift reg by value

get_color Reg Data; #extract pixel color form value to reg
set_color Reg Data; #set pixel color in reg to value
get_shade Reg Data; #extract pixel shade form value to reg
set_shade Reg Data; #set pixel shade in reg to value
add_shade Reg Data; #add value to pixel shade in reg

All available data for script:
Code: [Select]

#enum
blit_part #what sprite part is now edited

#posible values:
blit_torso
blit_leftarm
blit_rightarm
blit_legs
blit_collapse #dying animation and corpse on ground
blit_inventory #corpse in inventory screen


anim_frame #number of current frame
shade #0 - light, 16 - dark


health
health_max
energy
energy_max
stun
stun_max
morale
morale_max


fatalwounds #sum of fatalwounds
fatalwounds_head
fatalwounds_torso
fatalwounds_leftarm
fatalwounds_rightarm
fatalwounds_leftleg
fatalwounds_rightleg


armor_front
armor_left
armor_right
armor_rear
armor_under


unit_id
unit_rank
unit_float #is floating
unit_kneel #is kneeling

soldier_hair #solder hair color based on soldier_look
soldier_face #solder face color based on soldier_look


#enum
soldier_look #current solder look

#posible values:
soldier_look_blonde
soldier_look_brownhair
soldier_look_oriental
soldier_look_african


#enum
soldier_grender #current solder grender

#posible values:
soldier_grender_male
soldier_grender_female


#const colors
color_hair #color group of hair color in solder sprite
color_face #color group of hair color in solder sprite

color_null
color_yellow
color_red
color_green0
color_green1
color_gray
color_brown0 #equal color_face
color_blue0
color_blue1
color_brown1 #equal color_face
color_brown2
color_purple0
color_purple1
color_blue2
color_silver
color_special

Possible future extensions:
Recolor scripts for weapons.
Recolor scripts for paperdoll in inventory.
Use script for selecting different sprite index e.g.:
Code: [Select]
    spriteScript: |
      test blit_part blit_torso;
      ret_neq in;
      test soldier_grender soldier_grender_female;
      ret_neq in;
      ret sprite_female_torso;

« Last Edit: July 05, 2014, 06:43:05 pm by Yankes »

volutar

  • Guest
Re: Recoloring Script
« Reply #1 on: April 27, 2014, 07:20:07 pm »
Good approach, but wrong point of application.
Instead of unnecessary recoloring, it would be much more better to have spripted map generation.
Because tftd will be almost impossible without it. It has too complex and to varied map structure.

Offline Yankes

  • Commander
  • *****
  • Posts: 3293
    • View Profile
Re: Recoloring Script
« Reply #2 on: April 27, 2014, 09:22:19 pm »
This scripts was designed only for simple calculations, I even forbid loops to prevent game hangs.
It would pain in a** to use assembler like syntax to create complex algorithm for map generation.
For this task would be better use Lua or Python.

volutar

  • Guest
Re: Recoloring Script
« Reply #3 on: April 27, 2014, 09:38:17 pm »
Yankes, pixel "shader" as you made it is quite expensive in terms of CPU thing. Overloading pixel manipulation it with SCRIPTING (for each rendered pixel) could cause quite a fps drop. The only thing which excuses this is having not very much of recolored units in the view. But still..

LUA or python for simplest scripting (int variables, arithmetics, for, if/else, and two functions getmodule()/setmodule()) is too much... better to avoid any extra dynamic libraries.

Offline Yankes

  • Commander
  • *****
  • Posts: 3293
    • View Profile
Re: Recoloring Script
« Reply #4 on: April 27, 2014, 10:45:17 pm »
yup, naive test show that my scripts are 4 time slower than equivalent C function, but is some ways to migrate it.
I added some complex operation like `get_color` and `add_shade` that reduce number of script operations.
I can add some precalculation that alter script to made it work faster.
Next I can use SSE2 instruction to even further reduce scripts engine loops (for Uint8 it could be 16 pixel at once).
And finally OpenXcom is using caching for units sprites, this cause that my script is only call when unit move.
Right now I dont see any performance degradation when I use it to recolor whole squad of solders.

And about map scripts, you say that is "too complex and to varied map structure", how complex scripts are require to made maps?
My scripts cant call any function directly, but adding some state that can be altered by some function calls is possible.
Rest of functionality your require is available now, only custom variables and loops arent accessible for end user.

Offline Yankes

  • Commander
  • *****
  • Posts: 3293
    • View Profile
Re: Recoloring Script
« Reply #5 on: July 05, 2014, 06:57:45 pm »
Update to first post.

I add some youtube video presenting some possible usage.
And updated info because of new version.

Overall performance is very good, dont see any fps drops during using it.
Sometime I will test if I could redraw tiles too.

Offline luke83

  • Commander
  • *****
  • Posts: 1559
    • View Profile
    • openxcommods
Re: Recoloring Script
« Reply #6 on: July 08, 2014, 01:52:34 pm »
Is it possible to create a item with a Cloaking field yet?

Offline Yankes

  • Commander
  • *****
  • Posts: 3293
    • View Profile
Re: Recoloring Script
« Reply #7 on: July 08, 2014, 08:19:33 pm »
Is it possible to create a item with a Cloaking field yet?
Script have access only to unit and armor data. This mean it would require special armor for that.
Second problem is right now I directly draw to final surface. This cause problems because some pixel could be draw multiple times because of overlapping of body parts. In that places you could not distinguish how many times you draw there.
Third is that my mod only change look but not behavior of game. Cloaked or "invisible" unit will behave exactly like in original.
And lastly current version dont have access to destination pixel, but this is very easy fixable.

Offline Yankes

  • Commander
  • *****
  • Posts: 3293
    • View Profile
Re: Recoloring Script
« Reply #8 on: July 11, 2014, 10:41:44 pm »
I tried add access to pixels original value, some examples:





But I forgot about one painful thing when you tray do transparent units, when solders is moving all units he pass by are draw two times.
Its require lot of work to remove this effects. Its probably better to stick with opaque units for now.

Offline Aldorn

  • Commander
  • *****
  • Posts: 750
    • View Profile
Re: Recoloring Script
« Reply #9 on: July 12, 2014, 02:35:08 pm »
Invisibility ! Awesome...

Offline Ran

  • Colonel
  • ****
  • Posts: 196
    • View Profile
Re: Recoloring Script
« Reply #10 on: July 14, 2014, 02:27:19 am »
Might actually prove useful when creating an alien race with camouflage abilities.

Offline Solarius Scorch

  • Global Moderator
  • Commander
  • *****
  • Posts: 11675
  • WE MUST DISSENT
    • View Profile
    • Nocturmal Productions modding studio website
Re: Recoloring Script
« Reply #11 on: July 14, 2014, 07:01:12 am »
I would like to see rank indication on X-Com armours. Modify an armour by adding, say, a pure white element, like a stripe, a plate, or a shoulder pad, or even a whole helmet; make this element assume a certain colour according to rank.

Offline Aldorn

  • Commander
  • *****
  • Posts: 750
    • View Profile
Re: Recoloring Script
« Reply #12 on: July 14, 2014, 04:03:10 pm »
I would like to see rank indication on X-Com armours. Modify an armour by adding, say, a pure white element, like a stripe, a plate, or a shoulder pad, or even a whole helmet; make this element assume a certain colour according to rank.
Why not, but isn't it that biggest armours are usually assigned to higher level X-Com ? Also seeing a soldier dressed with a top armour means this X-Com unit is a high rank soldier ?  :o

It is true it will depend how you manage your soldiers, your armours, and which kind of armour your mod contains... :-[

Offline Solarius Scorch

  • Global Moderator
  • Commander
  • *****
  • Posts: 11675
  • WE MUST DISSENT
    • View Profile
    • Nocturmal Productions modding studio website
Re: Recoloring Script
« Reply #13 on: July 14, 2014, 04:37:30 pm »
Well, at some point (at least in the vanilla) everyone's wearing either a Power Suit or a Flying Suit. At least in my world. :)

Anyway, this suggestion was more for fluff than any real usefulness to the player.

Offline Yankes

  • Commander
  • *****
  • Posts: 3293
    • View Profile
Re: Recoloring Script
« Reply #14 on: July 14, 2014, 08:52:52 pm »
I would like to see rank indication on X-Com armours. Modify an armour by adding, say, a pure white element, like a stripe, a plate, or a shoulder pad, or even a whole helmet; make this element assume a certain colour according to rank.
It was one of my goals when I made this modification. All numeric properties can be changed to look.
I will try do example of this working today.