OpenGLで描画までのシンプルなプロジェクト

Windows / Androidで動作確認。Windowを作って描画するまでの最小セット。
シェーダーはmidiump / lowpを使って型を固定しておかないとAndroidでシェーダのコンパイルで失敗するので注意!
SimpleGLTestのダウンロード

レンダーテクスチャを使って描画する

//----------------------------------------------------
//
// シェーダーテスト用の最小プログラム
//
//----------------------------------------------------
#include <windows.h>
#include <windowsx.h>
#include <lib/glew-2.1.0/include/GL/glew.h>

//#include <GLES2/gl2.h>
//#include <GLES2/gl2ext.h>

#define WINDOW_WIDTH 512
#define WINDOW_HEIGHT 512
#define FPS (60)

#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "lib/glew-2.1.0/lib/Release/x64/glew32.lib")

//buffer for texture
int TextureWidth=256,TextureHeight=256;
unsigned int texImage1[256 * 256 * 4];	//image buffer for ue4 texture
unsigned int texImage2[256 * 256 * 4];	//image buffer for render texture
unsigned int texImage3[256 * 256 * 4];	//image buffer for capture texture

//shader programs
const GLchar  *vtxShader1[] = {
	"#version 330\n",
	"in  vec3 a_position;\n",
	"in  vec2 a_texCoord;\n",
	"in  vec4 a_color;\n",
	"out  vec4 v_vtxColor;\n",
	"out  vec2 v_texCoord;\n",
	"void main(void)\n",
	"{\n",
	"gl_Position = vec4( a_position , 1 );\n",
	"v_vtxColor    = a_color;\n",
	"v_texCoord    = a_texCoord;\n",
	"}\n",
};

const GLchar  *pxlShader1[] = {
	"#version 330\n",
	"in  vec4 v_vtxColor;\n",
	"in  int  v_palColor;\n",
	"in  vec2 v_texCoord;\n",
	"uniform sampler2D u_textureID1;\n",
	"void main(void)\n",
	"{\n",
	"  vec4 color1 = texture2D( u_textureID1 , v_texCoord.xy );\n",
	"  gl_FragColor = color1;\n",
	"}\n",
};


struct StWindow
{
	HINSTANCE m_hInstance;
	HWND      m_hWindow;
	WPARAM    m_wParam;
	HACCEL    m_hAccel;
	HDC		  m_WinDC;
	bool      g_bExit = false;
} Window;

struct StOpenGL
{
	HGLRC m_hRC;
	GLuint m_sTexIndex[8];
	GLuint shaderProgram;
	int    Sequence;

    GLuint s_offscreen_fbo;
} OpenGL;

typedef struct StCustomVertex2
{
	float x, y, z, rhw;
	unsigned int  argb;
	float u, v;
} StCustomVertex2;

//Windows

void makeWindow( );
void action();
void render();
void vSync();

LRESULT	CALLBACK WindowProc(HWND hw, UINT iMsg, WPARAM wParam, LPARAM lParam);

//openGL

void initGL();
void initTexture();
void initShader();
void drawGL();
void drawPrim( StCustomVertex2 *pVertex , int width , int height );

//extern unsigned char ue4[];
#if 1

int APIENTRY wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR    lpCmdLine, _In_ int nCmdShow)
{
	//Windows Main

	OpenGL.Sequence = 0;
	OpenGL.s_offscreen_fbo = -1;

	Window.m_hInstance = hInstance;

	//make Window
	makeWindow();

	//show Windows
	ShowWindow( Window.m_hWindow, nCmdShow );

	//main loop
	while(!Window.g_bExit)
	{
		action();
		vSync();
		SwapBuffers( Window.m_WinDC );
	}
}


void makeWindow( )
{
	//make window

	WNDCLASSEX	wndClass;

	wndClass.cbSize        = sizeof(wndClass);
	wndClass.style         = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc   = WindowProc;
	wndClass.cbClsExtra    = 0;
	wndClass.cbWndExtra    = 0;
	wndClass.hInstance     = Window.m_hInstance;
	wndClass.hIcon         = NULL;
	wndClass.hCursor       = NULL;
	wndClass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
	wndClass.lpszMenuName  = NULL;
	wndClass.lpszClassName = TEXT("glTest");
	wndClass.hIconSm       = NULL;

	ATOM hr = RegisterClassEx(&wndClass);

	RECT desktop;

	GetWindowRect(GetDesktopWindow(), (LPRECT)&desktop);

	int x, y, w, h;

	RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };

	AdjustWindowRect( &rect, WS_OVERLAPPEDWINDOW|WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, FALSE );

	w = rect.right  - rect.left;
	h = rect.bottom - rect.top;
	x = (desktop.right  - desktop.left)/2 - w/2;
	y = (desktop.bottom - desktop.top )/2 - h/2;

	if( x < 0) x = 0;
	if( y < 0) y = 0;

	Window.m_hWindow = CreateWindow(
				TEXT("glTest"),
				TEXT("ShaderTest"),
	            WS_OVERLAPPEDWINDOW|WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE,
				x,
				y,
				w,
				h,
				NULL,
				NULL,
				Window.m_hInstance,
			    NULL);

	Window.m_WinDC = GetDC( Window.m_hWindow );
}


