text: ﻿#include "Shader.h"
  
  Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
  {
      // 1. 파일 경로를 통해 vertex/fragment shader 소스 코드를 검색합니다.
      std::string vertexCode;
      std::string fragmentCode;
      std::ifstream vShaderFile;
      std::ifstream fShaderFile;
      // ifstream 객체들이 예외를 던질 수 있도록 합니다.
      vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
      fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
      try
      {
          // 파일 열기
          vShaderFile.open(("shader/" + string(vertexPath)).c_str());
          fShaderFile.open(("shader/" + string(fragmentPath)).c_str());
          std::stringstream vShaderStream, fShaderStream;
          // stream에 파일의 버퍼 내용을 읽기
          vShaderStream << vShaderFile.rdbuf();
          fShaderStream << fShaderFile.rdbuf();
          // 파일 핸들러 닫기
          vShaderFile.close();
          fShaderFile.close();
          // stream을 string으로 변환
          vertexCode = vShaderStream.str();
          fragmentCode = fShaderStream.str();
      }
      catch (std::ifstream::failure e)
      {
          std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
      }
      const char* vShaderCode = vertexCode.c_str();
      const char* fShaderCode = fragmentCode.c_str();
  
      // 2. shader 컴파일
      unsigned int vertex, fragment;
      int success;
      char infoLog[512];
  
      // vertex Shader
      vertex = glCreateShader(GL_VERTEX_SHADER);
      glShaderSource(vertex, 1, &vShaderCode, NULL);
      glCompileShader(vertex);
      // 오류가 발생한다면 컴파일 오류를 출력
      glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
      if (!success)
      {
          glGetShaderInfoLog(vertex, 512, NULL, infoLog);
          std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
      };
  
      // Fragment shader도 마찬가지
      fragment = glCreateShader(GL_FRAGMENT_SHADER);
      glShaderSource(fragment, 1, &fShaderCode, NULL);
      glCompileShader(fragment);
      // 오류가 발생한다면 컴파일 오류를 출력
      glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
      if (!success)
      {
          glGetShaderInfoLog(fragment, 512, NULL, infoLog);
          std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
      };
  
      // shader Program
      ID = glCreateProgram();
      glAttachShader(ID, vertex);
      glAttachShader(ID, fragment);
      glLinkProgram(ID);
      // 오류가 발생한다면 링킹 오류를 출력
      glGetProgramiv(ID, GL_LINK_STATUS, &success);
      if (!success)
      {
          glGetProgramInfoLog(ID, 512, NULL, infoLog);
          std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
      }
  
      glDetachShader(ID, vertex);
      glDetachShader(ID, fragment);
  
      // program 내부에서 shader들이 링크 완료되었다면 이제 필요 없으므로 shader들을 삭제
      glDeleteShader(vertex);
      glDeleteShader(fragment);
  }
  
  void Shader::use()
  {
      glUseProgram(ID);
  }
  
  void Shader::setBool(const std::string& name, bool value) const
  {
      glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
  }
  
  void Shader::setInt(const std::string& name, int value) const
  {
      glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
  }
  
  void Shader::setFloat(const std::string& name, float value) const
  {
      glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
  }
  
  void Shader::setVec2(const std::string& name, const glm::vec2& value) const
  {
  	glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
  }
  
  void Shader::setVec3(const std::string& name, const glm::vec3& value) const
  {
  	glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
  }
  
  void Shader::setMat4(const std::string& name, glm::mat4 value, bool transpose) const
  {
  	glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, transpose, glm::value_ptr(value));
  }
  
  
  
  
  // 함수형 쉐이더 로드
  /*
  
  GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) {
  
  	// 쉐이더들 생성
  	GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
  	GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
  
  	// 버텍스 쉐이더 코드를 파일에서 읽기
  	std::string VertexShaderCode;
  	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("파일 %s 를 읽을 수 없음. 정확한 디렉토리를 사용 중입니까 ? FAQ 를 우선 읽어보는 걸 잊지 마세요!\n", vertex_file_path);
  		getchar();
  		return 0;
  	}
  
  	// 프래그먼트 쉐이더 코드를 파일에서 읽기
  	std::string FragmentShaderCode;
  	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;
  
  
  	// 버텍스 쉐이더를 컴파일
  	printf("Compiling shader : %s\n", vertex_file_path);
  	char const* VertexSourcePointer = VertexShaderCode.c_str();
  	glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
  	glCompileShader(VertexShaderID);
  
  	// 버텍스 쉐이더를 검사
  	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]);
  	}
  
  
  
  	// 프래그먼트 쉐이더를 컴파일
  	printf("Compiling shader : %s\n", fragment_file_path);
  	char const* FragmentSourcePointer = FragmentShaderCode.c_str();
  	glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
  	glCompileShader(FragmentShaderID);
  
  	// 프래그먼트 쉐이더를 검사
  	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]);
  	}
  
  
  
  	// 프로그램에 링크
  	printf("Linking program\n");
  	GLuint ProgramID = glCreateProgram();
  	glAttachShader(ProgramID, VertexShaderID);
  	glAttachShader(ProgramID, FragmentShaderID);
  	glLinkProgram(ProgramID);
  
  	// 프로그램 검사
  	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;
  }
  
  GLubyte* LoadBmp(const char* Path, int* Width, int* Height)
  {
  	HANDLE hFile;
  	DWORD FileSize, dwRead;
  	BITMAPFILEHEADER* fh = NULL;
  	BITMAPINFOHEADER* ih;
  	BYTE* pRaster;
  	hFile = CreateFileA(Path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  	if (hFile == INVALID_HANDLE_VALUE)
  	{
  		return NULL;
  	}
  	FileSize = GetFileSize(hFile, NULL);
  	fh = (BITMAPFILEHEADER*)malloc(FileSize);
  	ReadFile(hFile, fh, FileSize, &dwRead, NULL);
  	CloseHandle(hFile);
  	int len = FileSize - fh->bfOffBits;
  	pRaster = (GLubyte*)malloc(len);
  	memcpy(pRaster, (BYTE*)fh + fh->bfOffBits, len); // RGB로 순서를 바꾼다.
  	for (BYTE * p = pRaster; p < pRaster + len - 3; p += 3)
  	{
  		BYTE b = * p; *p = * (p + 2); *(p + 2) = b;
  	}
  	ih = (BITMAPINFOHEADER *)((PBYTE)fh + sizeof(BITMAPFILEHEADER));
  	*Width = ih -> biWidth;
  	*Height = ih -> biHeight;
  	free(fh);
  
  	return pRaster;
  }
  
  */
  //출처: https://202psj.tistory.com/1456?category=273755 [알레폰드의 IT 이모저모]