スポンサーリンク

| キーワード:

glewを使用しないでC++からGLSLを使用

glewのライセンス

https://github.com/nigels-com/glew#copyright-and-licensing

GLEW is originally derived from the EXTGL project by Lev Povalahev. The source code is licensed under the Modified BSD License, the Mesa 3-D License (MIT) and the Khronos License (MIT).

The automatic code generation scripts are released under the GNU GPL.

glewはBSD LicenseかMITライセンス。普通誰も気にしないが、気に入らない場合は使用できない。

けれどやっていることはヘッダファイル側で定数を#defineしているのと、dll側でwglGetProcAddressしているだけ(多分)なので、必要な部分だけ自前で書くことも不可能ではない。

myglinit.hpp

#pragma once

#include <gl/GL.h>

typedef ptrdiff_t GLsizeiptr;
typedef char GLchar;

//サンプルのコンパイルに必要なものだけを取り出したもの


// 関数ポインタ型
using PFNGLGENBUFFERSPROC               = void(_stdcall*) (GLsizei n, GLuint* buffers);
using PFNGLBINDBUFFERPROC               = void(_stdcall*) (GLenum target, GLuint buffer);
using PFNGLBUFFERDATAPROC               = void(_stdcall*) (GLenum target, GLsizeiptr size, const void* data, GLenum usage);
using PFNGLCREATESHADERPROC             = GLuint(_stdcall*) (GLenum type);
using PFNGLSHADERSOURCEPROC             = void(_stdcall*) (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
using PFNGLCOMPILESHADERPROC            = void(_stdcall*) (GLuint shader);
using PFNGLGETSHADERIVPROC              = void(_stdcall*) (GLuint shader, GLenum pname, GLint* param);
using PFNGLGETSHADERINFOLOGPROC         = void(_stdcall*) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
using PFNGLCREATEPROGRAMPROC            = GLuint(_stdcall*) (void);
using PFNGLATTACHSHADERPROC             = void(_stdcall*) (GLuint program, GLuint shader);
using PFNGLLINKPROGRAMPROC              = void(_stdcall*) (GLuint program);
using PFNGLGETPROGRAMIVPROC             = void(_stdcall*) (GLuint program, GLenum pname, GLint* param);
using PFNGLGETPROGRAMINFOLOGPROC        = void(_stdcall*) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
using PFNGLUSEPROGRAMPROC               = void(_stdcall*) (GLuint program);
using PFNGLENABLEVERTEXATTRIBARRAYPROC  = void(_stdcall*) (GLuint index);
using PFNGLVERTEXATTRIBPOINTERPROC      = void(_stdcall*) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
using PFNGLDISABLEVERTEXATTRIBARRAYPROC = void(_stdcall*) (GLuint index);

// 定数
#define GL_ARRAY_BUFFER    0x8892
#define GL_STATIC_DRAW     0x88E4
#define GL_VERTEX_SHADER   0x8B31
#define GL_COMPILE_STATUS  0x8B81
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_LINK_STATUS     0x8B82

// wglGetProcAddressで取得したアドレスを格納する変数(グローバル)
PFNGLGENBUFFERSPROC               glGenBuffers;
PFNGLBINDBUFFERPROC               glBindBuffer;
PFNGLBUFFERDATAPROC               glBufferData;
PFNGLCREATESHADERPROC             glCreateShader;
PFNGLSHADERSOURCEPROC             glShaderSource;
PFNGLCOMPILESHADERPROC            glCompileShader;
PFNGLGETSHADERIVPROC              glGetShaderiv;
PFNGLGETSHADERINFOLOGPROC         glGetShaderInfoLog;
PFNGLCREATEPROGRAMPROC            glCreateProgram;
PFNGLATTACHSHADERPROC             glAttachShader;
PFNGLLINKPROGRAMPROC              glLinkProgram;
PFNGLGETPROGRAMIVPROC             glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC        glGetProgramInfoLog;
PFNGLUSEPROGRAMPROC               glUseProgram;
PFNGLENABLEVERTEXATTRIBARRAYPROC  glEnableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC      glVertexAttribPointer;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;


//関数のアドレスを取得
inline void myglinit() {

  glAttachShader             = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
  glBindBuffer               = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
  glBufferData               = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
  glCompileShader            = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
  glCreateProgram            = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
  glCreateShader             = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
  glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray");
  glEnableVertexAttribArray  = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
  glGenBuffers               = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
  glGetProgramInfoLog        = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog");
  glGetProgramiv             = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv");
  glGetShaderInfoLog         = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
  glGetShaderiv              = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
  glLinkProgram              = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
  glShaderSource             = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
  glUseProgram               = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
  glVertexAttribPointer      = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");

}

サンプルコード(本体)

元のソースコード

#include <iostream>

#pragma warning(disable:4996)

//#pragma comment(lib,"glew32.lib")  --- しない


//#include <gl/glew.h>   --- しない
#include <Windows.h>
#include <GL/glut.h>

#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>

#include "myglinit.hpp"


void init(void);
void display(void);

void link_program();
void prepare_buffers();
void prepare_vertex_shader();
void prepare_fragment_shader();



int main(int argc, char *argv[])
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA);
  glutCreateWindow(argv[0]);
  glutDisplayFunc(display);
  //■ glewInit(); // glewの初期化 --- しない
  myglinit();// glewInit()関数の代わり
  init();
  glutMainLoop();
  return 0;
}

