Esempio n. 1
0
void loadFontData(std::string path, std::vector<Glyph> &out, unsigned int &width, unsigned int &height) {
    TiXmlDocument file(path.c_str());

    if (!file.LoadFile()) {
        LOG("Unable to load font meta file: [%s]", path.c_str());
        return;
    }

    TiXmlElement *const root = file.RootElement();
    const char *textureName = root->Attribute("file");

    if (!textureName || !loadDDS(textureName, width, height)) {
        LOG("Unable to load texture file: [%s]", textureName);
        return;
    }

    for (TiXmlElement *current = root->FirstChildElement("character"); current; current = current->NextSiblingElement(
            "character")) {
        Glyph gl;
        current->Attribute("key", &gl.key);
        gl.height = extractIntValue("height", current);
        gl.width = extractIntValue("width", current);
        gl.x = extractIntValue("x", current);
        gl.y = extractIntValue("y", current);

        out.push_back(gl);
    }
}
Esempio n. 2
0
bool Texture::load(FS::IFile& file)
{
	PROFILE_FUNCTION();

	const char* path = getPath().c_str();
	size_t len = getPath().length();
	bool loaded = false;
	if (len > 3 && compareString(path + len - 4, ".dds") == 0)
	{
		loaded = loadDDS(file);
	}
	else if (len > 3 && compareString(path + len - 4, ".raw") == 0)
	{
		loaded = loadRaw(file);
	}
	else
	{
		loaded = loadTGA(file);
	}
	if (!loaded)
	{
		g_log_warning.log("Renderer") << "Error loading texture " << path;
		return false;
	}

	m_size = file.size();
	return true;
}
 ref<ResourceDatabase> loadResource(VirtualFile* file) const
 {
     ref<ResourceDatabase> res_db = new ResourceDatabase;
     ref<Image> img = loadDDS(file);
     if (img)
         res_db->resources().push_back(img);
     return res_db;
 }
