All pastes #19734 Raw Edit

Stuff

public text v1 · immutable
#19734 ·published 2005-08-10 17:55 UTC
rendered paste body
/* Revised the code since Attention_test_3.cpp

 * 2 slabs appear on the groun floor in constant positions, and 4 objects that randomly change positions;

 * association with the bar has been removed. ISI was removed.

 *

 * GOALS: 1. remove the difference between OBJ_NUM_1 and OBJ_NUM_2 because we don't have 2 frames anymore;

 *		  2. figure out how to add the slabs in the drawPolygons() function and randomize them 

 *		  independent of the other objects.

 *		  3. Clean up code

 *		  4. Change orientation of "slabs" between horizontal and vertical

 *		  Q: what is bshow doing here? how do the frame 2 objects disappear? (update: solved, 8/8/2005)

 */



//#include "stdafx.h"

#include <iostream>

#include <string>

#include <fstream>

#include <windows.h>  //comment for os x compiling
#include <stdio.h>

#include <stdlib.h> 

#include <string.h>

#include <time.h>

#include <math.h>       /* for cos(), sin(), and sqrt() */

#include <gl/glut.h>    /* OpenGL Utility Toolkit header */

//#include <GLUT/glut.h>  //use this for os x compiling
#include <mmsystem.h>  //comment for os x compiling

#include <assert.h>

#include <vector>



using namespace std;



#define FRAMELENGTH 750 // presentation duration of frame 1 & 2; should be 750



char subjStr[100];							//character input for subject name

char checkImage1[100][100][3];				//i don't know what this is but used to be char checkImage1[576][576][3];

FILE * infile;

FILE * outfile;

char infilename[40];

char outfilename[40];


//int abs(float num){return abs((int)num);}   //uncomment for os x compiling


//maximum number of objects in the scene for this program

const unsigned OBJECT_NUM_1 = 4;					//# of objects in Frame 1, used for array numOfObjects[0]

const unsigned OBJECT_NUM_2 = 4;					//# of objects in Frame 2, used for array numOfObjects[2]

const unsigned MAX_OBJECT_NUM = OBJECT_NUM_1;		//maximum limit to number of objects

const unsigned TEXTURE = 0; //0=.002, 1=.003, 2=.004, 3=.005

// 8 x 1 x 1 x 1 x 1 x 1 

// (heading, numOfObjects, RandomizedPostion, isi, bar, nearwide, leftright, contrast)

const unsigned CONDITIONS = 8; 

const unsigned REPETITION = 1;											//# of times each trial is repeated

const unsigned OBJ_RANDOM_NUM = 1;										//# of times all trials are repeated

const unsigned TOTALTRIALS = CONDITIONS * REPETITION * OBJ_RANDOM_NUM;	//TOTAL number of trials in the run

const unsigned REPEAT = 10;												//add this because of new floor without texture



const int SCENE_LEFT_BDR = -50;				//defines borders of screen

const int SCENE_RIGHT_BDR = 50;

const int SCENE_NEAR_BDR = -30;

const int SCENE_FAR_BDR = -273;

const int FIXED_OBJ_POS = 0;

const int RAND_SWITCH_OBJ_POS = 1;

const int RAND_MV_OBJ_KEEP_REL = 2;

const int RAND_MV_OBJ_NOKEEP_REL = 3;



const float L_MARGIN = 5;					//defines margin (of screen? or for objects? probably screen)

const float R_MARGIN = 5; 

const float U_MARGIN = 5;

const float D_MARGIN = 5;

const float  VISUAL_ANGLE = 20.0;			//i think this is the angle which the objs occupy, if too large, objs will disappear

const double M_PI = 3.14159265;				//pi value, comment for os x compiling



float XX,ZZ;

float mv_distance = 24.0;

float disp = 0;

float circlex[500];		//I need to figure out why these circles are not being drawn; these are supposed to be on the ground floor

float circlez[500];



int posMatrix[300][300];

int objorder[MAX_OBJECT_NUM];

int objPlacOrder[MAX_OBJECT_NUM];		

int	order[TOTALTRIALS];					//for ordering the total number of trials each time the exe. is ran

int correct = 0;

int frame = 0;

int phase = 0; //there are four phases to each trial:  frame1, blank, frame2, blank.

int ticks1, ticks0; /*clock_t*/

int moving, startx, starty;

int lightStartX, lightStartY;

int blank = 0;

//int duration = 3000; //increase time of frame presentation //1000

int resp = 0;

int resp_lock = 1; //when 1, no [4|6] responses will be accepted

int ntrials;	//number of trials in the block

int trial=0;	//initialize trial to 0



short ord_change_num, rel_to_eye_change_num;



unsigned windW = 1280, windH = 1024;		//window width and height



/* Variable controlling various rendering modes. */

int stencilReflection = 0, stencilShadow = 1, offsetShadow = 1;

int renderShadow = 1, renderPolygons = 1;

int linearFiltering = 0, useMipmaps = 1, useTexture = 1;

int reportSpeed = 0;

GLboolean lightSwitch = GL_TRUE;

int directionalLight = 1;

int forceExtension = 0;

/* Time varying or user-controled variables. */

float lightAngle = -12.0, lightHeight = 25;

GLfloat angle = 0;						//-150;	/* in degrees */ /*angle and angle2 for drawing the bar?*/

GLfloat angle2 = 0;						//30;   /* in degrees */



typedef struct {

/*  int   kind;							//looks like we're not using these variables at the moment

 *	float rot;

 *	float scale; */			

	float x[2];							//0 is frame 1, 1 is frame 2

	float z[2];

} objtype;



objtype obj[TOTALTRIALS][MAX_OBJECT_NUM];	/*for every object in frame 1 and for all the trials in the exp,

											 *specify the x and z positions of the objects on the plane */



/*build structure of type Condition with all these variables*/

typedef struct _condition {

	//float bar_angle;

	float abs_heading;	//4 heading angles

	float rel_heading;	//4 heading angles

	//float isi; //2 isi conditions

	int   contrast; //1 level of contrast, 180

	int   obj_num[2]; // number of objects in the first and second frames

	bool  bshow[MAX_OBJECT_NUM];//for every object, should we show it or not

	int   objRandom;

} Condition;



//32 conditions total, 2 repetitions for each condition

Condition trialConditions[TOTALTRIALS];	//creates an array (for all trials) containing the elements defined in structure "conditions"

Condition  trial_cond;						//trial_cond has all the vars. inside the structure Condition



enum {

	MISSING, EXTENSION, ONE_DOT_ONE

};

int polygonOffsetVersion;



GLfloat lightPosition[4];

GLfloat lightColor[] = {1.0, 1.0, 1.0, 1.0};



/* FUNCTION PROTOTYPES BEGIN!! */



void zeroMatrix();						/* initializes all params of posMatrix[][] to 0 */

void readTrialParams();

void MakeRandomPlacOrder(int, int);		/* Shuffle objects... but i don't know how */

void makeSubFile();

void GenerateConditions();

void MakeTrialOrderRandom(int, int);

int checkAroundMatrix(int, int);

int checkMatrix(float, float);

void setPosMatrix(float, float, int);

float RandomPosX();

float RandomPosZ();

float RandomPosXZ(float, float, float);

unsigned randMVObject(float);

void SortOrder(vector<float> & tan_v, vector<short> & order);

bool IsRelToEyeChange(objtype);

bool IsObjectOutOfView(objtype);

bool IsOrdRelChange(objtype);

void SetInitialObjPos(int, float);

void SetObjectPos(unsigned, int, objtype);

void setParams();

void makeCheckImage();

void makeFloorTexture();

void shadowMatrix(GLfloat, GLfloat, GLfloat);

