infinite GeUserArea Rectangle inside GeDialogue

On 10/01/2015 at 11:30, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   13+ 
Platform:   Windows  ;   
Language(s) :     C++  ;

---------
I have a GeDialogue, it contains a GeUserArea , what I want is to create a typically infinite area similar to xpresso.

I thought about drawing the background with DrawRectangle() using quite large numbers, but is this the correct approach? or I'm doing it wrong!!

another question: can I draw a user area inside another user area?? "like nodes, a node can be a group which contains another nodes"

and what about ScrollArea()? I tried using it, but it gives me errors in debug console "DrawBegin/End ist faul B" and hangs Cinema 4D

On 10/01/2015 at 12:23, xxxxxxxx wrote:

The GeUserArea must be a finite size.  The 'infinite' part is in using a virtual window into your display space that is represented by the GeUserArea to draw into.  Store your virtual space window offsets (x, y) and draw accordingly with GeUserArea::Draw().

You can't add a GeUserArea to a GeUserArea.  I draw nodes into it as separate entities.  So, I have a routine that knows how to draw a node and another that knows how to draw connections between nodes and so on.  With the bounding coordinates known, you can clip out nodes that aren't in the view and use SetClippingRegion() for anything partially drawn.

For an infinite virtual space window set up, I would not use ScrollArea().  Handle mouse grabs (like in Google Maps or something), update your window x,y (typically upper left) by the mouseX, mouseY deltas, redraw.

On 10/01/2015 at 20:14, xxxxxxxx wrote:

I see Tongue , thanks a lot Robert.

but here rises another 2 questions that are related:
1- if I use quite large GeUserArea Rectangle "for example (-10000000,-10000000. 10000000. 10000000) " is this possible?  (this will be the world, and the window will be a tiny drawing region of 1000 x 1000 size)

