/* Ivan Djordjevic */ #define _USE_MATH_DEFINES #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #include #include using namespace glm; using namespace std; #define MOVING_CONST 0.1 #define ROTATION_CONST 3.14f / 180.f #define LOOK_MOVEMENT_CONST 0.1f /*--------------------------------------------------*/ void PrintVector(vec3 vec) { printf("%.2f %.2f %.2f\n", vec.x, vec.y, vec.z); } char title[] = "Prozor"; int FPS = 60; vec3 MotorPosition(0.0, 1.0, 0.0); vec3 LookAt_vector(0.0, 1.0, 1.0); vec3 LookUp_vector(0.0, 1.0, 0.0); vector coordinateSystem; const int circle_dots = 50; const float height = 480; const float ratio = 16.f / 9.f; double upDownAngle = 0; int currentSpeed = 1; float arrowRotate = 0.f; vec3 operator* (mat4x4 mat, vec3 vec) { vec4 v(vec.x, vec.y, vec.z, 1.f); v = mat * v; return vec3(v.x, v.y, v.z); } vector operator* (mat4x4 mat, vector vectors) { for (int i = 0; i < vectors.size(); i++) vectors[i] = mat * vectors[i]; return vectors; } void Transform(mat4x4 transform, vector &poly) { for (int i = 0; i < poly.size(); i++) poly[i] = transform * poly[i]; } void Transform(mat4x4 transform, vector> &poly) { for (int i = 0; i < poly.size(); i++) for(int j = 0; j < poly[i].size(); j++) poly[i][j] = transform * poly[i][j]; } class Color { public: float r; float g; float b; Color(float r1, float g1, float b1): r(r1), g(g1), b(b1){} }; void DrawPolygon(vector poly) { glBegin(GL_POLYGON); for (int i = 0; i < poly.size(); i++) glVertex3f(poly[i].x, poly[i].y, poly[i].z); glEnd(); } void DrawPolygons(vector> polys) { for (int i = 0; i < polys.size(); i++) for (int j = 0; j < polys[i].size(); j++) DrawPolygon(polys[i]); } //o GLUT_BITMAP_TIMES_ROMAN_24 //o GLUT_BITMAP_TIMES_ROMAN_10 //o GLUT_BITMAP_HELVETICA_18 void RenderString(float x, float y, void* font, double r, double g, double b) { glColor3f(r, g, b); glRasterPos2f(x, y); char s[100]; sprintf(s, "x = %.2lf\ny = %.2lf\nz = %.2lf", MotorPosition.x, MotorPosition.y, MotorPosition.z); glutBitmapString(font, (const unsigned char*)s); } /*--------------------------------------------------*/ // BOJE Color white = Color(1.f, 1.f, 1.f); Color black = Color(0.f, 0.f, 0.f); Color green = Color(0.f, 1.f, 0.f); Color cyan = Color(0, 1, 1); Color gray = Color(0.5f, 0.5f, 0.5f); // MOJE FUNKCIJE vector> CreateGrid(int count, float distance) { vector> grid; grid.resize(4); for (int i = 0; i < 4; i++) grid[i].resize(count); float maxDistance = distance * count; for (int i = 0; i < count; i++) { grid[0][i] = vec3(i * distance, -0.1f, 0); grid[1][i] = vec3(i * distance, -0.1f, maxDistance); } for (int i = 0; i < count; i++) { grid[2][i] = vec3(0, -0.1f, i * distance); grid[3][i] = vec3(maxDistance, -0.0f, i * distance); } return grid; } void RenderGrid(vector> grid, Color color = green) { glLineWidth(1); glColor3f(green.r, green.g, green.b); glBegin(GL_LINES); for (int i = 0; i < grid[0].size(); i++) { // Z glVertex3f(grid[0][i].x, grid[0][i].y, grid[0][i].z); glVertex3f(grid[1][i].x, grid[1][i].y, grid[1][i].z); } glEnd(); glBegin(GL_LINES); for (int i = 0; i < grid[0].size(); i++) { glVertex3f(grid[2][i].x, grid[2][i].y, grid[2][i].z); glVertex3f(grid[3][i].x, grid[3][i].y, grid[3][i].z); } glEnd(); } vector> CreateRoad(float roadwayLength, float roadwayWidth, float stripeLength, float stripeWidth, float stripeOffset) { vector> road; road.resize(2); road[0].resize(4); road[0][0] = vec3(0, 0, 0); road[0][1] = vec3(roadwayWidth, 0, 0); road[0][2] = vec3(roadwayWidth, 0, roadwayLength); road[0][3] = vec3(0, 0, roadwayLength); int stripeCount = (int)(roadwayLength / (stripeLength + stripeOffset)); float currentStripeOffset = 0; road[1].resize(stripeCount * 4); for (int i = 0; i < stripeCount * 4; i += 4) { road[1][i] = translate(vec3((roadwayWidth / 2.f) - (stripeWidth / 2), 0.01f, currentStripeOffset)) * vec3(0, 0, 0); road[1][i + 1] = translate(vec3((roadwayWidth / 2.f) - (stripeWidth / 2), 0.01f, currentStripeOffset)) * vec3(stripeWidth, 0, 0); road[1][i + 2] = translate(vec3((roadwayWidth / 2.f) - (stripeWidth / 2), 0.01f, currentStripeOffset)) * vec3(stripeWidth, 0, stripeLength); road[1][i + 3] = translate(vec3((roadwayWidth / 2.f) - (stripeWidth / 2), 0.01f, currentStripeOffset)) * vec3(0, 0, stripeLength); currentStripeOffset += (stripeLength + stripeOffset); } return road; } void RenderRoad(vector> road) { glColor3f(gray.r, gray.g, gray.b); DrawPolygon(road[0]); glColor3f(white.r, white.g, white.b); vector poly; poly.resize(4); for (int i = 0; i < road[1].size(); i += 4) { poly[0] = road[1][i]; poly[1] = road[1][i+1]; poly[2] = road[1][i+2]; poly[3] = road[1][i+3]; DrawPolygon(poly); } } vector CreateCircle(int edgeCount, float radius) { vector motor; motor.resize(edgeCount); float delta = M_PI * 2 / (float)edgeCount; for (int i = 0; i < edgeCount; i++) { motor[i] = vec3(radius * cos(delta * i), radius * sin(delta * i), 0); } return motor; } vector CreateGUISquare() { vector square; square.resize(4); square[0] = vec3(0, 0, 1); square[1] = vec3(1, 0, 1); square[2] = vec3(1, 1, 1); square[3] = vec3(0, 1, 1); return square; } /*--------------------------------------------------*/ vector> grid; vector> road; // Motor vector motorGUI; vector brzinomer; vector kazaljka; float rotationSpeed = 1.f / (float)FPS; float maxRotationAngle = M_PI / (float)180 * 15.f; float rotationAngle = 0; // Motor float kmh = 20.f / (float)FPS; int brzina = 0; int brojBrzina = 4; // Nitro vector nitroGUI; vector nitroChargeGUI; bool nitroActive = false; float chargeTimer = 0.f; float nitroTimer = 3.f; void OnLoad() { // GRID grid = CreateGrid(5000, 1.f); Transform(translate(vec3(-2500, 0, -2500)), grid); // ROAD road = CreateRoad(2500, 10, 1, 0.5f, 0.5f); Transform(translate(vec3(-5, 0, 0)), road); motorGUI = CreateCircle(64, 0.5f); Transform(scale(vec3(1.f/ratio, 1, 1)), motorGUI); Transform(translate(vec3(0, -0.8f, 0)), motorGUI); brzinomer = CreateCircle(32, 0.1f); Transform(scale(vec3(1.f / ratio, 1, 1)), brzinomer); Transform(translate(vec3(0, -0.6f, 0)), brzinomer); kazaljka.resize(2); kazaljka[0] = vec3(0.0f, 0.f, 0.f); kazaljka[1] = vec3(0.0f, -1, 0.f); Transform(scale(vec3(0.1f / ratio, 0.1f, 0.1f)), kazaljka); // KAZALJKA Transform(translate(vec3(0, -0.6f, 0)), kazaljka); // NITRO nitroGUI = CreateGUISquare(); nitroChargeGUI = CreateGUISquare(); Transform(scale(vec3(0.035f, 0.15f, 1)), nitroGUI); Transform(scale(vec3(0.035f, 0.15f, 1)), nitroChargeGUI); Transform(translate(vec3(-0.15f, -0.7f, 0)), nitroGUI); Transform(translate(vec3(-0.15f, -0.7f, 0)), nitroChargeGUI); nitroChargeGUI[2] = nitroChargeGUI[1]; nitroChargeGUI[3] = nitroChargeGUI[0]; } void FixedUpdate() { // URADIO SAM DUPLU ROTACIJU (NAGIB PO Z OSI I ROTACIJU MOTORA PO Y OSI) JER LEPSE IZGLEDA LookAt_vector = rotate(rotationAngle, vec3(0, 1, 0)) * vec3(0, 1, 1); LookUp_vector = rotate(-rotationAngle, vec3(0, 0, 1)) * vec3(0, 1, 0); if (brzina > 0) MotorPosition = translate(vec3(rotationAngle / (float)5, 0, brzina * kmh)) * MotorPosition; else MotorPosition = translate(vec3(0, 0, brzina * kmh)) * MotorPosition; LookAt_vector = MotorPosition + vec3(0, 0, 1); // ISPRAVKA -------------------------------------------------------------------------------------------------------------------------------------- // Nisam proverio da li je brzina veca od 0 tj. da li se motor krece if (chargeTimer < 5 && brzina > 0) { // ISPRAVKA ---------------------------------------------------------------------------------------------------------------------------------- // Na kolokvijumu 1.f / (float)(FPS) nije davalo dobre rezultate, ali kod mene na racunaru daje // Verovatno su racunari slabiji i nisu dostizali 60FPS-a (iscrtavao sam mrezu od 20000 tacaka) pa se zbog toga chargeTimer uvecavao sporije // Na racunarima na fakultetu: < 60FPS * 1/60 => + dodaje manje od jedne sekunde 'po sekundi' // Na racunaru kod mene: Tacno 60FPS * 1/60 => dodaje tacno jednu sekundu 'po sekundi' // Zato sam na kolokvijumu stavio 3.f umesto 1.f da bih dodao priblizno sekundu po sekundi // Na kolokvijumu je ovo bilo moguce resiti prelazenjem VS configuracije iz Debug u Release mode chargeTimer += 1.f / (float)(FPS); printf("%f\n", chargeTimer); // ISPRAVKA ----------------------------------------------------------------------------------------------------------------------------------- // Na kolokvijumu sam ove funkcije uskladio sa 3.f / (float)(FPS) i usled toga ovde moram da smanjim Y translaciju nitroChargeGUI[2] = translate(vec3(0, 0.03f / (float)(FPS), 0)) * nitroChargeGUI[2]; nitroChargeGUI[3] = translate(vec3(0, 0.03f / (float)(FPS), 0)) * nitroChargeGUI[3]; } if (nitroActive) { if (nitroTimer > 0) nitroTimer -= 1.f / (float)(FPS); else { nitroActive = false; nitroTimer = 3.f; nitroChargeGUI[2] = nitroChargeGUI[1]; nitroChargeGUI[3] = nitroChargeGUI[0]; chargeTimer = 0; // ISPRAVKA ------------------------------------------------------------------------------------------------------------------------------- // Zaboravio da podelim oduzetu brzinu sa framerate-om kmh -= 50.f / (float)(FPS); if (kmh < 0) { kmh = 0; brzina = 0; } } } } void Render3D() { // GRID RenderGrid(grid); // ROAD RenderRoad(road); } void DrawNitro() { glColor3f(1, 1, 1); DrawPolygon(nitroGUI); glColor3f(1, 0, 0); DrawPolygon(nitroChargeGUI); } void DrawMotor(vector motorGUI) { glColor3f(0.55f, 1, 1); DrawPolygon(motorGUI); glColor3f(gray.r, gray.g, gray.b); DrawPolygon(brzinomer); glLineWidth(3); glColor3f(green.r, green.g, green.b); glBegin(GL_LINES); glVertex2f(kazaljka[0].x, kazaljka[0].y); glVertex2f(kazaljka[1].x, kazaljka[1].y); glEnd(); glLineWidth(1); DrawNitro(); } void Draw2D() { DrawMotor(motorGUI); glColor3f(0, 0, 0); glLineWidth(50); glBegin(GL_LINE_STRIP); glVertex2f(-0.2f, -0.85f); glVertex2f(0, -0.98f); glVertex2f(0.2f, -0.85f); glEnd(); glLineWidth(1); } void SpeedUp() { if (brzina < brojBrzina) { brzina++; printf("%d", brzina); Transform(translate(vec3(0, 0.6f, 0)), kazaljka); Transform(scale(vec3(ratio / 0.1f, 10.f, 10.f)), kazaljka); Transform(rotate((float)(-M_PI * 2 / 6.f), vec3(0, 0, 1)), kazaljka); Transform(scale(vec3(0.1f / ratio, 0.1f, 0.1f)), kazaljka); Transform(translate(vec3(0, -0.6f, 0)), kazaljka); } } void Brake() { if (brzina > 0) { brzina--; printf("%d", brzina); Transform(translate(vec3(0, 0.6f, 0)), kazaljka); Transform(scale(vec3(ratio / 0.1f, 10.f, 10.f)), kazaljka); Transform(rotate((float)(M_PI * 2 / 6.f), vec3(0, 0, 1)), kazaljka); Transform(scale(vec3(0.1f / ratio, 0.1f, 0.1f)), kazaljka); Transform(translate(vec3(0, -0.6f, 0)), kazaljka); } nitroChargeGUI[2] = nitroChargeGUI[1]; nitroChargeGUI[3] = nitroChargeGUI[0]; chargeTimer = 0; } void SteerLeft() { if(rotationAngle < maxRotationAngle) rotationAngle += rotationSpeed; } void SteerRight() { if (rotationAngle > -maxRotationAngle) rotationAngle -= rotationSpeed; } void Nitro() { if (chargeTimer >= 5) { nitroActive = true; // ISPRAVKA --------------------------------------------------------------------------------------------------------------------------- // Zaboravio da podelim dodatu brzinu sa framerate-om kmh += 50.f / (float)(FPS); } } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(100.f, 16.f / 9.f, 0.1f, 50.f); gluLookAt( MotorPosition.x, MotorPosition.y, MotorPosition.z, LookAt_vector.x, LookAt_vector.y, LookAt_vector.z, LookUp_vector.x, LookUp_vector.y, LookUp_vector.z ); Render3D(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glDisable(GL_DEPTH_TEST); Draw2D(); glEnable(GL_DEPTH_TEST); glutSwapBuffers(); } void timer(int v) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt( MotorPosition.x, MotorPosition.y, MotorPosition.z, LookAt_vector.x, LookAt_vector.y, LookAt_vector.z, LookUp_vector.x, LookUp_vector.y, LookUp_vector.z ); FixedUpdate(); glutTimerFunc(1000 / FPS, timer, v); glutPostRedisplay(); } void reshape(GLsizei width, GLsizei height) { if (height * ratio <= width) width = ratio * height; else height = width / ratio; glViewport(0, 0, width, height); } void initGL(void) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); } void mousePress(int button, int state, int x, int y) { switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) { //FUNKCIJA } break; case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) { //FUNKCIJA } break; default: break; } } void keyPress(unsigned char key, int x, int y) { switch (key) { case 27: //ESC key exit(0); break; case 'w': SpeedUp(); break; case 's': Brake(); break; case 'a': SteerLeft(); break; case 'd': SteerRight(); break; case ' ': Nitro(); break; } } /*--------------------------------------------------*/ int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL); glutInitWindowSize(height * ratio, height); glutInitWindowPosition(150, 50); glutCreateWindow(title); glutDisplayFunc(display); glutTimerFunc(100, timer, 0); glutReshapeFunc(reshape); glutMouseFunc(mousePress); glutKeyboardFunc(keyPress); OnLoad(); initGL(); glutMainLoop(); return 0; }