void vSync()
{
	//------------------------------------------
	//wait vsync
	//------------------------------------------

	MSG msg;
	static LONGLONG before    = 0;
	static LONGLONG vsyncratio = 0;
	LONGLONG time;

	QueryPerformanceCounter( (LARGE_INTEGER*)&time );

	if( vsyncratio == 0 )
	{
		// init vsync ratio
		QueryPerformanceCounter  ( (LARGE_INTEGER*)&before);
		QueryPerformanceFrequency((LARGE_INTEGER*)&vsyncratio);
		vsyncratio = vsyncratio / FPS;
		before = time;
	}

	do
	{
		// wait vsync

		QueryPerformanceCounter( (LARGE_INTEGER*)&time );

		while(PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
		{
			if( !GetMessage( &msg, NULL, 0, 0 ) )
			{
				 return;
			}

			if ( !TranslateAccelerator( Window.m_hWindow , Window.m_hAccel , &msg ) )
			{
				TranslateMessage( &msg );
				DispatchMessage( &msg );
			}
		}
	}
	while( time < ( before + vsyncratio ) );

	before = time;

}


LRESULT	CALLBACK WindowProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
	//------------------------------------------
	//windows procedure
	//------------------------------------------

	switch (iMsg) {
	case WM_CREATE:
		break;

	case WM_CLOSE:
		DestroyWindow( hWnd );
		break;

	case WM_DESTROY:
		Window.g_bExit = true;
		PostQuitMessage(0);
		return 0;

	case WM_SYSCOMMAND:
	case WM_COMMAND:
	default:
		break;
	}

	return DefWindowProc( hWnd, iMsg, wParam, lParam );
}
#endif

//-------------------------------------------------------------
// OpenGL code
//-------------------------------------------------------------

void action()
{
	if ( OpenGL.Sequence == 0 )
	{
		//init
		initGL();
		initTexture();
		initShader();

		glEnable ( GL_TEXTURE_2D );
/*毒*///		glEnable ( GL_NORMALIZE );
/*毒*///		glEnable ( GL_ALPHA_TEST );
		glEnable ( GL_BLEND );
		glDisable( GL_DEPTH_TEST );

		OpenGL.Sequence ++;
	}

	drawGL();
}


void initGL()
{
	//----------------------------------------------------------------------
	// OpenGL initialize
	//----------------------------------------------------------------------
#if 1
	int pixelFormat;

	static PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),   // size of this pfd 
		1,                     // version number 
		PFD_DRAW_TO_WINDOW |   // support window 
		PFD_SUPPORT_OPENGL |   // support OpenGL 
		PFD_DOUBLEBUFFER,      // double buffered 
		PFD_TYPE_RGBA,         // RGBA type 
		24,                    // 24-bit color depth 
		0, 0, 0, 0, 0, 0,      // color bits ignored 
		0,                     // no alpha buffer 
		0,                     // shift bit ignored 
		0,                     // no accumulation buffer 
		0, 0, 0, 0,            // accum bits ignored 
		32,                    // 32-bit z-buffer 
		1,                     // no stencil buffer 
		1,                     // no auxiliary buffer 
		PFD_MAIN_PLANE,        // main layer 
		0,                     // reserved 
		0, 0, 0                // layer masks ignored 
	};

	pixelFormat = ChoosePixelFormat(Window.m_WinDC, &pfd);
	SetPixelFormat(Window.m_WinDC, pixelFormat, &pfd);

	OpenGL.m_hRC = wglCreateContext(Window.m_WinDC);
	wglMakeCurrent(Window.m_WinDC, OpenGL.m_hRC);

	GLenum err = glewInit();

	//matrix
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	//Reset
	glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

	BOOL(WINAPI *wglSwapIntervalEXT)(int) = NULL;

	wglSwapIntervalEXT = (BOOL(WINAPI*)(int))wglGetProcAddress("wglSwapIntervalEXT");

	if (wglSwapIntervalEXT)
	{
		wglSwapIntervalEXT(0);
	}
