///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Sha256Finalise
//
//  Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After
//  calling this, Sha256Initialised must be used to reuse the context.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
    Sha256Finalise
    (
        Sha256Context*          Context,
        SHA256_HASH*            Digest
    )
{
    int i;

    if( Context->curlen >= sizeof(Context->buf) )
    {
       return;
    }

    // Increase the length of the message
    Context->length += Context->curlen * 8;

    // Append the '1' bit
    Context->buf[Context->curlen++] = (uint8_t)0x80;

    // if the length is currently above 56 bytes we append zeros
    // then compress.  Then we can fall back to padding zeros and length
    // encoding like normal.
    if( Context->curlen > 56 )
    {
        while( Context->curlen < 64 )
        {
            Context->buf[Context->curlen++] = (uint8_t)0;
        }
        TransformFunction(Context, Context->buf);
        Context->curlen = 0;
    }

    // Pad up to 56 bytes of zeroes
    while( Context->curlen < 56 )
    {
        Context->buf[Context->curlen++] = (uint8_t)0;
    }

    // Store length
    STORE64H( Context->length, Context->buf+56 );
    TransformFunction( Context, Context->buf );

    // Copy output
    for( i=0; i<8; i++ )
    {
        STORE32H( Context->state[i], Digest->bytes+(4*i) );
    }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Sha256Update
//
//  Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
//  calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Update
    (
        Sha256Context*      Context,
        void*               Buffer,
        uint32_t            BufferSize
    )
{
    uint32_t    n
        ;
    if( Context->curlen > sizeof(Context->buf) )
    {
       return;
    }

    while( BufferSize > 0 )
    {
        if( Context->curlen == 0 && BufferSize >= BLOCK_SIZE )
        {
           TransformFunction( Context, (uint8_t*)Buffer );
           Context->length += BLOCK_SIZE * 8;
           Buffer = (uint8_t*)Buffer + BLOCK_SIZE;
           BufferSize -= BLOCK_SIZE;
        }
        else
        {
           n = MIN( BufferSize, (BLOCK_SIZE - Context->curlen) );
           memcpy( Context->buf + Context->curlen, Buffer, (size_t)n );
           Context->curlen += n;
           Buffer = (uint8_t*)Buffer + n;
           BufferSize -= n;
           if( Context->curlen == BLOCK_SIZE )
           {
              TransformFunction( Context, Context->buf );
              Context->length += 8*BLOCK_SIZE;
              Context->curlen = 0;
           }
       }
    }
}
void myApp02::init() {

	globalAmbient = Col3f(1, .1, .1);
	shadowsOn();
	// wall
	plane = GroundPlane(Vec3(), Vec3(), Dim2f(8, 7), Col4f(1, 1, 0, 1), 1, 1, "orange.jpg");
	//Plane.textureOn();
	plane.setBumpMap("white_tile.jpg");
	plane.setTextureScale(Vec2f(.5));
	//Plane.setAmbientMaterial(Col4f(.02, .02, .02, 1.0));
	plane.setSpecularMaterial(Col4f(.1, .1, .1, 1.0));
	plane.setShininess(100);


	//tube = ProtoTube();

	float radius = .107;
	Vec3f v(0, 0, 0);

	int segments = 10; // 60;
	v = Vec3f(0, 0, 0);
	Vec3f spd(0, 0, 0);

	//cps.push_back(v);
	float turbulence = .1f;
	Dim3f size(4.25, 4.25, 4.25);


	float startY = -.5;

	int ribCount = 3;// 17;
	float ribSpan = 4.5;
	float ribRadius = 0;
	float ribRadiusMax = 2.0;
	float ribTheta = 0;

	float ribGap = ribSpan / ribCount;

	for (int i = 0; i < ribCount; ++i){

		float theta = 0, weaveTheta = 0;
		std::vector <Vec3> cps;
		Spline3 spline;
		ribRadius = fabs(sin(ribTheta) * ribRadiusMax);
		for (int j = 0; j < segments; ++j){
			//spd = Vec3(random(-turbulence*.1, turbulence*.1), 0, random(-turbulence*.1, turbulence*.1));
			//v = spd + Vec3f(sin(theta)*2+random(-turbulence, turbulence), startY+=.1, cos(theta)*2+random(-turbulence, turbulence));
			//cps.push_back(Vec3(v.x, v.y, v.z));
			cps.push_back(Vec3(sin(theta) * ribRadius, -ribSpan / 2 + ribGap*i + sin(weaveTheta) * .15, cos(theta) * ribRadius));
			theta += TWO_PI / segments;
			//weaveTheta += j*j*j*.125 * PI / 180;
			weaveTheta += TWO_PI / segments * (ribRadius * 4);
		}
		//trace("ribradius = ", ribRadius*4);
		ribTheta += PI / ribCount;

		//spline = Spline3(cps, 4, false, .5);
		spline = Spline3(cps, 5, false, .5);

		TransformFunction t1 = TransformFunction(TransformFunction::SINUSOIDAL, Tup2f(.02, .95 + (ribRadius*random(.07, .31))), 1/*int(random(1, 3))*/);

		ribs.push_back(ProtoTube(Vec3f(), Vec3f(), Dim3f(1), Col4f(1), spline, .09, 12, t1, true, "pitted.jpg", Vec2f(1, random(.0825, .2))));
		ribs.at(i).setIsClosed(0);
		ribs.at(i).setSpecularMaterial(Col4f(.4, .275, .1, 1));
		ribs.at(i).setShininess(6);
		ribs.at(i).setBumpMap("pitted.jpg");

		// rib tendrils
		std::vector <Vec3> ribCps;
		for (int j = 0; j < ribs.at(i).getFrenetFrameLength(); j += int(random(1, 3))){
			for (int k = 0; k < ribs.at(i).getCrossSectionDetail(); k += int(random(1, 3))){
				ribCps.push_back(ribs.at(i).getVertices().at(j*ribs.at(i).getCrossSectionDetail() + k).pos);
			}
		}

		Spline3 ribSpline = Spline3(ribCps, 2, false, .5);
		TransformFunction ribT = TransformFunction(TransformFunction::SINUSOIDAL, Tup2f(random(.05, .2), random(..3, .5)), int(random(5, 12)));
		ribBands.push_back(ProtoTube(Vec3f(), Vec3f(), Dim3f(1), Col4f(1), ribSpline, .09, 12, ribT, true, "vascular.jpg", Vec2f(1, random(.0825, 1))));
		ribBands.at(i).setIsClosed(0);
		ribBands.at(i).setSpecularMaterial(Col4f(.8, .275, .1, 1));
		ribBands.at(i).setShininess(5);
		ribBands.at(i).setBumpMap("vascular.jpg");
	}

	
	//yRot = xRot = 0;
	//xRotLast = yRotLast = 0;
	//mouseXIn = mouseYIn = 0;

}
void ProtoRootBall02::init() {

	//170, 150
	// set Materials for composite objects - or setup as multiple inheritance/interface
	rootBallCore = RootBall(Vec3f(), Vec3f(), Dim3f(2.55f), Col4f(.9f), 1, 30, .2, Tup2f(.5, 2.25), "shipPlate_yellow.jpg", 8);
	TransformFunction t1 = TransformFunction(TransformFunction::SINUSOIDAL, Tup2f(.2f, .75f), 3); // local, so can't be sent as reference
	rootBallCore.setTransformFunction(t1);


	//rootBall = RootBall(Vec3f(), Vec3f(), Dim3f(1.345f), Col4f(.9f), 1, 40, .2, Tup2f(.2, 3), "vascular3.jpg", 1);
	TransformFunction t2 = TransformFunction(TransformFunction::SINUSOIDAL, Tup2f(.14f, .22f), 80); // local, so can't be sent as reference
	//rootBall.setTransformFunction(t2);
	//std::vector<Tup4v> vs = rootBall.getGeomData();

	// export geometry data to 
	//std::vector<Tup4v> vs;
	//std::vector<Tup4v> temp = rootBallCore.getGeomData();
	//vs.insert(vs.end(), temp.begin(), temp.end());
	//std::vector<Tup4v> temp2 = rootBall.getGeomData();
	//vs.insert(vs.end(), temp2.begin(), temp2.end());
	//export(vs, STL);

	// wall
	plane = GroundPlane(Vec3(), Vec3(), Dim2f(8, 7), Col4f(1, 1, 1, 1), 1, 1, "leather2.jpg");
	//plane.textureOn();
	plane.setBumpMap("leather2.jpg");
	//plane.loadBumpMapTexture("shipPlate_normal.jpg");
	plane.setTextureScale(Vec2f(.5));
	//plane.setAmbientMaterial(Col4f(.02, .02, .02, 1.0));
	plane.setSpecularMaterial(Col4f(1, .9, 1, 1.0));
	plane.setShininess(4);
	//trace("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS =", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);

	// ground
	ground = GroundPlane(Vec3(), Vec3(), Dim2f(8, 7), Col4f(1, 1, 1, 1), 1, 1, "pink2.jpg");
	//plane.textureOn();
	ground.setBumpMap("pink2.jpg");
	//plane.loadBumpMapTexture("shipPlate_normal.jpg");
	ground.setTextureScale(Vec2f(.25));
	//plane.setAmbientMaterial(Col4f(.02, .02, .02, 1.0));
	ground.setSpecularMaterial(Col4f(1, 1, 1, 1.0));
	ground.setShininess(3);
	//trace("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS =", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);


	std::string texs[] = { "pebbles.jpg", "gold_foil2.jpg", "vascular.jpg", "greenCrocSkin.jpg", "pink2.jpg", "metal_screwHeads.jpg", "woodPlank.jpg", "metal_blue.jpg", "shipPlate_yellow.jpg", "reptile2_invert.jpg", "corroded_metal.jpg", "giraffe.jpg", "shipPlate.jpg", "metal_grate.jpg" };

	for (int i = 0; i < W*H*D; ++i){
		int sub = int(random(14));
		toroids[i] = Toroid(Vec3f(), Vec3f(random(45), random(45), random(45)), Dim3f(3, 3, 3), Col4f(.5, .5, .5, 1), 12, 12, 3, 1.2, texs[sub]);
		toroids[i].setBumpMap(texs[sub]);
		//toroids[i].setBumpMap("grime.jpg");
		toroids[i].setDiffuseMaterial(Col4f(.65, .75, 1, 1.0));
		toroids[i].setSpecularMaterial(Col4f(1, 1, 1, 1.0));
		toroids[i].setTextureScale(Vec2f(random(.25, 8.5)));
		toroids[i].setShininess(int(random(15, 40)));
	}



}