FFGL 2 SDK

FFGL, OSC, GLSL. If you like abbreviations, this is the forum for you
User avatar
flyingrub
Met Resolume in a bar the other day
Posts: 9
Joined: Thu Feb 21, 2019 10:24
Location: Out of space

Re: FFGL 2 SDK

Post by flyingrub » Thu Jul 18, 2019 11:30

Passing/returning ranges :
The thing is that there is no way to know the final type of an union, and accessing inactive union member is undefined behaviour.

As old plugins don't support this method the check if the result is FF_FAIL is important in Resolume Arena to check the range to { 0, 1 }. If you find a better way to fix this let me know. :)

Shared pointer
I find it handy to keep a shared pointer in the plugin too for direct access like here : https://github.com/flyingrub/ffgl/blob/ ... loom.h#L15. I think it is fine to let it like that.

Particles example
Yeah I know it is not working, I didn't found why already and I'm working on other stuff right now...

Passing shader uniforms
I have thought about it. We could definitely store them in a Map in FFGLShader.

Logging
If you use visual studio you will see the logging in the output window.

User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 142
Joined: Thu Jun 05, 2014 09:32
Location: Melbourne, AU

Re: FFGL 2 SDK

Post by subpixel » Mon Jul 22, 2019 11:14

Passing/returning ranges
My guess is that calls always check the result as if (result.UIntValue == FF_FAIL) before trying to cast the result as anything else.

Shared pointer
The pointers in your Plugin subclass can be regular pointers. The (main class) Plugin destructor can clean up the data associated with its vector of pointers. eg:

Code: Select all

Plugin::~Plugin()
{
	for( Param* param : params )
	{
		if(param != nullptr)
			delete param;
	}
}
Passing shader uniforms
I was thinking more along the lines of adding a protected member to class Param:

Code: Select all

unsigned int uniformLocation;
I haven't implemented this part yet. Considering to have a "uniformName" passed into the contructor; if none passed then assume the "name" (if it doesn't contain illegal characters).

User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 142
Joined: Thu Jun 05, 2014 09:32
Location: Melbourne, AU

Re: FFGL 2 SDK

Post by subpixel » Mon Jul 22, 2019 12:11

I've posted my current Work In Progress

http://subpixels.com/resolume/ffgl/wip/

spxl-resolume-ffgl-source-2019-07-22.zip - 522 kB

Stronger Typing
Scoped enumerations replace "static const FFUInt32" definitions for Function codes. Plugin types, Parameter types, Parameter usage, Input status, Plugin capabilities, etc. (declared in FFGL.h).

This drastically reduces the possibility of using the "untyped" constants in the wrong places, allows code completion hints, etc.

I came up with this idea to deal with "FF_FAIL" being returned from various functions. eg for Parameter Usage (for FFT buffer):

Code: Select all

// FFGL.h

typedef FFUInt32 FFResult;

enum FFSuccessFail : FFResult
{
    FF_SUCCESS = 0,
    FF_FAIL    = 0xFFFFFFFF
};

// Parameter usages
enum class FFParameterUsage : FFUInt32
{
    FF_USAGE_STANDARD = 0,
    FF_USAGE_FFT      = 1,
    FF_FAIL           = FFSuccessFail::FF_FAIL
};

typedef union FFMixed
{
    FFUInt32 UIntValue;
    void* PointerValue;

    float FloatValue;
    double* pDouble;
    const char* StrValue;

    FFInputStatus InputStatus;
    FFParameterType ParameterType;
    FFParameterUsage ParameterUsage;

    //...
} FFMixed;


// FFGLPluginManager.cpp
FFParameterUsage CFFGLPluginManager::GetParamUsage( unsigned int dwIndex ) const
{
    const ParamInfo* paramInfo = GetParamInfo( dwIndex );
    if( paramInfo == nullptr )
        return FFParameterUsage::FF_FAIL;

    return paramInfo->usage; // definition in FFGLPluginManager.h: FFParameterUsage usage;
}

// FFGL.cpp
FFParameterUsage getParameterUsage( unsigned int index )
{
    if( s_pPrototype == NULL )
    {
        FFResult dwRet = initialise();
        if( dwRet == FF_FAIL )
            return FFParameterUsage::FF_FAIL;
    }

    return s_pPrototype->GetParamUsage( index );
}

