nsi.hpp

   1#ifndef __nsi_hpp
   2#define __nsi_hpp
   3
   4#include "nsi.h"
   5
   6#include <cstdlib>
   7#include <cstring>
   8#include <vector>
   9#include <string>
  10
  11namespace NSI
  12{
  13
  14/* Interface which provides the C API. */
  15class CAPI
  16{
  17public:
  18	virtual ~CAPI() {}
  19
  20	virtual NSIContext_t NSIBegin(
  21		int nparams,
  22		const NSIParam_t *params ) const = 0;
  23
  24	virtual void NSIEnd(
  25		NSIContext_t ctx ) const = 0;
  26
  27	virtual void NSICreate(
  28		NSIContext_t ctx,
  29		NSIHandle_t handle,
  30		const char *type,
  31		int nparams,
  32		const NSIParam_t *params ) const = 0;
  33
  34	virtual void NSIDelete(
  35		NSIContext_t ctx,
  36		NSIHandle_t handle,
  37		int nparams,
  38		const NSIParam_t *params ) const = 0;
  39
  40	virtual void NSISetAttribute(
  41		NSIContext_t ctx,
  42		NSIHandle_t object,
  43		int nparams,
  44		const NSIParam_t *params ) const = 0;
  45
  46	virtual void NSISetAttributeAtTime(
  47		NSIContext_t ctx,
  48		NSIHandle_t object,
  49		double time,
  50		int nparams,
  51		const NSIParam_t *params ) const = 0;
  52
  53	virtual void NSIDeleteAttribute(
  54		NSIContext_t ctx,
  55		NSIHandle_t object,
  56		const char *name ) const = 0;
  57
  58	virtual void NSIConnect(
  59		NSIContext_t ctx,
  60		NSIHandle_t from,
  61		const char *from_attr,
  62		NSIHandle_t to,
  63		const char *to_attr,
  64		int nparams,
  65		const NSIParam_t *params ) const = 0;
  66
  67	virtual void NSIDisconnect(
  68		NSIContext_t ctx,
  69		NSIHandle_t from,
  70		const char *from_attr,
  71		NSIHandle_t to,
  72		const char *to_attr ) const = 0;
  73
  74	virtual void NSIEvaluate(
  75		NSIContext_t ctx,
  76		int nparams,
  77		const NSIParam_t *params ) const = 0;
  78
  79	virtual void NSIRenderControl(
  80		NSIContext_t ctx,
  81		int nparams,
  82		const NSIParam_t *params ) const = 0;
  83};
  84
  85/* Default API provider, used when linking directly with the renderer. */
  86class LinkedAPI : public CAPI
  87{
  88public:
  89	static CAPI& Instance() { static LinkedAPI api; return api; }
  90
  91	virtual NSIContext_t NSIBegin(
  92		int nparams,
  93		const NSIParam_t *params ) const
  94	{
  95		return ::NSIBegin( nparams, params );
  96	}
  97
  98	virtual void NSIEnd(
  99		NSIContext_t ctx ) const
 100	{
 101		::NSIEnd( ctx );
 102	}
 103
 104	virtual void NSICreate(
 105		NSIContext_t ctx,
 106		NSIHandle_t handle,
 107		const char *type,
 108		int nparams,
 109		const NSIParam_t *params ) const
 110	{
 111		::NSICreate( ctx, handle, type, nparams, params );
 112	}
 113
 114	virtual void NSIDelete(
 115		NSIContext_t ctx,
 116		NSIHandle_t handle,
 117		int nparams,
 118		const NSIParam_t *params ) const
 119	{
 120		::NSIDelete( ctx, handle, nparams, params );
 121	}
 122
 123	virtual void NSISetAttribute(
 124		NSIContext_t ctx,
 125		NSIHandle_t object,
 126		int nparams,
 127		const NSIParam_t *params ) const
 128	{
 129		::NSISetAttribute( ctx, object, nparams, params );
 130	}
 131
 132	virtual void NSISetAttributeAtTime(
 133		NSIContext_t ctx,
 134		NSIHandle_t object,
 135		double time,
 136		int nparams,
 137		const NSIParam_t *params ) const
 138	{
 139		::NSISetAttributeAtTime( ctx, object, time, nparams, params );
 140	}
 141
 142	virtual void NSIDeleteAttribute(
 143		NSIContext_t ctx,
 144		NSIHandle_t object,
 145		const char *name ) const
 146	{
 147		::NSIDeleteAttribute( ctx, object, name );
 148	}
 149
 150	virtual void NSIConnect(
 151		NSIContext_t ctx,
 152		NSIHandle_t from,
 153		const char *from_attr,
 154		NSIHandle_t to,
 155		const char *to_attr,
 156		int nparams,
 157		const NSIParam_t *params ) const
 158	{
 159		::NSIConnect( ctx, from, from_attr, to, to_attr, nparams, params );
 160	}
 161
 162	virtual void NSIDisconnect(
 163		NSIContext_t ctx,
 164		NSIHandle_t from,
 165		const char *from_attr,
 166		NSIHandle_t to,
 167		const char *to_attr ) const
 168	{
 169		::NSIDisconnect( ctx, from, from_attr, to, to_attr );
 170	}
 171
 172	virtual void NSIEvaluate(
 173		NSIContext_t ctx,
 174		int nparams,
 175		const NSIParam_t *params ) const
 176	{
 177		::NSIEvaluate( ctx, nparams, params );
 178	}
 179
 180	virtual void NSIRenderControl(
 181		NSIContext_t ctx,
 182		int nparams,
 183		const NSIParam_t *params ) const
 184	{
 185		::NSIRenderControl( ctx, nparams, params );
 186	}
 187};
 188
 189class ArgBase;
 190
 191/*
 192	StaticArgumentListProxy is a linked list of ArgBase references which is
 193	eventually flattened into an array of NSIParam_t.
 194
 195	What it allows is convenient syntax to build a list of static length
 196	inline:
 197
 198	ctx.SetAttribute( "handle",
 199		(
 200			NSI::IntegerArg( "arg1", 1 ),
 201			NSI::StringArg( "arg2", "2" )
 202		) );
 203*/
 204template<unsigned N>
 205class StaticArgumentListProxy
 206{
 207public:
 208	StaticArgumentListProxy(
 209		const ArgBase &a,
 210		const StaticArgumentListProxy<N-1> &prev )
 211	:
 212		m_arg( a ), m_prev( prev )
 213	{
 214	}
 215
 216	/* Write the list to a contiguous NSIParam_t array, from the end. */
 217	inline void FlattenList( NSIParam_t *p ) const;
 218
 219	/* This appends an argument to an existing list. */
 220	StaticArgumentListProxy<N+1> operator,( const ArgBase &a ) const
 221	{
 222		return StaticArgumentListProxy<N+1>( a, *this );
 223	}
 224
 225private:
 226	const ArgBase &m_arg;
 227	const StaticArgumentListProxy<N-1> &m_prev;
 228};
 229
 230
 231/*
 232	This template specialization exists so the object can be built directly
 233	from ArgBase's operator, without using any temporaries.
 234
 235	It also ends the recursive list. The the reason above is why it does not
 236	end with a <0> specialization which would have been much simpler.
 237*/
 238template<>
 239class StaticArgumentListProxy<2>
 240{
 241public:
 242	StaticArgumentListProxy(
 243		const ArgBase &a0,
 244		const ArgBase &a1 )
 245	:
 246		m_arg0( a0 ), m_arg1( a1 )
 247	{
 248	}
 249
 250	/* Write the list to a contiguous NSIParam_t array, from the end. */
 251	inline void FlattenList( NSIParam_t *p ) const;
 252
 253	/* This appends an argument to an existing list. */
 254	StaticArgumentListProxy<3> operator,( const ArgBase &a ) const
 255	{
 256		return StaticArgumentListProxy<3>( a, *this );
 257	}
 258
 259private:
 260	const ArgBase &m_arg0;
 261	const ArgBase &m_arg1;
 262};
 263
 264
 265class ArgBase
 266{
 267	/* Arguments are not meant to be copied around. */
 268	ArgBase( const ArgBase& );
 269	void operator=( const ArgBase& );
 270
 271public:
 272	/*
 273		It is a convention that argument names provided as C strings are not
 274		copied (caller must keep the string valid) while the names provided as
 275		C++ string are copied. This should fit with the general behavior of C
 276		vs C++ strings.
 277	*/
 278	ArgBase( const char *name )
 279	:
 280		m_name( name ), m_name_buf( 0 )
 281	{
 282	}
 283
 284	ArgBase( const std::string &name )
 285	:
 286		m_name_buf( new char[name.size() + 1u] )
 287	{
 288		m_name = m_name_buf;
 289		m_name_buf[ name.copy( m_name_buf, std::string::npos ) ] = 0;
 290	}
 291
 292	virtual ~ArgBase()
 293	{
 294		if( m_name_buf )
 295			delete[] m_name_buf;
 296	}
 297
 298	/* This starts building a list from (arg, arg). */
 299	StaticArgumentListProxy<2> operator,( const ArgBase &arg )
 300	{
 301		return StaticArgumentListProxy<2>( *this, arg );
 302	}
 303
 304	virtual void FillNSIParam( NSIParam_t &p ) const = 0;
 305
 306protected:
 307	const char *m_name;
 308	/* When we own the name string, this points to it. Otherwise 0. */
 309	char *m_name_buf;
 310};
 311
 312
 313template<unsigned N>
 314void StaticArgumentListProxy<N>::FlattenList( NSIParam_t *p ) const
 315{
 316	m_arg.FillNSIParam( *p );
 317	m_prev.FlattenList( p - 1 );
 318}
 319
 320void StaticArgumentListProxy<2>::FlattenList( NSIParam_t *p ) const
 321{
 322	m_arg1.FillNSIParam( p[0] );
 323	m_arg0.FillNSIParam( p[-1] );
 324}
 325
 326
 327/*
 328	Generic argument class to handle what is not easily done with the more
 329	specific classes.
 330*/
 331class Argument : public ArgBase
 332{
 333public:
 334	Argument( const char *name )
 335	:
 336		ArgBase( name ),
 337		m_data_buffer( 0 )
 338	{
 339		m_param.name = m_name;
 340		m_param.data = 0;
 341		m_param.type = NSITypeInvalid;
 342		m_param.arraylength = 0;
 343		m_param.count = 1;
 344		m_param.flags = 0;
 345	}
 346
 347	Argument( const std::string &name )
 348	:
 349		ArgBase( name ),
 350		m_data_buffer( 0 )
 351	{
 352		m_param.name = m_name;
 353		m_param.data = 0;
 354		m_param.type = NSITypeInvalid;
 355		m_param.arraylength = 0;
 356		m_param.count = 1;
 357		m_param.flags = 0;
 358	}
 359
 360	virtual ~Argument()
 361	{
 362		if( m_data_buffer )
 363			std::free( m_data_buffer );
 364	}
 365
 366	/*
 367		Those two, along with the SetXX returning this, are to support adding
 368		arguments to an ArgumentList without using a variable to hold the
 369		pointer. eg.
 370
 371		argument_list.Add(
 372			Argument::New( "attributename" )
 373			->SetType( NSITypeInteger )
 374			->SetCount( 4 )
 375			->CopyValue( att_value, 4*sizeof(int) ) );
 376	*/
 377	static Argument* New( const char *name )
 378		{ return new Argument( name ); }
 379	static Argument* New( const std::string &name )
 380		{ return new Argument( name ); }
 381
 382	virtual void FillNSIParam( NSIParam_t &p ) const
 383	{
 384		p = m_param;
 385	}
 386
 387	Argument* SetType( NSIType_t type )
 388	{
 389		m_param.type = type;
 390		m_param.flags &= ~int(NSIParamIsArray);
 391		return this;
 392	}
 393
 394	Argument* SetArrayType( NSIType_t type, size_t arraylength )
 395	{
 396		m_param.type = type;
 397		m_param.arraylength = int(arraylength);
 398		m_param.flags |= NSIParamIsArray;
 399		return this;
 400	}
 401
 402	Argument* SetCount( size_t count ) { m_param.count = count; return this; }
 403
 404	void* AllocValue( size_t value_size )
 405	{
 406		if( m_data_buffer )
 407			std::free( m_data_buffer );
 408		m_data_buffer = std::malloc( value_size );
 409		m_param.data = m_data_buffer;
 410		return m_data_buffer;
 411	}
 412
 413	Argument* CopyValue( const void *value, size_t value_size )
 414	{
 415		std::memcpy( AllocValue( value_size ), value, value_size );
 416		return this;
 417	}
 418
 419	Argument* SetValuePointer( const void *value )
 420	{
 421		m_param.data = value;
 422		return this;
 423	}
 424
 425	Argument* SetFlags( int flags )
 426	{
 427		m_param.flags |= flags;
 428		return this;
 429	}
 430
 431	Argument* ResetFlags( int flags )
 432	{
 433		m_param.flags &= ~flags;
 434		return this;
 435	}
 436
 437private:
 438	NSIParam_t m_param;
 439	void *m_data_buffer;
 440};
 441
 442class IntegerArg : public ArgBase
 443{
 444public:
 445	IntegerArg( const char *name, int v )
 446	:
 447		ArgBase( name ), m_v( v )
 448	{
 449	}
 450
 451	IntegerArg( const std::string &name, int v )
 452	:
 453		ArgBase( name ), m_v( v )
 454	{
 455	}
 456
 457	virtual void FillNSIParam( NSIParam_t &p ) const
 458	{
 459		p.name = m_name;
 460		p.data = &m_v;
 461		p.type = NSITypeInteger;
 462		p.count = 1;
 463		p.flags = 0;
 464	}
 465
 466private:
 467	int m_v;
 468};
 469
 470class FloatArg : public ArgBase
 471{
 472public:
 473	FloatArg( const char *name, float v )
 474	:
 475		ArgBase( name ), m_v( v )
 476	{
 477	}
 478
 479	FloatArg( const std::string &name, float v )
 480	:
 481		ArgBase( name ), m_v( v )
 482	{
 483	}
 484
 485	virtual void FillNSIParam( NSIParam_t &p ) const
 486	{
 487		p.name = m_name;
 488		p.data = &m_v;
 489		p.type = NSITypeFloat;
 490		p.count = 1;
 491		p.flags = 0;
 492	}
 493
 494private:
 495	float m_v;
 496};
 497
 498class DoubleArg : public ArgBase
 499{
 500public:
 501	DoubleArg( const char *name, double v )
 502	:
 503		ArgBase( name ), m_v( v )
 504	{
 505	}
 506
 507	DoubleArg( const std::string &name, double v )
 508	:
 509		ArgBase( name ), m_v( v )
 510	{
 511	}
 512
 513	virtual void FillNSIParam( NSIParam_t &p ) const
 514	{
 515		p.name = m_name;
 516		p.data = &m_v;
 517		p.type = NSITypeDouble;
 518		p.count = 1;
 519		p.flags = 0;
 520	}
 521
 522private:
 523	double m_v;
 524};
 525
 526template<int TYPE>
 527class F3Arg : public ArgBase
 528{
 529public:
 530	F3Arg( const char *name, const float *v )
 531	:
 532		ArgBase( name )
 533	{
 534		m_v[0] = v[0];
 535		m_v[1] = v[1];
 536		m_v[2] = v[2];
 537	}
 538
 539	F3Arg( const std::string &name, const float *v )
 540	:
 541		ArgBase( name )
 542	{
 543		m_v[0] = v[0];
 544		m_v[1] = v[1];
 545		m_v[2] = v[2];
 546	}
 547
 548	virtual void FillNSIParam( NSIParam_t &p ) const
 549	{
 550		p.name = m_name;
 551		p.data = &m_v[0];
 552		p.type = TYPE;
 553		p.count = 1;
 554		p.flags = 0;
 555	}
 556
 557private:
 558	float m_v[3];
 559};
 560
 561typedef F3Arg<NSITypeColor> ColorArg;
 562typedef F3Arg<NSITypePoint> PointArg;
 563typedef F3Arg<NSITypeVector> VectorArg;
 564typedef F3Arg<NSITypeNormal> NormalArg;
 565
 566class DoubleMatrixArg : public ArgBase
 567{
 568public:
 569	DoubleMatrixArg( const char *name, const double *v )
 570	:
 571		ArgBase( name )
 572	{
 573		for( int i=0; i<16; i++ )
 574			m_v[i] = v[i];
 575	}
 576
 577	DoubleMatrixArg( const std::string &name, const double *v )
 578	:
 579		ArgBase( name )
 580	{
 581		for( int i=0; i<16; i++ )
 582			m_v[i] = v[i];
 583	}
 584
 585	virtual void FillNSIParam( NSIParam_t &p ) const
 586	{
 587		p.name = m_name;
 588		p.data = &m_v[0];
 589		p.type = NSITypeDoubleMatrix;
 590		p.count = 1;
 591		p.flags = 0;
 592	}
 593
 594private:
 595	double m_v[16];
 596};
 597
 598/*
 599	This does not make a copy of the given string. Use StringArg if that string
 600	is shorter lived than the argument list.
 601*/
 602class CStringPArg : public ArgBase
 603{
 604public:
 605	CStringPArg( const char *name, const char *v )
 606	:
 607		ArgBase( name ), m_v( v )
 608	{
 609	}
 610
 611	CStringPArg( const std::string &name, const char *v )
 612	:
 613		ArgBase( name ), m_v( v )
 614	{
 615	}
 616
 617	virtual void FillNSIParam( NSIParam_t &p ) const
 618	{
 619		p.name = m_name;
 620		p.data = &m_v;
 621		p.type = NSITypeString;
 622		p.count = 1;
 623		p.flags = 0;
 624	}
 625
 626private:
 627	const char *m_v;
 628};
 629
 630class StringArg : public ArgBase
 631{
 632public:
 633	StringArg( const char *name, const char *v )
 634	:
 635		ArgBase( name ), m_s( v )
 636	{
 637	}
 638
 639	StringArg( const std::string &name, const char *v )
 640	:
 641		ArgBase( name ), m_s( v )
 642	{
 643	}
 644
 645	StringArg( const char *name, const std::string &v )
 646	:
 647		ArgBase( name ), m_s( v )
 648	{
 649	}
 650
 651	StringArg( const std::string &name, const std::string &v )
 652	:
 653		ArgBase( name ), m_s( v )
 654	{
 655	}
 656
 657	virtual void FillNSIParam( NSIParam_t &p ) const
 658	{
 659		m_v = m_s.c_str();
 660		p.name = m_name;
 661		p.data = &m_v;
 662		p.type = NSITypeString;
 663		p.count = 1;
 664		p.flags = 0;
 665	}
 666
 667private:
 668	std::string m_s;
 669	mutable const char *m_v;
 670};
 671
 672
 673class PointerArg : public ArgBase
 674{
 675public:
 676	PointerArg( const char *name, const void *v )
 677	:
 678		ArgBase( name ), m_v( v )
 679	{
 680	}
 681
 682	PointerArg( const std::string &name, const void *v )
 683	:
 684		ArgBase( name ), m_v( v )
 685	{
 686	}
 687
 688	virtual void FillNSIParam( NSIParam_t &p ) const
 689	{
 690		p.name = m_name;
 691		p.data = &m_v;
 692		p.type = NSITypePointer;
 693		p.count = 1;
 694		p.flags = 0;
 695	}
 696
 697private:
 698	const void *m_v;
 699};
 700
 701
 702/* This does not make a copy of the given integers array */
 703class IntegersArg : public ArgBase
 704{
 705public:
 706	IntegersArg( const char *name, const int *v, size_t count )
 707	:
 708		ArgBase( name ), m_v( v ), m_count( count )
 709	{
 710	}
 711
 712	IntegersArg( const std::string &name, const int *v, size_t count)
 713	:
 714		ArgBase( name ), m_v( v ), m_count( count )
 715	{
 716	}
 717
 718	virtual void FillNSIParam( NSIParam_t &p ) const
 719	{
 720		p.name = m_name;
 721		p.data = m_v;
 722		p.type = NSITypeInteger;
 723		p.count = m_count;
 724		p.flags = 0;
 725	}
 726
 727private:
 728	const int *m_v;
 729	size_t m_count;
 730};
 731
 732
 733/* This does not make a copy of the given points array */
 734class PointsArg : public ArgBase
 735{
 736public:
 737	PointsArg( const char *name, const float *v, size_t count )
 738	:
 739		ArgBase( name ), m_v( v ), m_count( count )
 740	{
 741	}
 742
 743	PointsArg( const std::string &name, const float *v, size_t count)
 744	:
 745		ArgBase( name ), m_v( v ), m_count( count )
 746	{
 747	}
 748
 749	virtual void FillNSIParam( NSIParam_t &p ) const
 750	{
 751		p.name = m_name;
 752		p.data = m_v;
 753		p.type = NSITypePoint;
 754		p.count = m_count;
 755		p.flags = 0;
 756	}
 757
 758private:
 759	const float *m_v;
 760	size_t m_count;
 761};
 762
 763
 764/* This does not make a copy of the given normals array */
 765class NormalsArg : public ArgBase
 766{
 767public:
 768	NormalsArg( const char *name, const float *v, size_t count )
 769	:
 770		ArgBase( name ), m_v( v ), m_count( count )
 771	{
 772	}
 773
 774	NormalsArg( const std::string &name, const float *v, size_t count)
 775	:
 776		ArgBase( name ), m_v( v ), m_count( count )
 777	{
 778	}
 779
 780	virtual void FillNSIParam( NSIParam_t &p ) const
 781	{
 782		p.name = m_name;
 783		p.data = m_v;
 784		p.type = NSITypeNormal;
 785		p.count = m_count;
 786		p.flags = 0;
 787	}
 788
 789private:
 790	const float *m_v;
 791	size_t m_count;
 792};
 793
 794
 795class ArgumentList
 796{
 797	ArgumentList( const ArgumentList& );
 798	void operator=( const ArgumentList& );
 799public:
 800	ArgumentList() {}
 801
 802	~ArgumentList() { clear(); }
 803
 804	void clear()
 805	{
 806		while( !m_args.empty() )
 807		{
 808			delete m_args.back();
 809			m_args.pop_back();
 810		}
 811	}
 812
 813	bool empty() const { return m_args.empty(); }
 814
 815	size_t size() const { return m_args.size(); }
 816	const ArgBase* operator[]( size_t i ) const { return m_args[i]; }
 817
 818	void Add( ArgBase *arg )
 819	{
 820		m_args.push_back( arg );
 821	}
 822
 823	void push( ArgBase *arg )
 824	{
 825		m_args.push_back( arg );
 826	}
 827
 828	void push_back( ArgBase *arg )
 829	{
 830		m_args.push_back( arg );
 831	}
 832
 833
 834private:
 835	std::vector<ArgBase*> m_args;
 836};
 837typedef ArgumentList DynamicArgumentList; /* backward compatibility */
 838
 839
 840
 841
 842class Context
 843{
 844	/*
 845		Don't allow copying because ownership semantics get really messy. If
 846		you really know what you're doing, use the Handle() method and build
 847		another context from it.
 848	*/
 849	Context( const Context& );
 850	void operator=( const Context& );
 851
 852private:
 853	class FlatArgumentList
 854	{
 855		void operator=( const FlatArgumentList& );
 856#if __cplusplus < 201103L
 857	/* Stupid rule with old C++ requires this to be visible. */
 858	public:
 859#endif
 860		FlatArgumentList( const FlatArgumentList& );
 861
 862	public:
 863		/* Empty list. */
 864		FlatArgumentList()
 865		:
 866			m_nsi_params( 0 ),
 867			m_size_nsi_params( 0 )
 868		{
 869		}
 870
 871		/* From dynamically built argument list. */
 872		FlatArgumentList( const ArgumentList &arglist )
 873		{
 874			m_size_nsi_params = arglist.size();
 875			m_nsi_params = new NSIParam_t[ m_size_nsi_params ];
 876			for( unsigned i = 0; i < m_size_nsi_params; ++i )
 877			{
 878				arglist[i]->FillNSIParam( m_nsi_params[i] );
 879			}
 880		}
 881
 882		/* From a static argument list. */
 883		template<unsigned N>
 884		FlatArgumentList( const StaticArgumentListProxy<N> &arglist )
 885		{
 886			m_size_nsi_params = N;
 887			m_nsi_params = new NSIParam_t[ m_size_nsi_params ];
 888			arglist.FlattenList( m_nsi_params + N - 1u );
 889		}
 890
 891		/* From a single argument. */
 892		FlatArgumentList( const ArgBase &arg )
 893		{
 894			m_size_nsi_params = 1;
 895			m_nsi_params = new NSIParam_t[ m_size_nsi_params ];
 896			arg.FillNSIParam( m_nsi_params[0] );
 897		}
 898
 899		~FlatArgumentList()
 900		{
 901			delete[] m_nsi_params;
 902		}
 903
 904		int size() const { return int(m_size_nsi_params); }
 905		const NSIParam_t* list() const { return m_nsi_params; }
 906
 907	private:
 908		mutable NSIParam_t *m_nsi_params;
 909		mutable size_t m_size_nsi_params;
 910	};
 911
 912public:
 913	/* Deprecated. */
 914	explicit Context( NSIContext_t ctx )
 915	:
 916		m_ctx( ctx ),
 917		m_owns_context( false ),
 918		m_api( LinkedAPI::Instance() )
 919	{
 920	}
 921
 922	Context( const CAPI &api = LinkedAPI::Instance() )
 923	:
 924		m_ctx( NSI_BAD_CONTEXT ),
 925		m_owns_context( false ),
 926		m_api( api )
 927	{
 928	}
 929
 930	/* Destroys the context, if owned by this object. */
 931	~Context()
 932	{
 933		if( m_owns_context )
 934			End();
 935	}
 936
 937	/*
 938		Use an existing C API handle. The context will not be destroyed with
 939		this object but End() may be called explicitly to destroy it.
 940	*/
 941	void SetHandle( NSIContext_t ctx )
 942	{
 943		if( m_owns_context && m_ctx != NSI_BAD_CONTEXT )
 944			End();
 945
 946		m_ctx = ctx;
 947		m_owns_context = false;
 948	}
 949
 950	/* Retrieve the C API handle. */
 951	NSIContext_t Handle() const { return m_ctx; }
 952
 953	/*
 954		Make this object no longer own the C API handle. Meaning the destructor
 955		will not End() it.
 956	*/
 957	void Detach() { m_owns_context = false; }
 958
 959	/* Create a new context. */
 960	void Begin( const FlatArgumentList &params = FlatArgumentList() )
 961	{
 962		if( m_owns_context && m_ctx != NSI_BAD_CONTEXT )
 963			End();
 964
 965		m_ctx = m_api.NSIBegin( params.size(), params.list() );
 966		m_owns_context = true;
 967	}
 968
 969	/* Destroy the context. */
 970	void End()
 971	{
 972		m_api.NSIEnd( m_ctx );
 973		m_ctx = NSI_BAD_CONTEXT;
 974		m_owns_context = false;
 975	}
 976
 977	void Create(
 978		const std::string &handle,
 979		const std::string &type,
 980		const FlatArgumentList &params = FlatArgumentList() )
 981	{
 982		m_api.NSICreate(
 983			m_ctx,
 984			handle.c_str(),
 985			type.c_str(),
 986			params.size(), params.list() );
 987	}
 988
 989	void Delete(
 990		const std::string &handle,
 991		const FlatArgumentList &params = FlatArgumentList() )
 992	{
 993		m_api.NSIDelete(
 994			m_ctx,
 995			handle.c_str(),
 996			params.size(), params.list() );
 997	}
 998
 999	void SetAttribute(
1000		const std::string &object,
1001		const FlatArgumentList &params = FlatArgumentList() )
1002	{
1003		m_api.NSISetAttribute(
1004			m_ctx,
1005			object.c_str(),
1006			params.size(), params.list() );
1007	}
1008
1009	void SetAttributeAtTime(
1010		const std::string &object,
1011		double time,
1012		const FlatArgumentList &params = FlatArgumentList() )
1013	{
1014		m_api.NSISetAttributeAtTime(
1015			m_ctx,
1016			object.c_str(),
1017			time,
1018			params.size(), params.list() );
1019	}
1020
1021	void DeleteAttribute(
1022		const std::string &object,
1023		const std::string &name )
1024	{
1025		m_api.NSIDeleteAttribute(
1026			m_ctx,
1027			object.c_str(),
1028			name.c_str() );
1029	}
1030
1031	void Connect(
1032		const std::string &from,
1033		const std::string &from_attr,
1034		const std::string &to,
1035		const std::string &to_attr,
1036		const FlatArgumentList &params = FlatArgumentList() )
1037	{
1038		m_api.NSIConnect(
1039			m_ctx,
1040			from.c_str(),
1041			from_attr.c_str(),
1042			to.c_str(),
1043			to_attr.c_str(),
1044			params.size(), params.list() );
1045	}
1046
1047	void Disconnect(
1048		const std::string &from,
1049		const std::string &from_attr,
1050		const std::string &to,
1051		const std::string &to_attr,
1052		const FlatArgumentList &params = FlatArgumentList() )
1053	{
1054		m_api.NSIDisconnect(
1055			m_ctx,
1056			from.c_str(),
1057			from_attr.c_str(),
1058			to.c_str(),
1059			to_attr.c_str() );
1060	}
1061
1062	void Evaluate(
1063		const FlatArgumentList &params = FlatArgumentList() )
1064	{
1065		m_api.NSIEvaluate(
1066			m_ctx,
1067			params.size(), params.list() );
1068	}
1069
1070	void RenderControl(
1071		const FlatArgumentList &params = FlatArgumentList() )
1072	{
1073		m_api.NSIRenderControl(
1074			m_ctx,
1075			params.size(), params.list() );
1076	}
1077
1078private:
1079	NSIContext_t m_ctx;
1080	bool m_owns_context;
1081	const CAPI &m_api;
1082};
1083
1084};
1085
1086#endif