void findPlane(GLfloat, GLfloat, GLfloat, GLfloat);

void drawPolygons(bool);

void drawBlankScreen();

void drawFloor();

void MoveEye(double, float);

void redraw();

void motion(int, int);

void idle();

void controlLights(int);

void visible(int);

void key(unsigned char, int, int);

int supportsOneDotOne();





/* FUNCTION DEFINITIONS BEGIN!! */



/* *INDENT-ON* */



void zeroMatrix()			/* initializes all params of posMatrix[][] to 0 */

{ 

  int i,k;

  for (i=0; i<101; ++i)

	for (k=0; k<201; ++k) 

	  posMatrix[i][k] = 0;

}



void readTrialParams(void)

{

  ntrials = TOTALTRIALS;

  printf("ntrials = %i\n", ntrials); 



  //trial_cond.bar_angle = trialConditions[order[trial]].bar_angle;

  trial_cond.rel_heading = trialConditions[order[trial]].abs_heading;

  //trial_cond.abs_heading = trial_cond.rel_heading + trialConditions[order[trial]].bar_angle;

  //trial_cond.isi = trialConditions[order[trial]].isi;

  trial_cond.contrast = trialConditions[order[trial]].contrast;

  trial_cond.obj_num[0] = trialConditions[order[trial]].obj_num[0];		//# of objs in Frame 1(?)

  trial_cond.obj_num[1] = trialConditions[order[trial]].obj_num[1];		//# of objs in Frame 2(?)

  trial_cond.objRandom = trialConditions[order[trial]].objRandom;



  unsigned i, obj_num = trial_cond.obj_num[0];

  for (i=0; i<obj_num; ++i) 

	trial_cond.bshow[i] = trialConditions[order[trial]].bshow[i];

}



void MakeRandomPlacOrder(int object_num, int obj_place_ord[])

{

  int i, j;

  int rep, temp;



  for(i=0; i<object_num; ++i){		//how does the loop know how many times to loop if we don't know value of Object_num?

	obj_place_ord[i] = i;

  }

  //checks for objects being in initial position after shuffle

  //can reduce rep without changing outcome to save time

  for(rep=0; rep<10; ++rep) {

	for(i=0; i<object_num; ++i) {
	  j = rand() % object_num; //use line below if shuffles don't seem sufficiently random
	  //j = (int)((float)rand()/(float)(RAND_MAX+1) * object_num);

	  temp = obj_place_ord[j]; 

	  obj_place_ord[j] = obj_place_ord[i];

	  obj_place_ord[i] = temp;

	}

  }			

}





void makeSubFile(void)

{

  char temp[100],base[100];

  int again;



  do {

	printf("Enter participant name:");

	gets(subjStr);

//	strcpy(base, subjStr);



//	if (RANDOMIZE_OBJECT_POS==FIXED_OBJ_POS) 

  	  sprintf(base,"data\\f_");

//	else if (RANDOMIZE_OBJECT_POS==RAND_SWITCH_OBJ_POS)

//  	  sprintf(base,"data\\o_");

//	else if (RANDOMIZE_OBJECT_POS==RAND_MV_OBJ_KEEP_REL)

//  	  sprintf(base,"data\\m_");

//	else if (RANDOMIZE_OBJECT_POS==RAND_MV_OBJ_NOKEEP_REL)

//  	  sprintf(base,"data\\b_");

//	else

//	  assert(0);



	strcat(base, subjStr);



//	if (trialConditions[order[trial]].isi==50)	/*took this out because we don't have an ISI option anymore */

  	  strcat(base, "A");

//	else

//  	  strcat(base, "B");



	printf("Enter run number (1 or 2):");

	gets(temp);

	strcat(base, temp);



	strcpy(infilename,base);

	strcpy(outfilename,base);



	strcat(outfilename, ".txt");



	printf("%s\n", infilename); 

	printf("data\\M%d%s\n", TEXTURE, outfilename);



	outfile = fopen(outfilename, "r+");

	if(outfile == NULL) {

	  outfile = fopen(outfilename, "w+");

		if (outfile==NULL) {

			cout << "Error: open file " << outfilename << "fail\n"; exit(1);

		}

	  again = 0;

	}

	else {

	  printf("File already exists. Try again.");

	  again = 1;

	}

  } while(again);

}



/*generate conditions, fills the array for every level of the variable,

and randomize them in the experiment*/

//4 heading, 2 nearwide, 3 of c for contrast == removed ISI condition

void GenerateConditions() 

{

  int i = 0;

  int r, h, l, nobj, c; //heading, location, nearwide, contrast

  int reps;

  float heading[8] = {-23, -17, -11, -5, 5, 11, 17, 23}; //in degrees

  //float isiA[2] = {50, 1000}; //isi

  int contrastA[3] = {120, 180, 240};

  int numOfObjects[2] = {OBJECT_NUM_1, OBJECT_NUM_2}; //{3,6,12,24};

  int objectRandom[4] = {FIXED_OBJ_POS, RAND_SWITCH_OBJ_POS, RAND_MV_OBJ_KEEP_REL,    

		RAND_MV_OBJ_NOKEEP_REL};



  //assert(REPETITION % 2 == 0);	//took this out because we don't need an even number of conditions for bar angle

//  short bar_side[REPETITION];

//  float bar_angle = 8.0;



  for (r=0; r<OBJ_RANDOM_NUM; ++r)				//# times all trials repeated, according to earlier comment

    for(h = 0; h < 8; ++h)						//heading index

	  for(c = 0; c < 1; ++c)					//c goes from 0 to 0 (loop once) (contrast)

  	    for(l = 2; l < 3; ++l)					//l goes from 2 to 2 (loop once) (location)

	  	  for(nobj = 0; nobj < 1; ++nobj) {		//nobj goes from 0 to 0 (loop once) (nearwide)

//			for (j = 0; j < REPETITION; ++j)	//repetition index

//			  bar_side[j] = -1;

			/*for (j = 0; j < REPETITION / 2; ++j) {

			  do {

				idx = rand() % REPETITION;

				if (bar_side[idx]==-1) {

				  bar_side[idx] = 1; break;

				}

			  } while(true);

			}*/



			for(reps = 0; reps < REPETITION; ++reps) {

			  trialConditions[i].abs_heading = heading[h];

			  //trialConditions[i].isi = isiA[0];							

			  trialConditions[i].contrast = contrastA[1];

			  trialConditions[i].obj_num[0] = numOfObjects[0];

			  trialConditions[i].obj_num[1] = numOfObjects[1];

			  trialConditions[i].objRandom = objectRandom[r];

//			  trialConditions[i].bar_angle = bar_side[reps] * bar_angle;



			  unsigned ii, idx, obj_num_1 = numOfObjects[0], obj_num_2 = numOfObjects[1];

			  for (ii=0; ii<obj_num_1; ++ii)

			  {

				  trialConditions[i].bshow[ii] = true;	//makes all objects (obj_num_1) visible 

			  }

			  for (ii=0; ii<obj_num_1-obj_num_2; ++ii)	//loop as many times as the difference between the max and min # of objects

			  { 

				while(true){								//do this forever until the break

  				  idx = rand() % obj_num_1;					//picks number from 0 to a value==obj_num_1

				  if (trialConditions[i].bshow[idx]==true)	//assign bshow[] true and break out of the while loop

					  break;

				}

				trialConditions[i].bshow[idx] = false;		//assign bshow[] false value

			  }												//go back up to for loop

			  ++i;

			}

		  }



  printf("\n\nTOTALTRIALS:%d  i:%d \n\n",TOTALTRIALS,i);

}





void MakeTrialOrderRandom(int trial_num, int trial_ord[])

