/**************************************************************************
                  frond.c is public domain software
**************************************************************************/

#include <dore/dore.h>
#include <math.h>


/* prototype declarations */
int segment_callback  (void);
int makeobjects  (void);
DtObject make_camera_group  (void);
int run_application  (DtObject);


int depth, go=0;
DtReal a, b, c;
DtObject ingrp, segment;


int segment_callback (void)
{
	if(depth-- && go) {
		DsExecuteObj(DoRotate(DcXAxis, a));
		DsExecuteObj(DoRotate(DcYAxis, b));
		DsExecuteObj(DoRotate(DcZAxis, c));
		DsExecuteObj(segment);
	}
}


int makeobjects (void)
{
	static DtReal sds[1]; /* sub division spec */
	static DtColorRGB cyan = {0.0, 1.0, 1.0};
	extern DtObject make_camera_group();

	sds[0] = .05;
	segment = DoGroup(DcTrue);
		DgAddObj(DoDiffuseColor(DcRGB, cyan));
		DgAddObj(DoScale(.9,.9,.9));
		DgAddObj(DoTranslate(0.,0.,-1.));
		DgAddObj(DoPushMatrix());
			DgAddObj(DoScale(.5,.5,1.));
			DgAddObj(DoPrimSurf(DcCylinder));
		DgAddObj(DoPopMatrix());
		DgAddObj(DoCallback(segment_callback, DcNullPtr));
	DgClose();

	DoGroup(DcTrue);
		DgAddObj(DoSubDivSpec(DcSubDivRelative, sds));
		DgAddObj(DoRepType(DcSurface));
		DgAddObj(DoInterpType(DcVertexShade));
		DgAddObj(DoTranslate(0.,-3.,0.));
		DgAddObj(DoRotate(DcXAxis, (1.57)));
		DgAddObj(segment);
	DsSetObjNameString(DgClose(), "objectgroup", DcFalse);

	DsSetObjNameString(make_camera_group(), "cameragroup",DcFalse);

	return 0;
}





DtObject make_camera_group (void)
{
	static DtPoint3
		origin = {0.,0.,0.},
		camera_from = {0.,0.,10.}, /* positive Z  */
		light0 = {0.,-8.,-2.},
		light1 = {8.,8.,8.};
	static DtVector3 up = {0.,1.,0.};

	DsSetObjNameString(DoGroup(DcTrue), "cameragroup", DcFalse);
		DgAddObj(DoPerspective(60.,-1.,-20.));  
		DgAddObj(DoPushMatrix());
			DgAddObj(DoLookAtFrom(origin, camera_from, up));
			DgAddObj(DoCamera());
		DgAddObj(DoPopMatrix());
		DgAddObj(DoPushMatrix());
			DgAddObj(DoLookAtFrom(origin, light0, up));
			DgAddObj(DoLightIntens(.7));
			DgAddObj(DoLight());
		DgAddObj(DoPopMatrix());
		DgAddObj(DoPushMatrix());
			DgAddObj(DoLookAtFrom(origin, light1, up));
			DgAddObj(DoLightIntens(.9));
			DgAddObj(DoLight());
		DgAddObj(DoPopMatrix());
	return(DgClose());
}



int run_application (DtObject view)
{
	int time=200;

	DvUpdate(view);
	DvSetUpdateType(view, DcUpdateDisplay);
	go = 1;
	while(time--) {
		depth = 12;

		a= 0.3 * sin(0.200000 * time);
		b= 0.5 * sin(0.221234 * time);
		c= 0.7 * sin(0.244098 * time);

		DvUpdate(view);
	}
	printf("Hit return to exit.\n");
        getchar();
}



int main (
    int argc,
    char *argv[])
{
	DtObject device, frame, view, camera_group, object_group;
	DtVolume volume;

	DsInitialize(0);

	/* Application specific call which creates camera and display groups */
	makeobjects();

	if (!(view = DoView())) {
		printf("can't create view\n");
		exit(1);
	}

	/* find camera and display groups built in makeobjects() */
	camera_group = DsInqObjViaString("cameragroup",DcTypeGroup);
	object_group = DsInqObjViaString("objectgroup",DcTypeGroup);

	if((camera_group == DcNullObject) || (object_group == DcNullObject)) {
		printf("can't find camera or object group\n");
		exit(1);
	}

	DgAddObjToGroup(DvInqDisplayGroup(view), object_group);

	DgAddObjToGroup(DvInqDefinitionGroup(view), camera_group);


	/* Uncomment the following line to use the previewer. */
	/* The previewer is a useful debugging utility.      */
	/* view_preview(view, 0, DcNullPtr); */

	device = DoDevice("stdx11", "-visualtype DcTrueColor -zbuffer -geometry 640x512");

	if( ! device) {
		printf("can't create device\n");
		exit(1);
	}

	DdInqExtent(device,&volume);

	if (!(frame = DoFrame())) {
		printf("can't create frame\n");
		exit(1);
	}

	DdSetFrame(device,frame);

	DfSetBoundary(frame,&volume);

	DgAddObjToGroup(DfInqViewGroup(frame), view);

	DvSetBoundary(view,&volume);

	/* Application specific call which does dynamic updates */
	run_application(view);

	printf("Goodbye!\n");

	DsReleaseObj(device);

	DsTerminate();
}




