#include "ge_math.h"
#include "c4d_tools.h"
#include "c4d_file.h"
#include "c4d_basecontainer.h"
#include "c4d_general.h"

#ifndef __API_INTERN__
	#include "c4d_basedocument.h"
#endif

SVector s_empty;
LVector l_empty;

Matrix MatrixMove(const Vector &t)
{
	Matrix erg;
	erg.off = t;
	return erg;
}

Matrix MatrixScale(const Vector &s)
{
	Matrix erg;

	erg.v1.x=s.x;
	erg.v2.y=s.y;
	erg.v3.z=s.z;
	return erg;
}

Matrix MatrixRotX(Real w)
{
	Matrix erg;
	Real cs = Cos(w), sn = Sin(w);

	erg.v3.z= cs;
	erg.v2.z=-sn;
	erg.v3.y= sn;
	erg.v2.y= cs;
	return erg;
}

Matrix MatrixRotY(Real w)
{
	Matrix erg;
	Real cs = Cos(w), sn = Sin(w);

	erg.v1.x= cs;
	erg.v3.x=-sn;
	erg.v1.z= sn;
	erg.v3.z= cs;
	return erg;
}

Matrix MatrixRotZ(Real w)
{
	Matrix erg;
	Real cs = Cos(w), sn = Sin(w);

	erg.v1.x = cs;
	erg.v2.x = sn;
	erg.v1.y =-sn;
	erg.v2.y = cs;
	return erg;
}

static Real GetNear(Real alt, Real *neu)
{
	Real diff = (*neu-alt)/RCO pi2;
	diff = (diff-Floor(diff))*RCO pi2;
	*neu = diff + alt;

	if (diff >= RCO pi)
	{
		diff -= RCO pi2;
		*neu -= RCO pi2;
	}

	return diff;
}

Vector GetOptimalAngle(const Vector &orot, const Vector &nrot, ROTATIONORDER order)
{
	Vector d1, d2, n2, n1=nrot;
	
	switch (order)
	{
		case ROTATIONORDER_XYZGLOBAL:
		case ROTATIONORDER_ZYXGLOBAL:					n2 = Vector(RCO pi+nrot.x,RCO pi-nrot.y,RCO pi+nrot.z);		break;
		case ROTATIONORDER_YZXGLOBAL:											
		case ROTATIONORDER_XZYGLOBAL:					n2 = Vector(RCO pi+nrot.x,RCO pi+nrot.y,RCO pi-nrot.z);		break;
																											
		case ROTATIONORDER_YXZGLOBAL:											
		case ROTATIONORDER_ZXYGLOBAL:					n2 = Vector(RCO pi-nrot.x,RCO pi+nrot.y,RCO pi+nrot.z);		break; 	

		default:
		case ROTATIONORDER_HPB:								n2 = Vector(RCO pi+nrot.x,RCO pi-nrot.y,RCO pi+nrot.z);		break; 	
	}

	d1.x = GetNear(orot.x,&n1.x);
	d1.y = GetNear(orot.y,&n1.y);
	d1.z = GetNear(orot.z,&n1.z);

	d2.x = GetNear(orot.x,&n2.x);
	d2.y = GetNear(orot.y,&n2.y);
	d2.z = GetNear(orot.z,&n2.z);

	if (Abs(d2.x)+Abs(d2.y)+Abs(d2.z)<Abs(d1.x)+Abs(d1.y)+Abs(d1.z))
		return n2;
	else
		return n1;
}

// Winkel eines Punkts bestimmen
Vector VectorToHPB(const Vector &p)
{
  Real l;
  Vector rot;

  l = Sqrt(p.x*p.x+p.z*p.z);

  if (l<0.00001)
	{
    if (p.y>0.0)
      rot = Vector(0.0, RCO pi05,0.0);
    else
      rot = Vector(0.0,-RCO pi05,0.0);
  }
	else
	{
    if (p.z>0.0)
      rot.x = -ASin(p.x/l);
    else
      rot.x = RCO pi+ASin(p.x/l);
    rot.y = ATan(p.y/l);
    rot.z = 0.0;
  }
	return rot;
}