{

  int i, j, k;

  int temp;



/*  for(i = 0; i < trial_num; ++i) {	//creates a list of numbers from 0 to (number of trials)-1

*	 trial_ord[i] = i;

*  }

*

*  for(k = 0; k < 1000; ++k)			//shuffles list of indices (created above) to the trials

*	for(i = 0; i < trial_num; ++i) {
*	  j = rand() % trial_num;  //use line below if trials don't seem sufficiently shuffled

*	  //j = (int)((float)rand()/(float)(RAND_MAX+1) * trial_num);		//pick a random number for j from 0 to (trial_num-1)

*	  temp = trial_ord[j];				//these three operations swap trial_ord[j] and trial_ord[i]

*	  trial_ord[j] = trial_ord[i]; 

*	  trial_ord[i] = temp;

*	}

*/

    for(i = 0; i < trial_num; ++i)
    {
        trial_ord[i]=-1;
    }

    for(i = 0; i < trial_num; ++i)
    {
        do
        {
            j = rand() % trial_num;
        } while(trial_ord[j] != -1);

        trial_ord[j]=i;
    }



  //prints out conditions for each level, showing that they're shuffled

  for(i = 0; i < trial_num; ++i) {	

    cout << " trial: " << i << " " << order[i];

	cout << " heading: " << trialConditions[trial_ord[i]].abs_heading;

//    cout << " isi: " << trialConditions[trial_ord[i]].isi;

	cout << " obj: (" << trialConditions[trial_ord[i]].obj_num[0];

	cout << ", " << trialConditions[trial_ord[i]].obj_num[1] << ") ";

    cout << " random:" << trialConditions[trial_ord[i]].objRandom;

    cout << " " << TEXTURE << endl;

  }

}



const unsigned STEPX = 7;	// 10 size of the matrix, X steps

const unsigned STEPZ = 15;  // 20 size of the matrix, Z steps



int checkAroundMatrix(int rX, int rZ)

{   

  int i, j;

  int check=0;

  // increase sp value to increase spacing allowed 

  // (how close objects can be to each other)

  int sp = 2; 



  for (j=rZ-sp; j<=rZ+sp; ++j)

	for (i=rX-sp; i<=rX+sp; ++i) 

	  if ((i>=0) && (j>=0))

		check = posMatrix[i][j] || check;



  return(check);

}





int checkMatrix(float X, float Z)

{

  int rX, rZ;



  rX = (X+50) / STEPX; 

  rZ = abs(Z / STEPZ);

	//printf("rx %d  rZ %d \n",rX,rZ);

  if ( checkAroundMatrix(rX,rZ) ) { // if position already taken, return NO GOOD 

	 return(0);

  }



  posMatrix[rX][rZ] = 1;   // else set the position as taken, and return GOOD

  return 1;

}



void setPosMatrix(float x, float z, int value)

{

  int rX, rZ;

  rX = (x+50) / STEPX; 

  rZ = abs(z / STEPZ);

  posMatrix[rX][rZ] = value;

}





float RandomPosX () 

{  

  // size of the visiable world is X: -50, 50

  unsigned width = abs(SCENE_RIGHT_BDR - SCENE_LEFT_BDR - L_MARGIN - R_MARGIN);

  return (((float)rand() / (float)(RAND_MAX+1) * width) + SCENE_LEFT_BDR + L_MARGIN);  

}





float RandomPosZ()

{

  // size of the visiable world in Z = -30 to -200

  unsigned length = abs(SCENE_NEAR_BDR - SCENE_FAR_BDR - U_MARGIN - D_MARGIN);

  return (((float)rand() / (float)(RAND_MAX + 1) * length) + SCENE_FAR_BDR + U_MARGIN); 

}





float RandomPosXZ(float *XX, float *ZZ, float dis_x) 

{

  float dis_xl_thr = dis_x + L_MARGIN + 10;

  float dis_xr_thr = dis_x + R_MARGIN + 10;



  unsigned it = 0;

  do {

	for (;;) {

	  *XX = RandomPosX();

	  if (*XX < 0 && fabs(*XX) > dis_xl_thr || *XX > 0 && *XX > dis_xr_thr) break;

	}

	*ZZ = RandomPosZ();

	// 40 degrees total, 20 degrees from the center, give 5 deg to be sure

	if (abs(*XX / *ZZ) < tan(VISUAL_ANGLE / 180.0 * M_PI) ) {  

  	  if (checkMatrix(*XX, *ZZ) ) {  

		//	printf("%3.2f  %3.2f \n",*XX,*ZZ);

		return 1;

	  }

	}



	++it;

  } while (it < 100);



  return 0;

}





unsigned randMVObject(float radius)

{

  zeroMatrix();

  unsigned i, move_num, old_move_num = 0;

  unsigned try_no, try2_no, try3_no, try4_no, try_thr = 100;

  double direction;

  unsigned num_object = trial_cond.obj_num[0];

  vector<short> move(num_object);



  unsigned trial_no = order[trial];



  for (i=0; i<unsigned(num_object); ++i) {

  	setPosMatrix(obj[trial_no][i].x[0], obj[trial_no][i].z[0], 1);	//

	move[i] = 0;

  }



  move_num = try2_no = try3_no = try4_no = 0;

  do {

    for (i=0; i<unsigned(num_object); ++i) {

	  if (move[i]) continue;



	  setPosMatrix(obj[trial_no][i].x[0], obj[trial_no][i].z[0], 0);  

	  try_no = 0;



	  do {

//		unsigned deg = rand() % 360;

	  	unsigned deg = (rand() % 2) * 180;

		direction = deg * M_PI / 180.0;



		float x_dis = float(radius * cos(direction));

		float z_dis = float(radius * sin(direction));

		float xn, zn;

		float x = obj[trial_no][i].x[0], z = obj[trial_no][i].z[0];

		xn = x + x_dis; zn = z + z_dis;

	  

		++try_no;



		if (xn < SCENE_LEFT_BDR + L_MARGIN || xn > SCENE_RIGHT_BDR - R_MARGIN ||

			zn < SCENE_FAR_BDR + U_MARGIN || zn > SCENE_NEAR_BDR - D_MARGIN)

		  continue;



		if (checkMatrix(xn, zn)) {

		  obj[trial_no][i].x[1] = xn; obj[trial_no][i].z[1] = zn;

		  ++move_num; 

		  move[i] = deg==0 ? 1 : -1; break;

		}



		if (try_no > try_thr) {

		  setPosMatrix(obj[trial_no][i].x[0], obj[trial_no][i].z[0], 1);  

		  break;

		}

	  } while(true);

	}



	if (move_num < unsigned(num_object)) {

	  if (old_move_num!=move_num) {

		old_move_num = move_num;

		try2_no = 0;

	  }

	  else {

		++try2_no;



		if (try2_no==10) {

		  if (++try3_no==10) return 0;



		  try2_no = move_num = old_move_num = 0;

		  zeroMatrix();

		  for (i=0; i<unsigned(num_object); ++i) {

			move[i] = 0;

			setPosMatrix(obj[trial_no][i].x[0], obj[trial_no][i].z[0], 1);

		  }

		}

	  }

	}

	else {

	  short sum = 0;

	  for (i=0; i<unsigned(num_object); ++i) sum += move[i];

		if (sum==-3 || sum==3) { // move along the same direction

		if (++try4_no==10) return 0;



		try2_no = move_num = old_move_num = 0; // I don't set try3_no = 0

		zeroMatrix();

		for (i=0; i<unsigned(num_object); ++i) {

		  move[i] = 0;

		  setPosMatrix(obj[trial_no][i].x[0], obj[trial_no][i].z[0], 1);

		}

	  }

	}

//		if (move_num) break;

  } while (move_num < unsigned(num_object));



  return move_num;

}