FFMixed __stdcall plugMain( FFUInt32 functionCode, FFMixed inputValue, FFInstanceID instanceID )
{
//...
    switch( (FFFunctionCode) functionCode )
    {
    //...
    case FFFunctionCode::FF_GETPARAMETERUSAGE:
        retval.ParameterUsage = getParameterUsage( inputValue.UIntValue );
        break;
    //...
    }

    return retval;
}
Similarly for Parameter Type.

User avatar
flyingrub
Met Resolume in a bar the other day
Posts: 9
Joined: Thu Feb 21, 2019 10:24
Location: Out of space

Re: FFGL 2 SDK

Post by flyingrub » Mon Jul 22, 2019 14:37

Passing/returning ranges

Code: Select all

result.UIntValue == FF_FAIL
is undefined behaviour if there is something in PointerValue.
We need to change FFMixed to be a struct if we want to access both at the same time.

User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 142
Joined: Thu Jun 05, 2014 09:32
Location: Melbourne, AU

Re: FFGL 2 SDK

Post by subpixel » Wed Jul 24, 2019 23:56

Attempting to read a union member that is not the last one written is undefined behaviour...

Is it "more undefined" than re-casting a void* ? Maybe.

Is re-casting between unsigned int (32 bits) and a pointer (how many bits?..) "safe"?

This is the the way the FFGL interface seems to work. Is there a "safer" way to do the bit packing? Is it worth the hassle?

User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 142
Joined: Thu Jun 05, 2014 09:32
Location: Melbourne, AU

WIP spxl-resolume-ffgl-source-2019-08-02.zip

Post by subpixel » Fri Aug 02, 2019 11:35

Updated Work In Progress

spxl-resolume-ffgl-source-2019-08-02.zip

Download from
http://subpixels.com/resolume/ffgl/wip/

Implemented caching of glGetUniformLocation() results, stored in Param objects:

Code: Select all

protected:
    std::string uniformName;
    GLint uniformLocation;
Unfortunately this is only for the Params added by client code; Plugin::sendDefaultParams() still uses Set(name, ...) methods.

Plugin::InitGL() now calls a new method, setParamaterUniformLocations(), which loops over the parameters and saves the result of shader.FindUniform( uniformName ).

Plugin::sendParams() has been updated to check that the uniformLocation is not -1 for each parameter before trying to set it, and new variants of FFGLShader::Set() that don't call FindUniform() again are used.

Bugfix - FFGLShader::LinkProgram(): first parameter to glGetProgramiv() should be programID, not fragmentShaderID.

User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 142
Joined: Thu Jun 05, 2014 09:32
Location: Melbourne, AU

Re: FFGL 2 SDK

Post by subpixel » Wed Aug 28, 2019 15:52

After some concerted effort, I have completely replaced the ParamInfoStruct linked list in the SDK with ffglquickstart-like params objects. A vector of pointers is held by the PluginManager class/object and the hassle of passing between the old system and the quickstart system has been eliminated!

spxl-resolume-ffgl-wip-2019-08-28b.zip - 226 kB

http://subpixels.com/resolume/ffgl/wip/

New: AddRGBRangeParam() is like AddRGBColorParam, but applies a range to the output value.

Constructor:

Code: Select all

AddRGBRangeParam( "Brightness", "adjustment", 0.0f, { -1.0f, 1.0f } );
GLSL:

Code: Select all

color.rgb += adjustment * mult;
Unfortunately Resolume still displays the parameters as 0 to 255 (with the "no change" value as 127.5).

I haven't managed to get Options to work yet. I can get them to appear in the UI, but am having trouble receiving data in the plugin. It also isn't clear what the "value" should be for an optioin element. The quickstart seemed to set 1,2,3 etc, and use that value coming in as an index to look up the nth elemnt and take the value from there. I think. Anyhow, I'm always getting zero values.
2019-08-28 spxlSubAdd e - effect panel default parameters.png
2019-08-28 spxlSubAdd e - effect panel default parameters.png (34.63 KiB) Viewed 1071 times
2019-08-28 spxlSubAdd f - effect panel default parameters expanded.png
2019-08-28 spxlSubAdd g -effect preview.png
Last edited by subpixel on Fri Aug 30, 2019 15:02, edited 1 time in total.

Menno
Team Resolume
Posts: 90
Joined: Tue Mar 12, 2013 13:56

Re: FFGL 2 SDK

Post by Menno » Thu Aug 29, 2019 10:51

