#include <FFGL.h>
#include <FFGLLib.h>
#include <stdio.h>
#include <cmath>
#include "FFGLChromaKey.h"
#include "utilities.h"
#ifdef _WIN32
#include "../common/opengl/include/glut.h"
#include <windows.h>
#else
#include <OpenGL/glu.h>
#endif
#ifdef __APPLE__
#include <Carbon.h>
#endif
#define FFPARAM_Tolerance (0)
#define FFPARAM_Feather (1)
#define FFPARAM_Hue (2)
#define FFPARAM_Saturation (3)
#define FFPARAM_Brightness (4)
#define FFPARAM_Linear (5)
#define FFPARAM_Ramp (6)
GLfloat texCoordOffsets[2*3*3];
bool hastime = false;
static CFFGLPluginInfo PluginInfo (
FFGLChromaKey::CreateInstance, "MCKY", "Chroma Key", 1, 000, 1, 100, FF_EFFECT, "Keys out a certain color in an image", "by Matias Wilkman" );
char *vertexShaderCode =
"void main()"
"{"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
" gl_TexCoord[0] = gl_MultiTexCoord0;"
" gl_FrontColor = gl_Color;"
"}";
char *fragmentShaderCode =
"uniform sampler2D sampler0;"
"uniform vec2 tc_offset[9];"
"uniform float feather;"
"uniform vec3 key;"
"uniform bool linear;"
"uniform float tolerance;"
"uniform float ramp;"
"uniform float kernel[9];"
"void main(void)"
"{"
" vec4 sum = vec4(0.0);"
" vec4 rgba = texture2D(sampler0, gl_TexCoord[0].st);"
" for (int i = 0; i < 9; i++)" " {"
" vec4 tmp = texture2D(sampler0, gl_TexCoord[0].st + feather*tc_offset[i]);"
" float d = distance(tmp.rgb, key);"
" if (d <= tolerance) {"
" tmp.a = 0.0;"
" }"
" if (linear) {"
" if (d <= tolerance) {"
" tmp.a = 0.0;"
" }"
" else {"
" tmp.a = d*ramp;"
" }"
" }"
" sum += tmp * kernel[i];"
" }"
" rgba.a = sum.a;"
" gl_FragColor = rgba;"
"}";
FFGLChromaKey::FFGLChromaKey()
:CFreeFrameGLPlugin(),
m_initResources(1)
{
SetMinInputs(1);
SetMaxInputs(1);
SetParamInfo(FFPARAM_Tolerance, "Tolerance", FF_TYPE_STANDARD, 0.2f);
m_tolerance = 0.2f;
SetParamInfo(FFPARAM_Feather, "Feather", FF_TYPE_STANDARD, 0.0f);
m_feather = 0.0f;
SetParamInfo(FFPARAM_Hue, "Hue", FF_TYPE_STANDARD, 0.33f);
m_key[0] = 0.33f;
SetParamInfo(FFPARAM_Saturation, "Saturation", FF_TYPE_STANDARD, 1.0f);
m_key[1] = 1.0f;
SetParamInfo(FFPARAM_Brightness, "Brightness", FF_TYPE_STANDARD, 1.0f);
m_key[2] = 1.0f;
SetParamInfo(FFPARAM_Linear, "Linear", FF_TYPE_BOOLEAN, false);
m_linearvalue = 0.0f;
m_linear = false;
SetParamInfo(FFPARAM_Ramp, "Ramp", FF_TYPE_STANDARD, 0.7f);
m_ramp = 0.7f;
}
DWORD FFGLChromaKey::InitGL(const FFGLViewportStruct *vp)
{
m_extensions.Initialize();
if (m_extensions.ARB_shader_objects==0)
return FF_FAIL;
m_shader.SetExtensions(&m_extensions);
if (!m_shader.Compile(vertexShaderCode,fragmentShaderCode))
return FF_FAIL;
bool success = false;
if (m_shader.IsReady())
if (m_shader.BindShader())
success = true;
if (!success)
{
printf("Shader binding failed!\n");
return FF_FAIL;
}
m_kernellocation = m_shader.FindUniform("kernel");
m_tcoffsetlocation = m_shader.FindUniform("tc_offset");
m_tolerancelocation = m_shader.FindUniform("tolerance");
m_featherlocation = m_shader.FindUniform("feather");
m_keylocation = m_shader.FindUniform("key");
m_linearlocation = m_shader.FindUniform("linear");
m_ramplocation = m_shader.FindUniform("ramp");
m_shader.UnbindShader();
return FF_SUCCESS;
}
DWORD FFGLChromaKey::DeInitGL()
{
m_shader.FreeGLResources();
return FF_SUCCESS;
}
DWORD FFGLChromaKey::ProcessOpenGL(ProcessOpenGLStruct *pGL)
{
if (pGL->numInputTextures<1) return FF_FAIL;
if (pGL->inputTextures[0]==NULL) return FF_FAIL;
FFGLTextureStruct &Texture = *(pGL->inputTextures[0]);
FFGLTexCoords maxCoords = GetMaxGLTexCoords(Texture);
float kernel[9] = {1.0/16.0, 2.0/16.0, 1.0/16.0, 2.0/16.0, 4.0/16.0, 2.0/16.0, 1.0/16.0, 2.0/16.0, 1.0/16.0};
float xInc = maxCoords.s/(GLfloat)Texture.HardwareWidth;
float yInc = maxCoords.t/(GLfloat)Texture.HardwareHeight;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
texCoordOffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc);
texCoordOffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc);
}
}
bool success = false;
if (m_shader.IsReady())
if (m_shader.BindShader())
success = true;
if (!success)
{
printf("Shader binding failed!\n");
return FF_FAIL;
}
m_extensions.glUniform2fvARB(m_tcoffsetlocation, 9, texCoordOffsets);
m_extensions.glUniform1fvARB(m_kernellocation, 9, kernel);
m_extensions.glUniform1fARB(m_featherlocation, m_feather);
m_extensions.glUniform1fARB(m_tolerancelocation, m_tolerance);
m_extensions.glUniform3fvARB(m_keylocation, 1, m_key_rgb);
m_extensions.glUniform1iARB(m_linearlocation, m_linear);
m_extensions.glUniform1fARB(m_ramplocation, (1.0f+m_ramp));
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Texture.Handle);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(-1.0, -1.0);
glTexCoord2f(0, maxCoords.t);
glVertex2f(-1.0, 1.0);
glTexCoord2f(maxCoords.s, maxCoords.t);
glVertex2f(1.0, 1.0);
glTexCoord2f(maxCoords.s, 0);
glVertex2f(1.0, -1.0);
glEnd();
m_shader.UnbindShader();
return FF_SUCCESS;
}
DWORD FFGLChromaKey::GetParameter(DWORD dwIndex)
{
DWORD dwRet;
switch (dwIndex) {
case FFPARAM_Tolerance:
*((float *)(unsigned)&dwRet) = m_tolerance;
return dwRet;
case FFPARAM_Feather:
*((float *)(unsigned)&dwRet) = m_feather;
return dwRet;
case FFPARAM_Hue:
case FFPARAM_Saturation:
case FFPARAM_Brightness:
*((float *)(unsigned)&dwRet) = m_key[dwIndex - FFPARAM_Hue];
return dwRet;
case FFPARAM_Linear:
*((float *)(unsigned)&dwRet) = m_linearvalue;
return dwRet;
case FFPARAM_Ramp:
*((float *)(unsigned)&dwRet) = m_ramp;
return dwRet;
default:
return FF_FAIL;
}
}
char* FFGLChromaKey::GetParameterDisplay(DWORD dwIndex)
{
DWORD dwType = m_pPlugin->GetParamType(dwIndex);
DWORD dwValue = m_pPlugin->GetParameter(dwIndex);
if ((dwValue != FF_FAIL) && (dwType != FF_FAIL))
{
if (dwType == FF_TYPE_TEXT)
{
return (char *)dwValue;
}
else
{
switch (dwIndex) {
case FFPARAM_Tolerance:
sprintf(m_Displayvalue, "%.1f", m_tolerance);
break;
case FFPARAM_Feather:
sprintf(m_Displayvalue, "%.1f", m_feather);
break;
case FFPARAM_Hue:
case FFPARAM_Saturation:
case FFPARAM_Brightness:
sprintf(m_Displayvalue, "%.1f", m_key[dwIndex - FFPARAM_Hue]);
break;
case FFPARAM_Linear:
sprintf(m_Displayvalue, "%s", m_linear?"On":"Off");
break;
case FFPARAM_Ramp:
sprintf(m_Displayvalue, "%.1f", m_ramp);
break;
default:
return NULL;
}
return m_Displayvalue;
}
}
return NULL;
}
DWORD FFGLChromaKey::SetParameter(const SetParameterStruct* pParam)
{
if (pParam != NULL) {
switch (pParam->ParameterNumber) {
case FFPARAM_Tolerance:
m_tolerance = *((float *)&(pParam->NewParameterValue));
break;
case FFPARAM_Feather:
m_feather = *((float *)&(pParam->NewParameterValue));
break;
case FFPARAM_Hue:
case FFPARAM_Saturation:
case FFPARAM_Brightness:
m_key[pParam->ParameterNumber - FFPARAM_Hue] = *((float *)&(pParam->NewParameterValue));
HSVtoRGB(m_key[0], m_key[1], m_key[2], &m_key_rgb[0], &m_key_rgb[1], &m_key_rgb[2]);
break;
case FFPARAM_Linear:
m_linearvalue = *((float *)&(pParam->NewParameterValue));
m_linear = (m_linearvalue > 0.5)?true:false;
break;
case FFPARAM_Ramp:
m_ramp = *((float *)&(pParam->NewParameterValue));
break;
default:
return FF_FAIL;
}
return FF_SUCCESS;
}
return FF_FAIL;
}