Esempio n. 4
0
void STexture::bind()
{
    if (this==0) return;

    if (videoReady()) {
        QString s=frameFilename(updateCurrentFrame());
        loadDDS(s);
        //qDebug() << s << ": " << texture;
    } else if (currentTexName.size()>0) {
        loadDDS(currentTexName);
    }

    if (texture) {
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, texture);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    } else {
        glDisable(GL_TEXTURE_2D);
    }
}
Esempio n. 5
0
void BackupItem::setItemIcon(const QString &path, int item_width, bool try_dds)
{
    ui->itemPicture->setMinimumWidth(item_width);
    QPixmap pixmap(path);
    if((pixmap.width() <= 0 || pixmap.height() <= 0) && try_dds) {
        QImage image;
        if(loadDDS(path, &image)) {
            pixmap = QPixmap::fromImage(image);
        }
    }
    ui->itemPicture->setPixmap(pixmap);
}
Esempio n. 6
0
void Texture::loaded(FS::IFile& file, bool success, FS::FileSystem& fs)
{
	PROFILE_FUNCTION();
	if (success)
	{
		const char* path = m_path.c_str();
		size_t len = m_path.length();
		bool loaded = false;
		if (len > 3 && strcmp(path + len - 4, ".dds") == 0)
		{
			loaded = loadDDS(file);
		}
		else if (len > 3 && strcmp(path + len - 4, ".raw") == 0)
		{
			loaded = loadRaw(file);
		}
		else
		{
			loaded = loadTGA(file);
		}
		if (!loaded)
		{
			g_log_warning.log("renderer") << "Error loading texture "
										  << m_path.c_str();
			onFailure();
		}
		else
		{
			m_size = file.size();
			decrementDepCount();
		}
	}
	else
	{
		g_log_warning.log("renderer") << "Error loading texture "
									  << m_path.c_str();
		onFailure();
	}
}
Esempio n. 7
0
bool Image::loadSupportedFormat(const char* path_)
{
  const char *verifiedPath = MediaPathManager::lookUpMediaPath(path_);
  
  if (!verifiedPath)
    return false;
    
  path = verifiedPath;
  
  if (isPNG(verifiedPath))
    return loadPNG(verifiedPath, this);
    
  if (isJPEG(verifiedPath))
    return loadJPG(verifiedPath);
    
  if (isTGA(verifiedPath))
    return loadTGA(verifiedPath);
    
  if (isDDS(verifiedPath))
    return loadDDS(verifiedPath);
    
  return false;
}
Esempio n. 8
0
void InitializeResources() {

	printf("InitializeResources()\n");
	// Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
	ProjectionMatrix = glm::perspective(
		45.0f,		 // The horizontal Field of View, in degrees : the amount of "zoom". Think "camera lens". Usually between 90° (extra wide) and 30° (quite zoomed in)
		4.0f / 3.0f, // Aspect Ratio. Depends on the size of your window. Notice that 4/3 == 800/600 == 1280/960, sounds familiar ?
		0.1f,		 // Near clipping plane. Keep as big as possible, or you'll get precision issues.
		100.0f		 // Far clipping plane. Keep as little as possible.
		);
	// Or, for an ortho camera :
	//glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); // In world coordinates

	// Camera matrix
	ViewMatrix = glm::lookAt(
		cameraLoc, // Camera is cameraLoc, in World Space
		cameraDir, // and looks to cameraDir
		orientation  // Head is orientation
		);
	ModelMatrix = glm::mat4(1.0f); // Model matrix : an identity matrix (model will be at the origin)
	// Our ModelViewProjection : multiplication of our 3 matrices
	MVP = ProjectionMatrix * ViewMatrix * ModelMatrix; // Remember, matrix multiplication is the other way around

	//loads object
	bool res = LoadAssimp("Resources/cheb.obj", indices, vertices, uvs, normals);

	// index the vbo
	indices.clear();
	indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs, indexed_normals);

	//  Vertex Array Object and set it as the current one
	glGenVertexArrays(1, &VertexArrayID);
	glBindVertexArray(VertexArrayID);

	// Create and compile our GLSL program from the shaders
	//ShaderIDs[0] = LoadShaders( "VertexShader.vs", "FragmentShader.fs" );
	pickingProgramID = LoadShaders( "Picking.vertexshader", "Picking.fragmentshader" );
	gprogramID = LoadShaders( "TransformVertexShader.vertexshader", "ColorFragmentShader.fragmentshader" );
	ProgramID = LoadShaders( "VertexShader.vs", "FragmentShader.fs" );
	ShaderIDs[0] = ProgramID;
	ProgramID = LoadShaders( "WireFrame_VertexShader.vs", "FragmentShader.fs" );
	ShaderIDs[1] = ProgramID;
		// Get a handle for our uniforms
	MatrixID = glGetUniformLocation(ProgramID, "MVP");
	ViewMatrixID = glGetUniformLocation(ProgramID, "V");
	ModelMatrixID = glGetUniformLocation(ProgramID, "M");
	NormalMatrixID = glGetUniformLocation(ProgramID, "NormalMatrix");

	// Loads the texture
	Texture = loadDDS("Resources/purple.DDS");
	// Sets the uniform for the texture sampler
	TextureID = glGetUniformLocation(ProgramID, "myTexturesampler");

	// Generate a vertex buffer, put the resulting identifier in vertexbuffer
	glGenBuffers(1, &vertexbuffer);
	// The following commands will talk about our 'vertexbuffer' buffer
	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
	// Give our vertices to OpenGL.
	glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3), &indexed_vertices[0], GL_STATIC_DRAW);

	// Generate a vertex buffer, put the resulting identifier in vertexbuffer
	glGenBuffers(1, &uvbuffer);
	// The following commands will talk about our 'uvbuffer' buffer
	glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
	// Give our uv's to OpenGL.
	glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(glm::vec2), &indexed_uvs[0], GL_STATIC_DRAW);

	// Generate a normal buffer, put the resulting identifier in normalbuffer
	glGenBuffers(1, &normalbuffer);
	// The following commands will talk about our 'normalbuffer' buffer
	glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
	// Give our normal's to OpenGL.
	glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3), &indexed_normals[0], GL_STATIC_DRAW);

	// Generate a index buffer, put the resulting identifier in elementbuffer
	glGenBuffers(1, &elementbuffer);
	// The following commands will talk about our 'elementbuffer' buffer
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
	// Give our index's to OpenGL.
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);

	// Use our shader
	glUseProgram(ShaderIDs[0]);
	LightPosID = glGetUniformLocation(ProgramID, "lightPos");
	CameraID = glGetUniformLocation(ProgramID, "C");


	gVertexArrayID;
	glGenVertexArrays(1, &gVertexArrayID);
	glBindVertexArray(gVertexArrayID);

	gvertexbuffer;
	glGenBuffers(1, &gvertexbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, gvertexbuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

	colorbuffer;
	glGenBuffers(1, &colorbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);
}
Esempio n. 9
0
void Texture::Load(const std::string& fileName)
{
	m_texture = loadDDS("Content/Textures/" + fileName + ".DDS");
}
int tutorial_10(GLFWwindow* window)
{
	// Initialise GLFW
	if (!glfwInit())
	{
		fprintf(stderr, "Failed to initialize GLFW\n");
		return -1;
	}

	glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want OpenGL 3.3
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //We don't want the old OpenGL 

	// Open a window and create its OpenGL context
	window = glfwCreateWindow(1024, 768, "Tutorial 10: Transparency", NULL, NULL); // (In the accompanying source code, this variable is global) 
	if (window == NULL){
		fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
		glfwTerminate();
		return -1;
	}

	glfwMakeContextCurrent(window); // Initialize GLEW 
	glewExperimental = true; // Needed in core profile 
	if (glewInit() != GLEW_OK) {
		fprintf(stderr, "Failed to initialize GLEW\n");
		return -1;
	}

	// Ensure we can capture the escape key being pressed below
	glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);

	// Dark blue background
	glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

	// Enable depth test
	glEnable(GL_DEPTH_TEST);
	// Accept fragment if it closer to the camera than the former one
	glDepthFunc(GL_LESS);
	// Cull triangles which normal is not towards the camera
	//glEnable(GL_CULL_FACE);

	//Create VertexArray element & bind it
	GLuint VertexArrayID;
	glGenVertexArrays(1, &VertexArrayID);
	glBindVertexArray(VertexArrayID);

	// Create and compile our GLSL program from the shaders
	GLuint programID = LoadShaders("..\\external\\shaders\\tutorial10.vert", "..\\external\\shaders\\tutorial10.frag");

	// Get a handle for our "MVP" uniform
	GLuint MatrixID = glGetUniformLocation(programID, "MVP");
	GLuint ViewMatrixID = glGetUniformLocation(programID, "V");
	GLuint ModelMatrixID = glGetUniformLocation(programID, "M");

	// Load the texture using any two methods
	//GLuint Texture = loadBMP_custom("..\\external\\textures\\uvtemplate.bmp");
	GLuint Texture = loadDDS("..\\external\\textures\\uvmap.DDS");

	// Get a handle for our "myTextureSampler" uniform
	GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler");

	// Read our .obj file
	std::vector<glm::vec3> vertices;
	std::vector<glm::vec2> uvs;
	std::vector<glm::vec3> normals;
	bool res = loadOBJ("..\\external\\objects\\suzanne.obj", vertices, uvs, normals);

	std::vector<unsigned short> indices;
	std::vector<glm::vec3> indexed_vertices;
	std::vector<glm::vec2> indexed_uvs;
	std::vector<glm::vec3> indexed_normals;
	indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs, indexed_normals);

	// Load it into a VBO

	GLuint vertexbuffer;
	glGenBuffers(1, &vertexbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);

	GLuint uvbuffer;
	glGenBuffers(1, &uvbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
	glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(glm::vec2), &uvs[0], GL_STATIC_DRAW);

	GLuint normalbuffer;
	glGenBuffers(1, &normalbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
	glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW);

	// Generate a buffer for the indices as well
	GLuint elementbuffer;
	glGenBuffers(1, &elementbuffer);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);

	// Get a handle for our "LightPosition" uniform
	glUseProgram(programID);
	GLuint LightID = glGetUniformLocation(programID, "LightPosition_worldspace");

	// Enable blending
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	do{
		// Clear the screen
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		// Use our shader
		glUseProgram(programID);

		// Compute the MVP matrix from keyboard and mouse input
		computeMatricesFromInputs(window);
		glm::mat4 ProjectionMatrix = getProjectionMatrix();
		glm::mat4 ViewMatrix = getViewMatrix();
		glm::mat4 ModelMatrix = glm::mat4(1.0);
		glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;

		// Send our transformation to the currently bound shader,
		// in the "MVP" uniform
		glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
		glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
		glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);

		glm::vec3 lightPos = glm::vec3(4, 4, 4);
		glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);

		// Bind our texture in Texture Unit 0
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, Texture);
		// Set our "myTextureSampler" sampler to user Texture Unit 0
		glUniform1i(TextureID, 0);

		// 1rst attribute buffer : vertices
		glEnableVertexAttribArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
		glVertexAttribPointer(
			0,                  // attribute. No particular reason for 0, but must match the layout in the shader.
			3,                  // size
			GL_FLOAT,           // type
			GL_FALSE,           // normalized?
			0,                  // stride
			(void*)0            // array buffer offset
			);

		// 2nd attribute buffer : UVs
		glEnableVertexAttribArray(1);
		glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
		glVertexAttribPointer(
			1,                                // attribute. No particular reason for 1, but must match the layout in the shader.
			2,                                // size : U+V => 2
			GL_FLOAT,                         // type
			GL_FALSE,                         // normalized?
			0,                                // stride
			(void*)0                          // array buffer offset
			);

		// 3rd attribute buffer : normals
		glEnableVertexAttribArray(2);
		glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
		glVertexAttribPointer(
			2,                                // attribute
			3,                                // size
			GL_FLOAT,                         // type
			GL_FALSE,                         // normalized?
			0,                                // stride
			(void*)0                          // array buffer offset
			);

		// Index buffer
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);

		// Draw the triangle !
		glDrawArrays(GL_TRIANGLES, 0, vertices.size());

		glDisableVertexAttribArray(0);
		glDisableVertexAttribArray(1);
		glDisableVertexAttribArray(2);

		// Swap buffers
		glfwSwapBuffers(window);
		glfwPollEvents();

	} // Check if the ESC key was pressed or the window was closed
	while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
	glfwWindowShouldClose(window) == 0);

	// Cleanup VBO and shader
	glDeleteBuffers(1, &vertexbuffer);
	glDeleteBuffers(1, &uvbuffer);
	glDeleteBuffers(1, &normalbuffer);
	glDeleteBuffers(1, &elementbuffer);
	glDeleteProgram(programID);
	glDeleteVertexArrays(1, &TextureID);
	glDeleteVertexArrays(1, &VertexArrayID);

	// Close OpenGL window and terminate GLFW
	glfwTerminate();

	return 0;
}
void ParticleSystem::initialize()
{
    initialized = true;
    Shader manager;

    /* sync data */
    gravity_y = gravity[Y];
    max_particles = m_max_particles;
    particle_direction[X] = main_direction[X];
    particle_direction[Y] = main_direction[Y];
    particle_direction[Z] = main_direction[Z];

    particles.resize(max_particles);
    getCameraMatrices();

    if (system_type != POINTS) {
        position_size_data = new GLfloat[max_particles * 4];
        color_data = new GLubyte[max_particles * 4];
        age_data = new GLfloat[max_particles];

        // Create and compile our GLSL program from the shaders
        programID = manager.loadShader(vertex_shader.c_str(), fragment_shader.c_str());

        // Vertex shader
        CameraRight_worldspace_ID = glGetUniformLocation(programID, "CameraRight_worldspace");
        CameraUp_worldspace_ID = glGetUniformLocation(programID, "CameraUp_worldspace");
        ViewProjMatrixID = glGetUniformLocation(programID, "VP");

        // fragment shader
        texture_ID  = glGetUniformLocation(programID, "myTextureSampler");

        /* get handle for buffers */
        squareVerticesID = glGetAttribLocation(programID, "squareVertices");
        xyzsID = glGetAttribLocation(programID, "xyzs");
        colorID = glGetAttribLocation(programID, "color");
        ageID = glGetAttribLocation(programID, "age");

        /* load dds files */
        if (system_type == DDS){
            texture = loadDDS(texture_file.c_str());
        }
        /* load ppm files */
        else if (system_type == IMAGE) {
            ppm image(texture_file);
            texture = image.createAsTexture();
        }

        /* VBO containing the particle billboard used to instance particles */
        glGenBuffers(1, &billboard_vertex_buffer);
        glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), 
                     g_vertex_buffer_data, GL_STATIC_DRAW);

        /* VBO containing the positions and sizes of the particles */
        glGenBuffers(1, &particles_position_buffer);
        glBindBuffer(GL_ARRAY_BUFFER, particles_position_buffer);
        glBufferData(GL_ARRAY_BUFFER, max_particles * 4 * sizeof(GLfloat), NULL, 
                     GL_STREAM_DRAW);

        /* The VBO containing particle colors */
        glGenBuffers(1, &particles_color_buffer);
        glBindBuffer(GL_ARRAY_BUFFER, particles_color_buffer);
        glBufferData(GL_ARRAY_BUFFER, max_particles * 4 * sizeof(GLubyte), NULL, 
                     GL_STREAM_DRAW);

        /* The VBO containing particle age */
        glGenBuffers(1, &particles_age_buffer);
        glBindBuffer(GL_ARRAY_BUFFER, particles_age_buffer);
        glBufferData(GL_ARRAY_BUFFER, max_particles * sizeof(GLfloat), NULL, 
                     GL_STREAM_DRAW);
    }
    last_time = glutGet(GLUT_ELAPSED_TIME);
}
Esempio n. 12
0
void test_10(){
    ////Test most basic Texturing
    int universeWidth = 720;
    int universeHeight = 480;

    int AmountOfObjects = 3;

    double pixRatio = 50;

    glfwWindowHint(GLFW_SAMPLES, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

    Universe universe(universeWidth/pixRatio, universeHeight/pixRatio);
    Window window = Window(&universe, pixRatio);

    addRandomObjects(universe,1,AmountOfObjects);
    glClearColor(0.2, 0.2, 0.3, 1.0);


    GLuint Texture = loadDDS("Asteroid.DDS");

    TextureShader myShader(Texture);
    GLuint programID = myShader.programID;
    // Get a handle for our "MVP" uniform
    glm::vec4 colour = {1.0f, 0.0f,0.0f,1.0f};
    CircleShader myCircle(colour);
    //myCircle.colour=colour;
    double size;
    double step = 0.001;
    double phi = 0.003;
    const GLfloat c = cos(phi);
    const GLfloat s = sin(phi);
    glm::mat3 rot = {
            c, -s, 0,
            s,  c, 0,
            0,  0, 1
    };
    do{
        size = cos(step+=0.01);
        myCircle.tMatrixReset();
        myCircle.tMatrixTranslate({size,0.0});
        myCircle.tMatrixScale({size,size});

        myShader.transformationMatrix *= rot;
        // Clear the screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        myShader.draw();
        myCircle.draw();
        // Swap buffers
        glfwSwapBuffers(window.GLFWpointer);
        glfwPollEvents();

    } // Check if the ESC key was pressed or the window was closed
    while( glfwGetKey(window.GLFWpointer, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
           glfwWindowShouldClose(window.GLFWpointer) == 0 );


    // Close OpenGL window and terminate GLFW
    glfwTerminate();
}
Esempio n. 13
0
Texture::Texture(char* filepath) {
	textureID = loadDDS(filepath);
}
Esempio n. 14
0
Texture::Texture(const char * texturePath) {
	loaded = loadDDS(texturePath);
}
Esempio n. 15
0
bool STexture::clearAndLoadDDS(QString s)
{
    clearCallBacks();
    return loadDDS(s);
}
MillerRender::MillerRender()
{
    gLookAtOther = true;
    gPosition1 = vec3(-1.5f, 0.0f, 0.0f);
   //  gOrientation1;
     // Initialise GLFW
     if( !glfwInit() )
     {
         fprintf( stderr, "Failed to initialize GLFW\n" );
         //return -1;exit
     }

     glfwWindowHint(GLFW_SAMPLES, 4);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

     // Open a window and create its OpenGL context
     window = glfwCreateWindow( 1024, 768, "Tutorial 17 - Rotations", NULL, NULL);
     if( window == NULL ){
         fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
         glfwTerminate();
        // return -1;exit
     }
     glfwMakeContextCurrent(window);

     // Initialize GLEW
     glewExperimental = true; // Needed for core profile
     if (glewInit() != GLEW_OK) {
         fprintf(stderr, "Failed to initialize GLEW\n");
        // return -1; exit
     }


     //initGL(window);

     // Initialize the GUI
     TwInit(TW_OPENGL_CORE, NULL);
     TwWindowSize(1024, 768);
     TwBar * EulerGUI = TwNewBar("Euler settings");
    //     TwBar * QuaternionGUI = TwNewBar("Quaternion settings");
     TwSetParam(EulerGUI, NULL, "refresh", TW_PARAM_CSTRING, 1, "0.1");
  //       TwSetParam(QuaternionGUI, NULL, "position", TW_PARAM_CSTRING, 1, "808 16");

     TwAddVarRW(EulerGUI, "Euler X", TW_TYPE_FLOAT, &gOrientation1.x, "step=0.01");
     TwAddVarRW(EulerGUI, "Euler Y", TW_TYPE_FLOAT, &gOrientation1.y, "step=0.01");
     TwAddVarRW(EulerGUI, "Euler Z", TW_TYPE_FLOAT, &gOrientation1.z, "step=0.01");
     TwAddVarRW(EulerGUI, "Pos X"  , TW_TYPE_FLOAT, &gPosition1.x, "step=0.1");
     TwAddVarRW(EulerGUI, "Pos Y"  , TW_TYPE_FLOAT, &gPosition1.y, "step=0.1");
     TwAddVarRW(EulerGUI, "Pos Z"  , TW_TYPE_FLOAT, &gPosition1.z, "step=0.1");


     //TwAddVarRW(QuaternionGUI, "Quaternion", TW_TYPE_QUAT4F, &gOrientation2, "showval=true open=true ");
     //TwAddVarRW(QuaternionGUI, "Use LookAt", TW_TYPE_BOOL8 , &gLookAtOther, "help='Look at the other monkey ?'");

     // Set GLFW event callbacks. I removed glfwSetWindowSizeCallback for conciseness
     glfwSetMouseButtonCallback(window, (GLFWmousebuttonfun)TwEventMouseButtonGLFW); // - Directly redirect GLFW mouse button events to AntTweakBar
     glfwSetCursorPosCallback(window, (GLFWcursorposfun)TwEventMousePosGLFW);          // - Directly redirect GLFW mouse position events to AntTweakBar
     glfwSetScrollCallback(window, (GLFWscrollfun)TwEventMouseWheelGLFW);    // - Directly redirect GLFW mouse wheel events to AntTweakBar
     glfwSetKeyCallback(window, (GLFWkeyfun)TwEventKeyGLFW);                         // - Directly redirect GLFW key events to AntTweakBar
     glfwSetCharCallback(window, (GLFWcharfun)TwEventCharGLFW);                      // - Directly redirect GLFW char events to AntTweakBar



     // Ensure we can capture the escape key being pressed below
     glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
     glfwSetCursorPos(window, 1024/2, 768/2);

     // Dark blue background
     glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

     // Enable depth test
     glEnable(GL_DEPTH_TEST);
     // Accept fragment if it closer to the camera than the former one
     glDepthFunc(GL_LESS);

     // Cull triangles which normal is not towards the camera
     glEnable(GL_CULL_FACE);


     // Read our .obj file
     std::vector<unsigned short> indices;
     std::vector<glm::vec3> indexed_vertices;
     std::vector<glm::vec2> indexed_uvs;
     std::vector<glm::vec3> indexed_normals;

     // load model
     //char* file = "/home/kaeon/MyProgram/src/rim.stl";
     //char* file = "/home/kaeon/MyProgram/src/box.stl";
     char* file = "/home/kaeon/MyProgram/OpenGL-33-myproject/src/cube.obj";
     //char* file = "/home/kaeon/MyProgram/OpenGL-33-myproject/src/ES4.STL";

     //char* file = "/home/kaeon/MyProgram/src/suzanne.obj";
     //char* file = "/home/kaeon/MyProgram/src/monkey.obj";
     //loadOBJ(file,outIndices,vertexArray,uvArray,normalArray);

     //bool res = loadAssImp(file, indices, indexed_vertices, indexed_uvs, indexed_normals);
     loadOBJ(file, indices,indexed_vertices,indexed_uvs,indexed_normals);

     ChangeVerticesCoord(indexed_vertices);



     GLuint VertexArrayID;   
     glGenVertexArrays(1, &VertexArrayID);
     glBindVertexArray(VertexArrayID);
     GLuint WP_VertexArrayID;
     glGenVertexArrays(1, &WP_VertexArrayID);
     glBindVertexArray(WP_VertexArrayID);

     // Create and compile our GLSL program from the shaders
     //GLuint programID = LoadShaders( "/home/kaeon/MyProgram/opengl_test_success/SimpleTransform.vertexshader", "/home/kaeon/MyProgram/opengl_test_success/SingleColor.fragmentshader" );
     programID = LoadShaders(
                 "/home/kaeon/MyProgram/OpenGL-33-myproject/src/StandardShading.vertexshader",
                 "/home/kaeon/MyProgram/OpenGL-33-myproject/src/StandardShading.fragmentshader" );


     // Get a handle for our "MVP" uniform
     MatrixID = glGetUniformLocation(programID, "MVP");
     ViewMatrixID = glGetUniformLocation(programID, "V");
     ModelMatrixID = glGetUniformLocation(programID, "M");

     // Load the texture
     Texture = loadDDS("/home/kaeon/MyProgram/OpenGL-33-myproject/src/uvmap.DDS");

     // Get a handle for our "myTextureSampler" uniform
     TextureID  = glGetUniformLocation(programID, "myTextureSampler");


     /***==================== My triangle=============================e **/
     std::vector<unsigned short> indices2;//(101*101);
     std::vector<glm::vec3> indexed_vertices2;//(101*101);
     std::vector<glm::vec2> indexed_uvs2;
     std::vector<glm::vec3> indexed_normals2;
     //
     /*
     for (int i = 0; i < 101; i++) {
         for (int j = 0; j < 101; j++) {
             double z = sin(float(i)/10.0)*sin(float(i)/10.0);
             indexed_vertices2[i] = glm::vec3( i-50, j-50, z-20.0);
         }
     }*/
     //   CalculateIndices(indices2);
     // calculate indices
     //loadOBJ("/home/kaeon/MyProgram/OpenGL-33-myproject/src/ES4.STL", indices2,indexed_vertices2,indexed_uvs2,indexed_normals2);
     loadOBJ("/home/kaeon/MyProgram/OpenGL-33-myproject/src/cube.obj", indices2,indexed_vertices2,indexed_uvs2,indexed_normals2);

     ChangeVerticesCoord(indexed_vertices2);
     /***==================================================================**/



     // Load it into a VBO

     GLuint vertexbuffer;
     glGenBuffers(1, &vertexbuffer);
     glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
//     glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3), &indexed_vertices[0], GL_STATIC_DRAW);
     glBufferData(GL_ARRAY_BUFFER, (indexed_vertices.size() + indexed_vertices2.size()) * sizeof(glm::vec3), 0, GL_STATIC_DRAW);
     glBufferSubData(GL_ARRAY_BUFFER, 0 ,indexed_vertices.size()*sizeof(glm::vec3), &indexed_vertices[0] );
     glBufferSubData(GL_ARRAY_BUFFER, indexed_vertices.size()*sizeof(glm::vec3), indexed_vertices2.size()*sizeof(glm::vec3), &indexed_vertices2[0]);


     GLuint uvbuffer;
     glGenBuffers(1, &uvbuffer);
     glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
     //glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(glm::vec2), &indexed_uvs[0], GL_STATIC_DRAW);
     glBufferData(GL_ARRAY_BUFFER, (indexed_uvs.size()+indexed_uvs2.size() )* sizeof(glm::vec2), 0, GL_STATIC_DRAW);
     glBufferSubData(GL_ARRAY_BUFFER, 0 ,indexed_uvs.size()*sizeof(glm::vec2), &indexed_uvs[0] );
     glBufferSubData(GL_ARRAY_BUFFER, indexed_uvs.size()*sizeof(glm::vec2), indexed_uvs2.size()*sizeof(glm::vec2), &indexed_uvs2[0]);

     GLuint normalbuffer;
     glGenBuffers(1, &normalbuffer);
     glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
     //glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3), &indexed_normals[0], GL_STATIC_DRAW);
     glBufferData(GL_ARRAY_BUFFER, (indexed_normals.size()+indexed_normals2.size() )* sizeof(glm::vec3), 0, GL_STATIC_DRAW);
     glBufferSubData(GL_ARRAY_BUFFER, 0 ,indexed_normals.size()*sizeof(glm::vec3), &indexed_normals[0] );
     glBufferSubData(GL_ARRAY_BUFFER, indexed_normals.size()*sizeof(glm::vec3), indexed_normals2.size()*sizeof(glm::vec3), &indexed_normals2[0]);


     // Generate a buffer for the indices as well
     GLuint elementbuffer;
     glGenBuffers(1, &elementbuffer);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
     //glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0] , GL_STATIC_DRAW);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, (indices.size()+indices2.size() )* sizeof(unsigned short), 0, GL_STATIC_DRAW);
     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0 ,indices.size()*sizeof(unsigned short), &indices[0] );
     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned short), indices2.size()*sizeof(unsigned short), &indices2[0]);

     // Get a handle for our "LightPosition" uniform
     glUseProgram(programID);
     GLuint LightID = glGetUniformLocation(programID, "LightPosition_worldspace");


     // For speed computation
     double lastTime = glfwGetTime();
     double lastFrameTime = lastTime;
     int nbFrames = 0;
     std::cout<<"test0"<<std::endl;
         float tt = 0.0;
     do{

         // Measure speed
         double currentTime = glfwGetTime();

         float deltaTime = (float)(currentTime - lastFrameTime);
         lastFrameTime = currentTime;

         nbFrames++;
         if ( currentTime - lastTime >= 1.0 ){ // If last prinf() was more than 1sec ago
             // printf and reset
             printf("%f ms/frame\n", 1000.0/double(nbFrames));
             nbFrames = 0;
             lastTime += 1.0;
         }


         // Clear the screen
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

         // Use our shader
         glUseProgram(programID);

         /*
         // Compute the MVP matrix from keyboard and mouse input
      //   computeMatricesFromInputs();
         glm::mat4 ProjectionMatrix = getProjectionMatrix();
         glm::mat4 ViewMatrix = getViewMatrix();
         glm::mat4 ModelMatrix = glm::mat4(1.0);
         glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;

         // Send our transformation to the currently bound shader,
         // in the "MVP" uniform
         glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
         glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
         glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
 */
         glm::mat4 ProjectionMatrix = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 110.0f);// display range
         glm::mat4 ViewMatrix = glm::lookAt(
                     //glm::vec3( 0, 0, 70 ), // Camera is here
                     glm::vec3( 20,30, 70 ), // Camera is here
                     //glm::vec3(gOrientation1.x,0,0),// and looks here
                    glm::vec3( 0, 0, 0 ), // and looks here
                     //glm::vec3( 0, 1, 0 )  // Head is up (set to 0,-1,0 to look upside-down)
                     glm::vec3( 3, 10, 5 )  // Head is up (set to 0,-1,0 to look upside-down)
                     );


         glm::vec3 lightPos = glm::vec3(gPosition1.x,2,10);
           //glm::vec3 lightPos = glm::vec3(0,2,10);
         glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);

         // Bind our texture in Texture Unit 0
         glActiveTexture(GL_TEXTURE0);
         glBindTexture(GL_TEXTURE_2D, Texture);
         // Set our "myTextureSampler" sampler to user Texture Unit 0
         glUniform1i(TextureID, 0);

         // 1rst attribute buffer : vertices
         glEnableVertexAttribArray(0);
         glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
         glVertexAttribPointer(
                     0,                  // attribute
                     3,                  // size
                     GL_FLOAT,           // type
                     GL_FALSE,           // normalized?
                     0,                  // stride
                     (void*)0            // array buffer offset
                     );


         // 2nd attribute buffer : UVs
         glEnableVertexAttribArray(1);
         glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
         glVertexAttribPointer(
                     1,                                // attribute
                     2,                                // size
                     GL_FLOAT,                         // type
                     GL_FALSE,                         // normalized?
                     0,                                // stride
                     (void*)0                          // array buffer offset
                     );

         // 3rd attribute buffer : normals
         glEnableVertexAttribArray(2);
         glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
         glVertexAttribPointer(
                     2,                                // attribute
                     3,                                // size
                     GL_FLOAT,                         // type
                     GL_FALSE,                         // normalized?
                     0,                                // stride
                     (void*)0                          // array buffer offset
                     );

         // Index buffer
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);


         glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);


         { // Euler

             // As an example, rotate arount the vertical axis at 180\B0/sec
         /*    gOrientation1.z += 3.14159f/2.0f * deltaTime * 5;
             gOrientation1.x = 3.14159f/2;
             gPosition1.y = 40;

             // Build the model matrix
             glm::mat4 RotationMatrix = eulerAngleYXZ(gOrientation1.y, gOrientation1.x, gOrientation1.z);
             glm::mat4 TranslationMatrix = translate(mat4(), gPosition1); // A bit to the left
             glm::mat4 ScalingMatrix = scale(mat4(), vec3(1.0f, 1.0f, 1.0f));
             glm::mat4 ModelMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix;*/
             gOrientation1.z += 3.14159f/2.0f * deltaTime;
             gOrientation1.x = 20;3.14159f/2;
             gPosition1.y = 10;
             tt = tt + 0.01f;
             gPosition1.x = 20.0*sin(tt);
             //gPosition1.z = tt;//20.0*sin(tt);

             // Build the model matrix
             glm::mat4 RotationMatrix = eulerAngleYXZ(gOrientation1.y, gOrientation1.x, gOrientation1.z);
             glm::mat4 TranslationMatrix = translate(mat4(), gPosition1); // A bit to the left
             glm::mat4 ScalingMatrix = scale(mat4(), vec3(1.0f, 1.0f, 1.0f));
            glm::mat4 ModelMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix;
            //  glm::mat4 ModelMatrix = eulerAngleYXZ((float)3,(float)0,(float)0)*translate(mat4(), glm::vec3(5,0,0)) *TranslationMatrix* RotationMatrix * ScalingMatrix;



             glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;

             // Send our transformation to the currently bound shader,
             // in the "MVP" uniform
             glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
             glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
             glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);



             // Draw the triangles !
             glDrawElements(
                         GL_TRIANGLES,      // mode
                         indices.size(),    // count
                         GL_UNSIGNED_SHORT,   // type
                         (void*)0           // element array buffer offset
                         );

         }
