
/*
 * Copyright (c) 2012
 *	Side Effects Software Inc.  All rights reserved.
 *
 * Redistribution and use of Houdini Development Kit samples in source and
 * binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. The name of Side Effects Software may not be used to endorse or
 *    promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ----------------------------------------------------------------------
 * Point Create
 * 
 * derived from SOP_Star.C example
 *
 * By Deborah Fowler
 * Creates a point at a given location.
 *
 * Similar to the point by Nate Usiak, but not using polys
 * First HDK test.
 *
 * Date: Dec 16 2012
 * Modified by Deborah Fowler
 * Date: Feb 27 2014
 * Update for H13.0.237
 *
 * Another example of creating a point 
 *
 */

#include <limits.h>
#include <SYS/SYS_Math.h>
#include <UT/UT_DSOVersion.h>
#include <UT/UT_Interrupt.h>
//#include <GD/GD_Detail.h>
#include <GU/GU_Detail.h>
#include <GU/GU_PrimPoly.h>
#include <CH/CH_LocalVariable.h>
#include <PRM/PRM_Include.h>
#include <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>

#include "sopNewPointCreate.h"

using namespace HDK_Sample;

///
/// newSopOperator is the hook that Houdini grabs from this dll
/// and invokes to register the SOP.  In this case we add ourselves
/// to the specified operator table.
///
void
newSopOperator(OP_OperatorTable *table)
{
    table->addOperator(
	    new OP_Operator("NewPointCreate",			// Internal name - node name
			    "NewPointCreateHDK",				// UI name - tab menu name
			     SOP_pointCreate::myConstructor,	// How to build the SOP
			     SOP_pointCreate::myTemplateList,	// My parameters
			     0,									// Min # of sources - these are if you want input into your node
			     0,									// Max # of sources
			     SOP_pointCreate::myVariables,		// Local variables
			     OP_FLAG_GENERATOR)					// Flag it as generator
	    );
}

static PRM_Name variableName("curious","Curious");
static PRM_Default variableDefaults(0);
static PRM_Range variableRange(PRM_RANGE_UI,0,PRM_RANGE_UI,1000);

// Parameter List
// This is used to bind these parameters to the Template List from which Houdini builds the UI
// The empty PRM_Template() indicates the close of the list
PRM_Template
SOP_pointCreate::myTemplateList[] = {
    PRM_Template(PRM_XYZ, 3, &PRMcenterName),
	PRM_Template( PRM_FLT, 1, &variableName, &variableDefaults,	0, &variableRange ),
    PRM_Template()
};


// Here's how we define local variables for the SOP.
enum 
{
	VAR_PT,		// Point number of the star
	VAR_NPT		// Number of points in the star
};

// Declares a list of variables using type CH_LocalVariable
CH_LocalVariable
SOP_pointCreate::myVariables[] = 
{
    { "PT",	VAR_PT, 0 },		// The table provides a mapping
    { "NPT",	VAR_NPT, 0 },		// from text string to integer token
    { 0, 0, 0 },
};


// In this function, we indicate what to do when the "case" enumerators are used
bool
SOP_pointCreate::evalVariableValue(fpreal &val, int index, int thread)
{
    // myCurrPoint will be negative when we're not cooking so only try to
    // handle the local variables when we have a valid myCurrPoint index.
    if (myCurrPoint >= 0)
    {
		// Note that "gdp" may be null here, so we do the safe thing
		// and cache values we are interested in.
		switch (index)
		{
			case VAR_PT:
				val = (fpreal) myCurrPoint;
				return true;
			case VAR_NPT:
				val = (fpreal) myTotalPoints;
				return true;
			default:
			/* do nothing */;
		}
    }
    // Not one of our variables, must delegate to the base class.
    return SOP_Node::evalVariableValue(val, index, thread);
}

// The constructor's job is to ensure the node is put into the proper network
OP_Node *
SOP_pointCreate::myConstructor(OP_Network *net, const char *name, OP_Operator *op)
{
    return new SOP_pointCreate(net, name, op);
}

SOP_pointCreate::SOP_pointCreate(OP_Network *net, const char *name, OP_Operator *op)
	: SOP_Node(net, name, op)
{
    myCurrPoint = -1;	// To prevent garbage values from being returned
}

SOP_pointCreate::~SOP_pointCreate() {}


// An example of cookMySop that creates point information
OP_ERROR
SOP_pointCreate::cookMySop(OP_Context &context)
{
    fpreal		 	now = context.getTime();
    float		 	tx, ty, tz, curious;
    UT_Vector4		pos;
	// GEO Point is deprecated in H13 
    // GEO_Point		*ppt;
    UT_Interrupt	*boss;

    // Since we don't have inputs, we don't need to lock them.
    myTotalPoints = 1;		// Set the NPT local variable value
    myCurrPoint   = 0;		// Initialize the PT local variable

    tx	       = CENTERX(now);
    ty	       = CENTERY(now);
    tz	       = CENTERZ(now);
	curious 	= evalFloat("curious",0,now);

    // Check to see that there hasn't been a critical error in cooking the SOP.
    if (error() < UT_ERROR_ABORT)
    {
		boss = UTgetInterrupt();
		gdp->clearAndDestroy();

		// Start the interrupt server

		if (boss->opStart("Building Point"))
		{
		
			// Used deprecated H12 data structures
			//ppt = gdp->appendPoint();
			//pos.assign(tx,ty,tz,1);
			//ppt->setPos(pos);
			
			
			// Using H13 data structures
			GA_Offset newPpt = gdp->appendPointOffset();
			gdp->setPos3(newPpt,tx,ty,tz);
			
			
			
			// On Windows when you run houdini from the command line, it will write out to a pop up console log window
			// On Linux you likely will have to flush the data
			cout << "Hello There - This is New Point " << curious << endl;
			cout.flush();
		}


		// Tell the interrupt server that we've completed. Must do this
		// regardless of what opStart() returns.
		boss->opEnd();
    }

    // Notify the display cache that we have directly edited
    // points, this lets NURBs surfaces know that they need to rebuild,
    // for example.
    // In this case it isn't needed, but included in case this
    // code is reused for a more complicated example.
    //gdp->notifyCache(GU_CACHE_ALL);

    myCurrPoint = -1;
    return error();
}