I'm sorry but i'm kind of confused as to what the purpose of this thread is.
Do you just want to provide feedback, do you have questions, or is your intention to get some changes pulled into the ffgl sdk? If you want to make changes to the sdk, could you please make multiple issue reports on our github repo, one for each issue you're encountering. Then if you have made some changes to solve one of the issues could you make a pull request on the github page so that we may review it?
It's not manageable for us to use .zip as a version control system, been there, done that, didn't work :lol:
We've also tried allowing 'everything has changed' pull requests, but due to the number of changes made these are impossible to review and as a result tend to introduce just as many new issues as fixes into the sdk.

About the linked list, are you talking about the params in the CFFGLPluginManager class? This list has already been replaced on the repo's master branch. For option parameters, FFGL treats values as the value for the option that's being set. See the Particles example's PID_MAX_AGE parameter. ffgl quickstart however, fills in option element values asif they're an index to the option. This has as a result that the ParamOption's GetValue will return when index, you need to call GetRealValue instead. Plugin::SendParams doesn't seem to respect option's real values, is that maybe the cause of your issue?

User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 142
Joined: Thu Jun 05, 2014 09:32
Location: Melbourne, AU

Re: FFGL 2 SDK

Post by subpixel » Fri Aug 30, 2019 14:55

I initially had questions. I decided to start fixing problems myself, and wasn't familiar with how to contribute to git/GitHub projects, so I started posting my version of the code for other people to view and comment on. In general, looking for a way to discuss ideas, problems and solutions.

My intention is to have updates pulled into the main SDK branch. I noticed that some work had been done on the SDK since I started my changes, including file renaming and identifier renaming (eg TitleCaseFunctionNames). I have GitHub Desktop but didn't (and still don't!) know how to get the latest changes from the main repo into my project. Maybe that is "too hard" now and I will just have to post a fork.

I liked some of the ffglquickstart ideas to manage Params, but it had bugs in it and it was duplicating the structure in CFFGLPluginManager, copying everything from one system to the other and overall being a confusing mess.

I have changed my version so quickstart-inspired params now live in the (CFFGL)PluginManager. Code snippets to demonstrate:

PluginManager class/objet:

Code: Select all

// ffgl/PluginManager.h

namespace ffgl
{
class PluginManager
{
public:
	/// This function allows you to add a new parameter to the plugin. There is differents kind of
	/// parameters available, Adding a parameter allows the plugin to be
	/// aware of them, make them available to the host and take of all the communication with it.
	/// It can also allow the plugin to automatically pass the current value of each parameter to the
	/// shader before drawing (see ffglqs::Plugin::SendParams()).
	/// \param	param		The parameter to add
	void AddParam( ParamBase* param );

protected:
	// Plugin parameters. ParamBase is used for polymorphism.
	std::vector< ParamBase* > params;
Example effect header:

Code: Select all

#pragma once
#include "ffgl/ParamOption.h"
#include "ffglquickstart/Effect.h"
#include "ffglquickstart/ParamHSBAStruct.h"
#include "ffglquickstart/ParamRGBStruct.h"

namespace spxl
{
namespace ffgl
{
namespace effect
{
class SubAdd : public ffglqs::Effect
{
public:
	SubAdd();
	~SubAdd();

	void Update() override;

protected:
	ffglqs::ParamRGBStruct adjustment;
	ffglqs::ParamHSBAStruct col1;
	ffglqs::ParamHSBAStruct col2;