Vector MatrixToHPB(const Matrix &m, ROTATIONORDER rot_order)
{
	LVector rot,v1=!(m.v1.ToLV()),v2=!(m.v2.ToLV()),v3=!(m.v3.ToLV()); // v1 has to be normalized
	LReal tsin = 0.0, tcos = 0.0;

	switch (rot_order)
	{
		case ROTATIONORDER_YXZGLOBAL:
		{
			rot.x = ASin(-v2.z); //h
			LReal a = -Cos(rot.x);
			if (Abs(a) > 0.005)
			{
				tsin = v1.z;// / a;
				tcos = v3.z;// / a;
				rot.y = atan2(tsin, tcos); //p
				tsin = v2.x;// / a;
				tcos = v2.y;// / a;
				rot.z = atan2(tsin, tcos); //b
			}
			else
			{
				rot.z = RCO 0.0;
				tsin = v1.y; //V
				tcos = v1.x; //W
				rot.y = atan2(tsin, tcos);
				if (v2.z > 0) rot.y = pi2 - rot.y;
			}
		}
		break;

		case ROTATIONORDER_YZXGLOBAL:
		{
			rot.z = ASin(v2.x);
			LReal e = Cos(rot.z);
			if (Abs(e) > 0.005)
			{
				tsin = -v2.z;// / e;
				tcos = v2.y;// / e;
				rot.x = atan2(tsin, tcos);
				tsin = -v3.x;// / e;
				tcos = v1.x;// / e;
				rot.y = atan2(tsin, tcos);
			}
			else
			{
				rot.x = RCO 0.0;
				tsin = v1.z; //V
				tcos = -v1.y; //W
				rot.y = atan2(tsin, tcos);
				if (v2.x < 0) rot.y = pi - rot.y;
			}
		}
		break;

		case ROTATIONORDER_ZYXGLOBAL:
		{
			rot.y = ASin(-v3.x);
			LReal c = Cos(rot.y);
			if (Abs(c) > 0.005)
			{
				tsin = v2.x;// / c; //f
				tcos = v1.x;// / c; //e
				rot.z = atan2(tsin, tcos);
				tsin = v3.y;// / c; //b
				tcos = v3.z;// / c; //a
				rot.x = atan2(tsin, tcos);
			}
			else
			{
				rot.z = RCO 0.0;
				tsin = -v1.y; //V
				tcos = v2.y; //W
				rot.x = atan2(tsin, tcos);
				if (v3.x < 0) rot.x = -rot.x;
			}
		}
		break;

		case ROTATIONORDER_XZYGLOBAL:
		{
			rot.z = ASin(-v1.y);
			LReal e = -Cos(rot.z);
			if (Abs(e) > 0.005)
			{
				tsin = v1.z;// / e; //d
				tcos = v1.x;// / e; //c
				rot.y = atan2(tsin, tcos);
				tsin = v3.y;// / e; //b
				tcos = v2.y;// / e; //a
				rot.x = atan2(tsin, tcos);
			}
			else
			{
				rot.y = RCO 0.0;
				tsin = v3.x; //V
				tcos = v2.x; //W
				rot.x = atan2(tsin, tcos);
				if (v1.y > 0) rot.x += pi;
			}
		}
		break;

		case ROTATIONORDER_XYZGLOBAL:
		{
			rot.y = ASin(v1.z);
			LReal c = Cos(rot.y);
			if (Abs(c) > 0.005)
			{
				tsin = -v1.y;// / c; //f
				tcos = v1.x;// / c; //e
				rot.z = atan2(tsin, tcos);
				tsin = -v2.z;// / c; //b
				tcos = v3.z;// / c; //a
				rot.x = atan2(tsin, tcos);
			}
			else
			{
				rot.z = RCO 0.0;
				tsin = v2.x; //V
				tcos = -v3.x; //W
				rot.x = atan2(tsin, tcos);
				if (v1.z < 0.0)	rot.x -= pi;
			}
		}
		break;

	case ROTATIONORDER_ZXYGLOBAL:
		{
			rot.x = ASin(v3.y);
			LReal a = Cos(rot.x);
			if (Abs(a) > 0.005)
			{
				tsin = -v3.x;// / a; //d
				tcos = v3.z;// / a; //c
				rot.y = atan2(tsin, tcos);
				tsin = -v1.y;// / a; //f
				tcos = v2.y;// / a; //e
				rot.z = atan2(tsin, tcos);
			}
			else
			{
				rot.z = RCO 0.0;
				tsin = v2.x; //V
				tcos = v1.x; //W
				rot.y = atan2(tsin, tcos);
				if (v3.y < 0.0)	rot.y = -rot.y;
			}
		}
		break;

	case ROTATIONORDER_HPB:
	default:
		{
			LReal l = Sqrt(v3.x*v3.x+v3.z*v3.z);

			if (l<0.00001)
			{
				rot.x = 0.0;
				rot.z = ACos(LVector(1.0,0.0,0.0) * v1);

				if (v3.y>0.0)
				{
					rot.y = pi05;
					if (v1.z<0.0) rot.z = pi2-rot.z;
				}
				else
				{
					rot.y = -pi05;
					if (v1.z>0.0) rot.z = pi2-rot.z;
				}
			}
			else
			{
				if (v3.z>0.0)
					rot.x = -ASin(v3.x/l);
				else
					rot.x = pi+ASin(v3.x/l);

				if (rot.x<0.0) rot.x += pi2;
				rot.y = ATan((LReal)v3.y/l);
				rot.z = ACos(LVector(Cos(rot.x),0.0,Sin(rot.x)) * v1);

				if (v1.y>0.0) rot.z = pi2-rot.z;
			}
		}
		break;
	}

	return rot.ToRV();
}

