Breaking out reusable parts of blade styles

I’ll start by saying that I feel like I’ve seen a similar discussion on The Rebel Armory before, but for the life of me, I can’t find that thread anymore.

I am using styles from Fett263’s style library – which are astounding, may I add – and I tend to stick to having the same effects for blast, lockup, etc. across multiple presets. Which got me thinking, why not define a core of effects once and then replace it in each style with one word to save loads of space, instead of having 8 copies of the same thing. Obviously, if changes need to be made, then it’s also a lot easier to make them in just one place.

How would I go about doing this? I have tried placing using before the Preset block, but it won’t compile and raises errors. Defining it as a variable means that I have to assign it a type, and I don’t know what type it ought to be.

Here’s one of the styles I’m using:

    StylePtr<Layers<
      ColorChange<TrBoing<500,3>,AudioFlicker<Blue,Rgb<0,128,0>>,AudioFlicker<Red,Rgb<128,0,0>>>,
      LockupTrL<NavajoWhite,TrConcat<TrInstant,TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<200>,EFFECT_LOCKUP_BEGIN>,TrFade<400>>,TrConcat<TrInstant,TransitionEffect<NavajoWhite,Rgb<255,225,0>,TrInstant,TrFade<200>,EFFECT_LOCKUP_BEGIN>,TrFade<400>>,SaberBase::LOCKUP_NORMAL>,
      ResponsiveLightningBlockL<Strobe<White,AudioFlicker<White,Blue>,50,1>,TrConcat<TrInstant,AlphaL<White,Bump<Int<12000>,Int<18000>>>,TrFade<200>>,TrConcat<TrInstant,HumpFlickerL<AlphaL<White,Int<16000>>,30>,TrSmoothFade<600>>>,
      ResponsiveStabL<White,TrWipeIn<600>,TrWipe<600>>,
      BlastFadeoutL<TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<50>,EFFECT_BLAST>>,
      SimpleClashL<TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<100>,EFFECT_CLASH>>,
      LockupTrL<AlphaL<BrownNoiseFlickerL<White,Int<300>>,SmoothStep<Int<30000>,Int<5000>>>,TrWipeIn<400>,TrFade<300>,SaberBase::LOCKUP_DRAG>,
      LockupTrL<AlphaL<Mix<TwistAngle<>,Red,Orange>,SmoothStep<Int<28000>,Int<5000>>>,TrWipeIn<600>,TrFade<300>,SaberBase::LOCKUP_MELT>,
      InOutTrL<TrWipeX<Scale<IsLessThan<BladeAngle<>,Int<16000>>,Int<200>,Int<500>>>,TrWipeInX<Scale<IsLessThan<BladeAngle<>,Int<16000>>,Int<300>,Int<800>>>,Black>
    >>(),

And the section that I want to break out is this:

      LockupTrL<NavajoWhite,TrConcat<TrInstant,TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<200>,EFFECT_LOCKUP_BEGIN>,TrFade<400>>,TrConcat<TrInstant,TransitionEffect<NavajoWhite,Rgb<255,225,0>,TrInstant,TrFade<200>,EFFECT_LOCKUP_BEGIN>,TrFade<400>>,SaberBase::LOCKUP_NORMAL>,
      ResponsiveLightningBlockL<Strobe<White,AudioFlicker<White,Blue>,50,1>,TrConcat<TrInstant,AlphaL<White,Bump<Int<12000>,Int<18000>>>,TrFade<200>>,TrConcat<TrInstant,HumpFlickerL<AlphaL<White,Int<16000>>,30>,TrSmoothFade<600>>>,
      ResponsiveStabL<White,TrWipeIn<600>,TrWipe<600>>,
      BlastFadeoutL<TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<50>,EFFECT_BLAST>>,
      SimpleClashL<TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<100>,EFFECT_CLASH>>,
      LockupTrL<AlphaL<BrownNoiseFlickerL<White,Int<300>>,SmoothStep<Int<30000>,Int<5000>>>,TrWipeIn<400>,TrFade<300>,SaberBase::LOCKUP_DRAG>,
      LockupTrL<AlphaL<Mix<TwistAngle<>,Red,Orange>,SmoothStep<Int<28000>,Int<5000>>>,TrWipeIn<600>,TrFade<300>,SaberBase::LOCKUP_MELT>,
      InOutTrL<TrWipeX<Scale<IsLessThan<BladeAngle<>,Int<16000>>,Int<200>,Int<500>>>,TrWipeInX<Scale<IsLessThan<BladeAngle<>,Int<16000>>,Int<300>,Int<800>>>,Black>

