0001: // ----------------------------------------------------------------------------
0002: //
0003: // main.cpp - GLUT で Cg のサンプルソース
0004: // 
0005: // Copyright (c) 2002 今給黎 隆 (imagire@nify.com)
0006: // All Rights Reserved.
0007: //
0008: // ----------------------------------------------------------------------------
0009: #define GLH_EXT_SINGLE_FILE
0010: #ifdef _WIN32
0011: #pragma warning (disable:4786)
0012: #endif
0013: #pragma warning (disable:4267)
0014: 
0015: #include <math.h>
0016: #include <stdio.h>
0017: #include <assert.h>
0018: #include <GL/glut.h>
0019: #include <Cg/cg.h>
0020: #include <Cg/cgGL.h>
0021: #include <glh_glut.h>
0022: #include "matrix.h"
0023: #include "noise.h"
0024: 
0025: // ---------------------------------------------------------------------------
0026: // オブジェクト
0027: // ---------------------------------------------------------------------------
0028: 
0029: static float r = 0.0f;      // ポリゴンの回転角
0030: 
0031: // テクスチャ
0032: static CNoise           noise;
0033: static int              g_iNoiseTex;
0034: static int              g_iPilseTrainTex;
0035: 
0036: // Cg のオブジェクト
0037: cgContext               *CgContext              = NULL;
0038: // 頂点プログラム
0039: static cgProgramIter    *VertexProgramIter      = NULL;
0040: static cgBindIter       *WPMatrix               = NULL;
0041: static cgBindIter       *WMatrix                = NULL;
0042: static cgBindIter       *WITMatrix              = NULL;
0043: static cgBindIter       *LightPos               = NULL;
0044: static cgBindIter       *ShaderMatrix           = NULL;
0045: // フラグメントプログラム
0046: static cgProgramIter    *FragmentProgramIter    = NULL;
0047: static cgBindIter       *fLightWoodColorBind    = NULL;
0048: static cgBindIter       *fDarkWoodColorBind     = NULL;
0049: static cgBindIter       *fHighNoiseLevelBind    = NULL;
0050: static cgBindIter       *fBaseRadiusFreqBind    = NULL;
0051: static cgBindIter       *fLowPulseAmpBind       = NULL;
0052: static cgBindIter       *NoiseMapBind           = NULL;
0053: static cgBindIter       *PulseTrainMapBind      = NULL;
0054: 
0055: void myRotationMatrix(const float fDegree, const float fX, const float fY, const float fZ, float* m_fData)
0056: {
0057:     float sinA, cosA;
0058:     float invCosA;
0059:     float x, y, z;
0060:     float xy, xz, yz;
0061:     float xx, yy, zz;
0062:     float fRadian = fDegree * 0.0174532925199f;
0063: 
0064:     x = fX;
0065:     y = fY;
0066:     z = fZ;
0067: 
0068:     float mult = 1.0f / sqrtf(x * x + y * y + z * z);
0069:     x *= mult;
0070:     y *= mult;
0071:     z *= mult;
0072: 
0073: 
0074:     sinA = (float)sinf(fRadian);
0075:     cosA = (float)cosf(fRadian);
0076:     invCosA = 1.0f - cosA;
0077: 
0078:     xy = x * y;
0079:     xz = x * z;
0080:     yz = y * z;
0081: 
0082:     xx = x * x;
0083:     yy = y * y;
0084:     zz = z * z;
0085: 
0086:     m_fData[0 ] = (invCosA * xx) + (cosA);
0087:     m_fData[1 ] = (invCosA * xy) - (sinA * z );
0088:     m_fData[2 ] = (invCosA * xz) + (sinA * y );
0089:     m_fData[3 ] = 0.0F;
0090: 
0091:     m_fData[4 ] = (invCosA * xy) + (sinA * z);
0092:     m_fData[5 ] = (invCosA * yy) + (cosA);
0093:     m_fData[6 ] = (invCosA * yz) - (sinA * x);
0094:     m_fData[7 ] = 0.0F;
0095: 
0096:     m_fData[8 ] = (invCosA * xz) - (sinA * y);
0097:     m_fData[9 ] = (invCosA * yz) + (sinA * x);
0098:     m_fData[10] = (invCosA * zz) + (cosA);
0099:     m_fData[11] = 0.0F;
0100: 
0101:     m_fData[12] = m_fData[13] = m_fData[14] = 0.0F;
0102:     
0103:     m_fData[15] = 1.0F;
0104: }
0105: 
0106: // ---------------------------------------------------------------------------
0107: // min から max の間を0から1まで、スムーズにつなぐ
0108: // ---------------------------------------------------------------------------
0109: float getSmoothStep(float min, float max, float x)
0110: {
0111:     if (x < min) {
0112:         return 0;
0113:     }else if (x > max) {
0114:         return 1;
0115:     }else{
0116:         float t = (x-min)/(max-min);
0117:         return (3 - 2*t)*t*t;
0118:     }
0119: }
0120: // ---------------------------------------------------------------------------
0121: // いい感じの山になっているテクスチャを作る
0122: // ---------------------------------------------------------------------------
0123: GLint generateSmoothPulseTrain()
0124: {
0125:     const int iWidth = 512;
0126:     unsigned char* pCharBuf = new unsigned char[iWidth];
0127: 
0128:     for (int i = 0; i < iWidth; ++i) {
0129:         float fX = float(i) / float(iWidth);
0130:         float fVal = getSmoothStep(0.1, 0.65, fX) - getSmoothStep(0.8, 0.95, fX);
0131:         pCharBuf[i] = 255 * fVal;
0132:     }
0133: 
0134:     GLuint texid;
0135:     glGenTextures(1, &texid);
0136:     glBindTexture(GL_TEXTURE_1D, texid);
0137:     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
0138:     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
0139:     glTexParameteri(GL_TEXTURE_1D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
0140:     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
0141:     glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE, iWidth, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pCharBuf);
0142: 
0143:     delete [] pCharBuf;
0144:     return texid;
0145: }
0146: // ---------------------------------------------------------------------------
0147: // ライト方向の設定
0148: // ---------------------------------------------------------------------------
0149: void updateLights()
0150: {
0151:     ifVector4 v = {-5.0f, 5.0f, 3.0f, 1.0f};// ライトの位置
0152:     ifMatrix m;
0153: 
0154:     // ビュー行列を所得
0155:     glGetFloatv(GL_TRANSPOSE_MODELVIEW_MATRIX_ARB, (float*)&m[0][0]);
0156: 
0157:     // ライトの位置をビュー座標系に変換
0158:     ifMatrixTranspose(&m, (const ifMatrix *)&m);
0159:     ifVec4Transform(&v, &v, (const ifMatrix *)&m);
0160: 
0161:     cgGLBindUniform4f(VertexProgramIter, LightPos, v[0], v[1], v[2], v[3]);
0162: }
0163: // ---------------------------------------------------------------------------
0164: // 画面描画
0165: // ---------------------------------------------------------------------------
0166: void display(void)
0167: {
0168:     ifMatrix mWorld, m;
0169:     cgError Ret;
0170:     
0171:     // -----------------------------------------------------------------------
0172:     // 画面のクリア
0173:     // -----------------------------------------------------------------------
0174:     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
0175: 
0176:     // -----------------------------------------------------------------------
0177:     // ビュー行列の設定
0178:     // -----------------------------------------------------------------------
0179:     glMatrixMode(GL_MODELVIEW);
0180:     glLoadIdentity();
0181:     gluLookAt(  0.0, 4.0, 6.0,      // 視点
0182:                 0.0, 1.0, 0.0,      // 注目点
0183:                 0.0, 1.0, 0.0);     // 上方向
0184: 
0185:     glPushMatrix();                 // ビュー行列が他のポリゴンでも使えるよう退避
0186: 
0187:     // -----------------------------------------------------------------------
0188:     // ライト方向の設定
0189:     // -----------------------------------------------------------------------
0190:     updateLights();
0191: 
0192:     // -----------------------------------------------------------------------
0193:     // Cg による描画へ切り替え
0194:     // -----------------------------------------------------------------------
0195:     Ret = cgGLBindProgram(VertexProgramIter);
0196:     assert(Ret == cgNoError);
0197:     cgGLEnableProgramType(cgVertexProfile);
0198: 
0199:     Ret = cgGLBindProgram(FragmentProgramIter);
0200:     assert(Ret == cgNoError);
0201:     cgGLEnableProgramType(cgFragmentProfile);
0202: 
0203:     // -----------------------------------------------------------------------
0204:     // テクスチャの設定
0205:     // -----------------------------------------------------------------------
0206:     cgGLActiveTexture(NoiseMapBind);
0207:     glEnable(GL_TEXTURE_3D_EXT);
0208:     glBindTexture(GL_TEXTURE_3D_EXT, g_iNoiseTex); 
0209: 
0210:     cgGLActiveTexture(PulseTrainMapBind);
0211:     glEnable(GL_TEXTURE_1D);
0212:     glBindTexture(GL_TEXTURE_1D, g_iPilseTrainTex); 
0213: 
0214:     // -----------------------------------------------------------------------
0215:     // 行列を設定する
0216:     // -----------------------------------------------------------------------
0217:     ifMatrixIdentity( &mWorld );
0218:     ifMatrixRotationX(&m, -IF_PI*90/180);
0219:     ifMatrixMultiply( &mWorld, (const ifMatrix *)&mWorld, (const ifMatrix *)&m );
0220:     ifMatrixRotationY(&m,  IF_PI* r/180);
0221:     ifMatrixMultiply( &mWorld, (const ifMatrix *)&mWorld, (const ifMatrix *)&m );
0222:     
0223:     glMultMatrixf((const float *)&mWorld);
0224: 
0225: #if 0
0226:     // さびた感じ
0227:     cgGLBindUniform4f(FragmentProgramIter, fLightWoodColorBind, 0.76, 0.41, 0.17, 0.0);
0228:     cgGLBindUniform4f(FragmentProgramIter, fDarkWoodColorBind,  0.42, 0.22, 0.03, 0.0);
0229:     cgGLBindUniform4f(FragmentProgramIter, fHighNoiseLevelBind, 0.04, 0.0, 0.0, 0.0);
0230:     cgGLBindUniform4f(FragmentProgramIter, fBaseRadiusFreqBind, 0.70, 0.0, 0.0, 0.0);
0231:     cgGLBindUniform4f(FragmentProgramIter, fLowPulseAmpBind,    1.5, 0.0, 0.0, 0.0);    
0232:     cgGLBindUniformMatrixcf(VertexProgramIter, ShaderMatrix, (const float *)&mWorld[0][0]);
0233: #else
0234:     // 木の感じ
0235:     cgGLBindUniform4f(FragmentProgramIter, fLightWoodColorBind, 0.76, 0.54, 0.32, 0.0);
0236:     cgGLBindUniform4f(FragmentProgramIter, fDarkWoodColorBind,  0.62, 0.38, 0.20, 0.0);
0237:     cgGLBindUniform4f(FragmentProgramIter, fBaseRadiusFreqBind, 1.10, 0.0, 0.0, 0.0);
0238:     cgGLBindUniform4f(FragmentProgramIter, fHighNoiseLevelBind, 0.03, 0.0, 0.0, 0.0);
0239:     cgGLBindUniform4f(FragmentProgramIter, fLowPulseAmpBind,     1.0, 0.0, 0.0, 0.0);   
0240: 
0241:     ifMatrix m0, m1;
0242:     ifMatrixScaling( &m0, 10, 10, 10 ); 
0243:     myRotationMatrix(20, 1.0f, 1.0f, 0.0f , (float*)&m1[0][0]);
0244:     ifMatrixMultiply(&m0, (const ifMatrix *)&m0, (const ifMatrix *)&m1);
0245:     ifMatrixTranspose(&m0, (const ifMatrix *)&m0);
0246:     cgGLBindUniformMatrixcf(VertexProgramIter, ShaderMatrix, (const float *)&m0[0][0]);
0247: #endif
0248: 
0249:     // local ⇒ proj
0250:     cgGLBindUniformStateMatrix(VertexProgramIter, WPMatrix, 
0251:         cgGLModelViewProjectionMatrix, cgGLMatrixIdentity);
0252:     // local ⇒ view
0253:     cgGLBindUniformStateMatrix(VertexProgramIter, WMatrix, 
0254:         cgGLModelViewMatrix, cgGLMatrixIdentity);
0255:     // view ⇒ local
0256:     cgGLBindUniformStateMatrix(VertexProgramIter, WITMatrix, 
0257:         cgGLModelViewMatrix, cgGLMatrixTranspose | cgGLMatrixInverse);
0258: 
0259:     // -----------------------------------------------------------------------
0260:     // 描画
0261:     // -----------------------------------------------------------------------
0262:     glutSolidTeapot(1);             // ティーポットの描画
0263: 
0264:     // -----------------------------------------------------------------------
0265:     // 描画の終了
0266:     // -----------------------------------------------------------------------
0267:     // テクスチャの無効化
0268:     cgGLActiveTexture(NoiseMapBind);        glDisable(GL_TEXTURE_3D_EXT);
0269:     cgGLActiveTexture(PulseTrainMapBind);   glDisable(GL_TEXTURE_1D);
0270:     // シェーダの無効化
0271:     cgGLDisableProgramType(cgFragmentProfile);
0272:     cgGLDisableProgramType(cgVertexProfile);
0273: 
0274:     glPopMatrix();                  // ビュー行列に現在の行列を戻す
0275:     glutSwapBuffers();              // 画面の更新の終了
0276: }
0277: // ---------------------------------------------------------------------------
0278: // 画面がリサイズされたとき
0279: // ---------------------------------------------------------------------------
0280: void resize(int w, int h)
0281: {
0282:     // ビューポートの設定
0283:     glViewport(0, 0, w, h);
0284: 
0285:     // 射影行列の設定
0286:     glMatrixMode(GL_PROJECTION);
0287:     glLoadIdentity();
0288:     gluPerspective( 60.0,           // 画角
0289:                     1.0,            // アスペクト比
0290:                     0.1, 10.0);     // 前方面、後方面
0291: }
0292: // ---------------------------------------------------------------------------
0293: // ひまなときに実行される
0294: // ---------------------------------------------------------------------------
0295: void idle()
0296: {
0297:     // ポリゴンの回転
0298:     r = r + 3.0f;
0299:     while (360.0f < r) r -= 360.0f;
0300: 
0301:     // 再描画リクエスト
0302:     glutPostRedisplay();
0303: }
0304: // ---------------------------------------------------------------------------
0305: // OpenGL に関する初期化
0306: // ---------------------------------------------------------------------------
0307: static void InitializeGlut(int argc, char *argv[])
0308: {
0309:     // ウィンドウの作成
0310:     glutInit(&argc, argv);              // GLの初期化
0311:     glutInitDisplayMode(GLUT_DOUBLE     // 描画モード
0312:                      | GLUT_RGBA        // wバッファ+RGBA+深度バッファ
0313:                      | GLUT_DEPTH);
0314:     glutInitWindowPosition(100, 100);   // 表示位置
0315:     glutInitWindowSize(512, 512);       // サイズ
0316:     glutCreateWindow("Wood");   // ウィンドウの生成
0317: 
0318:     // コールバック関数の設定
0319:     glutDisplayFunc(display);   // 描画関数
0320:     glutReshapeFunc(resize);    // 画面が変形したとき
0321:     glutIdleFunc(idle);         // ひまなとき
0322: 
0323:     // 一度だけすればいい設定
0324:     glClearColor(0.23, 0.43, 0.64, 0.0);    // 背景色の設定
0325:     glEnable(GL_DEPTH_TEST);            // 深度バッファの使用
0326: }
0327: // ---------------------------------------------------------------------------
0328: // Cgの初期化
0329: // ---------------------------------------------------------------------------
0330: static void InitializeCg()
0331: {
0332:     cgError Ret;
0333:     
0334:     // Cg の作成
0335:     CgContext = cgCreateContext();
0336:     assert(CgContext != NULL);
0337: 
0338:     // 頂点プログラムの作成
0339:     Ret = cgAddProgramFromFile(CgContext, "vp.cg", cgVertexProfile, NULL);
0340:     fprintf(stderr, "LAST LISTING----%s----\n", cgGetLastListing(CgContext));
0341:     assert(Ret == cgNoError);
0342: 
0343:     // プログラム名でプログラムを結びつける
0344:     VertexProgramIter = cgProgramByName(CgContext, "main");
0345:     assert(VertexProgramIter != NULL);
0346: 
0347: #if 0
0348:     // ソースの表示
0349:     fprintf(stderr, "---- プログラム はじめ ----\n"
0350:                     "%s"
0351:                     "---- プログラム 終わり ----\n",
0352:     cgGetProgramObjectCode(VertexProgramIter));
0353: #endif
0354: 
0355:     if(VertexProgramIter != NULL) {
0356:         GLuint ProgId = 1;
0357: 
0358:         Ret = cgGLLoadProgram(VertexProgramIter, ProgId);
0359:         assert(Ret == cgNoError);
0360: 
0361:         LightPos    = cgGetBindByName(VertexProgramIter, "LightPosition");
0362:         WPMatrix    = cgGetBindByName(VertexProgramIter, "ModelViewProj");
0363:         WMatrix     = cgGetBindByName(VertexProgramIter, "ModelView");
0364:         WITMatrix   = cgGetBindByName(VertexProgramIter, "ModelViewIT");
0365:         ShaderMatrix= cgGetBindByName(VertexProgramIter, "ShaderMatrix");
0366: 
0367:         // エラーチェック
0368:         assert(LightPos != NULL);
0369:         assert(WPMatrix != NULL);
0370:         assert(WMatrix != NULL);
0371:         assert(WITMatrix != NULL);
0372:         assert(ShaderMatrix != NULL);
0373:     }
0374: 
0375:  
0376:     // フラグメントプログラム
0377:     Ret = cgAddProgramFromFile(CgContext, "fp.cg", cgFragmentProfile, NULL);
0378:     assert(Ret == cgNoError);
0379: 
0380:     // プログラム名でプログラムを結びつける
0381:     FragmentProgramIter = cgProgramByName(CgContext, "main");
0382:     assert(FragmentProgramIter != NULL);
0383: 
0384: #if 0
0385:     // ソースの表示
0386:     fprintf(stderr, "---- プログラム はじめ ----\n"
0387:                     "%s"
0388:                     "---- プログラム 終わり ----\n",
0389:     cgGetProgramObjectCode(FragmentProgramIter));
0390: #endif
0391:     if(FragmentProgramIter != NULL) {
0392:         GLuint ProgId = 2;
0393: 
0394:         Ret = cgGLLoadProgram(FragmentProgramIter, ProgId);
0395:         assert(Ret == cgNoError);
0396: 
0397:         fLightWoodColorBind = cgGetBindByName(FragmentProgramIter, "fLightWood");
0398:         fDarkWoodColorBind  = cgGetBindByName(FragmentProgramIter, "fDarkWood");
0399:         fHighNoiseLevelBind = cgGetBindByName(FragmentProgramIter, "fHighNoiseLevel");
0400:         fBaseRadiusFreqBind = cgGetBindByName(FragmentProgramIter, "fBaseRadiusFreq");
0401:         fLowPulseAmpBind    = cgGetBindByName(FragmentProgramIter, "fLowPulseAmp");
0402:         NoiseMapBind        = cgGetBindByName(FragmentProgramIter, "NoiseMap");
0403:         PulseTrainMapBind   = cgGetBindByName(FragmentProgramIter, "PulseTrainMap");
0404: 
0405:         // エラーチェック
0406:         assert(fLightWoodColorBind != NULL);
0407:         assert(fDarkWoodColorBind != NULL);
0408:         assert(fHighNoiseLevelBind != NULL);
0409:         assert(fBaseRadiusFreqBind != NULL);
0410:         assert(fLowPulseAmpBind != NULL);
0411:         assert(NoiseMapBind != NULL);
0412:         assert(PulseTrainMapBind != NULL);
0413:     }
0414:     
0415: }
0416: // ---------------------------------------------------------------------------
0417: // Cg の後片付け
0418: // ---------------------------------------------------------------------------
0419: static void CleanupCg()
0420: {
0421:     // フラグメントプログラム
0422:     if(PulseTrainMapBind    )cgFreeBindIter( PulseTrainMapBind );
0423:     if(NoiseMapBind         )cgFreeBindIter( NoiseMapBind );
0424:     if(fLowPulseAmpBind     )cgFreeBindIter( fLowPulseAmpBind );
0425:     if(fBaseRadiusFreqBind  )cgFreeBindIter( fBaseRadiusFreqBind );
0426:     if(fHighNoiseLevelBind  )cgFreeBindIter( fHighNoiseLevelBind );
0427:     if(fDarkWoodColorBind   )cgFreeBindIter( fDarkWoodColorBind );
0428:     if(fLightWoodColorBind  )cgFreeBindIter( fLightWoodColorBind );
0429:     cgFreeProgramIter( FragmentProgramIter );
0430: 
0431:     // 頂点プログラム
0432:     if(LightPos     )cgFreeBindIter( LightPos );
0433:     if(WPMatrix     )cgFreeBindIter( WPMatrix );
0434:     if(WMatrix      )cgFreeBindIter( WMatrix );
0435:     if(WITMatrix    )cgFreeBindIter( WITMatrix );
0436:     if(ShaderMatrix )cgFreeBindIter( ShaderMatrix );
0437:     cgFreeProgramIter( VertexProgramIter );
0438: 
0439:     cgFreeContext( CgContext );
0440:     cgCleanup( );
0441: }
0442: // ---------------------------------------------------------------------------
0443: // メイン関数
0444: // ---------------------------------------------------------------------------
0445: int main(int argc, char *argv[])
0446: {
0447:     // 初期化
0448:     InitializeGlut(argc, argv);
0449:     InitializeCg();
0450:     // テクスチャの生成
0451:     g_iNoiseTex = noise.CreateNoiseTexture3D(64,64,64,1.0,1.0);
0452:     g_iPilseTrainTex = generateSmoothPulseTrain();
0453:   
0454:     // メインループ
0455:     glutMainLoop();
0456: 
0457:     // 後片付け
0458:     CleanupCg();
0459:     
0460:     return 0;
0461: }