2- I want to do the behavior of re scaling , when you have an xpresso node, and mouse hovers the borders, it changes cursor and you can drag it to scale the node, how to do something similar? "in other words which functions to check, so if there is something automatic like a border function for them, or I will have to store all drawings """ nodes """ borders and check for mouse position against them "" will be a bad approach "" "

On 11/01/2015 at 04:15, xxxxxxxx wrote:

1. The GeUserArea rectangle is your window.  Your world is virtual and the GUA rectangle shows the portion given by your window offsets and GUA dimensions.  Typically, you would initialize this so that your world (0,0) are at the top, left of the GUA rectangle.

2. When did you think you wouldn't have to store the position and dimensions of every existing node in the virtual world (in the node, of course)?  And then search them.  This is exactly what I did in the development phase.  There are many ways to increase search speed such as using sorting, hash tables, or binary space partitioning (divide and conquer).

// iSUserArea.IsOverNode
//*---------------------------------------------------------------------------*
ShaderNode* iSUserArea::IsOverNode(LONG* pX, LONG* pY, const LONG& mx, const LONG& my)
//*---------------------------------------------------------------------------*
{
	LONG h;
	// Is mouse over ShaderNode? (Z-order search)
	for (ShaderNode* snode = controller->GetLastSNode(); snode; snode = (ShaderNode* )snode->GetPrev())
	{
		h =			GetSNodeHeight(snode->GetType(), snode->GetExpanded(), snode->GetShowPreview());
		snode->GetPos(pX, pY);
		(*pX) -=	windowX;
		(*pY) -=	windowY;
		if ((mx >= *pX) && (mx < (*pX+cellWidth)) && (my >= *pY) && (my < (*pY+h))) return snode;
	}
	return NULL;
}

After you determine if you are over a node and which one, then you can refine where in the node to define locational functionality.

*Note: my nodes here are all a fixed width with varying height by node type.

On 11/01/2015 at 05:05, xxxxxxxx wrote:

thanks Robert 🙂, I know that I have to store all node data in the node class "like node size, position, inputs and outputs connections, etc.." , one last question that I didn't find an answer in the documentation:

DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg);

what are the values of x1,y1, x2,y2? is the the "window" of the world?

On 11/01/2015 at 05:34, xxxxxxxx wrote:

I wouldn't worry about them.  I use them to set clipping and clear before drawing and that is it:

// GeUserArea.Draw
//*---------------------------------------------------------------------------*
void iSUserArea::DrawMsg(LONG x1, LONG y1, LONG x2, LONG y2, const BaseContainer& msg)
//*---------------------------------------------------------------------------*
{
	// No flicker
	OffScreenOn();
	SetClippingRegion(x1,y1,x2,y2);
	// Clear area
	DrawSetPen(isUAColor[ISCOLOR_BG]);
	DrawRectangle(x1,y1,x2,y2);
        ...

What is more important is that you maintain your window offset in your GUA-derived class.  As noted, I initialize my windowX and windowY to (0,0) and then update them with LMB-down scrolls (I'm doing rectangular selection at the end, but it is easily modified for scrolling behavior) :

// iSUserArea.GetWindowOffset
//*---------------------------------------------------------------------------*
void iSUserArea::GetWindowOffset(LONG* wx, LONG* wy)
//*---------------------------------------------------------------------------*
{
	*wx = windowX;
	*wy = windowY;
}
// iSUserArea.OffsetWindow
//*---------------------------------------------------------------------------*
void iSUserArea::OffsetWindow(const LONG& dx, const LONG& dy)
//*---------------------------------------------------------------------------*
{
	windowX += dx;
	windowY += dy;
	Redraw();
}
// GeUserArea.InputEvent()
//*---------------------------------------------------------------------------*
Bool iSUserArea::InputEvent(const BaseContainer &msg)
//*---------------------------------------------------------------------------*
{
	// Mouse Events
	if (msg.GetLong(BFM_INPUT_DEVICE) == BFM_INPUT_MOUSE) return HandleMouseEvents(msg);
	return FALSE;
}
// iSUserArea.HandleMouse
//*---------------------------------------------------------------------------*
Bool iSUserArea::HandleMouseEvents(const BaseContainer& msg)
//*---------------------------------------------------------------------------*
{
	// Get Mouse Click location and other information
	LONG	chn =						msg.GetLong(BFM_INPUT_CHANNEL);
	// Left Button
	if (chn == BFM_INPUT_MOUSELEFT)		return HandleMouse_LeftButton(msg);
	// Right Button: Context PopupMenu
	if (chn == BFM_INPUT_MOUSERIGHT)	return HandleMouse_RightButton(msg.GetLong(BFM_INPUT_X), msg.GetLong(BFM_INPUT_Y));
	return TRUE;
}
//*---------------------------------------------------------------------------*
Bool iSUserArea::HandleMouse_LeftButton(const BaseContainer& msg)
//*---------------------------------------------------------------------------*
{
	// Get Mouse Click location and other information
	LONG			mx =		msg.GetLong(BFM_INPUT_X);
	LONG			my =		msg.GetLong(BFM_INPUT_Y);
	Global2Local(&mx,&my);
	LONG			pX, pY;
	ShaderNode*		snode =		IsOverNode(&pX, &pY, mx, my);
	// Do Something with ShaderNode
	if (snode)					return HandleMouse_LBNode(snode, msg, pX, pY, mx, my);
	// Over Background Area
	// - Click - Remove all current selections
	// - Drag - Create/Add to/Remove from Selection
	return HandleMouse_LBBackground(msg, mx, my);
}
//*---------------------------------------------------------------------------*
Bool iSUserArea::HandleMouse_LBBackground(const BaseContainer& msg, LONG mx, LONG my)
//*---------------------------------------------------------------------------*
{
	// Do nothing on DoubleClick
	if (msg.GetBool(BFM_INPUT_DOUBLECLICK))
	{
		PUM_Edit(NULL);
		return TRUE;
	}
  
	// Check for Keyboard Qualifiers
	Bool			selmode;
	LONG			qua =		msg.GetLong(BFM_INPUT_QUALIFIER);
	if (qua == QSHIFT)			selmode = TRUE;
	else if (qua == QCTRL)		selmode = FALSE;
	else
	{
		controller->SelectAll(FALSE);
		dialog->SelectedSNodes(FALSE);
		selmode = TRUE;
	}
  
	// Setup for dragging
	BaseContainer	action(BFM_ACTION);
	BaseContainer	state;
	action.SetLong(BFM_ACTION_ID,GetId());
	action.SetLong(BFM_ACTION_VALUE,0L);
  
	// General variables
	LONG			width =		GetWidth();
	LONG			height =	GetHeight();
	LONG			hw =		width>>1;
	LONG			hh =		height>>1;
	LONG			rectX1 =	mx;
	LONG			rectY1 =	my;
	LONG			rectX2, rectY2;
	// Drag Selecting
	startX = rectX1;
	startY = rectY1;
	drawMode = ISUA_DRAWMODE_SELECTING;
	while (GetInputState(BFM_INPUT_MOUSE,BFM_INPUT_MOUSELEFT,state))
	{
		if (state.GetLong(BFM_INPUT_VALUE) == 0) break;
  
		endX = state.GetLong(BFM_INPUT_X);
		endY = state.GetLong(BFM_INPUT_Y);
		Global2Local(&endX,&endY);
		mx = endX/2L;
		my = endY/2L;
  
		// Check for UserArea boundary, scroll if necessary
		if (endX <= 0L)
		{
			windowX += mx;
			startX -= mx;
		}
		else if (endX >= width)
		{
			windowX += (mx-hw);
			startX -= (mx-hw);
		}
		if (endY <= 0L)
		{
			windowY += my;
			startY -= my;
		}
		else if (endY >= height)
		{
			windowY += (my-hh);
			startY -= (my-hh);
		}
  
		Redraw();
		action.SetLong(BFM_ACTION_INDRAG,TRUE);
		SendParentMessage(action);
	}
	drawMode = ISUA_DRAWMODE_NORMAL;
	rectX2 = endX;
	rectY2 = endY;
  
	// Swap so that 1 is always UL, 2 LR
	if (rectX1 > rectX2)
	{
		mx = rectX1;
		rectX1 = rectX2;
		rectX2 = mx;
	}
	if (rectY1 > rectY2)
	{
		my = rectY1;
		rectY1 = rectY2;
		rectY2 = my;
	}
  
	// Find and Select/Deselect all ShaderNodes overlapped by Rectangle
	LONG			pX, pY;
	for (ShaderNode* snode = controller->GetFirstSNode(); snode; snode = (ShaderNode* )snode->GetNext())
	{
		snode->GetPos(&pX, &pY);
		pX -= windowX;
		mx = pX+cellWidth;
		pY -= windowY;
		my = pY+GetSNodeHeight(snode->GetType(), snode->GetExpanded(), snode->GetShowPreview());
  
		if ((my < rectY1) || (pY > rectY2) || (mx < rectX1) || (pX > rectX2)) continue;
		controller->SelectNode(snode, selmode);
		if (!selmode) dialog->SelectedSNodes(controller->AreSelectedSNodes());
		else dialog->SelectedSNodes(TRUE);
	}
  
	// Update and Notify
	Redraw();
	action.SetLong(BFM_ACTION_INDRAG,FALSE);
	SendParentMessage(action);
	return TRUE;
}

On 11/01/2015 at 06:48, xxxxxxxx wrote:

thanks a lot Robert 🙂

On 11/01/2015 at 07:36, xxxxxxxx wrote:

Can I ask you guys a stupid question?
What are these "Nodes" in your code. And where do the come from?

I've used the UA to draw shapes and move them around.
But how to you create these "nodes" that you can connect together in the UA?

I'm not having any luck with trying to put an xpresso window in a GeDialog. I can only launch a new one.
So I'm thinking that maybe I need to do what you guys are doing to creating my own "nodes" in my own UA. Instead of trying to use the existing xpresso window?
But I don't know how to create these "Nodes".

Sorry for the newbish question.
-ScottA

On 11/01/2015 at 09:13, xxxxxxxx wrote:

Scott, indeed, these nodes are classes I wrote.  The base class establishes a doubly-linked list set up (for easy insertion/deletion of nodes), position and size of the node graphically, inputs and outputs as NodeInput classes for connectivity, node ids, flags, methods, and other information.  The code is rather old and I would probably do it differently today having learned much over time.

////////////////////////////////////////////////////////////////
// NodeInput.h
////////////////////////////////////////////////////////////////
// Node Input Class include
////////////////////////////////////////////////////////////////
  
#ifndef _NODEINPUT_H_
#define _NODEINPUT_H_
  
#include "ShaderNodeDefs.h"
  
// Predefine for cross-referencing
class ShaderNode;
  
// Input within Node
class NodeInput
{
	private:
		// NodeInput name
		String			name;
		// Vector(x,y,z), Color(R,G,B), Value(current,min,max), List(current,listtype,numitems)
		Vector			value;
		// Value Type - see NodeInput Type Defintions in ShaderNodeDefs
		LONG			type;
		// Whether Node accepts input connections
		Bool			acceptConnection;
		// ShaderNodes connected to this NodeInput
		LONG			numNodes;
		ShaderNode*		node;
		// - id of ShaderNode (for Read/Write/CopyTo)
		LONG			id;
		// ID of corresponding Edit Gadget in Dialog
		LONG			editID;
		// Name of bitmap file
		String			file;
	public:
		NodeInput();
		~NodeInput();
		// Initialize NodeInput
		void			Init(const String& t_name, const Vector& t_value, const LONG& t_type, const Bool& t_acceptConnection, ShaderNode* t_node, const String& t_file);
		// String name
		void			SetName(const String& t_name);
		String			GetName();
		// Vector value
		void			SetValue(const Vector& t_value);
		void			SetValueBool(const Bool& t_value);
		void			SetValueList(const LONG& t_value);
		void			SetValueReal(const Real& t_value);
		Vector			GetValue();
		Bool			GetValueBool();
		LONG			GetValueList();
		Real			GetValueReal();
		// LONG type
		Bool			IsInstanceOf(const LONG& t_type);
		void			SetType(const LONG& t_type);
		LONG			GetType();
		// Bool acceptConnection
		void			SetAcceptConnection(const Bool& t_acceptConnection);
		Bool			GetAcceptConnection();
		// ShaderNode *node
		void			SetNode(ShaderNode* t_node);
		ShaderNode*		GetNode();
		void			SetNodeID(const LONG& t_id);
		LONG			GetNodeID();
		// String file
		void			SetFile(String t_file);
		String			GetFile();
		// LONG editID
		void			SetEditID(const LONG& t_editID);
		LONG			GetEditID();
		// Read/Write/CopyTo
		Bool			Read(HyperFile* hf, LONG level);
		Bool			Write(HyperFile* hf);
		Bool			CopyTo(NodeInput* dni, Bool dataOnly);
};
  
#endif //_NODEINPUT_H_
////////////////////////////////////////////////////////////////
// NodeInput.cpp
////////////////////////////////////////////////////////////////
// Node Input Class
////////////////////////////////////////////////////////////////
  
// Includes
  
#include "../glload.h"
#include "../general.h"
#include "NodeInput.h"
#include "ShaderNode.h"
  
// ****************************************************************************
// METHODS: NodeInput
// Constructor #1
//*---------------------------------------------------------------------------*
NodeInput::NodeInput()
//*---------------------------------------------------------------------------*
{
	name =				String("");
	value =				Vector(0.0);
	type =				NODEINPUTTYPE_NONE;
	acceptConnection =	FALSE;
	numNodes =			0L;
	node =				NULL;
	id =				-1L;
	file =				String("");
	editID =			-1L;
}
// Destructor
//*---------------------------------------------------------------------------*
NodeInput::~NodeInput()
//*---------------------------------------------------------------------------*
{
}
// Initialize NodeInput
//*---------------------------------------------------------------------------*
void NodeInput::Init(const String& t_name, const Vector& t_value, const LONG& t_type, const Bool& t_acceptConnection, ShaderNode* t_node, const String& t_file)
//*---------------------------------------------------------------------------*
{
	name =				t_name;
	value =				Vector(t_value.x, t_value.y, t_value.z);
	type =				t_type;
	acceptConnection =	t_acceptConnection;
	node =				t_node;
	if (node)			id = node->GetID();
	else				id = -1L;
	file =				t_file;
}
// String name
//*---------------------------------------------------------------------------*
void NodeInput::SetName(const String& t_name)
//*---------------------------------------------------------------------------*
{
	name = t_name;
}
//*---------------------------------------------------------------------------*
String NodeInput::GetName()
//*---------------------------------------------------------------------------*
{
	return name;
}
// Vector value
//*---------------------------------------------------------------------------*
void NodeInput::SetValue(const Vector& t_value)
//*---------------------------------------------------------------------------*
{
	value = Vector(t_value.x, t_value.y, t_value.z);
}
//*---------------------------------------------------------------------------*
void NodeInput::SetValueBool(const Bool& t_value)
//*---------------------------------------------------------------------------*
{
	value.x = (Real)t_value;
}
//*---------------------------------------------------------------------------*
void NodeInput::SetValueList(const LONG& t_value)
//*---------------------------------------------------------------------------*
{
	value.x = (Real)t_value;
}
//*---------------------------------------------------------------------------*
void NodeInput::SetValueReal(const Real& t_value)
//*---------------------------------------------------------------------------*
{
	value.x = t_value;
}
//*---------------------------------------------------------------------------*
Vector NodeInput::GetValue()
//*---------------------------------------------------------------------------*
{
	return value;
}
//*---------------------------------------------------------------------------*
Bool NodeInput::GetValueBool()
//*---------------------------------------------------------------------------*
{
	return (Bool)(value.x);
}
//*---------------------------------------------------------------------------*
LONG NodeInput::GetValueList()
//*---------------------------------------------------------------------------*
{
	return (LONG)(value.x);
}
//*---------------------------------------------------------------------------*
Real NodeInput::GetValueReal()
//*---------------------------------------------------------------------------*
{
	return value.x;
}
// Bool acceptConnection
//*---------------------------------------------------------------------------*
void NodeInput::SetAcceptConnection(const Bool& t_acceptConnection)
//*---------------------------------------------------------------------------*
{
	acceptConnection = t_acceptConnection;
}
//*---------------------------------------------------------------------------*
Bool NodeInput::GetAcceptConnection()
//*---------------------------------------------------------------------------*
{
	return acceptConnection;
}
// LONG type
//*---------------------------------------------------------------------------*
Bool NodeInput::IsInstanceOf(const LONG& t_type)
//*---------------------------------------------------------------------------*
{
	return (type == t_type);
}
//*---------------------------------------------------------------------------*
void NodeInput::SetType(const LONG& t_type)
//*---------------------------------------------------------------------------*
{
	type = t_type;
}
//*---------------------------------------------------------------------------*
LONG NodeInput::GetType()
//*---------------------------------------------------------------------------*
{
	return type;
}
// ShaderNode* node
//*---------------------------------------------------------------------------*
void NodeInput::SetNode(ShaderNode* t_node)
//*---------------------------------------------------------------------------*
{
	node =		t_node;
	if (node)	id = node->GetID();
	else		id = -1L;
}
//*---------------------------------------------------------------------------*
ShaderNode* NodeInput::GetNode()
//*---------------------------------------------------------------------------*
{
	return node;
}
//*---------------------------------------------------------------------------*
void NodeInput::SetNodeID(const LONG& t_id)
//*---------------------------------------------------------------------------*
{
	id = t_id;
}
//*---------------------------------------------------------------------------*
LONG NodeInput::GetNodeID()
//*---------------------------------------------------------------------------*
{
	return id;
}
// String file
//*---------------------------------------------------------------------------*
void NodeInput::SetFile(String t_file)
//*---------------------------------------------------------------------------*
{
	file = t_file;
}
//*---------------------------------------------------------------------------*
String NodeInput::GetFile()
//*---------------------------------------------------------------------------*
{
	return file;
}
// LONG editID
//*---------------------------------------------------------------------------*
void NodeInput::SetEditID(const LONG& t_editID)
//*---------------------------------------------------------------------------*
{
	editID = t_editID;
}
//*---------------------------------------------------------------------------*
LONG NodeInput::GetEditID()
//*---------------------------------------------------------------------------*
{
	return editID;
}
// Read/Write/CopyTo
// - Read NodeInput info
//*---------------------------------------------------------------------------*
Bool NodeInput::Read(HyperFile* hf, LONG level)
//*---------------------------------------------------------------------------*
{
	if (!hf->ReadString(&name))				return FALSE;
	if (!hf->ReadVector(&value))			return FALSE;
	if (!hf->ReadLong(&type))				return FALSE;
	if (!hf->ReadBool(&acceptConnection))	return FALSE;
	// ShaderNode* node - Unique Index!
	if (!hf->ReadLong(&id))					return FALSE;
	if (!hf->ReadString(&file))				return FALSE;
	return TRUE;
}
// - Write NodeInput info
//*---------------------------------------------------------------------------*
Bool NodeInput::Write(HyperFile* hf)
//*---------------------------------------------------------------------------*
{
	if (!hf->WriteString(name))				return FALSE;
	if (!hf->WriteVector(value))			return FALSE;
	if (!hf->WriteLong(type))				return FALSE;
	if (!hf->WriteBool(acceptConnection))	return FALSE;
	// ShaderNode* node - Unique Index!
	if (!hf->WriteLong(id))					return FALSE;
	if (!hf->WriteString(file))				return FALSE;
	return TRUE;
}
// - Copy Source NodeInput info to Destination NodeInput
//*---------------------------------------------------------------------------*
Bool NodeInput::CopyTo(NodeInput* dni, Bool dataOnly)
//*---------------------------------------------------------------------------*
{
	dni->name = name;
	dni->value = Vector(value.x, value.y, value.z);
	dni->type = type;
	dni->acceptConnection = acceptConnection;
	dni->file = file;
	if (!dataOnly) dni->id = id;
	return TRUE;
}
////////////////////////////////////////////////////////////////
// ShaderNode.h
////////////////////////////////////////////////////////////////
// Shader Node Base Class include
////////////////////////////////////////////////////////////////
  
#ifndef _SHADERNODE_H_
#define _SHADERNODE_H_
  
#include "ShaderNodeDefs.h"
  
// ShaderNode flags
#define SHADERNODE_FLAGS_NONE			0L
#define SHADERNODE_FLAGS_SHOWPREVIEW	(1<<0)
#define SHADERNODE_FLAGS_SELECTED		(1<<1)
#define SHADERNODE_FLAGS_CONNECTING		(1<<2)
#define SHADERNODE_FLAGS_EXPANDED		(1<<3)
  
//class glload;
class NodeInput;
struct NodeInputDef;
  
// Node within Tree
class ShaderNode
{
	public:
		ShaderNode*		prev;
		ShaderNode*		next;
		// - ShaderNode name
		String			name;
		// - UL Position within interface
		LONG			xPos;
		LONG			yPos;
		// - Unique ID
		LONG			id;
		// - Flags (see above)
		LONG			flags;
		// - Node Type - see ShaderNode Type Definitions in ShaderNodeDefs
		LONG			type;
		// NodeInputs: count
		LONG			numNodeInputs;
		LONG			acceptCount;
		// Number of outgoing connections
		LONG			connections;
		NodeInput*		nodeInputs;
        // OpenGL Support
		//glload*			previewGL;
		// Bitmaps
		BaseBitmap*		previewBitmap;
		// For Output()
		ShaderNode*		sn;
		NodeInput*		ni;
  
		// Methods
		ShaderNode();
		ShaderNode(const LONG& t_type, const LONG& t_numNodeInputs, const LONG& t_xPos, const LONG& t_yPos, const LONG& t_flags);
		virtual ~ShaderNode();
		Bool			Append(ShaderNode* previous);
		void			Remove();
		ShaderNode*		GetPrev();
		ShaderNode*		GetNext();
		// Initial ShaderNode
		Bool			Init(const LONG& t_xPos, const LONG& t_yPos, const LONG& t_pDim, const LONG& t_flags);
		Bool			InitInputs(NodeInputDef* nid);
		// String name
		void			SetName(const String& t_name);
		String			GetName();
		// Vector pos
		void			SetPos(const LONG& t_xPos, const LONG& t_yPos);
		void			GetPos(LONG* t_xPos, LONG* t_yPos);
		void			Move(const LONG& xDelta, const LONG& yDelta);
		// LONG id
		void			SetID(const LONG& t_id);
		LONG			GetID();
		// Bool showPreview
		void			SetShowPreview(const Bool& t_showPreview);
		Bool			GetShowPreview();
		void			InvertShowPreview();
		// Bool selected
		void			SetSelected(const Bool& t_selected);
		Bool			GetSelected();
		// Bool expanded
		void			SetExpanded(const Bool& t_expanded);
		Bool			GetExpanded();
		void			InvertExpanded();
		// LONG type
		Bool			IsInstanceOf(const LONG& t_type);
		void			SetType(const LONG& t_type);
		LONG			GetType();
		// NodeInputs
		LONG			GetNodeCount();
		LONG			GetAcceptCount();
		void			ClearInputs();
		// LONG connections
		void			SetConnections(const LONG& count);
		void			IncConnect();
		void			DecConnect();
		LONG			Connected();
		// Bool connecting
		void			SetConnecting(const Bool& t_connecting);
		Bool			IsConnecting();
		// NodeInput *nodeInputs - retrieve by index
		NodeInput*		GetNodeInput(LONG index=0L);
		// Read/Write/CopyTo
		Bool			Read(HyperFile* hf, LONG level);
		Bool			Write(HyperFile* hf);
		Bool			CopyTo(ShaderNode* dsn, Bool uniqueID);
		void			ReestablishNodeLinks(ShaderNode* firstSNode);
		// Preview Bitmap
		BaseBitmap*		GetPreview();
		// Pure Virtuals (no more)
		void			SetPreview(BaseMaterial* chn, Bool fromFile);
		Vector			Output(BaseMaterial* chn, ChannelData* cd);
};
  
#endif //_SHADERNODE_H_
////////////////////////////////////////////////////////////////
// ShaderNode.cpp
////////////////////////////////////////////////////////////////
// Shader Node and Node Input Class
////////////////////////////////////////////////////////////////
  
// Includes
//#include "../glload.h"
#include "../general.h"
#include "NodeInputDefs.h"
#include "NodeInput.h"
#include "ShaderNode.h"
#include "ShaderNodeStr.h"
  
  
// ****************************************************************************
// METHODS: ShaderNode
// Constructor #1
//*---------------------------------------------------------------------------*
ShaderNode::ShaderNode()
//*---------------------------------------------------------------------------*
{
	nodeInputs =	NULL;
	previewBitmap =	NULL;
	//previewGL	=   NULL;
	prev =			NULL;
	next =			NULL;
	xPos =			0L;
	yPos =			0L;
	flags =			SHADERNODE_FLAGS_NONE;
	type =			SHADERNODETYPE_NONE;
	numNodeInputs = 0L;
	acceptCount =	0L;
	connections =	0L;
}
// Constructor #2
//*---------------------------------------------------------------------------*
ShaderNode::ShaderNode(const LONG& t_type, const LONG& t_numNodeInputs, const LONG& t_xPos, const LONG& t_yPos, const LONG& t_flags)
//*---------------------------------------------------------------------------*
{
	nodeInputs =	NULL;
	previewBitmap =	NULL;
	//previewGL	=   NULL;
	prev =			NULL;
	next =			NULL;
	xPos =			t_xPos;
	yPos =			t_yPos;
	flags =			t_flags;
	type =			t_type;
	numNodeInputs =	t_numNodeInputs;
	acceptCount =	0L;
	connections =	0L;
}
// Destructor
//*---------------------------------------------------------------------------*
ShaderNode::~ShaderNode()
//*---------------------------------------------------------------------------*
{
	//gDelete(previewGL);
	BaseBitmap::Free(previewBitmap);
	bDelete(nodeInputs);
}
// Append node to list
//*---------------------------------------------------------------------------*
Bool ShaderNode::Append(ShaderNode* previous)
//*---------------------------------------------------------------------------*
{
	if (!previous)		return ErrorException::Throw(GeLoadString(CANERR_MEMORY), "ShaderNode.Append.previous");
	prev =				previous;
	previous->next =	this;
	return TRUE;
}
// Remove node from list
//*---------------------------------------------------------------------------*
void ShaderNode::Remove()
//*---------------------------------------------------------------------------*
{
	ShaderNode*	p =	prev;
	ShaderNode*	n =	next;
	prev =			NULL;
	next =			NULL;
	if (p)			p->next = n;
	if (n)			n->prev = p;
}
// Get Previous node
//*---------------------------------------------------------------------------*
ShaderNode* ShaderNode::GetPrev()
//*---------------------------------------------------------------------------*
{
	return prev;
}
// Get Next node
//*---------------------------------------------------------------------------*
ShaderNode* ShaderNode::GetNext()
//*---------------------------------------------------------------------------*
{
	return next;
}
// Initialize ShaderNode
//*---------------------------------------------------------------------------*
Bool ShaderNode::Init(const LONG& t_xPos, const LONG& t_yPos, const LONG& t_pDim, const LONG& t_flags)
//*---------------------------------------------------------------------------*
{
	if (!previewBitmap)
	{
		previewBitmap =			BaseBitmap::Alloc();
		if (!previewBitmap)		return ErrorException::Throw(GeLoadString(CANERR_MEMORY), "ShaderNode.Init.previewBitmap");
		if (previewBitmap->Init(t_pDim, t_pDim, 32L) != IMAGERESULT_OK)
			return ErrorException::Throw(GeLoadString(CANERR_MEMORY), "ShaderNode.Init.previewBitmap.Init");
		previewBitmap->Clear(255L,255L,255L);
	}
	/*
	if (!previewGL)
	{
		previewGL =				gNew glload;
		if (!previewGL)			return ErrorException::Throw(GeLoadString(CANERR_MEMORY), "ShaderNode.Init.previewGL");
		if (!previewGL->Init())	return ErrorException::Throw(GeLoadString(CANERR_GENERAL), "ShaderNode.Init.previewGL.Init");
	}
	*/
	name =						ShaderNodeStrings[type];
	xPos =						t_xPos;
	yPos =						t_yPos;
	flags =						t_flags;
	return TRUE;
}
// Initialize ShaderNode Inputs
//*---------------------------------------------------------------------------*
Bool ShaderNode::InitInputs(NodeInputDef* nid)
//*---------------------------------------------------------------------------*
{
	// Initialize NodeInputs by ShaderNode type
	// - Delete default NodeInput array
	bDelete(nodeInputs);
	nodeInputs =		NULL;
	if (!numNodeInputs)	return ErrorException::Throw(GeLoadString(CANERR_GENERAL), "ShaderNode.InitInputs.numNodeInputs");
	// - Allocate NodeInput array
	nodeInputs =		bNew NodeInput[numNodeInputs];
	if (!nodeInputs)	return ErrorException::Throw(GeLoadString(CANERR_MEMORY), "ShaderNode.InitInputs.nodeInputs");
	// - Configure NodeInput array
	for (LONG i = 0L; i != numNodeInputs; ++i)
	{
		nodeInputs[i].Init(nid[i].name, Vector(nid[i].a, nid[i].b, nid[i].c), nid[i].type, nid[i].accept, NULL, String(""));
		if (nid[i].accept) ++acceptCount;
	}
	return TRUE;
}
// String name
//*---------------------------------------------------------------------------*
void ShaderNode::SetName(const String& t_name)
//*---------------------------------------------------------------------------*
{
	name = t_name;
}
//*---------------------------------------------------------------------------*
String ShaderNode::GetName()
//*---------------------------------------------------------------------------*
{
	return name;
}
// LONG xPos, yPos
//*---------------------------------------------------------------------------*
void ShaderNode::SetPos(const LONG& t_xPos, const LONG& t_yPos)
//*---------------------------------------------------------------------------*
{
	xPos = t_xPos;
	yPos = t_yPos;
}
//*---------------------------------------------------------------------------*
void ShaderNode::GetPos(LONG* t_xPos, LONG* t_yPos)
//*---------------------------------------------------------------------------*
{
	*t_xPos = xPos;
	*t_yPos = yPos;
}
//*---------------------------------------------------------------------------*
void ShaderNode::Move(const LONG& xDelta, const LONG& yDelta)
//*---------------------------------------------------------------------------*
{
	// Move position by amount
	xPos += xDelta;
	yPos += yDelta;
}
// LONG id
//*---------------------------------------------------------------------------*
void ShaderNode::SetID(const LONG& t_id)
//*---------------------------------------------------------------------------*
{
	id = t_id;
}
//*---------------------------------------------------------------------------*
LONG ShaderNode::GetID()
//*---------------------------------------------------------------------------*
{
	return id;
}
// Bool showPreview
//*---------------------------------------------------------------------------*
void ShaderNode::SetShowPreview(const Bool& t_showPreview)
//*---------------------------------------------------------------------------*
{
	if (t_showPreview)	flags |= SHADERNODE_FLAGS_SHOWPREVIEW;
	else				flags &= ~SHADERNODE_FLAGS_SHOWPREVIEW;
}
//*---------------------------------------------------------------------------*
Bool ShaderNode::GetShowPreview()
//*---------------------------------------------------------------------------*
{
	return (flags & SHADERNODE_FLAGS_SHOWPREVIEW);
}
//*---------------------------------------------------------------------------*
void ShaderNode::InvertShowPreview()
//*---------------------------------------------------------------------------*
{
	if (flags & SHADERNODE_FLAGS_SHOWPREVIEW)	flags &= ~SHADERNODE_FLAGS_SHOWPREVIEW;
	else										flags |= SHADERNODE_FLAGS_SHOWPREVIEW;
}
// Bool selected
//*---------------------------------------------------------------------------*
void ShaderNode::SetSelected(const Bool& t_selected)
//*---------------------------------------------------------------------------*
{
	if (t_selected)		flags |= SHADERNODE_FLAGS_SELECTED;
	else				flags &= ~SHADERNODE_FLAGS_SELECTED;
}
//*---------------------------------------------------------------------------*
Bool ShaderNode::GetSelected()
//*---------------------------------------------------------------------------*
{
	return (flags & SHADERNODE_FLAGS_SELECTED);
}
// Bool expanded
//*---------------------------------------------------------------------------*
void ShaderNode::SetExpanded(const Bool& t_expanded)
//*---------------------------------------------------------------------------*
{
	if (t_expanded)		flags |= SHADERNODE_FLAGS_EXPANDED;
	else				flags &= ~SHADERNODE_FLAGS_EXPANDED;
}
//*---------------------------------------------------------------------------*
Bool ShaderNode::GetExpanded()
//*---------------------------------------------------------------------------*
{
	return (flags & SHADERNODE_FLAGS_EXPANDED);
}
//*---------------------------------------------------------------------------*
void ShaderNode::InvertExpanded()
//*---------------------------------------------------------------------------*
{
	if (flags & SHADERNODE_FLAGS_EXPANDED)	flags &= ~SHADERNODE_FLAGS_EXPANDED;
	else									flags |= SHADERNODE_FLAGS_EXPANDED;
}
// LONG type
//*---------------------------------------------------------------------------*
Bool ShaderNode::IsInstanceOf(const LONG& t_type)
//*---------------------------------------------------------------------------*
{
	return (type == t_type);
}
//*---------------------------------------------------------------------------*
void ShaderNode::SetType(const LONG& t_type)
//*---------------------------------------------------------------------------*
{
	type = t_type;
}
//*---------------------------------------------------------------------------*
LONG ShaderNode::GetType()
//*---------------------------------------------------------------------------*
{
	return type;
}
// LONG numNodeInputs
//*---------------------------------------------------------------------------*
LONG ShaderNode::GetNodeCount()
//*---------------------------------------------------------------------------*
{
	return numNodeInputs;
}
// LONG acceptCount
//*---------------------------------------------------------------------------*
LONG ShaderNode::GetAcceptCount()
//*---------------------------------------------------------------------------*
{
	return acceptCount;
}
//*---------------------------------------------------------------------------*
void ShaderNode::ClearInputs()
//*---------------------------------------------------------------------------*
{
	if (!nodeInputs)	return;
	for (LONG i = 0L; i != numNodeInputs; ++i)
	{
		nodeInputs[i].SetNode(NULL);
	}
}
// LONG connections
//*---------------------------------------------------------------------------*
void ShaderNode::SetConnections(const LONG& count)
//*---------------------------------------------------------------------------*
{
	connections = count;
}
//*---------------------------------------------------------------------------*
void ShaderNode::IncConnect()
//*---------------------------------------------------------------------------*
{
	++connections;
}
//*---------------------------------------------------------------------------*
void ShaderNode::DecConnect()
//*---------------------------------------------------------------------------*
{
	if (connections > 0L) --connections;
}
//*---------------------------------------------------------------------------*
LONG ShaderNode::Connected()
//*---------------------------------------------------------------------------*
{
	return connections;
}
// Bool connecting
//*---------------------------------------------------------------------------*
void ShaderNode::SetConnecting(const Bool& t_connecting)
//*---------------------------------------------------------------------------*
{
	if (t_connecting)	flags |= SHADERNODE_FLAGS_CONNECTING;
	else				flags &= ~SHADERNODE_FLAGS_CONNECTING;
}
//*---------------------------------------------------------------------------*
Bool ShaderNode::IsConnecting()
//*---------------------------------------------------------------------------*
{
	return (flags & SHADERNODE_FLAGS_CONNECTING);
}
// NodeInput* nodeInputs - retrieve by index
//*---------------------------------------------------------------------------*
NodeInput* ShaderNode::GetNodeInput(LONG index)
//*---------------------------------------------------------------------------*
{
	if (!nodeInputs)				return NULL;
	if (!numNodeInputs)				return NULL;
	if (index >= numNodeInputs)	return NULL;
	return &nodeInputs[index];
}
// Read/Write/CopyTo
// - Read NodeInput info
//*---------------------------------------------------------------------------*
Bool ShaderNode::Read(HyperFile* hf, LONG level)
//*---------------------------------------------------------------------------*
{
	if (!hf->ReadString(&name))			return FALSE;
	if (!hf->ReadLong(&xPos))			return FALSE;
	if (!hf->ReadLong(&yPos))			return FALSE;
	if (!hf->ReadLong(&id))				return FALSE;
	if (!hf->ReadLong(&flags))			return FALSE;
	if (!hf->ReadLong(&type))			return FALSE;
	if (!hf->ReadLong(&numNodeInputs))	return FALSE;
	if (!hf->ReadLong(&acceptCount))	return FALSE;
	if (!hf->ReadLong(&connections))	return FALSE;
	if (!nodeInputs)					return TRUE;
	for (LONG i = 0L; i != numNodeInputs; ++i)
	{
		if (!nodeInputs[i].Read(hf, level)) return FALSE;
	}
	return TRUE;
}
// - Write NodeInput info
//*---------------------------------------------------------------------------*
Bool ShaderNode::Write(HyperFile* hf)
//*---------------------------------------------------------------------------*
{
	if (!hf->WriteString(name))			return FALSE;
	if (!hf->WriteLong(xPos))			return FALSE;
	if (!hf->WriteLong(yPos))			return FALSE;
	if (!hf->WriteLong(id))				return FALSE;
	if (!hf->WriteLong(flags))			return FALSE;
	if (!hf->WriteLong(type))			return FALSE;
	if (!hf->WriteLong(numNodeInputs))	return FALSE;
	if (!hf->WriteLong(acceptCount))	return FALSE;
	if (!hf->WriteLong(connections))	return FALSE;
	if (!nodeInputs)					return TRUE;
	for (LONG i = 0L; i != numNodeInputs; ++i)
	{
		if (!nodeInputs[i].Write(hf)) return FALSE;
	}
	return TRUE;
}
// - Copy Source NodeInput info to Destination NodeInput
//*---------------------------------------------------------------------------*
Bool ShaderNode::CopyTo(ShaderNode* dsn, Bool uniqueID)
//*---------------------------------------------------------------------------*
{
	dsn->name =				name;
	dsn->xPos =				xPos;
	dsn->yPos =				yPos;
	if (!uniqueID)			dsn->id = id;
	dsn->flags =			flags;
	dsn->type =				type;
	dsn->numNodeInputs =	numNodeInputs;
	dsn->acceptCount =		acceptCount;
	dsn->connections =		connections;
	if (!nodeInputs)		return TRUE;
	for (LONG i = 0L; i != numNodeInputs; ++i)
	{
		nodeInputs[i].CopyTo(&(dsn->nodeInputs[i]), FALSE);
	}
	return TRUE;
}
// - Reestablish NodeInput* node links from id's
//*---------------------------------------------------------------------------*
void ShaderNode::ReestablishNodeLinks(ShaderNode* firstSNode)
//*---------------------------------------------------------------------------*
{
	if (!nodeInputs)	return;
	ShaderNode*	sn =	NULL;
	for (LONG i = 0L; i != numNodeInputs; ++i)
	{
		ni = &nodeInputs[i];
		for (sn = firstSNode; sn; sn = (ShaderNode* )sn->GetNext())
		{
			if (sn->id == ni->GetNodeID())
			{
				ni->SetNode(sn);
				break;
			}
		}
	}
}
//*---------------------------------------------------------------------------*
void ShaderNode::SetPreview(BaseMaterial* chn, Bool fromFile)
//*---------------------------------------------------------------------------*
{
}
//*---------------------------------------------------------------------------*
Vector ShaderNode::Output(BaseMaterial* chn, ChannelData* cd)
//*---------------------------------------------------------------------------*
{
	return Vector(1.0);
}
// BaseBitmap *previewBitmap
//*---------------------------------------------------------------------------*
BaseBitmap* ShaderNode::GetPreview()
//*---------------------------------------------------------------------------*
{
	/*
	if (!previewGL)		return NULL;
	if (!previewBitmap)	return NULL;
	// Create the shader node preview using OpenGL and store in 'previewBitmap'
	previewGL->Draw();
	// pointers for processing
	UCHAR*	redbuff =	previewGL->GetRender();
	UCHAR*	greenbuff =	redbuff+65536L;
	UCHAR*	bluebuff =	greenbuff+65536L;
  
	// 256x256 pixels
	LONG	x;
	LONG	r, g, b;
	for (LONG y = 255L; y != -1L; --y)
	{
		for (x = 0L; x != 256L; ++x)
		{
			r =	*redbuff++;
			g =	*greenbuff++;
			b =	*bluebuff++;
			previewBitmap->SetPixel(x, y, r, g, b);
		}
	}
	*/
  
	return previewBitmap;
}

On 11/01/2015 at 09:38, xxxxxxxx wrote:

Thanks a lot Robert.
I'll try to make sense of that. But it's lot of code to sift through.

That's not your fault though. I know that link lists always requires a ton of code. Which is one reason why I was hoping I could use the existing xpresso node system and just add my own custom nodes to it. Instead of writing the entire thing by hand.
But I'm running into a lot of things I can't figure out.

-ScottA