	::ffgl::ParamOption* testOption;
};

}// namespace effect
}// namespace ffgl
}// namespace spxl
Example effect code:

Code: Select all

// spxlSubAdd Effect Plugin
// More or less the same result as the AddSubtract sample plugin, with extra parameters for testing purposes.
// The "multiplier" parameter is used to scale the R,G,B addition/subtraction.

// 2019-08-12 ffgl@subpixels.com
// - Created, based on AddSubbtract sample code

#include "spxlSubAdd.h"
#include "ffgl/ParamBool.h"
#include "ffgl/ParamBuffer.h"
#include "ffgl/ParamFloat.h"
#include "ffgl/ParamInteger.h"
#include "ffgl/ParamOption.h"
#include "ffgl/ParamRange.h"
#include "ffgl/ParamText.h"
#include "ffglquickstart/ParamEvent.h"
#include "ffglquickstart/ParamFFT.h"
#include "ffglquickstart/ParamTrigger.h"

using namespace ffgl;
using namespace ffglex;
using namespace ffglqs;

namespace spxl
{
namespace ffgl
{
namespace effect
{
static ::ffgl::PluginInfo pluginInfo(
	PluginFactory< SubAdd >,// Create method
#ifdef _DEBUG
	"?e01",   // Plugin unique ID of maximum length 4.
	"?SubAdd",// Plugin name
#else
	"_e01",   // Plugin unique ID of maximum length 4.
	"_SubAdd",// Plugin name
#endif
	2,                    // API major version number
	1,                    // API minor version number
	1,                    // Plugin major version number
	0,                    // Plugin minor version number
	PluginType::FF_EFFECT,// Plugin type

	"Subtract and Add colours",                        // Plugin description
	"Resolume FFGL Example (mod by ffgl@subpixels.com)"// About
);

static const char _fragmentShaderCode[] = R"(
void main()
{
	vec4 color = texture( inputTexture, i_uv );
	//The InputTexture contains premultiplied colors, so we need to unpremultiply first to apply our effect on straight colors.
	if( color.a > 0.0 )
		color.rgb /= color.a;

	color.rgb += adjustment * mult;

	if (TestBool) color.rgb += col1.rgb * factor1;
	if (b2) color.rgb -= col2.rgb * factor2;

	//The plugin has to output premultiplied colors, this is how we're premultiplying our straight color while also
	//ensuring we aren't going out of the LDR the video engine is working in.
	color.rgb = clamp( color.rgb * color.a, vec3( 0.0 ), vec3( color.a ) );
	fragColor = color;
}
)";

SubAdd::SubAdd()
{
	//We declare that this plugin has a Brightness parameter which is a RGB param.
	//The name here must match the one you declared in your fragment shader.
	adjustment = AddRGBRangeParam( "Brightness", "adjustment", 0.0f, { -1.0f, 1.0f } );

	// Test Parameters
	AddParam( new ParamFloat( "Col Mult", "mult", 1.0f ) );


	col1 = AddHueColorParam( "MyColor1", "col1", { 0.0f, 1.0f, 0.75f, 1.0f } );
	col2 = AddHueColorParam( "MyColor2", "col2", { 0.666667f, 0.9f, 1.0f, 0.5f } );

	AddParam( new ParamFloat( "Scale 1", "factor1" ) );
	AddParam( new ParamFloat( "Scale 2", "factor2", 0.25f ) );

	AddParam( new ParamFloat( "NameTypeValue", ParameterType::FF_TYPE_BRIGHTNESS, 0.9f ) );
	AddParam( new ParamBool( "TestBool" ) );
	AddParam( new ParamBool( "TestBool2", "b2", true ) );
	AddParam( new ParamEvent( "TestEvent" ) );
	AddAudioParam( new ParamFFT( "TestFFT", 8 ) );

	testOption = new ParamOption( "TestOption", 2U );
	testOption->AddOption( { "Test1", 11.1f } );
	testOption->AddOption( { "Test2", 22.2f } );
	testOption->AddOption( { "Test3", 33.3f } );
	AddParam( testOption );

	AddParam( new ParamRange( "TestRange", "temperature", 27.5f, { 0.0f, 100.0f } ) );
	AddParam( new ParamInteger( "TestInteger", "xscale", 64, { -1920.0f, 1920.0f } ) );
	AddParam( new ParamText( "TestText", "Lorem ipsum blah blah amet" ) );
	AddParam( new ParamTrigger( "TestTrigger" ) );

	SetFragmentShader( _fragmentShaderCode );

	SetTimeSupported( true );
}

SubAdd::~SubAdd()
{
}

void SubAdd::Update()
{
	// Try out accessing parameter values

	float r = adjustment.red->GetFloatValue();
	float g = adjustment.green->GetFloatValue();
	float b = adjustment.blue->GetFloatValue();

	float average = ( r + g + b ) / 3.0f;

	HSBAColor color1 = col1.GetColor();
	HSBAColor color2 = col2.GetColor();

	float hue1 = color1.hue;

	std::string uniformName = col1.hue->GetUniformName();

	FFUInt32 selectedOption   = testOption->GetIndex();
	std::string selectedName  = testOption->GetOptionName( selectedOption );

	float selectedValue;
	FFResult res = testOption->GetOptionValue( selectedOption, selectedValue );

	float selectedValueDirect = testOption->GetFloatValue();
}

}// namespace effect
}// namespace ffgl
}// namespace spxl

User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 142
Joined: Thu Jun 05, 2014 09:32
Location: Melbourne, AU

Re: FFGL 2 SDK

Post by subpixel » Fri Aug 30, 2019 14:59

tl;dr version: I have gone away and written/changed code to address the issues I originally posted about, some of which have been addressed by Ronan(/others?) in the main branch as a result of the discussion in this thread. I'm a git newb and don't know how to address the mismatched codebase.

-spxl

Post Reply