// angles in Rad-/Euler system
Matrix HPBToMatrix(const Vector &w, ROTATIONORDER rot_order)
{
	if (w==0.0) return Matrix(); // speedup

	Real a,b,c,d,e,f,cosksinn,sinksinn;

	if (rot_order==ROTATIONORDER_DEFAULT)
	{
		SinCos(w.x,d,c); //y = h
		SinCos(w.y,b,a); //x = p
	}
	else
	{
		SinCos(w.x,b,a); //y = y
		SinCos(w.y,d,c); //x = x
	}
	SinCos(w.z,f,e); //z = b

	switch (rot_order)
	{
	case ROTATIONORDER_YXZGLOBAL:
		{
			sinksinn = d * b;
			cosksinn = c * b;

			return Matrix(Vector(0.0),
										Vector(c * e + sinksinn * f, -c * f + sinksinn * e, d * a),
										Vector(a * f, a * e, -b),
										Vector(-d * e + cosksinn * f, d * f + cosksinn * e, c * a));
		} break;
	case ROTATIONORDER_YZXGLOBAL:
		{
			sinksinn = c * f;
			cosksinn = d * f;

			return Matrix(Vector(0.0),
										Vector(c * e, -sinksinn * a + d * b, sinksinn * b + d * a),
										Vector(f, e * a, -e * b),
										Vector(-d * e, cosksinn * a + c * b, -cosksinn * b + c * a));
		} break;
	case ROTATIONORDER_ZYXGLOBAL:
		{
			sinksinn = e * d;
			cosksinn = f * d;

			return Matrix(Vector(0.0),
										Vector(e * c, -f * a + sinksinn * b, f * b + sinksinn * a),
										Vector(f * c, e * a + cosksinn * b, -e * b + cosksinn * a),
										Vector(-d, c * b, c * a));
		} break;
	case ROTATIONORDER_XZYGLOBAL:
		{
			sinksinn = a * f;
			cosksinn = b * f;

			return Matrix(Vector(0.0),
										Vector(e * c, -f, e * d),
										Vector(sinksinn * c + b * d, a * e, sinksinn * d - b * c),
										Vector(cosksinn * c - a * d, b * e, cosksinn * d + a * c));
		} break;
	case ROTATIONORDER_XYZGLOBAL:
		{
			sinksinn = b * d;
			cosksinn = a * d;

			return Matrix(Vector(0.0),
										Vector(c * e, -c * f, d),
										Vector(sinksinn * e + a * f, -sinksinn * f + a * e, -b * c),
										Vector(-cosksinn * e + b * f, cosksinn * f + b * e, a * c));
		} break;

	default:
		// make the compiler happy
		break;
	}

	// ROTATIONORDER_DEFAULT / ROTATIONORDER_HPB / ROTATIONORDER_YXZLOCAL / ROTATIONORDER_ZXYGLOBAL
	cosksinn = e * b;
	sinksinn = f * b;

	return Matrix(Vector(0.0),
								Vector(e * c - sinksinn * d, -f * a, e * d + sinksinn * c),
								Vector(f * c + cosksinn * d, e * a, f * d - cosksinn * c),
								Vector(-a * d, b, a * c));
}