#endif

}


void initShader()
{
	//----------------------------------------------------------------------
	// init shader
	//----------------------------------------------------------------------
	GLint status;
	GLsizei bufSize;
	GLsizei length;
	GLchar *infoLog;

	//make program

	OpenGL.shaderProgram    = glCreateProgram();

	//compile vtxShader

	GLuint  vshader;
	vshader = glCreateShader(GL_VERTEX_SHADER);

	glShaderSource(vshader, sizeof(vtxShader1) / sizeof(vtxShader1[0]), (GLchar const* const*)vtxShader1, NULL);
	glCompileShader(vshader);
	glGetShaderiv(vshader, GL_COMPILE_STATUS, &status);

	if (status == GL_FALSE)
	{
		glGetShaderiv(vshader, GL_INFO_LOG_LENGTH, &bufSize);
		infoLog = (GLchar*)malloc(bufSize);
		glGetShaderInfoLog(vshader, bufSize, &length, infoLog);
		infoLog[512 - 1] = 0x00;
		free(infoLog);
	}

	//compile pxlShader

	GLuint  pshader;
	pshader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(pshader, sizeof(pxlShader1) / sizeof(pxlShader1[0]), (GLchar const* const*)pxlShader1, NULL);
	glCompileShader(pshader);
	glGetShaderiv(pshader, GL_COMPILE_STATUS, &status);

	if (status == GL_FALSE)
	{
		glGetShaderiv(pshader, GL_INFO_LOG_LENGTH, &bufSize);
		infoLog = (GLchar*)malloc(bufSize);
		glGetShaderInfoLog(pshader, bufSize, &length, infoLog);
		free(infoLog);
	}

	//attach prog program

	glAttachShader( OpenGL.shaderProgram , vshader );
	glAttachShader( OpenGL.shaderProgram , pshader );

	//link shader program

	glLinkProgram ( OpenGL.shaderProgram );
	glGetProgramiv(OpenGL.shaderProgram, GL_LINK_STATUS, &status);

	if (status == GL_FALSE)
	{
		glGetProgramiv(OpenGL.shaderProgram, GL_INFO_LOG_LENGTH, &bufSize);
		infoLog = (GLchar*)malloc(bufSize);
		glGetProgramInfoLog(OpenGL.shaderProgram, bufSize, &length, infoLog);
		free(infoLog);
	}

	glDeleteShader( vshader );
	glDeleteShader( pshader );
}


void initTexture()
{
	//----------------------------------------------------------------------
	//init texture x2
	//----------------------------------------------------------------------

	glGenTextures( 8, OpenGL.m_sTexIndex );

	//make src texture 1( ue4 )
	unsigned int argb;
	for (int ii = 0; ii < 256 * 256 * 1;ii++)
	{
		argb = *(int*)(&texImage1[ii*4]);
		texImage1[ii] = ((argb>>24)&0xff)<<24 | ((argb>>16)&0xff)<<8 | ((argb>>8)&0xff)<<16 | ((argb>>0)&0xff)<<0;	//ue4
	}

	//make dst texture 2( noise )

	for (int ii = 0; ii < 512 * 512 * 1;ii++)
	{
		texImage2[ii] = 0xff000000 | (rand()%255)<<16 | (rand()%255)<<8  | (rand()%255)<<0  ;	//noise
	}

	// bind texture1

	glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[0] );
	glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage1 );

	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );	//<--- important!
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

	// bind texture2

	glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[1] );
	glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage2 );

	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

	// bind texture3

	glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[2] );
	glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage3 );

	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

	//--------------------------------------------------------------
	//create frame buffer object( fbo ) from texture
	//--------------------------------------------------------------

	if( OpenGL.s_offscreen_fbo != -1 )
	{
		glDeleteFramebuffers( 1 , &OpenGL.s_offscreen_fbo );
	}

	glGenFramebuffers( 1, &OpenGL.s_offscreen_fbo );
	glBindFramebuffer( GL_FRAMEBUFFER, OpenGL.s_offscreen_fbo );

	//attach texture as color buffer of frame buffer
	glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OpenGL.m_sTexIndex[1], 0 );

	//restore frame buffer state
	glBindFramebuffer( GL_FRAMEBUFFER, 0 );
	glBindTexture( GL_TEXTURE_2D, 0 );
}