void SortOrder(vector<float> & tan_v, vector<short> & order)

{

  float tan_tmp;

  short order_tmp;

  int num_object = trial_cond.obj_num[0];



  int i, j;

  for (i=0; i<num_object-1; ++i)

	for (j=i+1; j<num_object; ++j)

	  if (tan_v[i] > tan_v[j]) {

		tan_tmp = tan_v[i]; tan_v[i] = tan_v[j]; tan_v[j] = tan_tmp;

		order_tmp = order[i]; order[i] = order[j]; order[j] = order_tmp;

	  }

}





bool IsRelToEyeChange(objtype obj[])

{

  int num_object = trial_cond.obj_num[0];

  vector<short> order_bm(num_object), order_am(num_object);

  vector<float> tan_bm(num_object), tan_am(num_object);

  float eyex = mv_distance * sin(trial_cond.abs_heading * M_PI / 180);

  float eyez = 80.0 - mv_distance * cos(trial_cond.abs_heading * M_PI / 180);

  float x, z;

  int i;



  for (i=0; i<num_object; ++i) {

	order_bm[i] = i+1;

	x = obj[i].x[0]; z = 80.0 - obj[i].z[0]; tan_bm[i] = x / z; // z cannot be 0.

  }



  SortOrder(tan_bm, order_bm);



  for (i=0; i<num_object; ++i) {

	order_am[i] = i+1;

	x = obj[i].x[1] - eyex; z = eyez - obj[i].z[1]; 

	tan_am[i] = x / z; // z cannot be 0.

  }



  SortOrder(tan_am, order_am);



  rel_to_eye_change_num = 0;



  for (i=0; i<num_object; ++i)

	if (order_bm[i] != order_am[i]) 

	  rel_to_eye_change_num += 1;



  if (rel_to_eye_change_num) return true;

  return false;

}





bool IsObjectOutOfView(objtype obj[])

{

  float eyex = mv_distance * sin(trial_cond.abs_heading * M_PI / 180);

  float eyez = 80.0 - mv_distance * cos(trial_cond.abs_heading * M_PI / 180);

  float x, z;

  int num_object = trial_cond.obj_num[0];

  int i;



  for (i=0; i<num_object; ++i) {

	x = obj[i].x[1] - eyex; z = eyez - obj[i].z[1]; 

	if (x > 0) x += R_MARGIN;

	else if (x < 0) x -= L_MARGIN;

	if (abs(x / z) >= tan(VISUAL_ANGLE / 180.0 * M_PI))

	  return true;

  }



  return false;

}





bool IsOrdRelChange(objtype obj[])

{

  int num_object = trial_cond.obj_num[0];

  vector<vector<short> > x_order_bm(num_object), x_order_am(num_object);

  vector<vector<short> > z_order_bm(num_object), z_order_am(num_object);



  int i, j;

  for (i=0; i<num_object; ++i) {

	x_order_bm[i].resize(num_object);

	z_order_bm[i].resize(num_object);

	x_order_am[i].resize(num_object);

	z_order_am[i].resize(num_object);



	for (j=0; j<num_object; ++j) {

	  if (obj[i].x[0] < obj[j].x[0])

		x_order_bm[i][j] = -1;

	  else if (obj[i].x[0] > obj[j].x[0])

		x_order_bm[i][j] = 1;

	  else

		x_order_bm[i][j] = 0;



	  if (obj[i].x[1] < obj[j].x[1])

		x_order_am[i][j] = -1;

	  else if (obj[i].x[1] > obj[j].x[1])

		x_order_am[i][j] = 1;

	  else

		x_order_am[i][j] = 0;



	  if (obj[i].z[0] < obj[j].z[0])

		z_order_bm[i][j] = -1;

	  else if (obj[i].z[0] > obj[j].z[0])

		z_order_bm[i][j] = 1;

	  else

		z_order_bm[i][j] = 0;



	  if (obj[i].z[1] < obj[j].z[1])

		z_order_am[i][j] = -1;

	  else if (obj[i].z[1] > obj[j].z[1])

		z_order_am[i][j] = 1;

	  else

		z_order_am[i][j] = 0;

	}

  }



  vector<vector<short> > ord_rel(num_object);

  for (i=0; i<num_object; ++i) {

	ord_rel[i].resize(num_object);



	for (j=0; j<num_object; ++j) ord_rel[i][j] = 0;



	for (j=0; j<num_object; ++j) {

	  if (x_order_bm[i][j]!=x_order_am[i][j])

		ord_rel[i][j] = 1;

	  if (z_order_bm[i][j]!=z_order_am[i][j])

		ord_rel[i][j] = 1;

	}

  }



  short sum = 0;

  vector<short> rel(num_object);

  for (i=0; i<num_object; ++i) {

	rel[i] = 0;

	for (j=0; j<num_object; ++j) {

	  rel[i] += ord_rel[i][j];

	}

	sum += rel[i];

  }



  assert(sum % 2 == 0);

  ord_change_num = sum / 2;

  bool bret = false;

  if (sum) bret = true;

  return bret;

}





void SetInitialObjPos(int object_num, float obj_coord[MAX_OBJECT_NUM][2])

{

  int obj_no;

  bool bdone;

  float dis_x = mv_distance * fabs(sin(trial_cond.abs_heading * M_PI / 180));



  do {

	bdone = true;

    zeroMatrix();



    for(obj_no = 0; obj_no < object_num; ++obj_no) {

	  if (RandomPosXZ(&XX, &ZZ, dis_x)==0) {

		bdone = false; break;

	  }

	  

	  obj_coord[obj_no][0]=XX;

	  obj_coord[obj_no][1]=ZZ;

	}

  } while (!bdone);

/*

  cout << '\n';

  for(obj_no = 0; obj_no < num_object; ++obj_no) {

	XX =obj_coord[obj_no][0]; ZZ = obj_coord[obj_no][1];

	cout << XX << " --- " << ZZ << '\n';

  }

  cout << '\n';

*/

}





void SetObjectPos(unsigned trial_num, int trial_ord[], objtype obj_pos[][MAX_OBJECT_NUM])

{

  unsigned i, obj, trial_no, obj_num;



  cout << '\n';

  for (i=0; i<trial_num; ++i) {

	trial_no = trial_ord[i];

	obj_num = trialConditions[trial_no].obj_num[0];

	cout << i << ": set object positions for trial " << trial_no << '\n';



	float obj_coord[MAX_OBJECT_NUM][2];

	SetInitialObjPos(obj_num, obj_coord);



	for(obj=0; obj<obj_num; ++obj) {

	  obj[trial_no][obj].x[1] = obj[trial_no][obj].x[0] = obj_coord[obj][0];

	  obj[trial_no][obj].z[1] = obj[trial_no][obj].z[0] = obj_coord[obj][1];

	}

  }

  cout << '\n';

}





void setParams(void)