Matrix RebuildMatrix( const Matrix &mg )
{
	Matrix m = mg;

	Bool collapsed[3] = { m.v1 == 0.0, m.v2 == 0.0, m.v3 == 0.0 };
	LONG ccnt = collapsed[0] + collapsed[1] + collapsed[2], i = 0;

	switch (ccnt) 
	{
	default: case 0: return m; break;
	case 3: m = Matrix(); break;
	case 2:
		{
			for (i = 0; i < 3; i++)
			{
				if (!collapsed[i]) 
				{
					m = RotAxisToMatrix(m[i + 1], 0.0);
					break;
				}
			}
		} break;
	case 1:
		{
			m.Normalize();
			if (collapsed[0])
			{
				m.v1 = m.v3 % m.v2;
				if (m.v1 == 0.0)	m.v1.x = 1.0;
			}
			if (collapsed[1])
			{
				m.v2 = m.v3 % m.v1;
				if (m.v2 == 0.0) m.v2.y = 1.0;
			}
			if (collapsed[2])
			{
				m.v3 = m.v1 % m.v2;
				if (m.v3 == 0.0) m.v3.z = 1.0;
			}
			m = m.GetTensorMatrix();
		} break;
	}

	for (i = 0; i < 3; i++)
	{
		if (!collapsed[i]) m[i + 1] *= Len(mg[i + 1]);
	}

	m.off = mg.off;

	return m;
}


void MatrixToRotAxis(const Matrix &mm, Vector *v, Real *w)
{
	Matrix m = mm;
	// MatrixVectoren MUESSEN normiert sein!!!
	m.v1=!m.v1;
	m.v2=!m.v2;
	m.v3=!m.v3;

	// Winkel berechnen
	*w = ACos((m.v1.x+m.v2.y+m.v3.z-RCO 1.0)/RCO 2.0);

	// Achse berechnen
	v->x= m.v2.z-m.v3.y;
	v->y= m.v3.x-m.v1.z;
	v->z= m.v1.y-m.v2.x;
	*v = !(*v);

	if (*v==0.0)
	{
		*v = Vector(0.0,1.0,0.0);
		*w = 0.0;
	}
}