void drawGL()
{
	//----------------------------------------------------------------------
	//rendering
	//----------------------------------------------------------------------

	//clear bg( red )
	glBindFramebuffer( GL_FRAMEBUFFER, 0 );
	glClearColor( 1.0f, 0.0f, 0.0f, 1.f );
	glClear( GL_COLOR_BUFFER_BIT );

	render();

	//restore default
	glBindFramebuffer( GL_FRAMEBUFFER, 0 );

	//	glActiveTexture(GL_TEXTURE0 + 0);
	//	glActiveTexture(GL_TEXTURE0 + 1);
}


void render()
{
	//----------------------------------------------------------------------
	//rendering
	//----------------------------------------------------------------------

	StCustomVertex2 pVertex1[4] = {
		//rect1 Z
		{ 0.f     ,0.f    ,0.f  ,1.f , 0xffffffff , 0.f ,0.f },
		{ 256.f   ,0.f    ,0.f  ,1.f , 0xffffffff , 1.0 ,0.0 },
		{ 0.f     ,256.f  ,0.f  ,1.f , 0xffffffff , 0.0 ,1.0 },
		{ 256/2.f ,256.f  ,0.f  ,1.f , 0xffffffff , 1.0 ,1.0 },
	};

	StCustomVertex2 pVertex2[4] = {
		//rect2
		{ 256 ,256 ,0  ,1 , 0xffffffff , 0   ,0 },
		{ 512 ,256 ,0  ,1 , 0xffffffff , 1.0 ,0.0 },
		{ 256 ,512 ,0  ,1 , 0xffffffff , 0.0 ,1.0 },
		{ 512 ,512 ,0  ,1 , 0xffffffff , 1.0 ,1.0 },
	};

	StCustomVertex2 pVertex3[4] = {
		//rect3
		{ 0     ,256 ,0  ,1 , 0xffffffff , 0   ,0 },
		{ 256   ,256 ,0  ,1 , 0xffffffff , 1.0 ,0.0 },
		{ 0     ,512 ,0  ,1 , 0xffffffff , 0.0 ,1.0 },
		{ 256   ,512 ,0  ,1 , 0xffffffff , 1.0 ,1.0 },
	};

	glActiveTexture( GL_TEXTURE0 + 0 );

	//--------------------------------------------------
	//src draw to "render texture"
	//--------------------------------------------------
	{
		//adjust screensize to Texture size
		glViewport( 0, 0, TextureWidth , TextureHeight );
		glBindFramebuffer( GL_FRAMEBUFFER, OpenGL.s_offscreen_fbo );

		//clear "render texture"
		glClearColor( 0.0f, 1.0f, 0.0f, 1.f );	//(green)
		glClear(GL_COLOR_BUFFER_BIT);

		glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[0] );	//use "noise texture"
		drawPrim( pVertex1 , TextureWidth , TextureHeight );
	}

	//--------------------------------------------------
	//"render texture" draw to "frame buffer"
	//--------------------------------------------------
	{
		//adjust screensize to Window size
		glViewport(0, 0, WINDOW_WIDTH,WINDOW_HEIGHT );

		glBindFramebuffer( GL_FRAMEBUFFER, 0 );
		glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[1] );	//use "render texture"

		drawPrim( pVertex2 , WINDOW_WIDTH , WINDOW_HEIGHT );
	}

	//--------------------------------------------------
	//capture "rgba data" from "render texture" 
	//--------------------------------------------------

	glBindFramebuffer( GL_FRAMEBUFFER, OpenGL.s_offscreen_fbo );
//	glReadBuffer(GL_COLOR_ATTACHMENT0);
	glReadPixels( 0, 0, TextureWidth, TextureHeight, GL_RGBA, GL_UNSIGNED_BYTE,  texImage3 );

	//make "capture texture" from "rgba data"

	glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[2] );
	glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage3 );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );	//<--- important!
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

	//draw "capture texture" to "frame buffer"

	glBindFramebuffer( GL_FRAMEBUFFER, 0 );
	drawPrim( pVertex3 , WINDOW_WIDTH , WINDOW_HEIGHT );
}