Then, if the above is defined as ‘Effex’, for example, the desired outcome of the exercise would be:

    StylePtr<Layers<
      ColorChange<TrBoing<500,3>,AudioFlicker<Blue,Rgb<0,128,0>>,AudioFlicker<Red,Rgb<128,0,0>>>,
      Effex
    >>(),

Given that I have 2 blades defined and plan to have around 8 styles, I don’t want to make changes to this 16 times when I decide that I want to change White to Yellow, for example. And yes, I know, I can just find and replace all, but that’s not the point. With 2 blades, the space savings is also a desired property of this exercise.

I feel like this might be useful for others out there as well, and any help would be appreciated! :smiley:

See Style Options and Edit Mode in OS6 :wink:

Sorry, I think I’m not following you. Are you saying that this is not possible to do until OS6? I thought OS6 primarily adds the ability to change presets and copy them and so on directly on the saber. And wouldn’t then I need to do that manually 16 times? I’m not really looking to do that. I’d like to break out a repeating code chunk primarily to

  • save space;
  • improve readability of the file;
  • make propagating changes easier.

Is there a way I can define an entire code chunk rather than a variable?

No, I’m saying the Style Options in OS6 will accomplish this (but in a different manner). Style Options and the other “options” in OS6 allow a single style to contain multiple options (for example the Edit Mode test styles have something like 64 unique combinations plus unlimited colors per effect) this allows you to get many, many presets from a single style saving a bunch of space on the board while also being able to edit nearly every aspect of the style still, like individual colors, speeds, positions, effects, etc.
The primary concept behind the “options” in Edit Mode is to reduce the need to make multiple styles that share a lot of similarities, in OS6 the library will enable you to build a single style that can then be used to generate 100s of unique presets :wink:

Here’s just a small example, the OS6 library will actually generate many more options in a single style expanding on this concept.

There are two current options that work well. Neither of them saves any memory, but they do save a lot of typing.

Option #1, use a define:

#define Effex \
      LockupTrL<NavajoWhite,TrConcat<TrInstant,TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<200>,EFFECT_LOCKUP_BEGIN>,TrFade<400>>,TrConcat<TrInstant,TransitionEffect<NavajoWhite,Rgb<255,225,0>,TrInstant,TrFade<200>,EFFECT_LOCKUP_BEGIN>,TrFade<400>>,SaberBase::LOCKUP_NORMAL>, \
      ResponsiveLightningBlockL<Strobe<White,AudioFlicker<White,Blue>,50,1>,TrConcat<TrInstant,AlphaL<White,Bump<Int<12000>,Int<18000>>>,TrFade<200>>,TrConcat<TrInstant,HumpFlickerL<AlphaL<White,Int<16000>>,30>,TrSmoothFade<600>>>,	\
      ResponsiveStabL<White,TrWipeIn<600>,TrWipe<600>>,			\
      BlastFadeoutL<TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<50>,EFFECT_BLAST>>, \
      SimpleClashL<TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<100>,EFFECT_CLASH>>, \
      LockupTrL<AlphaL<BrownNoiseFlickerL<White,Int<300>>,SmoothStep<Int<30000>,Int<5000>>>,TrWipeIn<400>,TrFade<300>,SaberBase::LOCKUP_DRAG>, \
      LockupTrL<AlphaL<Mix<TwistAngle<>,Red,Orange>,SmoothStep<Int<28000>,Int<5000>>>,TrWipeIn<600>,TrFade<300>,SaberBase::LOCKUP_MELT>, \
      InOutTrL<TrWipeX<Scale<IsLessThan<BladeAngle<>,Int<16000>>,Int<200>,Int<500>>>,TrWipeInX<Scale<IsLessThan<BladeAngle<>,Int<16000>>,Int<300>,Int<800>>>,Black>

This should work pretty much the way you want. Defines are processed before the actual compiler works on the text of the config file, so its effectively like a sort of cut-n-paste.

Option #2, use “using”, but for each individual layer:

using MyLockupLayer = LockupTrL<NavajoWhite,TrConcat<TrInstant,TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<200>,EFFECT_LOCKUP_BEGIN>,TrFade<400>>,TrConcat<TrInstant,TransitionEffect<NavajoWhite,Rgb<255,225,0>,TrInstant,TrFade<200>,EFFECT_LOCKUP_BEGIN>,TrFade<400>>,SaberBase::LOCKUP_NORMAL>;
using MyLBLayer = ResponsiveLightningBlockL<Strobe<White,AudioFlicker<White,Blue>,50,1>,TrConcat<TrInstant,AlphaL<White,Bump<Int<12000>,Int<18000>>>,TrFade<200>>,TrConcat<TrInstant,HumpFlickerL<AlphaL<White,Int<16000>>,30>,TrSmoothFade<600>>>;
using MyStabLayer = ResponsiveStabL<White,TrWipeIn<600>,TrWipe<600>>;
using MyBlastLayer = BlastFadeoutL<TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<50>,EFFECT_BLAST>>;
using MyClashLayer = SimpleClashL<TransitionEffect<Rgb<255,225,0>,NavajoWhite,TrInstant,TrFade<100>,EFFECT_CLASH>>;
using MyDragLayer = LockupTrL<AlphaL<BrownNoiseFlickerL<White,Int<300>>,SmoothStep<Int<30000>,Int<5000>>>,TrWipeIn<400>,TrFade<300>,SaberBase::LOCKUP_DRAG>;
using MyMeltLayer = LockupTrL<AlphaL<Mix<TwistAngle<>,Red,Orange>,SmoothStep<Int<28000>,Int<5000>>>,TrWipeIn<600>,TrFade<300>,SaberBase::LOCKUP_MELT>;
using MyInOutLayer = InOutTrL<TrWipeX<Scale<IsLessThan<BladeAngle<>,Int<16000>>,Int<200>,Int<500>>>,TrWipeInX<Scale<IsLessThan<BladeAngle<>,Int<16000>>,Int<300>,Int<800>>>,Black>;

Then when you use it, you’ll have to list all the layers:

StylePtr<Layers<
ColorChange<TrBoing<500,3>,AudioFlicker<Blue,Rgb<0,128,0>>,AudioFlicker<Red,Rgb<128,0,0>>>,
      MyLockupLayer,
      MyLBLayer,
      MyStabLayer,
      MyBlastLayer,
      MyClashLayer,
      MyDragLayer,
      MyMeltLayer,
      MyInOutLayer
    >>(),

Of course, you could also combine the two:

#define Effex \
     MyLockupLayer, \
      MyLBLayer, \
      MyStabLayer, \
      MyBlastLayer, \
      MyClashLayer, \
      MyDragLayer, \
      MyMeltLayer, \
      MyInOutLayer

Please note that the “using” statements can’t be inside the preset array, they have to go before the preset array.

1 Like

That’s perfect, thank you! I tried the using approach, but it didn’t work because I had combined all the layers, and the compiler kept complaining about the commas between layers. I figured that I’d need to break then out separately, but I thought I’d ask in case there was a way to do it as one whole. I will give #define a shot as well.

I was not aware that there’s no memory saving from this approach. I thought that it was based on the number of characters, so I was trying to reduce that number. But still, it’s really helpful to save on copy-pasting. :slight_smile:

No, the compiler will process the config file, generating machine code for all of these styles, and it’s that machine code that takes up space. The translatation from config file text to machine code is large and complicated. In general, more configuration means more machine code, but the specifics are not that simple. In this specific case, the compiler will actually produce the same code weather you type it all out, or if you make the config file smaller by using defines or “using” to avoid repetition. Either way you type it, the compiler will know that identical layers are the same, and so it may choose to only generate that code once… or not… If you choose “fastest” in Arduino → Tools → Optimization, then it will almost always choose to inline the code, which means that your identical layers will be duplicated many times in the generated machine code. If you choose “smallest”, it will usually elect not to inline code, so identical layers will only be translated into machine code once, which saves memory.

‘using’ expects only one type.
I package all my reused effects this way. I have a package for light colored blades, Red blades, White blades, crystal chambers etc…

The trick to having multiple layers within one ‘using’ is to sandwich all the layers within a Layers<>
See my BC_effects_1 below for example.

First you include the file with a statement in the CONFIG_PRESETS section like this for example: (my file is in an ‘aliases’ folder I placed inside ‘/config’, so the path is ProffieOS/config/aliases)

#ifdef CONFIG_PRESETS
#include "aliases/BC_effects_1.h" 

My styles end up as just

StylePtr<Layers<
-- Base color here --,
BC_effects_1,
InOutTrL< --ignition / retraction stuff here -- >>()

BC_effects_1.h file:

// Main Blade effects package for non-red blades

using BC_effects_1 =
Layers<

// Dim Blade 50% "Power Save" button combo
    EffectSequence<EFFECT_POWERSAVE,
        AlphaL<Black,Int<16384>>,
        AlphaL<Black,Int<0>>>,