Matrix RotAxisToMatrix(const Vector &v, Real w)
{
	Matrix m;

	if ((v.x==0.0 && v.y==0.0 && v.z==0.0) || w==0.0) return m;

//	// zuerst mal den Vector normieren ...
//	m.v2 = !v;
//
//	// jetzt ein rechtes KS basteln
//	m.v1 = m.v2%Vector(0.0,0.0,1.0);
//
//	if (Len(m.v1)>MIN_EPSILON)
//	{
//		m.v3 = m.v1%m.v2;
//	}
//	else
//	{
//		m.v3 = Vector(1.0,0.0,0.0)%m.v2;
//		m.v1 = m.v2%m.v3;
//	}
//
//	// Rotationsmatrix im Pleft- und Rechtssystem um Y ist gleich
//	m = (m*MatrixRotY(w)) * !m;

	// faster version:
  Real whalf = 0.5*w;
  Real hsin = Sin(whalf);
  Real hcos = Cos(whalf);

	Vector vn=!v * hsin;

	Real fTx  = 2.0*vn.x;
	Real fTy  = 2.0*vn.y;
	Real fTz  = 2.0*vn.z;
	Real fTwx = fTx*hcos;
	Real fTwy = fTy*hcos;
	Real fTwz = fTz*hcos;
	Real fTxx = fTx*vn.x;
	Real fTxy = fTy*vn.x;
	Real fTxz = fTz*vn.x;
	Real fTyy = fTy*vn.y;
	Real fTyz = fTz*vn.y;
	Real fTzz = fTz*vn.z;

	m.v1 = Vector(1.0-(fTyy+fTzz),fTxy-fTwz,fTxz+fTwy);
	m.v2 = Vector(fTxy+fTwz,1.0-(fTxx+fTzz),fTyz-fTwx);
	m.v3 = Vector(fTxz-fTwy,fTyz+fTwx,1.0-(fTxx+fTyy));

	return m;
}

Random::Random(void)
{
	Init(100);
}

void Random::Init(ULONG s)
{
	iset = 0;
	seed = s;
}

Real Random::Get01(void)
{
	const Real teiler = Real(2147483648.0+1.0); // +1.0, falls evtl. Ungenauigkeiten auftreten

  seed = ((seed+1)*69069) & 0x7FFFFFFF;
  return Real(seed)/teiler;
}

Real Random::Get11(void)
{
	return Get01()*RCO 2.0-RCO 1.0;
}

Real Random::GetG01(void)
{
	Real fac,rsq,v1,v2;

	if (iset==0)
	{
		do
		{
			v1 = Get11();
			v2 = Get11();
			rsq = v1*v1 + v2*v2;
		}
		while (rsq>=1.0 || rsq==0.0);

		fac  = Sqrt(RCO -2.0*Ln(rsq)/rsq);
		gset = v1*fac;
		iset = 1;
		return v2*fac*RCO 0.09+RCO 0.5;
	}
	else
	{
		iset=0;
		return gset*RCO 0.09+RCO 0.5;
	}
}

Real Random::GetG11(void)
{
	Real fac,rsq,v1,v2;

	if (iset==0)
	{
		do
		{
			v1 = Get11();
			v2 = Get11();
			rsq = v1*v1 + v2*v2;
		}
		while (rsq>=1.0 || rsq==0.0);

		fac  = Sqrt(RCO -2.0*Ln(rsq)/rsq);
		gset = v1*fac;
		iset = 1;
		return v2*fac*RCO 0.18;
	}
	else
	{
		iset=0;
		return gset*RCO 0.18;
	}
}

LVector ReflectRay(const LVector &v, const LVector &n)
{
	return v-n*(2.0*(n*v));
}

Vector RGBToHSV(const Vector &col)
{
  Real r,g,b,h,s,v,delta,max,min;

  r = col.x;
  g = col.y;
  b = col.z;

  max = r; if (g>max) max = g; if (b>max) max = b;
  min = r; if (g<min) min = g; if (b<min) min = b;

  v  = max;
  if (max>0.0)
  {
    s = RCO 1.0-min/max;

    if (s<MIN_EPSILON)
    {
      return Vector(0.0,0.0,min);
    }
	}
	else
	{
    return 0.0;
  }

  delta = max-min;
  if (r==max)
    h = (g-b)/delta;
  else if (g==max)
    h = RCO 2.0+(b-r)/delta;
  else
    h = RCO 4.0+(r-g)/delta;

  h /= 6.0;
  if (h<0.0) h += 1.0;
  return Vector(h,s,v);
}

