text: #include "Viewport3DView.h"
  
  #include <imgui.h>
  #include <string>
  #include <vector>
  #include <iostream>
  #include <fstream>
  #include <sstream>
  
  
  
  Viewport3DView::Viewport3DView(Viewport3DModel &model) : model(model) {
  	this->Init();
  }
  
  Viewport3DView::~Viewport3DView() {
  	this->DeInit();
  }
  
  void Viewport3DView::Init() {
  
  	// framebuffer configuration
      // -------------------------
  
  	 // framebuffer configuration
  	// -------------------------
  	
  	glGenFramebuffers(1, &framebuffer);
  	glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  	// create a color attachment texture
  	
  	glGenTextures(1, &textureColorbuffer);
  	glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
  	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
  	// create a renderbuffer object for depth and stencil attachment (we won't be sampling these)
  	
  	glGenRenderbuffers(1, &rbo);
  	glBindRenderbuffer(GL_RENDERBUFFER, rbo);
  	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600); // use a single renderbuffer object for both a depth AND stencil buffer.
  	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it
  
  
  	// now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
  	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
  
  
  	}
  		//cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
  	glBindFramebuffer(GL_FRAMEBUFFER, 0);
  
  
  
  	// opengl trianle
  	// Generate 1 buffer, put the resulting identifier in vertexbuffer
  	glGenBuffers(1, &this->vertexbuffer);
  	// The following commands will talk about our 'vertexbuffer' buffer
  	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
  	// Give our vertices to OpenGL.
  	
  	static const GLfloat g_vertex_buffer_data[] = {
     -1.0f, -1.0f, 0.0f,
     1.0f, -1.0f, 0.0f,
     0.0f,  1.0f, 0.0f,
  	};
  	glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
  
  	this->ProgramID = this->loadShaders();
  }
  
  void Viewport3DView::Render() {
  
  	ImGui::Begin("3D Viewport", &this->isOpen, ImGuiWindowFlags_NoScrollbar);
  
  	ImVec2 vMin = ImGui::GetWindowContentRegionMin();
  	ImVec2 vMax = ImGui::GetWindowContentRegionMax();
  
  	vMin.x += ImGui::GetWindowPos().x;
  	vMin.y += ImGui::GetWindowPos().y;
  	vMax.x += ImGui::GetWindowPos().x;
  	vMax.y += ImGui::GetWindowPos().y;
  
  	//ImGui::GetForegroundDrawList()->AddRect(vMin, vMax, IM_COL32(255, 255, 0, 255));
  	
  
  
  
  	static int textureWidth = 0;  // = vMax.x - vMin.x;
  	static int textureHeight = 0; // = vMax.y - vMin.y;
  
  	int currWidth  = vMax.x - vMin.x;
  	int currHeight = vMax.y - vMin.y;
  
  	if (textureWidth != currWidth || 
  		textureHeight != currHeight) {
  
  		textureWidth  = vMax.x - vMin.x;
  		textureHeight = vMax.y - vMin.y;
  
  		this->setViewportSize(textureWidth, textureHeight);
  	}
  
  	// =====================
  	// = Draw viewport     =
  	// =====================
  
  
  	glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  
  	glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
  	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  	glUseProgram(this->ProgramID);
  
  	// Draw triangle
  	glEnableVertexAttribArray(0);
  	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
  	glVertexAttribPointer(
  		0,                  // attribute 0. 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
  	);
  	// Draw the triangle !
  	glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
  	glDisableVertexAttribArray(0);
  
  	glBindFramebuffer(GL_FRAMEBUFFER, 0);
  
  
  
  	//ImGui::ImageButton((void*)textureColorbuffer, ImVec2(textureWidth, textureHeight));
  	ImGui::Image((void*)textureColorbuffer, ImVec2(textureWidth, textureHeight));
  	
  	ImDrawList* draw_list = ImGui::GetWindowDrawList();
  	draw_list->AddRect(ImVec2(vMin.x, vMin.y), ImVec2(vMax.x, vMax.y), IM_COL32(255, 255, 0, 255));
  
  	ImGui::End();
  }
  
  void Viewport3DView::DeInit() {
  
  }
  
  void Viewport3DView::setViewportSize(int width, int height) {
  
  	glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
  	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
  
  
  	glBindRenderbuffer(GL_RENDERBUFFER, rbo);
  	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
  	
  
  }
  
  
  GLuint Viewport3DView::loadShaders() {
  
  	// Create the shaders
  	GLuint VertexShaderID   = glCreateShader(GL_VERTEX_SHADER);
  	GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
  
  	// Read the Vertex Shader code from the file
  	std::string VertexShaderCode = 
  		"#version 330 core\n"
  		"layout(location = 0) in vec3 vertexPosition_modelspace;\n"
  		"void main(){\n"
  		"gl_Position.xyz = vertexPosition_modelspace;\n"
  		"gl_Position.w = 1.0;\n"
  		"}";
  
  	/*
  	std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
  	if (VertexShaderStream.is_open()) {
  		std::stringstream sstr;
  		sstr << VertexShaderStream.rdbuf();
  		VertexShaderCode = sstr.str();
  		VertexShaderStream.close();
  	}
  	else {
  		printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path);
  		getchar();
  		return 0;
  	}*/
  
  	// Read the Fragment Shader code from the file
  	std::string FragmentShaderCode=
  		"#version 330 core\n"
  		"out vec3 color;\n"
  		"void main() {\n"
  		"color = vec3(1, 0, 0);\n"
  		"}";
  	/*std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
  	if (FragmentShaderStream.is_open()) {
  		std::stringstream sstr;
  		sstr << FragmentShaderStream.rdbuf();
  		FragmentShaderCode = sstr.str();
  		FragmentShaderStream.close();
  	}*/
  
  	GLint Result = GL_FALSE;
  	int InfoLogLength;
  
  	// Compile Vertex Shader
  	//printf("Compiling shader : %s\n", vertex_file_path);
  	char const * VertexSourcePointer = VertexShaderCode.c_str();
  	glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
  	glCompileShader(VertexShaderID);
  
  	// Check Vertex Shader
  	glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
  	glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
  	if (InfoLogLength > 0) {
  		std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
  		glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
  		printf("%s\n", &VertexShaderErrorMessage[0]);
  	}
  
  	// Compile Fragment Shader
  	//printf("Compiling shader : %s\n", fragment_file_path);
  	char const * FragmentSourcePointer = FragmentShaderCode.c_str();
  	glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
  	glCompileShader(FragmentShaderID);
  
  	// Check Fragment Shader
  	glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
  	glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
  	if (InfoLogLength > 0) {
  		std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
  		glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
  		printf("%s\n", &FragmentShaderErrorMessage[0]);
  	}
  
  	// Link the program
  	printf("Linking program\n");
  	GLuint ProgramID = glCreateProgram();
  	glAttachShader(ProgramID, VertexShaderID);
  	glAttachShader(ProgramID, FragmentShaderID);
  	glLinkProgram(ProgramID);
  
  	// Check the program
  	glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
  	glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
  	if (InfoLogLength > 0) {
  		std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
  		glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
  		printf("%s\n", &ProgramErrorMessage[0]);
  	}
  
  	glDetachShader(ProgramID, VertexShaderID);
  	glDetachShader(ProgramID, FragmentShaderID);
  
  	glDeleteShader(VertexShaderID);
  	glDeleteShader(FragmentShaderID);
  
  	return ProgramID;
  }