#include <RixPattern.h> 
#include <RixShadingUtils.h>
#include <RixShading.h>
#include <cstring>
  
class CutrSideMask : public RixPattern {
public:
  
    CutrSideMask();
    virtual ~CutrSideMask() { }
  
    // The next four methods override those of the base class.
    virtual int Init(RixContext &, char const *pluginpath);
    virtual RixSCParamInfo const *GetParamTable();
    virtual void Finalize(RixContext &) { }
    virtual int ComputeOutputParams(RixShadingContext const *sctx,
                                    RtInt *noutputs, 
                                    OutputSpec **outputs,
                                    RtConstPointer instanceData,
                                    RixSCParamInfo const *ignored);
    private:
        RixMessages *m_msg;
        RtColorRGB    m_input_outsideRGB;
        RtColorRGB    m_input_insideRGB;
  
    };
// Constructor - does nothing except initializes our member variables
// in the same sequence in which they are declared.
CutrSideMask::CutrSideMask():
    m_msg(NULL),  
    m_input_outsideRGB(1,0.4,0.4),
    m_input_insideRGB(0.5,1,0.5)
    { }
    
int CutrSideMask::Init(RixContext &ctx, char const *pluginpath) {
    m_msg = (RixMessages*)ctx.GetRixInterface(k_RixMessages);
    
    RixRenderState *rstate = (RixRenderState*)ctx.GetRixInterface(k_RixRenderState);
    RixRenderState::Type optType;
    RtInt optNumValues, err;
  
    RtColorRGB bkcolor;
    err = rstate->GetOption("imager:background:color", &bkcolor, sizeof(bkcolor),
                                           &optType, &optNumValues);
    if(err == 0 && optType == RixRenderState::k_Color) {
        m_msg->Info("background:color: %f %f %f", bkcolor.r,bkcolor.g,bkcolor.b);
        }
  
    
    return (!m_msg) ? 1 : 0;
    }
  
RixSCParamInfo const *CutrSideMask::GetParamTable() {
    static RixSCParamInfo s_ptable[] = {
        // Output
        RixSCParamInfo("resultRGB", k_RixSCColor, k_RixSCOutput),
        // Input
        RixSCParamInfo("input_outsideRGB", k_RixSCColor),
        RixSCParamInfo("input_insideRGB", k_RixSCColor),
        RixSCParamInfo() // end of table
        };
    return &s_ptable[0];
    }
  
enum paramIndex {
    k_resultRGB = 0,
    k_input_outsideRGB,
    k_input_insideRGB
    };
    
int CutrSideMask::ComputeOutputParams(RixShadingContext const *sctx,
                                RtInt *noutputs, 
                                OutputSpec **outputs,
                                RtConstPointer instanceData,
                                RixSCParamInfo const *ignored) {
    bool varying = true;
  
    // Declare a pointer for each input.
    RtColorRGB    const *input_outsideRGB;
    RtColorRGB    const *input_insideRGB;
  
    sctx->EvalParam(k_input_outsideRGB, -1, &input_outsideRGB, &m_input_outsideRGB, varying);
    sctx->EvalParam(k_input_insideRGB, -1, &input_insideRGB, &m_input_insideRGB, varying);
  
    // Allocate memory for the OutputSpec data structure.
    RixShadingContext::Allocator pool(sctx);
    OutputSpec *outSpec = pool.AllocForPattern<OutputSpec>(1);
    *outputs = outSpec;
  
    // Allocate memory for each output.
    RtColorRGB    *resultRGB = pool.AllocForPattern<RtColorRGB>(sctx->numPts);
    // Prepare the OutputSpec to the output(s).
    *noutputs = 1;
    outSpec[0].paramId = k_resultRGB;
    outSpec[0].detail = k_RixSCVarying;
    outSpec[0].value = resultRGB;
  
    // Access the primitive variables that will be needed for the 
    // calculation of the output values. 
    RtNormal3 const *Ngn;    // normalized geometric normal
    RtVector3 const *Vn;    // normalized view vector
    sctx->GetBuiltinVar(RixShadingContext::k_Ngn, &Ngn);
    sctx->GetBuiltinVar(RixShadingContext::k_Vn, &Vn);    
    
    // Assign values to each point.
    for(int i = 0; i < sctx->numPts; i++) {
        // Calculate the dot product and use it to determine if the
        // point being shaded is facing the camera. 
        float NdotV = Dot(Ngn[i], Vn[i]);
        if (NdotV > 0.f) {
            resultRGB[i] = input_outsideRGB[i];
            }
        else
            {
            resultRGB[i] = input_insideRGB[i];
            }
        } 
    return 0;
    }
  
RIX_PATTERNCREATE {
    return new CutrSideMask();
    }
RIX_PATTERNDESTROY {
    delete ((CutrSideMask*)pattern);
    }