Vector HSVToRGB(const Vector &col)
{
	Real r=0.0,g=0.0,b=0.0,h,s,v,f,p,q,t,i;
	LONG j;

  h = col.x;
  s = col.y;
  v = col.z;

  if (s<MIN_EPSILON)
	{
    r=g=b=v;
	}
	else
	{
    if (h==1.0) h=0.0;

    h *= RCO 6.0;
    i = Floor(h);
    f = h-i;
    p = v*(RCO 1.0-s);
    q = v*(RCO 1.0-s*f);
    t = v*(RCO 1.0-s*(RCO 1.0-f));
    j=(LONG)i;
    switch (j)
		{
			default:
      case 0: r = v; g = t; b = p; break;
      case 1: r = q; g = v; b = p; break;
      case 2: r = p; g = v; b = t; break;
      case 3: r = p; g = q; b = v; break;
      case 4: r = t; g = p; b = v; break;
      case 5: r = v; g = p; b = q; break;
    }
	}
  return Vector(r,g,b);
}

Vector RGBToHSL(const Vector &col)
{
	Real r, g, b, v, m, vm, r2, g2, b2, h, s, l;

	r = col.x;
	g = col.y;
	b = col.z;

	v = FMax(r, g);
	v = FMax(v, b);
	m = FMin(r, g);
	m = FMin(m, b);

	l = (m + v) * RCO 0.5;

	if (l <= RCO 0.0)
	{
		s = RCO 0.0;
		h = RCO 0.0;
	}
	else
	{
		s = vm = v - m;
		if (s <= RCO 0.0) 
		{
			h = s = RCO 0.0;
			return Vector(RCO 0.0);
		}

		Real div = (l <= RCO 0.5) ? (v + m) : (RCO 2.0 - v - m);
		if (div != RCO 0.0) s /= div;

		if (vm != RCO 0.0)
		{
			r2 = (v - r) / vm;
			g2 = (v - g) / vm;
			b2 = (v - b) / vm;
		}
		else
		{
			r2 = RCO 0.0;
			g2 = RCO 0.0;
			b2 = RCO 0.0;
		}

		if (r == v)
			h = (g == m ? RCO 5.0 + b2 : RCO 1.0 - g2);
		else if (g == v)
			h = (b == m ? RCO 1.0 + r2 : RCO 3.0 - b2);
		else
			h = (r == m ? RCO 3.0 + g2 : RCO 5.0 - r2);

		h /= RCO 6.0;		// Convert hue to 0.0 ... 1.0
	}

	return Vector(h, s, l);
} 

inline Real HSLtoRGB_value(Real nl, Real n2, Real hue)
{
	if (hue > RCO 360.0)
		hue -= RCO 360.0;
	else if (hue < RCO 0.0)
		hue += RCO 360.0;
	if (hue < RCO 60.0)
		return nl + (n2 - nl) * hue / RCO 60.0;
	if (hue < RCO 180.0)
		return n2;
	if (hue < RCO 240.0)
		return nl + (n2 - nl) * (RCO 240 - hue) / RCO 60.0;
	return nl;
} 

Vector HSLtoRGB(const Vector &col)
{ 
	Real h, s, l, m1, m2, r, g, b;

	h = col.x * RCO 360.0;
	s = col.y;
	l = col.z;

	if (l <= RCO 0.5)
		m2 = l * (RCO 1.0 + s);
	else
		m2 = l + s - l * s;
	m1 = RCO 2.0 * l - m2; 
	if (s == RCO 0.0 || h == RCO -1.0)
		r = g = b = l;
	else
	{
		r = HSLtoRGB_value(m1, m2, h + RCO 120.0);
		g = HSLtoRGB_value(m1, m2, h);
		b = HSLtoRGB_value(m1, m2, h - RCO 120.0);
	}

	return Vector(r, g, b);
}

Vector PointLineDistance(const Vector &p0, const Vector &v, const Vector &p)
{
	Real vsquare = v*v;
	if (vsquare==0.0) return 0.0;
	return p-(p0+(((p-p0)*v)/vsquare)*v);
}

#ifndef __API_INTERN__

VolumeData *VolumeData::Alloc(void)
{
	return C4DOS.Sh->AllocVolumeData();
}

void VolumeData::Free(VolumeData *&vd)
{
	C4DOS.Sh->FreeVolumeData(vd);
	vd=NULL;
}

TexData *TexData::Alloc(void)
{
	return C4DOS.Sh->AllocTexData();
}

void TexData::Free(TexData *&vd)
{
	C4DOS.Sh->FreeTexData(vd);
	vd=NULL;
}

void TexData::Init(void)
{
	C4DOS.Sh->InitTexData(this);
}

LONG VPBuffer::GetInfo(VPGETINFO type)
{
	return C4DOS.Sh->VPGetInfo(this,type);
}

Bool VPBuffer::GetLine(LONG x, LONG y, LONG cnt, void *data, LONG bitdepth, Bool dithering)
{
	return C4DOS.Sh->VPGetLine(this,x,y,cnt,data,bitdepth,dithering);
}

Bool VPBuffer::SetLine(LONG x, LONG y, LONG cnt, void *data, LONG bitdepth, Bool dithering)
{
	return C4DOS.Sh->VPSetLine(this,x,y,cnt,data,bitdepth,dithering);
}

Bool Render::AllocateBuffer(LONG id, LONG subid, LONG bitdepth, Bool visible)
{
	return C4DOS.Sh->VPAllocateBuffer(this,id,subid,bitdepth,visible);
}

LONG Render::AllocateBufferFX(LONG id, const String &name, LONG bitdepth, Bool visible)
{
	return C4DOS.Sh->VPAllocateBufferFX(this,id,name,bitdepth,visible);
}

void Render::IccConvert(void *data, LONG xcnt, LONG components, Bool inverse)
{
	C4DOS.Sh->VPIccConvert(this,data,xcnt,components,inverse);
}

VPBuffer *Render::GetBuffer(LONG id, LONG subid)
{
	return C4DOS.Sh->VPGetBuffer(this,id,subid);
}

BaseContainer Render::GetRenderData(void)
{
	BaseContainer bc;
	C4DOS.Sh->VPGetRenderData(this,&bc);
	return bc;
}

void Render::SetRenderData(const BaseContainer &ct)
{
	C4DOS.Sh->VPSetRenderData(this,&ct);
}

VolumeData *Render::GetInitialVolumeData(LONG cpu)
{
	return C4DOS.Sh->VPGetInitialVolumeData(this,cpu);
}

void *Render::GetPrivateData(void)
{
	return C4DOS.Sh->VPGetPrivateData(this);
}

Bool Render::SetRenderProperty(LONG id, const GeData &dat)
{
	return C4DOS.Sh->SetRenderProperty(this,id,dat);
}

RayObject *AllocRayObject(LONG tex_cnt)
{
	return C4DOS.Sh->AllocRayObject(tex_cnt,NULL);
}

void FreeRayObject(RayObject *&op)
{
	C4DOS.Sh->FreeRayObject(op);
	op=NULL;
}

RayLight *AllocRayLight(BaseDocument *doc, BaseObject *op)
{
	return C4DOS.Sh->AllocRayLight(doc,op);
}

void FreeRayLight(RayLight *&lgt)
{
	C4DOS.Sh->FreeRayLight(lgt);
	lgt=NULL;
}