{

  readTrialParams();

  unsigned trial_no = order[trial];

  /*from the original positions i added -20 in the z to move back the objects

	farther into the scene closer to the wall, then adjusted the individual

	coordinances so it would look more "randomly" spread out*/

  int object_num = trial_cond.obj_num[0];

  float obj_coord[MAX_OBJECT_NUM][2];

  MakeRandomPlacOrder(object_num, objPlacOrder);



  float radius = 9.0;



  if (trial_cond.objRandom == FIXED_OBJ_POS) {

	ord_change_num = rel_to_eye_change_num = 0;

  }

  else if (trial_cond.objRandom == RAND_SWITCH_OBJ_POS) {

	for (;;) {

	  unsigned move_num, try_no = 0, try_thr = 100;

	  do {

  		move_num = randMVObject(radius);

		ord_change_num = rel_to_eye_change_num = 0;

		if (move_num==object_num && !IsObjectOutOfView(obj[trial_no]) &&

			(IsOrdRelChange(obj[trial_no]) || IsRelToEyeChange(obj[trial_no]))) break;

		++try_no;

	  } while(try_no < try_thr);



	  if (try_no < try_thr) break;

	  SetInitialObjPos(object_num, obj_coord);

	  MakeRandomPlacOrder(object_num, objPlacOrder);

	}

  }

  else if (trial_cond.objRandom == RAND_MV_OBJ_KEEP_REL) {

 	for (;;) {

	  unsigned move_num, try_no = 0, try_thr = 100;

	  do {

  		move_num = randMVObject(radius);

		ord_change_num = rel_to_eye_change_num = 0;

		if (move_num==object_num && !IsObjectOutOfView(obj[trial_no]) &&

		  !IsOrdRelChange(obj[trial_no]) && !IsRelToEyeChange(obj[trial_no])) break;

		++try_no;

	  } while(try_no < try_thr);



	  if (try_no < try_thr) break;

	  SetInitialObjPos(object_num, obj_coord);

	  MakeRandomPlacOrder(object_num, objPlacOrder);

	}

  }

  else if (trial_cond.objRandom == RAND_MV_OBJ_NOKEEP_REL) {

	assert(false);

  }

  else

	assert(false);

}



/*This must be for making some sort of code for the floor texture; related to the next function MakeFloorTexture*/

void makeCheckImage(void)

{

 /* 

  int i, j, c;

  for (i=0; i<100; ++i)

	for (j=0; j<100; ++j) {

	  c = (((i&0x8)==0)^((j&0x8)==0))*255;

	  checkImage1[i][j][0] = GLubyte(c);

	  checkImage1[i][j][1] = GLubyte(c);

	  checkImage1[i][j][2] = GLubyte(c);

//	  checkImage1[i][j][3] = GLubyte(c);

	}

  */

  int i, j;

  GLfloat temp1,temp2,temp3;



  // loop to move from input array to proper checkImage array 

  for (i=0; i<100; ++i) {

	for (j=0; j<100; ++j) {

	  if(rand()>.5*RAND_MAX) {

		temp1 = 90;

	  }

	  else {

		temp1 = 90; //trialConditions[order[trial]].contrast; 

	  }



	  if(rand()>.5*RAND_MAX) {

		temp2 = 0;

	  }

	  else {

		temp2 = 1;

	  }



	  if(rand()>.5*RAND_MAX) {

		temp3=0;

	  }

	  else {

		temp3=1;

	  }



	  checkImage1[i][100-1-j][0] = temp1;

	  checkImage1[i][100-1-j][1] = temp1;

	  checkImage1[i][100-1-j][2] = temp1;

	}

  }

}

//end new texture code



/*Create the floor texture*/

void makeFloorTexture(void)

{

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);



  if (useMipmaps) {

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,

					GL_LINEAR_MIPMAP_LINEAR);

	gluBuild2DMipmaps(GL_TEXTURE_2D,3,100,40,GL_RGB, GL_UNSIGNED_BYTE, &checkImage1[0][0][0]);

  } 

  else { 

	if (linearFiltering) {

	  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	} 

	else {

	  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	}

	glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,

			     GL_RGB, GL_UNSIGNED_BYTE, &checkImage1[0][0][0]);

  }

}



enum {

	X, Y, Z, W

};



enum {

	A, B, C, D

};



/* Create a matrix that will project the desired shadow. */

void shadowMatrix(GLfloat shadowMat[4][4], GLfloat groundplane[4],

				  GLfloat lightpos[4])

{

  GLfloat dot;



  /* Find dot product between light position vector and ground plane normal. */

  dot = groundplane[X] * lightpos[X] + groundplane[Y] * lightpos[Y] +

		groundplane[Z] * lightpos[Z] + groundplane[W] * lightpos[W];



  shadowMat[0][0] = dot - lightpos[X] * groundplane[X];

  shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];

  shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];

  shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];



  shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];

  shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];

  shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];

  shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];



  shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];

  shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];

  shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];

  shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];



  shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];

  shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];

  shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];

  shadowMat[3][3] = dot - lightpos[W] * groundplane[W];

}



/* Find the plane equation given 3 points. */

void findPlane(GLfloat plane[4],

			   GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])

{

  GLfloat vec0[3], vec1[3];



  /* Need 2 vectors to find cross product. */

  vec0[X] = v1[X] - v0[X];

  vec0[Y] = v1[Y] - v0[Y];

  vec0[Z] = v1[Z] - v0[Z];



  vec1[X] = v2[X] - v0[X];

  vec1[Y] = v2[Y] - v0[Y];

  vec1[Z] = v2[Z] - v0[Z];



  /* find cross product to get A, B, and C of plane equation */

  plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];

  plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);

  plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];



  plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);

}



void drawPolygons(bool bShadow)

{

  int i;

  int object_num = trial_cond.obj_num[0];	//i think this is the max # of objects (in other words, objs in Frame 1

  float X, Z;

  unsigned trial_no;



  for(i=0; i<object_num; ++i) {						//loop until all objects are drawn

	//if (frame==2 && !trial_cond.bshow[i]) continue; //if it is frame 2 and bshow[] is false, skip all this stuff below and go back up to the top of this for loop



	GLfloat mat_specular_old[4];

	GLfloat mat_diffuse_old[4];

	GLfloat mat_ambient_old[4];

	GLfloat mat_shine_old[1];



	if (!bShadow && trial_cond.bshow[i]) {

	  glGetMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular_old);

	  glGetMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse_old);

	  glGetMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_old);

	  glGetMaterialfv(GL_FRONT, GL_SHININESS, mat_shine_old);

	  GLfloat rf_sp = 0, rf_df = 1.0, rf_ab = 1.0;

//	  GLfloat mat_specular[] = {rf_sp, rf_sp, rf_sp, 1.0};

//	  GLfloat mat_diffuse[] = {rf_df, rf_df, rf_df, 1.0};

//	  GLfloat mat_ambient[] = {rf_ab, rf_ab, rf_ab, 1.0};

	  GLfloat mat_specular[] = {1.0, 0.0, 0.0, 1.0};

	  GLfloat mat_diffuse[] = {1.0, 0.0, 0.0, 1.0};

	  GLfloat mat_ambient[] = {1.0, 0.0, 0.0, 1.0};

//	  GLfloat mat_diffuse[] = {rf_df, 0, 0, 1.0};

//	  GLfloat mat_ambient[] = {rf_ab, 0, 0, 1.0};

	  GLfloat mat_shine[] = {50.0};

	  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

	  glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);

	  glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);

	  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shine);

	}



	trial_no = order[trial];

	X = obj[trial_no][i].x[frame-1];

	Z = obj[trial_no][i].z[frame-1];



	/* Push/Draw polygons on the floor */

	glPushMatrix(); 



	/* TO DO: put slab on the right place; create 2 of them

	 * Also, put the slabs in another function (or whatever) 

	 * so they can switch between orientations randomly??   */



	/* draw objects in the scene */

	switch (objPlacOrder[i]) {

	  case 0: //cube 1

		glTranslatef(X, 3, Z); 

		//glRotatef(150.0, 0.0, 1.0, 0.0);

		//glScalef(2.0, 0.5, 4.0);

		glutSolidCube(6);

		break;



	  case 1: //cone

		glTranslatef(X, 0, Z); 

		glRotatef(270.0, 1.0, 0.0, 0.0);

		glutSolidCone(3.25, 10.5, 45, 22.5);	

		break;



	  case 2: //slab 1

		glTranslatef(-30, 1.0, -100);			//make x and z positions constant, not defined by obj[] array (see above)

		//glRotatef(150.0, 0.0, 1.0, 0.0);

		glScalef(3.0, (GLfloat)0.2, 10.0);

		glutSolidCube(9);

		break;



	  case 3: //slab 2

		glTranslatef(25, 1.0, -130);			//make x and z positions constant, not defined by obj[] array (see above)

		//glRotatef(150.0, 0.0, 1.0, 0.0);

		glScalef(3.0, (GLfloat)0.2, 20.0);

		glutSolidCube(9);

		break;



	  case 4: //sphere

		glTranslatef(X, 3, Z); 

		glutSolidSphere(3, 30, 15);	

		break;



	  case 5: //wirecone stretched vertically a litte bit

		glTranslatef(X, 0., Z);

		glScalef(1, (GLfloat)1.3, 1);

		glRotatef(270.0, 1.0, 0.0, 0.0);

		glutWireCone(3.25, 10.5, 8, 6);	

		break;



	  case 6: //solid sphere stretched out vertically

		glTranslatef(X, 5, Z); 

		glScalef(1 , (GLfloat)1.7 , 1);

		glutSolidSphere(3., 30, 15);	

		break;



	  case 7: //wirecube stretched out horizontally

		glTranslatef(X, 3., Z);

		glScalef(2, (GLfloat)0.9, (GLfloat)0.9);

		glRotatef(160.0, 0.0, 1.0, 0.0);

		glutWireCube(6);	

		break;



	  default: //problem!!!  define more objects/cases

		glScalef(4.0, 4.0, 4.0);

		glutSolidCube(6);	

		break;

	}



	if (!bShadow && trial_cond.bshow[i]) {

	  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular_old);

	  glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse_old);

	  glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_old);

	  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shine_old);

	}



	glPopMatrix();	//end PushMatrix()

  }					//end "for" loop

}					//end function





void drawBlankScreen(void)

{

  if(blank==1) {

	glDisable(GL_LIGHTING);

  }



  if (useTexture) {

	glEnable(GL_TEXTURE_2D);

  }



  glBegin(GL_QUADS);

	glVertex3f(-100, -100, 32);

	glVertex3f(-100, 100, 32);

	glVertex3f(100, 100, 32);

	glVertex3f(100, -100, 32);

  glEnd(); 



  if (useTexture) {

	glDisable(GL_TEXTURE_2D);

  }



  if(blank==1){

	glEnable(GL_LIGHTING); 

  }

}





/*vertices for textured floor and wall*/

GLfloat floorVertices[4][3] = {

	{ -200.0, 0.0, 100.0 },

	{ 200.0, 0.0, 100.0 },

	{ 200.0, 0.0, -300.0 },

	{ -200.0, 0.0, -300.0 },

};



/*vertices for grid on floor */

GLfloat gridVertices[4][3] = {

	{ -200.0, 0.0, 100.0 },

	{ 200.0, 0.0, 100.0 },

	{ 200.0, 0.0, -300.0 },

	{ -200.0, 0.0, -300.0 },

};



//This code is to draw a textured floor; from Objects no texture (Expt. 3) cpp file

void drawFloor(void)

//generate 20 circles randomly placed on the ground for each trial

{

  int i, j, cosine, sine;

  float textureA[4] = {(GLfloat)0.002, (GLfloat)0.003, (GLfloat)0.004, (GLfloat)0.005};

  float texmult=textureA[TEXTURE];



  glDisable(GL_LIGHTING);



  if (useTexture) {

    glEnable(GL_TEXTURE_2D);

  }



  glBegin(GL_QUADS);

//    glTexCoord2f(0.0, 0.0);

//	glTexCoord2f(texmult*floorVertices[0][0],texmult*floorVertices[0][2]);

    glVertex3fv(floorVertices[0]);

//    glTexCoord2f(0.0, REPEAT);

//	glTexCoord2f(texmult*floorVertices[1][0],texmult*floorVertices[1][2]);

	glVertex3fv(floorVertices[1]);

//    glTexCoord2f(REPEAT, REPEAT);

//	glTexCoord2f(texmult*floorVertices[2][0],texmult*floorVertices[2][2]);

    glVertex3fv(floorVertices[2]);

//    glTexCoord2f(REPEAT, 0.0);

//	glTexCoord2f(texmult*floorVertices[3][0],texmult*floorVertices[3][2]);

    glVertex3fv(floorVertices[3]);

  glEnd();



  //make cirlces on the ground

  for (i = 0; i < 500; ++i) {	

	glBegin (GL_POLYGON);

	//Generate the points of the circle

	for (j = 0; j < 100; ++j) {

	  cosine = cos(j * 2 * 3.14 / 100.0);

	  sine   = sin(j * 2 * 3.14 / 100.0);

	  glVertex3f(cosine+circlex[i], 0, sine+circlez[i]);

	  //or glVertex3f(2*cosine+circlex[i], 0, 2*sine+circlez[i]);

	}

	glEnd(); 

  }	





  if (useTexture) {

    glDisable(GL_TEXTURE_2D);

  }



  glEnable(GL_LIGHTING);

}



GLfloat floorPlane[4];

GLfloat floorShadow[4][4];



void MoveEye(double theta, float disp)

{

  glLoadIdentity();  

  gluLookAt(0.0 + disp * (sin(theta * (M_PI / 180))), 16.0, 

			80.0 - (disp * (cos(theta * (M_PI / 180)))),

			0.0 + disp * (sin(theta * (M_PI / 180))), 16.0, 

			0.0 - (disp * (cos(theta * (M_PI / 180)))),

	  		0.0, 1.0, 0.); /* up is in positive Y direction */

} 



// short ph = 0;

void redraw(void)     

{

  int start, end;

 // int frame = 0;

 // static float bar_angle; 



  ticks1 = (int)(clock()*1000/CLOCKS_PER_SEC); //milliseconds



  if (phase == 0) {								// press ' ' to set phase to 1 		

	MoveEye(trial_cond.abs_heading, 0);

	blank = 2;

	ticks0 = (int)(clock()*1000/CLOCKS_PER_SEC);

  }

  //phase 1==frame 1; taken out in this current program because we told phase == 0 to step over

  //to phase ==3 so that we only see one frame instead of 2 frames with a shift in eye movement

  //someday i will fix this and take out phase 1 and 2 completely, and refine the other phases

  else if (phase == 1){

	frame = 1;

	disp = 0;

	MoveEye(trial_cond.abs_heading, 0);

	blank = 0;

	if ((ticks1-ticks0)>=FRAMELENGTH){

	  //phase = 2;

	  ticks0 = (int)(clock()*1000/CLOCKS_PER_SEC);

	}

  }

  //phase 2 is also taken out because it's not necessary; see description in phase 1

  else if(phase == 2){ //blank; ISI presentation

	blank = 1;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	disp = 0;

	//if ((ticks1-ticks0)>= trial_cond.isi){

	  phase = 3;

//	  bar_angle = trialConditions[order[trial]].bar_angle;

	  ticks0 = (int)(clock()*1000/CLOCKS_PER_SEC);

//	}

  }

  else if (phase == 3){ //frame2

	blank = 0;

	frame = 2; 

	MoveEye(trial_cond.abs_heading, mv_distance);



	if ((ticks1-ticks0)>=(FRAMELENGTH-250));  //this isn't doing anything



	if ((ticks1-ticks0)>=FRAMELENGTH){	

	  phase = 4;

	  resp_lock=0; // responses will be accepted from now til lock is reengaged

	  ticks0 = (int)(clock()*1000/CLOCKS_PER_SEC);

	}

  }

    else if (phase == 4){ //wait for	response

	printf("phase = %i   trial = %i\n",	phase, trial);

	blank =	0;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

//	MoveEye(trial_cond.abs_heading, 0);

	if(resp!=0){

	  resp_lock=1;

	  ticks0 = (int)(clock()*1000/CLOCKS_PER_SEC);

	  blank =	1;	

	  phase =	5;

	}

  }

  else if (phase ==  5){ //inter trial interval (ITI)

	blank = 1;

	MoveEye(trial_cond.abs_heading, 0);

	if (((ticks1-ticks0) >= FRAMELENGTH) && resp != 0){	 

	  resp_lock=1;//to prevent multiple responses being entered in the ITI



	  disp = 0;	//goes back to 0 position

	  correct = ((resp * trial_cond.rel_heading) / 

				 (abs(resp) * abs(trial_cond.rel_heading)) + 1) / 2;

		fprintf(outfile, "%s, %d, %d, %f, %4.2f, %d, %d, %d, %d, %f, %d, %d, \n", 

		//fprintf(outfile, "%s, %d, %d, %f, %d, %d, %d, %d, %d, \n", 

			  subjStr, trial, FRAMELENGTH, trial_cond.rel_heading,					//removed trial_cond.isi, 

			  trial_cond.obj_num[0], trial_cond.obj_num[1], trial_cond.objRandom,

		  //  resp, correct, bar_angle --removed these because these all depend ond the bar angle

			  ord_change_num, rel_to_eye_change_num); //changetype was here



	  fflush(outfile);

	  if (!correct) cout << "\7\n";

	  resp=0; //remember to write to file before resetting!

	  ++trial;

	  if(trial==ntrials){

		fclose(outfile);

		exit(0);

	  }

			

	  //makeCheckImage();

	  //makeFloorTexture();

	  //setParams();



	  phase = 3;

	  ticks0 = (int)(clock()*1000/CLOCKS_PER_SEC);

	}

  }



  if (reportSpeed) {

	start = glutGet(GLUT_ELAPSED_TIME);

  }



  /* Clear; default stencil clears to zero. */	

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);	



  lightPosition[0] = 1000+12*cos(lightAngle);

  lightPosition[1] = 50*lightHeight;

  lightPosition[2] = 12*sin(lightAngle);

  if (directionalLight) {

	lightPosition[3] = 0.0;

  } 

  else {

	lightPosition[3] = 1.0;

  }



  shadowMatrix(floorShadow, floorPlane, lightPosition);



  glPushMatrix();

  /* Perform scene rotations based on user mouse input. */

  glRotatef(angle2, 1.0, 0.0, 0.0);

  glRotatef(angle, 0.0, 1.0, 0.0);



  /* Tell GL new light source position. */

  glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);

	

  /* Back face culling will get used to only draw either the top or the

	 bottom floor.  This let's us get a floor with two distinct

	 appearances.  The top floor surface is reflective and kind of red.

	 The bottom floor surface is not reflective and blue. */



  /* Draw "bottom" of floor in blue. */

  glFrontFace(GL_CW);  /* Switch face orientation. */

  glColor4f((GLfloat)0.1, (GLfloat)0.1, (GLfloat)0.7, 1.0);

  glColor4f(1.0, 1.0, 1.0, (GLfloat)0.3);

  //drawWall();



  if (blank!=0) {

	drawBlankScreen();

  }



  glFrontFace(GL_CCW);



  if (phase==1 || phase==3 || phase==4 || phase==5){

	if (renderShadow) {

	  if (stencilShadow) {

//	     Draw the floor with stencil value 3.  This helps us only 

//		 draw the shadow once per floor pixel (and only on the

//		 floor pixels). 

		glEnable(GL_STENCIL_TEST);

		glStencilFunc(GL_ALWAYS, 3, 0xffffffff);

		glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

	  }

	}

  }



  /* Draw "top" of floor.  Use blending to blend in reflection. */

  //    glEnable(GL_BLEND);

  //    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glColor4f((GLfloat)0.7, 0.0, 0.0, (GLfloat)0.3);

  glColor4f(1.0, 1.0, 1.0, (GLfloat)0.3);

  drawFloor();



  if (blank!=1){//*******************why is this 1, when 0 in other similar cases?

	drawBlankScreen();

  }

  glDisable(GL_BLEND);



  if (renderPolygons) {										/* Draw "actual" Polygons, not its reflection. */

	if (phase==1 || phase==3 || phase==4 || phase==5) {		/* don't draw objs when not frame 1 or 2*/

	  drawPolygons(false);

	}

  }



  if (phase==1 || phase==3 || phase==4 || phase==5){

	if (renderShadow) {

	/* Render the projected shadow. */

	  if (stencilShadow) {

		/* Now, only render where stencil is set above 2 (ie, 3 where

		   the top floor is).  Update stencil with 2 where the shadow

		   gets drawn so we don't redraw (and accidently reblend) the

		   shadow). */

//		glStencilFunc(GL_LESS, 2, 0xffffffff);  /* draw if ==1 */

//		glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

	  }



	/* To eliminate depth buffer artifacts, we use polygon offset

	   to raise the depth of the projected shadow slightly so

	   that it does not depth buffer alias with the floor. */

  	  if (offsetShadow) {

		switch (polygonOffsetVersion) {

#ifdef GL_EXT_polygon_offset

		  case EXTENSION:

			glEnable(GL_POLYGON_OFFSET_EXT);

			break;

#endif

#ifdef GL_VERSION_1_1

		  case ONE_DOT_ONE:

			glEnable(GL_POLYGON_OFFSET_FILL);

			break;

#endif

		  case MISSING:

		  /* Oh well. */

			break;

		}

	  }



	  /* Render 50% black shadow color on top of whatever the

		 floor appareance is. */

	  glEnable(GL_BLEND);

	  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	  glDisable(GL_LIGHTING);  /* Force the 50% black. */

	  glColor4f(0.0, 0.0, 0.0, 0.5);



	  glPushMatrix();

	  /* Project the shadow. */

	  glMultMatrixf((GLfloat *) floorShadow);

	  drawPolygons(true);

	  glPopMatrix();



	  glDisable(GL_BLEND);

	  glEnable(GL_LIGHTING);



	  if (offsetShadow) {

		switch (polygonOffsetVersion) {

#ifdef GL_EXT_polygon_offset

		  case EXTENSION:

			glDisable(GL_POLYGON_OFFSET_EXT);

			break;

#endif

#ifdef GL_VERSION_1_1

		  case ONE_DOT_ONE:

			glDisable(GL_POLYGON_OFFSET_FILL);

			break;

#endif

		  case MISSING:

		  /* Oh well. */

			break;

		}

	  }



	  if (stencilShadow) {

		glDisable(GL_STENCIL_TEST);

	  }

	}

  }



  glPopMatrix();



  if (reportSpeed) {

	glFinish();

	end = glutGet(GLUT_ELAPSED_TIME);

	printf("Speed %.3g frames/sec (%d ms)\n", 1000.0/(end-start), end-start);

  }



  glutSwapBuffers();

}





/* ARGSUSED1 */

void motion(int x, int y)

{

  if (moving) {

	angle = angle + (x - startx);

	angle2 = angle2 + (y - starty);

	startx = x;

	starty = y;

	glutPostRedisplay();

  }	

}



/* Advance time varying state when idle callback registered. */

void idle(void)