void drawPrim( StCustomVertex2 *pVertex , int width , int height )
{
	//----------------------------------------------------------------------
	//render primitive
	//div rect to triangle x2.
	//----------------------------------------------------------------------
	//vtx (-1,+1) - (+1,+1)
	//    (-1,-1) - (+1,-1)
	//uvs ( 0,+1) - (+1,+1)
	//    ( 0, 0) - (+1, 0)
	//----------------------------------------------------------------------

	float vtx[] = {
		//Vertices
		pVertex[0].x / (width / 2) - 1.0f, -(pVertex[0].y / (height / 2) - 1.0f) , 0.0f,
		pVertex[1].x / (width / 2) - 1.0f, -(pVertex[1].y / (height / 2) - 1.0f) , 0.0f,
		pVertex[2].x / (width / 2) - 1.0f, -(pVertex[2].y / (height / 2) - 1.0f) , 0.0f,

		pVertex[2].x / (width / 2) - 1.0f, -(pVertex[2].y / (height / 2) - 1.0f) , 0.0f,
		pVertex[1].x / (width / 2) - 1.0f, -(pVertex[1].y / (height / 2) - 1.0f) , 0.0f,
		pVertex[3].x / (width / 2) - 1.0f, -(pVertex[3].y / (height / 2) - 1.0f) , 0.0f,
	};

	float uvs[] = {
		//UVs
		pVertex[0].u , 1.0f-pVertex[0].v,
		pVertex[1].u , 1.0f-pVertex[1].v,
		pVertex[2].u , 1.0f-pVertex[2].v,

		pVertex[2].u , 1.0f-pVertex[2].v,
		pVertex[1].u , 1.0f-pVertex[1].v,
		pVertex[3].u , 1.0f-pVertex[3].v,
	};

	GLfloat cols[] = {
		//Colors
		(int((pVertex[0].argb>>24)&0xff)/255.0f),(int((pVertex[0].argb>>16)&0xff)/255.0f),(int((pVertex[0].argb>>8)&0xff)/255.0f),(int((pVertex[0].argb>>0)&0xff)/255.0f),	//1.0 ,1.0 ,1.0 , 1.0,
		(int((pVertex[1].argb>>24)&0xff)/255.0f),(int((pVertex[1].argb>>16)&0xff)/255.0f),(int((pVertex[1].argb>>8)&0xff)/255.0f),(int((pVertex[1].argb>>0)&0xff)/255.0f),	//1.0 ,1.0 ,1.0 , 1.0,
		(int((pVertex[2].argb>>24)&0xff)/255.0f),(int((pVertex[2].argb>>16)&0xff)/255.0f),(int((pVertex[2].argb>>8)&0xff)/255.0f),(int((pVertex[2].argb>>0)&0xff)/255.0f),	//1.0 ,1.0 ,1.0 , 1.0,

		(int((pVertex[2].argb>>24)&0xff)/255.0f),(int((pVertex[2].argb>>16)&0xff)/255.0f),(int((pVertex[2].argb>>8)&0xff)/255.0f),(int((pVertex[2].argb>>0)&0xff)/255.0f),	//1.0 ,1.0 ,1.0 , 1.0,
		(int((pVertex[1].argb>>24)&0xff)/255.0f),(int((pVertex[1].argb>>16)&0xff)/255.0f),(int((pVertex[1].argb>>8)&0xff)/255.0f),(int((pVertex[1].argb>>0)&0xff)/255.0f),	//1.0 ,1.0 ,1.0 , 1.0,
		(int((pVertex[3].argb>>24)&0xff)/255.0f),(int((pVertex[3].argb>>16)&0xff)/255.0f),(int((pVertex[3].argb>>8)&0xff)/255.0f),(int((pVertex[3].argb>>0)&0xff)/255.0f),	//1.0 ,1.0 ,1.0 , 1.0,
	};

	//draw with shader

	glEnableVertexAttribArray( 0 );

	GLuint position = glGetAttribLocation( OpenGL.shaderProgram, "a_position" );
	glVertexAttribPointer( position, 3, GL_FLOAT, GL_FALSE, 0, vtx );
	glEnableVertexAttribArray(position);

	GLuint texcoord = glGetAttribLocation( OpenGL.shaderProgram, "a_texCoord" );
	glVertexAttribPointer( texcoord, 2, GL_FLOAT, GL_FALSE, 0, uvs );
	glEnableVertexAttribArray( texcoord );

	GLuint color = glGetAttribLocation( OpenGL.shaderProgram, "a_color" );
	glVertexAttribPointer( color, 4, GL_FLOAT, GL_FALSE, 0, cols );
	glEnableVertexAttribArray( color );

	int textureID1;
	textureID1 = glGetUniformLocation( OpenGL.shaderProgram, "u_textureID1" );
	glUniform1i(textureID1, 0 );

	glUseProgram( OpenGL.shaderProgram );

	glDrawArrays( GL_TRIANGLES, 0, 6 );

	glDisableVertexAttribArray( 0 );

}

頂点バッファなしで描画する

頂点バッファありで描画する(VBO)

Indexバッファを使って描画する