Bool IlluminateRayLight(RayLight *rl, Vector *color, LVector *light_vector, const LVector &p, const LVector &n)
{
	return C4DOS.Sh->Illuminate(NULL,rl,color,light_vector,p,n,n,n,0.0,ILLUMINATEFLAGS_0,RayHitID(),RAYBIT_0,FALSE,NULL);
}

void CalcRestrictionInc(ObjectRestriction *lr, RayObject *op, Bool &nodif, Bool &nospec)
{
	if (!op || !op->link || op->restriction_index>=lr->object_cnt) return;
	if (lr->object[op->restriction_index]&LIGHTRESTRICTION_NODIFFUSE) nodif=TRUE;
	if (lr->object[op->restriction_index]&LIGHTRESTRICTION_NOSPECULAR) nospec=TRUE;
}

BAKE_TEX_ERR BakeTexture(BaseDocument* doc, const BaseContainer &data, BaseBitmap *bmp, BaseThread* th, BakeProgressHook* hook, BakeProgressInfo* info)
{
	return C4DOS.Sh->BakeTexture(doc, data, bmp, th, hook, info);
}

BaseDocument* InitBakeTexture(BaseDocument* doc, TextureTag* textag, UVWTag* texuvw, UVWTag* destuvw, const BaseContainer &bc, BAKE_TEX_ERR* err, BaseThread* th)
{
  return C4DOS.Sh->InitBakeTexture(doc, textag, texuvw, destuvw, bc, err, th);
}

BaseDocument* InitBakeTexture(BaseDocument* doc, TextureTag** textags, UVWTag** texuvws, UVWTag** destuvws, LONG cnt, const BaseContainer &bc, BAKE_TEX_ERR* err, BaseThread* th)
{
  return C4DOS.Sh->InitBakeTextureA(doc, textags, texuvws, destuvws, cnt, bc, err, th);
}

GeCipher256::GeCipher256()
{
	hnd = NULL;
}

GeCipher256::~GeCipher256()
{
	if (hnd)
		Close();
}

Bool GeCipher256::Open(const void *key, LONG klength, Bool stream)
{
	if (hnd)
		Close();
	hnd = C4DOS.Ge->GeCipher256Open((const UCHAR*)key, klength, stream);
	return hnd != NULL;
}

void GeCipher256::Close()
{
	if (hnd)
	{
		C4DOS.Ge->GeCipher256Close(hnd);
		hnd=NULL;
	}
}

void GeCipher256::Encrypt(void *mem, LONG bytes)
{
	if (hnd)
		C4DOS.Ge->GeCipher256Encrypt(hnd, (UCHAR*)mem, bytes);
}

void GeCipher256::Decrypt(void *mem, LONG bytes)
{
	if (hnd)
		C4DOS.Ge->GeCipher256Decrypt(hnd, (UCHAR*)mem, bytes);
}

LONG InitRenderStruct::GetThreadCount() const
{
	return vd?vd->GetCPUCount():1;
}

void InitRenderStruct::Init(BaseDocument *t_doc)
{
	version=GetC4DVersion();
	doc=t_doc;
	errorlist=NULL;
	matname=NULL;
	vd=NULL;
	thread=NULL;
	flags=INITRENDERFLAG_TEXTURES;
	linear_workflow=FALSE;
	document_colorprofile=DOCUMENT_COLORPROFILE_SRGB;

	if (t_doc)
	{
		docpath=t_doc->GetDocumentPath();
		fps=t_doc->GetFps();
		time=t_doc->GetTime();

		BaseContainer *bc = t_doc->GetDataInstance();
		if (bc)
		{
			linear_workflow=bc->GetBool(DOCUMENT_LINEARWORKFLOW);
			document_colorprofile=bc->GetLong(DOCUMENT_COLORPROFILE);
		}
	}
	else
		fps=30;
}
#endif
