C言語でdemoを作る。
demoを作るには、c言語は、避けて通れません。なのでc言語の話から。
c言語を使って作るのですが、c言語のスキルなんて、ほぼいらないです。なんとかなります。
以前iq氏のページを見たのですが、デバック用とリリース用のc言語のソースが載ってました。
考えてみれば、当たり前ですね。で、今回はデバック用のコードを載せてみました。
#include <windows.h> #include <GL/gl.h> #include <GL/glext.h> #include <mmreg.h> #include <stdio.h> static const char *vsh = \ "void main()" "{" "gl_Position = gl_Vertex;" "}"; static const char *fsh = \ "uniform vec2 resolution;" "uniform float time;" "void main()" "{" "vec2 p = (2.0 * gl_FragCoord.xy - resolution.xy) / resolution.y;" "p += vec2(cos(time), sin(time)) * 0.5;" "float g = exp(-1.5 * dot(p,p));" "gl_FragColor = vec4(g, g, g, 1.0);" "}"; const char *msh = \ "#version 330\n" "out vec2 gain;" "uniform float sampleRate;" "void main()" "{" "float time = float(gl_VertexID) / sampleRate;" "gain = vec2(sin(6.2831*440.0*fract(time)));" "}"; #define U_RESOLUTION "resolution" #define U_SAMPLERATE "sampleRate" #define U_TIME "time" #define O_GAIN "gain" #define SND_DURATION 180 #define SAMPLE_RATE 44100 #define SND_NUMCHANNELS 2 #define XPOS 500 #define YPOS 200 #define XRES 640 #define YRES 480 #define SND_NUMSAMPLES (SND_DURATION*SAMPLE_RATE) #define SND_NUMSAMPLESC (SND_NUMSAMPLES*SND_NUMCHANNELS) float samples[SND_NUMSAMPLESC]; void checkShader(GLuint shader){ GLint compile_status = 0; ((PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv"))(shader, GL_COMPILE_STATUS, &compile_status); if(compile_status != GL_TRUE){ GLint info_length; GLsizei buffer_size; ((PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv"))(shader, GL_INFO_LOG_LENGTH, &info_length); GLchar message[info_length]; ((PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog"))(shader, info_length, &buffer_size, message); printf( message); } } void compile(GLuint program, const char *source, GLenum type){ GLuint shader = ((PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"))(type); ((PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"))(shader, 1, &source, 0); ((PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"))(shader); checkShader(shader); ((PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"))(program, shader); } int main(){ HWND hWnd = CreateWindow((LPCSTR)0xC018,"demoscene",WS_OVERLAPPEDWINDOW|WS_VISIBLE,XPOS,YPOS,XRES,YRES,0,0,0,0); HDC hDC = GetDC(hWnd); PIXELFORMATDESCRIPTOR pfd={0,1,PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,32,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0}; SetPixelFormat(hDC, ChoosePixelFormat(hDC, &pfd) , &pfd); HGLRC hGLrc = wglCreateContext(hDC); wglMakeCurrent(hDC, hGLrc); GLuint programMzk = ((PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"))(); compile(programMzk, msh, GL_VERTEX_SHADER); const GLchar* outs[] = {O_GAIN}; ((PFNGLTRANSFORMFEEDBACKVARYINGSPROC)wglGetProcAddress("glTransformFeedbackVaryings"))(programMzk, 1, outs, GL_INTERLEAVED_ATTRIBS); ((PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram"))(programMzk); ((PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram"))(programMzk); GLuint tmp; ((PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers"))(1, &tmp); ((PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer"))(GL_ARRAY_BUFFER, tmp); ((PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData"))(GL_ARRAY_BUFFER, SND_NUMSAMPLESC*sizeof(float), 0, GL_STATIC_READ); ((PFNGLBINDBUFFERBASEPROC)wglGetProcAddress("glBindBufferBase"))(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tmp); tmp = ((PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation"))(programMzk, U_SAMPLERATE); ((PFNGLUNIFORM1FPROC)wglGetProcAddress("glUniform1f"))(tmp, (float)SAMPLE_RATE); glEnable(GL_RASTERIZER_DISCARD); ((PFNGLBEGINTRANSFORMFEEDBACKPROC)wglGetProcAddress("glBeginTransformFeedback"))(GL_POINTS); glDrawArrays(GL_POINTS, 0, SND_NUMSAMPLES); ((PFNGLENDTRANSFORMFEEDBACKPROC)wglGetProcAddress("glEndTransformFeedback"))(); glDisable(GL_RASTERIZER_DISCARD); ((PFNGLGETBUFFERSUBDATAPROC)wglGetProcAddress("glGetBufferSubData"))(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(samples), samples); GLint program, loc; program = ((PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"))(); compile(program, vsh, GL_VERTEX_SHADER); compile(program, fsh, GL_FRAGMENT_SHADER); ((PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram"))(program); ((PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram"))(program); loc = ((PFNGLGETUNIFORMLOCATIONARBPROC)wglGetProcAddress("glGetUniformLocation"))(program, U_RESOLUTION); ((PFNGLUNIFORM2FPROC)wglGetProcAddress("glUniform2f"))(loc, (float)XRES, (float)YRES); WAVEFORMATEX wave_format = { WAVE_FORMAT_IEEE_FLOAT, SND_NUMCHANNELS, SAMPLE_RATE, SAMPLE_RATE*sizeof(float)*SND_NUMCHANNELS, sizeof(float)*SND_NUMCHANNELS, sizeof(float)*8, 0 }; WAVEHDR wave_hdr = {(LPSTR)samples, sizeof(samples)}; HWAVEOUT hWaveOut; waveOutOpen(&hWaveOut, WAVE_MAPPER, &wave_format, (DWORD_PTR)hWnd, 0, CALLBACK_WINDOW); waveOutPrepareHeader(hWaveOut, &wave_hdr, sizeof(wave_hdr)); waveOutWrite(hWaveOut, &wave_hdr, sizeof(wave_hdr)); static MMTIME mmt = { TIME_SAMPLES }; MSG msg; int done=0; int fps = 0; int cnt = 0; float t0 = 0.0; while (!done) { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_NCLBUTTONDOWN && msg.wParam == HTCLOSE) done=1; DispatchMessage(&msg); } if (GetAsyncKeyState(VK_ESCAPE)) done = 1; if (mmt.u.sample == SND_NUMSAMPLES) done = 1; waveOutGetPosition(hWaveOut, &mmt, sizeof(mmt)); float time = (float)mmt.u.sample / (float)SAMPLE_RATE; loc = ((PFNGLGETUNIFORMLOCATIONARBPROC)wglGetProcAddress("glGetUniformLocation"))(program, U_TIME); ((PFNGLUNIFORM1FPROC)wglGetProcAddress("glUniform1f"))(loc, time); glRects(1, 1, -1, -1); SwapBuffers(hDC); if (time - t0 > 1.0) { fps = cnt; cnt = -1; t0 = time; } cnt++; printf("\r FPS : %d Time : %5.1f", fps, time); } waveOutReset(hWaveOut); waveOutUnprepareHeader(hWaveOut,&wave_hdr,sizeof(WAVEHDR)); waveOutClose(hWaveOut); wglMakeCurrent(NULL, NULL); wglDeleteContext(hGLrc); ReleaseDC(hWnd, hDC); PostQuitMessage(0); ExitProcess(0); return 0; }
では、これをdemo.c
という名で保存してgcc.exe
でコンパイルしてみます。
私はmingw-w64のgccを使ってます。
gcc demo.c -O3 -Wall -lopengl32 -lgdi32 -lwinmm -o demo.exe
これで、デモが出来上がりました。このデモはエスケープキーで終了します。デモを作るのに必要なc言語のソースのプロトタイプが手に入りました。ここから派生させて自分で作りやすい環境に整備していきます。次は、このソースを元にpythonのctypesを使い、pythonでデモを作れるように持って行きます。その後webGL との関連性とか研究して、pythonを中心にwebGLとdemoを行ったり来たりしていきたいと思います。
リリース用のソースは
に載ってます。