//=============================================================================//
         glEnableVertexAttribArray(0);
         glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
         glVertexAttribPointer(
                     0,                  // attribute
                     3,                  // size
                     GL_FLOAT,           // type
                     GL_FALSE,           // normalized?
                     0,                  // stride
                     (void*)(0+indexed_vertices.size()*sizeof(glm::vec3))            // array buffer offset
                     );


         // 2nd attribute buffer : UVs
         glEnableVertexAttribArray(1);
         glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
         glVertexAttribPointer(
                     1,                                // attribute
                     2,                                // size
                     GL_FLOAT,                         // type
                     GL_FALSE,                         // normalized?
                     0,                                // stride
                     (void*)(0+indexed_uvs.size()*sizeof(glm::vec2))                          // array buffer offset
                     );

         // 3rd attribute buffer : normals
         glEnableVertexAttribArray(2);
         glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
         glVertexAttribPointer(
                     2,                                // attribute
                     3,                                // size
                     GL_FLOAT,                         // type
                     GL_FALSE,                         // normalized?
                     0,                                // stride
                     (void*)(0+indexed_normals.size()*sizeof(glm::vec3))                          // array buffer offset
                     );

         // Index buffer
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);


         glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);


         { // Euler

             // As an example, rotate arount the vertical axis at 180\B0/sec
         /*    gOrientation1.z += 3.14159f/2.0f * deltaTime * 5;
             gOrientation1.x = 3.14159f/2;
             gPosition1.y = 40;

             // Build the model matrix
             glm::mat4 RotationMatrix = eulerAngleYXZ(gOrientation1.y, gOrientation1.x, gOrientation1.z);
             glm::mat4 TranslationMatrix = translate(mat4(), gPosition1); // A bit to the left
             glm::mat4 ScalingMatrix = scale(mat4(), vec3(1.0f, 1.0f, 1.0f));
             glm::mat4 ModelMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix;*/
             gOrientation1.z += 3.14159f/2.0f * deltaTime/1000.0;
             gOrientation1.x = 3.14159f/2;
             gPosition1.y = 10;40;
             tt = tt + 0.01f;
             gPosition1.x = 20.0*sin(tt/100.0);
             //gPosition1.z = tt;//20.0*sin(tt);

             // Build the model matrix
             glm::mat4 RotationMatrix = eulerAngleYXZ(gOrientation1.y, gOrientation1.x, gOrientation1.z);
             glm::mat4 TranslationMatrix = translate(mat4(), gPosition1); // A bit to the left
             glm::mat4 ScalingMatrix = scale(mat4(), vec3(1.0f, 1.0f, 1.0f));
            glm::mat4 ModelMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix;
            //  glm::mat4 ModelMatrix = eulerAngleYXZ((float)3,(float)0,(float)0)*translate(mat4(), glm::vec3(5,0,0)) *TranslationMatrix* RotationMatrix * ScalingMatrix;



             glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;

             // Send our transformation to the currently bound shader,
             // in the "MVP" uniform
             glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
             glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
             glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);



             // Draw the triangles !
             glDrawElements(
                         GL_TRIANGLES,      // mode
                         indices2.size(),    // count
                         GL_UNSIGNED_SHORT,   // type
                         (void*)(0 + indices.size())           // element array buffer offset
                         );

         }


         //======================================================================================//



         glDisableVertexAttribArray(0);
         glDisableVertexAttribArray(1);
         glDisableVertexAttribArray(2);

         // Draw GUI
         TwDraw();

         // Swap buffers
         glfwSwapBuffers(window);
         glfwPollEvents();

     } // Check if the ESC key was pressed or the window was closed
     while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
            glfwWindowShouldClose(window) == 0 );

     // Cleanup VBO and shader
     glDeleteBuffers(1, &vertexbuffer);
     glDeleteBuffers(1, &uvbuffer);
     glDeleteBuffers(1, &normalbuffer);
     glDeleteBuffers(1, &elementbuffer);
     glDeleteProgram(programID);
     glDeleteTextures(1, &Texture);
     glDeleteVertexArrays(1, &VertexArrayID);
     glDeleteVertexArrays(1, &WP_VertexArrayID);
}
Esempio n. 17
0
void
TextureLoader::load( const std::string& _path,
					 const FILE_FORMAT _fileFormat )
{
	// argument checks
	if ( _path.empty() )
		GEM_ERROR( "Path argument is empty." );


	// always create new
	if ( isLoaded_ )
		clear();


	// local variables
	FILE_FORMAT fileFormat = _fileFormat;
	std::string path = _path;


	// split path
	std::string dir, name, ext;
	splitPath( path, &dir, &name, &ext );


	// Tell the user that we are trying to load the file
	GEM_CONSOLE( "Loading texture " + name + (ext.empty() ? "" : ".") + ext );


	// Determine file format from extension
	if ( fileFormat == FILE_FORMAT_NONE )
	{
		if ( ext == "bmp" )
		{
			fileFormat = FILE_FORMAT_BMP;
		}
		else if ( ext == "pfm" )
		{
			fileFormat = FILE_FORMAT_PFM;
		}
		else if ( ext == "dds" )
		{
			fileFormat = FILE_FORMAT_DDS;
		}
	}


	// activate the right file loader depending on file type
	try
	{
		switch ( fileFormat )
		{
		case FILE_FORMAT_BMP:
			loadBMP( path );
			break;
		case FILE_FORMAT_PFM:
			loadPFM( path );
			break;
		case FILE_FORMAT_DDS:
			loadDDS( path );
			break;
		default:
			GEM_THROW( "Unsupported file type ." + ext );
			break;
		}
	}
	catch( const std::exception& e )
	{
		clear();
		GEM_ERROR( e.what() );
	}


	// we got this far, so we are ok to setup member variables
	path_ = path;
	fileFormat_ = fileFormat;
	isLoaded_ = true;
}