void init(void)
{

  //頂点データと色情報の作成
  prepare_buffers();

  //頂点シェーダの準備
  prepare_vertex_shader();

  //フラグメントシェーダの準備
  prepare_fragment_shader();

  //プログラムのリンク
  link_program();

}

//バッファとデータ
typedef GLfloat points_t[3];
GLuint vertexbuffer;//バッファのIDを格納する変数
GLuint colorbuffer;//バッファのIDを格納する変数
points_t position[3];
points_t color[3];

//////////////////////////////////////////////////
void prepare_buffers() {

  //頂点座標
  position[0][0] = 0;
  position[0][1] = 0.5;
  position[0][2] = 0;

  position[1][0] = 0.5;
  position[1][1] = -0.5;
  position[1][2] = 0;

  position[2][0] = -0.5;
  position[2][1] = -0.5;
  position[2][2] = 0;


  //色
  color[0][0] = 1.0;
  color[0][1] = 0.0;
  color[0][2] = 0.0;

  color[1][0] = 0.0;
  color[1][1] = 1.0;
  color[1][2] = 0.0;

  color[2][0] = 0.0;
  color[2][1] = 0.0;
  color[2][2] = 1.0;

  glGenBuffers(1, &vertexbuffer);
  glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
  glBufferData(
    GL_ARRAY_BUFFER,
    3 * 3 * sizeof(GLfloat),
    position,
    GL_STATIC_DRAW);

  glGenBuffers(1, &colorbuffer);
  glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
  glBufferData(
    GL_ARRAY_BUFFER,
    3 * 3 * sizeof(GLfloat),
    color,
    GL_STATIC_DRAW);

}

GLuint VertexShaderID;

void prepare_vertex_shader() {

  //////////////////////////////////////////////
    // シェーダを作ります
    // (作るといっても宣言みたいなもの)
  VertexShaderID = glCreateShader(GL_VERTEX_SHADER);

  ////////////////////////////////////////////
  // ファイルから頂点シェーダを読み込みます。
  // 注意 ここはSTLのifstreamとかstringstreamの使い方の話で、
  // OpenGL命令は一つも無い。
  const char * vertex_file_path = ".\\verts.sh";
  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();
  }
  ////////////////////////////////////////////
  // 頂点シェーダをコンパイルします。
  printf("Compiling shader : %s\n", vertex_file_path);
  char const * VertexSourcePointer = VertexShaderCode.c_str();
  glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
  glCompileShader(VertexShaderID);

  ////////////////////////////////////////////
  // エラーチェック
  GLint Result = GL_FALSE;
  int InfoLogLength;

  // 頂点シェーダをチェックします。
  glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
  glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
  if (Result == FALSE) {
    std::vector<char> VertexShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
    fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
  }

}