// Clash 1 - BladeAngle responsive. Yellowish impact
    TransitionEffectL<TrConcat<TrInstant,GreenYellow,TrDelay<25>,AlphaL<TransitionEffect<BrownNoiseFlicker<Rgb<255,150,0>,Black,50>,White,TrInstant,TrFade<300>,EFFECT_CLASH>,Bump<Scale<BladeAngle<>,Int<25000>,Int<8000>>,Int<18000>>>,TrFade<600>>,EFFECT_CLASH>,
// Stab - OrangeRed stripes
    TransitionEffectL<TrConcat<TrInstant,GreenYellow,TrDelay<25>,AlphaL<Black,Int<0>>,TrWipeIn<300>,AlphaL<Stripes<5000,1000,Orange,DarkOrange,Rgb<150,60,0>,Rgb<60,30,0>,Rgb<150,14,0>,OrangeRed>,SmoothStep<Int<20000>,Int<20000>>>,TrJoin<TrSmoothFade<900>,TrWipe<700>>>,EFFECT_STAB>,
// Blast
    TransitionEffectL<TrConcat<
        // Impact Flash - BC always
        TrInstant,GreenYellow,TrDelay<25>>,EFFECT_BLAST>,
        // Waves
        BlastL<White,850,250,351>,
        // Impact point afterimage
        //AlphaL<TransitionEffectL<TrConcat<TrFade<200>,Red,TrFade<600>>,EFFECT_BLAST>,BlastF<700,250,100000>>,
        AlphaL<TransitionEffectL<TrConcat<TrFade<300>,Rgb<255,70,70>,TrFade<300>>,EFFECT_BLAST>,BlastF<700,250,100000>>,
        // Impact point
        //BlastL<White,500,350,100000>,
        BlastL<White,300,350,100000>,
// Lockup 1 - BC custom range mid-blade to hilt w/random strobe flash
    TransitionEffectL<TrConcat<TrInstant,Strobe<GreenYellow,Black,20,30>,TrFade<200>,BrownNoiseFlickerL<AlphaL<White,Int<16000>>,Int<5000>>,TrJoinR<TrWipe<200>,TrWipeIn<200>,TrFade<300>>>,EFFECT_LOCKUP_END>,
    LockupTrL<Layers<
        //Random Strobe Flash no dimming
        AlphaL<TransitionLoopL<TrConcat<TrDelayX<Scale<SlowNoise<Int<3000>>,Int<30>,Int<800>>>,Mix<SlowNoise<Int<1000>>,Black,Black,White,Black>,TrDelayX<Scale<SlowNoise<Int<1000>>,Int<10>,Int<50>>>>>,Int<32768>>,
        //AlphaL<White,StrobeF<Scale<SlowNoise<Int<1000>>,Int<1>,Int<3>>,Scale<SlowNoise<Int<1000>>,Int<10>,Int<50>>>>,
        // Bottom Layer Bump - random width
        AlphaL<Blinking<Tomato,Strobe<Yellow,Black,15,30>,60,500>,                                               Bump<Scale<BladeAngle<5000,28000>,Scale<BladeAngle<8000,16000>,Int<3000>,Int<44000>>,Int<3000>>,Scale<SlowNoise<Int<3000>>,Int<8000>,Int<18000>>>>,
        // Top Layer Bump - fixed width
        AlphaL<Blinking<BrownNoiseFlicker<White,Black,50>,BrownNoiseFlicker<Yellow,Tomato,50>,100,500>,          Bump<Scale<BladeAngle<5000,28000>,Scale<BladeAngle<8000,16000>,Int<3000>,Int<44000>>,Int<3000>>,Int<9000>>>>,
        // Begin Lockup Transition
        TrConcat<TrInstant,AlphaL<Blinking<White,Strobe<BrownNoiseFlicker<Yellow,Black,500>,Black,15,30>,60,500>,Bump<Scale<BladeAngle<5000,28000>,Scale<BladeAngle<8000,16000>,Int<3000>,Int<44000>>,Int<3000>>,Scale<SlowNoise<Int<3000>>,Int<25000>,Int<32000>>>>,TrFade<500>>,
        // End Lockup Transition
        TrSmoothFade<900>,SaberBase::LOCKUP_NORMAL>,
    TransitionEffectL<TrConcat<TrInstant,AlphaL<Strobe<GreenYellow,Black,20,30>,                               Bump<Scale<BladeAngle<5000,28000>,Scale<BladeAngle<8000,16000>,Int<3000>,Int<44000>>,Int<3000>>,Int<15000>>>,TrFade<600>>,EFFECT_LOCKUP_BEGIN>,
    TransitionEffectL<TrConcat<TrInstant,GreenYellow,TrDelay<25>,HumpFlickerL<Strobe<AlphaL<White,Int<20000>>,Black,20,30>,30>,TrSmoothFade<225>>,EFFECT_LOCKUP_BEGIN>,
// Non-Responsive Drag - BC custom drag fadeout
    LockupTrL<AlphaL<AudioFlicker<BrownNoiseFlicker<Strobe<Black,OrangeRed,20,25>,Yellow,200>,White>,SmoothStep<Int<30000>,Int<2000>>>,TrConcat<TrInstant,GreenYellow,TrDelay<25>,AlphaL<Black,Int<0>>,TrFade<150>>,TrColorCycle<1500,-2000,100>,SaberBase::LOCKUP_DRAG>,
// Lightning Block - Non-responsive. BC custom color (purple hint w/ random strobe flashes because....lightning)
    LockupTrL<Layers<
        //Random Strobe Flash and 16000 = 50% base blade dimming to make lb pop
        AlphaL<Black,Int<16000>>,
        AlphaL<White,StrobeF<Scale<SlowNoise<Int<1000>>,Int<1>,Int<6>>,Scale<SlowNoise<Int<1000>>,Int<10>,Int<50>>>>,
        AlphaL<RandomFlicker<Strobe<White,Rgb<83,0,255>,50,10>,BrownNoiseFlicker<Rgb<83,0,255>,Black,500>>,LayerFunctions<
        Bump<Scale<SlowNoise<Int<2000>>,Int<3000>,Int<16000>>,Scale<BrownNoiseF<Int<10>>,Int<14000>,Int<8000>>>,
        Bump<Scale<SlowNoise<Int<2300>>,Int<26000>,Int<8000>>,Scale<NoisySoundLevel,Int<5000>,Int<10000>>>,
        Bump<Scale<SlowNoise<Int<2300>>,Int<20000>,Int<30000>>,Scale<IsLessThan<SlowNoise<Int<1500>>,Int<8000>>,Scale<NoisySoundLevel,Int<5000>,Int<0>>,Int<0>>>>>>,
        // Begin Lightning Transition
        TrConcat<TrInstant,GreenYellow,TrDelay<25>,BrownNoiseFlicker<Rgb<83,0,255>,Black,500>,TrFade<100>>,
        // End Lightning Transition    
        TrConcat<TrInstant,GreenYellow,TrDelay<25>,BrownNoiseFlicker<Rgb<83,0,255>,Black,500>,TrFade<150>,BrownNoiseFlickerL<AlphaL<White,Int<16000>>,Int<50>>,TrJoinR<TrWipe<200>,TrWipeIn<200>,TrFade<400>> >,SaberBase::LOCKUP_LIGHTNING_BLOCK>,
// Melt - BC custom melt effects, uses twistangle<>
    LockupTrL<
        AlphaL<Mix<TwistAngle<>,Yellow,RandomPerLEDFlicker<Orange,OrangeRed>,BrownNoiseFlicker<Rgb16<20095,128,128>,Rgb16<35103,8175,298>,150>,StyleFire<Rgb16<20393,93,93>,Red,0,4,FireConfig<0,2000,5>,FireConfig<3000,0,0>,FireConfig<0,4000,0>>>,
        // Melt Shape
        SmoothStep<Scale<TwistAngle<>,Int<24000>,Int<29000>>,Int<2000>>>,
        // Melt Begin and End transitions
        TrConcat<TrInstant,GreenYellow,TrDelay<25>,AlphaL<Black,Int<0>>,TrWipeIn<600>>,TrColorCycle<1500,-2000,100>,SaberBase::LOCKUP_MELT>
     
     >;

Yup, I go for the smallest option. I have never set it to any other. So then there’s some savings to be had with this approach; nice! :slight_smile:

So, you end up with Layers<> inside another outer Layers<> statement? Does that work?

Also, jeez, that is some lengthy and elaborate effects! No wonder you need to break those out! But it looks well structured, and it’s a great idea to have separate effects presets for colored, red, and white blades. I will have to swipe that one, I think! :wink:

I am currently building a double-ended Red/Blue in-hilt LED saber, and that means that I will have to make a separate config for the red blade style… :man_facepalming:t2: As if it wasn’t difficult enough trying to decide on all the options in Fett’s style builder once! :sweat_smile:

If you want, the 5.9 fork I did has all of the aliased effect files and a sample config file that uses them :wink:

1 Like

Thank you! I will be assembling a pixel saber next, and then these effects will come in handy. I’ll save them for that. There’s not much point to trying this out with a Red/Blue saber. I don’t even have white on it. :sweat_smile: