#define GLFW_INCLUDE_GL3 #define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_EXPOSE_NATIVE_WGL //#include #include #include "glfw3.h" #include "glfw3native.h" #include "SOIL.h" // Размеры окна, px int const WINDOW_W = 1024; int const WINDOW_H = 768; // Размеры игрового поля // Левый верхиний угол, px int const GAME_FIELD_X1 = 224; int const GAME_FIELD_Y1 = 54; // Правый нижний угол, px int const GAME_FIELD_X2 = 800; int const GAME_FIELD_Y2 = 630; // Необходимое количество правильно повернут труб для выигрыша int const NEED_TO_WIN = 15; // скорость анимации, параметр GL_ALPHA_FUNC float const ANIM_SPEED= 2.0f;//1.1f; // продолжительность анимации, с float const ANIM_TIME= 0.5f;//1.0f; // Файлы ресурсов const char* BACK_JPG = "back.jpg"; const int PIPE_MAX = 3; const int COLUM_MAX = 6; const int ROW_MAX = 6; const int PIPE_ON_FIELD_MAX = 36; const char* PIPE1 = "pipe1.png"; const char* PIPE3 = "pipe3.png"; const char* PIPE7 = "pipe7.png"; // Текстура трубы struct _pipe { GLuint id; // Идентификатор текстуры const char* file; // Файл ресурса }; // Труба на игровом поле struct _pipeInField { GLfloat x; // центр по x GLfloat y; // центр по y GLuint id; // Идентификатор текстуры GLuint angle_scale; // Множитель угола поворота GLuint win_angle_scale; // Множитель угола поворота необходимый для победы GLboolean is_in_right_path; // труба проходит через выигрышный путь }; namespace nsPipes { enum PipeName {P1, P3, P7}; } GLdouble mx, my; // Координаты мыши GLuint back_identif; // Идентификатор текстуры фона GLboolean IsMousePressedInGameFiled = false; GLint NeedAnimating = -1; // Идентификатор анимируемой трубы GLuint CompleteToWin = 0; // Количество правильно повернут труб для выигрыша GLboolean IsReversAnimating = false; // Флаг анимации (исчезает/появляется) GLboolean IsWin = false; // Флаг выигрыша _pipe Pipes[PIPE_MAX]; // Текстуры _pipeInField PipesInField[PIPE_ON_FIELD_MAX]; // Интерактивные объекты static void error_callback( int error, const char* description ) { //fputs(description, stderr); fputs(description, stderr); } static void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods ) { if ( key == GLFW_KEY_ESCAPE && action == GLFW_PRESS ) glfwSetWindowShouldClose( window, GL_TRUE ); } void mouse_button_callback( GLFWwindow* window, int button, int action, int mods ) { int const arraysize = 300; //TCHAR pszDest[arraysize]; char pszDest[arraysize]; //size_t cbDest = arraysize * sizeof(TCHAR); size_t cbDest = arraysize * sizeof( char ); if ( button != GLFW_MOUSE_BUTTON_LEFT ) return; if ( action == GLFW_PRESS ) { if (NeedAnimating == -1) { glfwGetCursorPos(window, &mx, &my); //StringCbPrintf(pszDest, cbDest, TEXT("mx: '%f' my: '%f'\n"), mx, my); //::OutputDebugString(pszDest); printf("mx: '%f' my: '%f'\n", mx, my); if ( (mx >= GAME_FIELD_X1 && mx <= GAME_FIELD_X2 ) && ( my >= GAME_FIELD_Y1 && my <= GAME_FIELD_Y2 ) ) { //StringCbPrintf(pszDest, cbDest, TEXT("Action\n")); printf( "Action\n" ); //::OutputDebugString(pszDest); IsMousePressedInGameFiled = true; } } } } void InitTexture() { int const arraysize = 300; TCHAR pszDest[arraysize]; size_t cbDest = arraysize * sizeof(TCHAR); Pipes[nsPipes::P1].file = PIPE1; Pipes[nsPipes::P3].file = PIPE3; Pipes[nsPipes::P7].file = PIPE7; // устанавливаем выравнивание glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); back_identif = SOIL_load_OGL_texture( BACK_JPG, SOIL_LOAD_RGB, SOIL_CREATE_NEW_ID, 0 ); if( back_identif == 0 ) { //StringCbPrintf (pszDest, cbDest, TEXT("SOIL loading error: '%s'\n"), SOIL_last_result()); //::OutputDebugString(pszDest); printf( "SOIL loading error: '%s'\n", SOIL_last_result() ) ; } //делаем текстуру активной glBindTexture( GL_TEXTURE_2D, back_identif ); //устанавливаем параметры текстуры glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); //устанавливаем взаимодействие текстуры с объектом glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); for ( int i = 0; i < PIPE_MAX; i++ ) { Pipes[i].id = SOIL_load_OGL_texture ( Pipes[i].file, SOIL_LOAD_RGBA, SOIL_CREATE_NEW_ID, 0 ); if ( Pipes[i].id == 0 ) { //StringCbPrintf( pszDest, cbDest, TEXT("SOIL loading error: '%s'\n"), SOIL_last_result() ); //::OutputDebugString( pszDest ); printf( "SOIL loading error: '%s'\n", SOIL_last_result() ) ; } glBindTexture( GL_TEXTURE_2D, Pipes[i].id ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); } // получаем действительные идентификаторы текстур for ( int i = 0; i < PIPE_ON_FIELD_MAX; i++ ) { PipesInField[i].id = Pipes[PipesInField[i].id].id; } } void SetupGLFW( GLFWwindow** window ) { GLFWmonitor* monitor; const GLFWvidmode* mode; glfwSetErrorCallback( error_callback ); /* Initialize the library */ if ( !glfwInit() ) exit( EXIT_FAILURE ); monitor = glfwGetPrimaryMonitor(); if ( !monitor ) { glfwTerminate(); exit( EXIT_FAILURE ); } glfwWindowHint( GLFW_RESIZABLE, GL_FALSE ); glfwWindowHint( GLFW_VISIBLE, GL_FALSE ); /* Create a windowed mode window and its OpenGL context */ *window = glfwCreateWindow( WINDOW_W, WINDOW_H, "WaterPipe", NULL, NULL ); if ( !window ) { glfwTerminate(); exit( EXIT_FAILURE ); } mode = glfwGetVideoMode( monitor ); glfwSetWindowPos( *window, ( mode->width - WINDOW_W ) / 2, ( mode->height - WINDOW_H ) / 2 ); /* Make the window's context current */ glfwMakeContextCurrent( *window ); glfwSetKeyCallback( *window, *key_callback ); //IsMousePressedInGameFiled = false; glfwSetMouseButtonCallback( *window, mouse_button_callback ); printf( "GL_VERSION: %s\n", glGetString( GL_VERSION ) ); printf( "GL_VENDOR: %s\n", glGetString( GL_VENDOR ) ); printf( "GL_RENDERER: %s\n", glGetString( GL_RENDERER ) ); glfwShowWindow( *window ); } void SetupGL( GLFWwindow* window, GLsizei &width, GLsizei &height ) { glEnable( GL_BLEND ); // straight alpha glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glClear( GL_COLOR_BUFFER_BIT ); // размер поля просмотра устанавливается равным размеру окна glfwGetFramebufferSize(window, &width, &height); glViewport( 0, 0, width, height ); glMatrixMode( GL_PROJECTION ); glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); glLoadIdentity(); if ( width <= height ) glOrtho( -1.0, 1.0, -1.0 * (float)height / width, 1.0 * (float)height / width, -1.0f, 1.0f ); else glOrtho( -1.0 * width / (float)height, 1.0 * width / (float)height, -1.0, 1.0, -1.0f, 1.0f ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } void SetupRC(GLboolean IsReSetup) { //glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); GLfloat step = 1.0f/384.0f; GLfloat half_pipe = 48.0f*step; GLfloat full_pipe = 96.0f*step; CompleteToWin = 0; // игровое поле с неправильными углами поворота труб GLuint angles[PIPE_ON_FIELD_MAX] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 3, 0, 0, 2, 0, 0, 3, 0, 0 }; // игровое поле с правильными для победы углами поворота труб GLuint win_angles[PIPE_ON_FIELD_MAX] = { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 3, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0 }; GLboolean checked_angles[PIPE_ON_FIELD_MAX] = { false, true, true, true, true, true, false, true, false, false, false, false, false, true, true, true, false, false, false, false, false, true, false, false, true, true, true, true, false, false, true, false, false, false, false, false }; // трубы на игровом поле GLuint id[PIPE_ON_FIELD_MAX] = { nsPipes::P7, nsPipes::P3, nsPipes::P1, nsPipes::P1, nsPipes::P1, nsPipes::P1, nsPipes::P1, nsPipes::P1, nsPipes::P7, nsPipes::P7, nsPipes::P1, nsPipes::P7, nsPipes::P7, nsPipes::P3, nsPipes::P1, nsPipes::P3, nsPipes::P3, nsPipes::P1, nsPipes::P1, nsPipes::P7, nsPipes::P7, nsPipes::P1, nsPipes::P3, nsPipes::P3, nsPipes::P3, nsPipes::P1, nsPipes::P1, nsPipes::P3, nsPipes::P7, nsPipes::P7, nsPipes::P3, nsPipes::P7, nsPipes::P7, nsPipes::P7, nsPipes::P1, nsPipes::P7 }; PipesInField[0].x = -240.0f*step; PipesInField[0].y = 282.5f*step; int i, x, y; for ( i = 0, y = 0; y < ROW_MAX; y++ ) { for ( x = 0; x < COLUM_MAX; x++ ) { PipesInField[i].x = PipesInField[0].x + full_pipe*x; PipesInField[i].y = PipesInField[0].y - full_pipe*y; // подготавливаем желаемые идентификаторы текстур if (!IsReSetup) { PipesInField[i].id = id[i]; } PipesInField[i].angle_scale = angles[i]; PipesInField[i].win_angle_scale = win_angles[i]; PipesInField[i].is_in_right_path = checked_angles[i]; if (PipesInField[i].angle_scale == PipesInField[i].win_angle_scale && PipesInField[i].is_in_right_path == true) { CompleteToWin++; } i++; } } } int SearchPipesToRotate() { GLfloat step = 1.0f/384.0f; GLfloat half_pipe = 48.0f*step; GLfloat full_pipe = 96.0f*step; GLdouble mXObj; GLdouble mYObj; int const arraysize = 300; TCHAR pszDest[arraysize]; size_t cbDest = arraysize * sizeof(TCHAR); // переводим оконные координаты курсора в объектные if ( ( mYObj = my - WINDOW_H/2 ) > WINDOW_H/2 ) { mYObj *= step; } else { mYObj *= -step; } mXObj = ( mx - WINDOW_W/2 ) * step; for ( int i = 0; i < PIPE_ON_FIELD_MAX; i++) { if ( ( PipesInField[i].x - half_pipe ) <= mXObj && (PipesInField[i].x + half_pipe ) >= mXObj && ( PipesInField[i].y - half_pipe ) <= mYObj && (PipesInField[i].y + half_pipe ) >= mYObj ) { //StringCbPrintf(pszDest, cbDest, TEXT("Action in Search: PipesInField[%d]\n"), i); //::OutputDebugString(pszDest); printf( "Action in Search: PipesInField[%d]\n", i ); // пустые клетки не поворачивать if ( PipesInField[i].id == Pipes[nsPipes::P7].id ) return -1; glfwSetTime( 0.0f ); return i; } } return -1; } void RenderScene( GLFWwindow* window, int &width, int &height, float &ratio ) { GLfloat step = 1.0f/384.0f; GLfloat half_pipe = 48.0f*step; GLfloat full_pipe = 96.0f*step; if ( IsMousePressedInGameFiled ) { NeedAnimating = SearchPipesToRotate(); IsMousePressedInGameFiled = false; } // рисуем фон glPushMatrix(); //glColor3f(1.0f, 1.0f, 1.0f); // разрешаем режим наложения текстуры glEnable(GL_TEXTURE_2D); // активная текстура - back.png glBindTexture(GL_TEXTURE_2D, back_identif); glBegin(GL_QUADS); glTexCoord2f(0.0f, 1.0f); glVertex2f(-ratio, -1.0f); // Низ лево glTexCoord2f(1.0f, 1.0f); glVertex2f( ratio, -1.0f); // Низ право glTexCoord2f(1.0f, 0.0f); glVertex2f( ratio, 1.0f); // Верх право glTexCoord2f(0.0f, 0.0f); glVertex2f(-ratio, 1.0f); // Верх лево glEnd(); glDisable( GL_TEXTURE_2D ); glPopMatrix(); // рисуем трубы for (int i = 0; i < PIPE_ON_FIELD_MAX; i++) { glPushMatrix(); glEnable( GL_TEXTURE_2D ); glTranslatef( PipesInField[i].x, PipesInField[i].y, 0.0 ); glRotatef( 90.0f * PipesInField[i].angle_scale, 0.0f, 0.0f, 1.0f ); if (i == NeedAnimating) { glEnable( GL_ALPHA_TEST ); if ( IsReversAnimating ) { if ( glfwGetTime() <= ANIM_TIME ) { glAlphaFunc( GL_LESS, (float) glfwGetTime() * ANIM_SPEED ); } else { IsReversAnimating = false; NeedAnimating = -1; glDisable( GL_ALPHA_TEST ); } } else { if ( glfwGetTime() <= ANIM_TIME ) { glAlphaFunc( GL_GREATER, (float) glfwGetTime() * ANIM_SPEED ); } else { if (PipesInField[i].angle_scale == 0) { if (PipesInField[i].id == Pipes[nsPipes::P1].id) { PipesInField[i].angle_scale = 1; } else { PipesInField[i].angle_scale = 3; } } else { PipesInField[i].angle_scale--; } for ( int j = 0, CompleteToWin = 0; j < PIPE_ON_FIELD_MAX; j++ ) { if ((PipesInField[j].angle_scale == PipesInField[j].win_angle_scale) && (PipesInField[j].is_in_right_path == true)) { CompleteToWin++; } if ( CompleteToWin == NEED_TO_WIN ) IsWin = true; } IsReversAnimating = true; glfwSetTime(0.0f); //glDisable( GL_ALPHA_TEST ); } } } glBindTexture(GL_TEXTURE_2D, PipesInField[i].id); glBegin(GL_QUADS); glTexCoord2f(0.0f, 1.0f); glVertex2f(-half_pipe, -half_pipe); // Низ лево glTexCoord2f(1.0f, 1.0f); glVertex2f(-half_pipe + full_pipe, -half_pipe); // Низ право glTexCoord2f(1.0f, 0.0f); glVertex2f(-half_pipe + full_pipe, -half_pipe + full_pipe); // Верх право glTexCoord2f(0.0f, 0.0f); glVertex2f(-half_pipe, -half_pipe + full_pipe); // Верх лево glEnd(); // запрещаем режим наложения текстуры if (i == NeedAnimating) { glDisable( GL_ALPHA_TEST ); } glDisable(GL_TEXTURE_2D); glPopMatrix(); } /* Swap front and back buffers */ glfwSwapBuffers(window); } int main(void) { printf("Start\n"); GLFWwindow* window = NULL; int ret_mbox = 0; float ratio = 0; GLsizei width = 0; GLsizei height = 0; SetupGLFW( &window ); SetupGL( window, width, height ); ratio = width / (float) height; GLfloat step = 1.0f/384.0f; GLfloat half_pipe = 48.0f*step; GLfloat full_pipe = 96.0f*step; SetupRC(false); InitTexture(); /* Loop until the user closes the window */ while (!glfwWindowShouldClose(window)) { /* Render here */ RenderScene( window, width, height, ratio ); if ( IsWin && ( glfwGetTime() > 2*ANIM_TIME ) ) { ret_mbox = ::MessageBox( glfwGetWin32Window( window ), TEXT("Вы выиграли!\r\nЖелаете сыграть еще раз?"), TEXT("WaterPipe"), MB_APPLMODAL | MB_ICONINFORMATION | MB_YESNO ); if ( ret_mbox == IDYES ) { SetupRC( true ); IsWin = false; } else { glfwDestroyWindow( window ); glfwTerminate(); exit( EXIT_SUCCESS ); } } /* Poll for and process events */ glfwPollEvents(); } glfwDestroyWindow( window ); glfwTerminate(); exit( EXIT_SUCCESS ); }