{

  static float time = 0.0;



  time = glutGet(GLUT_ELAPSED_TIME) / 500.0;

  glutPostRedisplay();

}



enum {

	M_NONE, M_MOTION, M_LIGHT, M_TEXTURE, M_SHADOWS, M_REFLECTION, M_Polygons,

	M_STENCIL_REFLECTION, M_STENCIL_SHADOW, M_OFFSET_SHADOW,

	M_POSITIONAL, M_DIRECTIONAL, M_PERFORMANCE

};



void controlLights(int value)

{

  switch (value) {

	case M_NONE:

	  return;

  

	case M_LIGHT:

	  lightSwitch = !lightSwitch;

	  if (lightSwitch) {

		  glEnable(GL_LIGHT0);

	  } else {

		  glDisable(GL_LIGHT0);

	  }

	  break;



	case M_TEXTURE:

	  useTexture = !useTexture;

	  break;



	case M_SHADOWS:

	  renderShadow = 1 - renderShadow;

	  break;



	case M_Polygons:

	  renderPolygons = 1 - renderPolygons;

	  break;



	case M_STENCIL_REFLECTION:

	  stencilReflection = 1 - stencilReflection;

	  break;



	case M_STENCIL_SHADOW:

	  stencilShadow = 1 - stencilShadow;

	  break;



	case M_OFFSET_SHADOW:

	  offsetShadow = 1 - offsetShadow;

	  break;



	case M_POSITIONAL:

	  directionalLight = 0;

	  break;



	case M_DIRECTIONAL:

	  directionalLight = 1;

	  //	frame2 = 1;

	  break;



	case M_PERFORMANCE:

	  reportSpeed = 1 - reportSpeed;

	  break;

  }



  glutPostRedisplay();

}



/* When not visible, stop animating.  Restart when visible again. */

void visible(int vis)

{

  glutIdleFunc(idle);

}



/* Press any key to redraw; good when motion stopped and

   performance reporting on. */

/* ARGSUSED */

void key(unsigned char c, int x, int y)

{

  switch (c) {

	case ' ':

	  if (phase==0) {

		phase = 3;

	  }

		/*

		else if (phase==1)

			phase = 2;

		else if (phase==2)

			phase = 3;

		else if (phase==3 && ph==0) {

			ph = 1;

		}

		else if (ph==1) {

			ph = 0;

			phase = 4;

		}

		*/

	  break;



	case '4':

	  if (phase==4 && resp_lock!=1) {

		resp = -1;

	  }

	  break;



	case '6':

	  if (phase==4 && resp_lock!=1){

		resp = 1;

	  }

	  break;



	case 27:  //esc key exits program

	  exit(0);

  }



  glutPostRedisplay();

}





int supportsOneDotOne(void)

{

  const char *version;

  int major, minor;



  version = (char *) glGetString(GL_VERSION);

  if (sscanf(version, "%d.%d", &major, &minor) == 2)

	return major >= 1 && minor >= 1;

  return 0; /* OpenGL version string malformed! */

}





int main(int argc, char **argv)

{

  int i;



  glutInit(&argc, argv);

  unsigned seed = (unsigned int)time(NULL);	//give me the current time as an integer



  srand(seed);								//sets up rand num generator using the current time as its seed; should be done only once

  ticks0 = clock()/CLOCKS_PER_SEC*1000;



  ofstream ofs("seed.txt");

  assert(ofs);

  ofs << "seed = " << seed << '\n';

  assert(ofs);

  ofs.close();



  GenerateConditions();

  MakeTrialOrderRandom(TOTALTRIALS, order);

  SetObjectPos(TOTALTRIALS, order, obj);

  makeSubFile();

  setParams();



  for (i=1; i<argc; ++i) {

	if (!strcmp("-linear", argv[i])) {

	  linearFiltering = 1;

	} 

	else if (!strcmp("-mipmap", argv[i])) {

	  useMipmaps = 1;

	} 

	else if (!strcmp("-ext", argv[i])) {

	  forceExtension = 1;

	}

  }



  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL | 

					  GLUT_MULTISAMPLE);

  glutCreateWindow("Lots of objects");



  if (glutGet(GLUT_WINDOW_STENCIL_SIZE) <= 1) {

	printf("dinoshade: Sorry, I need at least 2 bits of stencil.\n");

		//exit(1);

  }



	/* Register GLUT callbacks. */

  glutDisplayFunc(redraw);

  glutMotionFunc(motion);

  glutVisibilityFunc(visible);

  glutKeyboardFunc(key);

  glutCreateMenu(controlLights);



  glutAddMenuEntry("Toggle motion", M_MOTION);

  glutAddMenuEntry("-----------------------", M_NONE);

  glutAddMenuEntry("Toggle light", M_LIGHT);

  glutAddMenuEntry("Toggle texture", M_TEXTURE);

  glutAddMenuEntry("Toggle shadows", M_SHADOWS);

  glutAddMenuEntry("Toggle reflection", M_REFLECTION);

  glutAddMenuEntry("Toggle Polygons", M_Polygons);

  glutAddMenuEntry("-----------------------", M_NONE);

  glutAddMenuEntry("Toggle reflection stenciling", M_STENCIL_REFLECTION);

  glutAddMenuEntry("Toggle shadow stenciling", M_STENCIL_SHADOW);

  glutAddMenuEntry("Toggle shadow offset", M_OFFSET_SHADOW);

  glutAddMenuEntry("----------------------", M_NONE);

  glutAddMenuEntry("Positional light", M_POSITIONAL);

  glutAddMenuEntry("Directional light", M_DIRECTIONAL);

  glutAddMenuEntry("-----------------------", M_NONE);

  glutAddMenuEntry("Toggle performance", M_PERFORMANCE);

  glutAttachMenu(GLUT_RIGHT_BUTTON);



#ifdef GL_VERSION_1_1

  if (supportsOneDotOne() && !forceExtension) {

	polygonOffsetVersion = ONE_DOT_ONE;

	glPolygonOffset(-2.0, -1.0);

  } else

#endif

  {

#ifdef GL_EXT_polygon_offset

	/* check for the polygon offset extension */

	if (glutExtensionSupported("GL_EXT_polygon_offset")) {

	  polygonOffsetVersion = EXTENSION;

	  glPolygonOffsetEXT(-0.1, -0.002);

	} else 

#endif

	{

	  polygonOffsetVersion = MISSING;

	  printf("\ndinoshine: Missing polygon offset.\n");

	  printf("           Expect shadow depth aliasing artifacts.\n\n");

	}

  }



  glEnable(GL_CULL_FACE);

  glEnable(GL_DEPTH_TEST);

  glEnable(GL_TEXTURE_2D);

  glLineWidth(3.0);



  glViewport (0, 0, windW, windH);

  glMatrixMode(GL_PROJECTION);

  gluPerspective( /* field of view in degree */ 36.0,

		          /* aspect ratio */ float(windW) / windH,

		          /* Z near */ 47.0, /* Z far */ 1000.0);

  glMatrixMode(GL_MODELVIEW);



  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);

  glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);

  glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)0.1);

  glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.05);

  glEnable(GL_LIGHT0);

  glEnable(GL_LIGHTING);



  glClearColor(0.515f, 0.515f, 0.515f, 1.0f);  //(0.6f, 0.6f, 1.0f, 1.0f);

  glutFullScreen();

  glutSetCursor(GLUT_CURSOR_NONE);



  makeCheckImage();

  makeFloorTexture();

  readTrialParams();

	/* Setup floor plane for projected shadow calculations. */

  findPlane(floorPlane, floorVertices[1], floorVertices[2], floorVertices[3]);



  glutMainLoop();

  return 0; /* ANSI C requires main to return int. */

}