GLuint FragmentShaderID;

void prepare_fragment_shader() {

  /////////////////////////////////////////////
  // シェーダを作ります。
  FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

  /////////////////////////////////////////////
  // ファイルからフラグメントシェーダを読み込みます。
  const char * fragment_file_path = ".\\frags.sh";
  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();
  }

  /////////////////////////////////////////////
  // フラグメントシェーダをコンパイルします。
  printf("Compiling shader : %s\n", fragment_file_path);
  char const * FragmentSourcePointer = FragmentShaderCode.c_str();
  glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
  glCompileShader(FragmentShaderID);

  GLint Result = GL_FALSE;
  int InfoLogLength;

  /////////////////////////////////////////////
  // フラグメントシェーダをチェックします。
  glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
  glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
  if (Result == GL_FALSE) {
    std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
    fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
  }
}

GLuint ProgramID;

void link_program() {

  GLint Result = GL_FALSE;
  int InfoLogLength;

  ////////////////////////////////////////
  // プログラムをリンクします。
  fprintf(stdout, "Linking program\n");
  ProgramID = glCreateProgram();
  glAttachShader(ProgramID, VertexShaderID);
  glAttachShader(ProgramID, FragmentShaderID);
  glLinkProgram(ProgramID);

  ////////////////////////////////////////
  // プログラムをチェックします。
  glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
  glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
  std::vector<char> ProgramErrorMessage((std::max)(InfoLogLength, int(1)));
  glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
  fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);

}

void display(void)
{
  glClearColor(0, 0, 0, 1);
  glClear(GL_COLOR_BUFFER_BIT);

  glLoadIdentity();
  glTranslated(0.5, 0.0, 0.0);//平行移動

  // シェーダを使う
  glUseProgram(ProgramID);

  // 頂点バッファ:頂点
  glEnableVertexAttribArray(0);
  glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
  glVertexAttribPointer(
    0,                  // シェーダ内のlayoutとあわせる
    3,                  // 1要素の要素数(x,y,z)で3要素
    GL_FLOAT,           // タイプ
    GL_FALSE,           // 正規化しない(データが整数型の時)
    0,                  // ストライド
    (void*)0            // 配列バッファオフセット
  );

  // カラーバッファを有効にする
  glEnableVertexAttribArray(1);
  glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
  glVertexAttribPointer(
    1,                  // シェーダ内のlayoutとあわせる
    3,                  // 1要素の要素数(r,g,b)で3要素
    GL_FLOAT,           // タイプ
    GL_FALSE,           // 正規化しない(データが整数型の時)
    0,                  // ストライド
    (void*)0            // 配列バッファオフセット
  );

  // 三角形を描きます!
  glDrawArrays(GL_TRIANGLES, 0, 3);

  glDisableVertexAttribArray(0);//バッファを無効にする
  glDisableVertexAttribArray(1);

  glFlush();
}

後書き

他にもリンクしちゃいけないときとかもこの方法をとることになると思う。ただその場合はglext.hを使えば自分で#define やtypedefを並べたりしなくて良くなる・・・のか?

「MIT Licenseを気にする状況ってどんな状況?」とか言う人がいそうなのだけれど、個人でならともかく業務でやっていると、自分より上の層で「俺が理解できないものは低品質なガラクタ」とか「俺の知らないものは使えないゴミ」等の謎理論で意味不明な利用制限がかかったりするので、できるかできないかぐらいは把握しておいた方がいい。後は、そういう契約になってるんだ!とか後から言われたり。しないかな?しないよね。

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: