#include "glInterface.h" #include "GlobalLinesRenderer.h" #include "common.h" #include "RenderTexture.h" #include "Preprocessor.h" #include "GlRenderer.h" #include "Exporter.h" // the devil library #include #include #include #include #include //#include namespace GtpVisibilityPreprocessor { static CGcontext sCgContext = NULL; static CGprogram sCgDepthPeelingProgram = NULL; static CGprogram sCgPassThroughProgram = NULL; static CGprofile sCgFragmentProfile; static CGparameter sTextureParam; GlobalLinesRenderer *globalLinesRenderer = NULL; static int texWidth = 256; static int texHeight = 256; static bool isDepth = true; static void InitDevIl() { ilInit(); ILuint ImageName; ilGenImages(1, &ImageName); ilBindImage(ImageName); ilEnable(IL_FILE_OVERWRITE); // ilRegisterFormat(IL_RGBA); // ilRegisterType(IL_FLOAT); // ilEnable(IL_ORIGIN_SET); // ilOriginFunc(IL_ORIGIN_UPPER_LEFT); } static void cgErrorCallback() { CGerror lastError = cgGetError(); if(lastError) { printf("%s\n\n", cgGetErrorString(lastError)); printf("%s\n", cgGetLastListing(sCgContext)); printf("Cg error, exiting...\n"); exit(0); } } static void PrintGLerror(char *msg) { GLenum errCode; const GLubyte *errStr; if ((errCode = glGetError()) != GL_NO_ERROR) { errStr = gluErrorString(errCode); fprintf(stderr,"OpenGL ERROR: %s: %s\n", errStr, msg); } } void Reshape(int w, int h) { if (h == 0) h = 1; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 3, 5000.0); //gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 0.5, 10.0); glOrtho(-1, 1, -1, 1, 0.5, 15); } void SetFrustum(const int sizeX, const int sizeY, const float nearPlane, const float farPlane) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-sizeX * 0.5, sizeX * 0.5, -sizeY * 0.5, sizeY * 0.5, nearPlane, farPlane); /*glOrtho(0, sizeX, 0, sizeY , nearPlane, farPlane);*/ } void Display() { //globalLinesRenderer->DrawGeometry(); //globalLinesRenderer->CastGlobalLines(Beam(), 0); globalLinesRenderer->DisplayBuffer(isDepth); PrintGLerror("display"); glutSwapBuffers(); } void Idle() { glutPostRedisplay(); } void Keyboard(unsigned char key, int x, int y) { switch(key) { case '2': { VssRayContainer rays; ++ globalLinesRenderer->mMaxDepth; globalLinesRenderer->ApplyDepthPeeling(rays, Beam(), 0); cout << "max depth: " << globalLinesRenderer->mMaxDepth << endl; CLEAR_CONTAINER(rays); return; } case '1': { VssRayContainer rays; -- globalLinesRenderer->mMaxDepth; cout << "max depth: " << globalLinesRenderer->mMaxDepth << endl; globalLinesRenderer->ApplyDepthPeeling(rays, Beam(), 0); CLEAR_CONTAINER(rays); return; } case '3': { //globalLinesRenderer->ApplyDepthPeeling(Beam(), 0); globalLinesRenderer->ExportDepthBuffer(); return; } case '4': { //globalLinesRenderer->ApplyDepthPeeling(Beam(), 0); globalLinesRenderer->ExportItemBuffer(); return; } case '8': { isDepth = !isDepth; return; } case '9': { VssRayContainer rays; globalLinesRenderer->ApplyDepthPeeling(rays, Beam(), 0); VssRayContainer outRays; VssRayContainer::const_iterator vit, vit_end = rays.end(); const float p = 8.0f / (float)rays.size(); for (vit = rays.begin(); vit != vit_end; ++ vit) { if (Random(1.0f) < p) { outRays.push_back(*vit); } } globalLinesRenderer->Visualize(rays); CLEAR_CONTAINER(rays); return; } case '0': { VssRayContainer rays; globalLinesRenderer->ApplyDepthPeeling(rays, Beam(), 0); CLEAR_CONTAINER(rays); return; } default: return; } } /*GlobalLinesRenderer::GlobalLinesRenderer(RenderTexture *buffer1, RenderTexture *buffer2, Preprocessor *preprocessor, GlRenderer *renderer) : mNewTexture(buffer1), mOldTexture(buffer2), mPreprocessor(preprocessor), mMaxDepth(100), mRenderer(renderer) { } */ GlobalLinesRenderer::GlobalLinesRenderer(Preprocessor *preprocessor, GlRenderer *renderer): mNewTexture(NULL), mOldTexture(NULL), mMaxDepth(0), mRenderer(renderer), mPreprocessor(preprocessor) { } void GlobalLinesRenderer::DisplayBuffer(const bool isDepth) { if (!isDepth) mNewTexture->Bind(); else mNewTexture->BindDepth(); mNewTexture->EnableTextureTarget(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (mNewTexture->IsRectangleTexture()) { glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-1, -1, -0.5f); glTexCoord2f(mNewTexture->GetWidth(), 0); glVertex3f( 1, -1, -0.5f); glTexCoord2f(mNewTexture->GetWidth(), mNewTexture->GetHeight()); glVertex3f( 1, 1, -0.5f); glTexCoord2f(0, mNewTexture->GetHeight()); glVertex3f(-1, 1, -0.5f); glEnd(); } else { glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-1, -1, -0.5f); glTexCoord2f(1, 0); glVertex3f( 1, -1, -0.5f); glTexCoord2f(1, 1); glVertex3f( 1, 1, -0.5f); glTexCoord2f(0, 1); glVertex3f(-1, 1, -0.5f); glEnd(); } mNewTexture->DisableTextureTarget(); PrintGLerror("displaytexture"); } GlobalLinesRenderer::~GlobalLinesRenderer() { if (sCgDepthPeelingProgram) cgDestroyProgram(sCgDepthPeelingProgram); if (sCgContext) cgDestroyContext(sCgContext); // init the receiving buffers delete mNewDepthBuffer; delete mOldDepthBuffer; delete mNewItemBuffer; delete mOldItemBuffer; } void GlobalLinesRenderer::CastGlobalLines(Beam &beam, const int samples) { VssRayContainer rays; // bind pixel shader implementing the front depth buffer functionality ApplyDepthPeeling(rays, beam, samples); } void GlobalLinesRenderer::RenderObject(Intersectable *obj) { mRenderer->RenderIntersectable(obj); } void GlobalLinesRenderer::DrawGeometry() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glPushMatrix(); { //glLoadIdentity(); ObjectContainer::const_iterator oit, oit_end = mPreprocessor->mObjects.end(); Intersectable::NewMail(); for (oit = mPreprocessor->mObjects.begin(); oit != oit_end; ++ oit) { cout << (*oit)->GetId() << " "; RenderObject(*oit); } } glPopMatrix(); } void GlobalLinesRenderer::SwitchRenderTextures() { RenderTexture *buffer = mOldTexture; mOldTexture = mNewTexture; mNewTexture = buffer; } void GlobalLinesRenderer::ComputeLookAt(const float alpha, const float beta, Vector3 &eye, Vector3 &up, Vector3 left) { //float x = cos(alpha); //float y = sin(alpha); eye.x = sin(alpha) * cos(beta); eye.y = sin(alpha) * sin(beta); eye.z = cos(beta); eye.RightHandedBase(up, left); } void GlobalLinesRenderer::InitGl() { InitDevIl(); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutInitWindowPosition(50, 50); glutInitWindowSize(512, 512); glutCreateWindow("TestRenderDepthTexture"); int err = glewInit(); if (GLEW_OK != err) { // problem: glewInit failed, something is seriously wrong fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); exit(-1); } glutKeyboardFunc(Keyboard); glutDisplayFunc(Display); glutIdleFunc(Idle); glutReshapeFunc(Reshape); Reshape(512, 512); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // initialise the receiving buffers mNewDepthBuffer = new float[texWidth * texHeight]; mNewItemBuffer = new unsigned char[texWidth * texHeight * 4]; mOldDepthBuffer = new float[texWidth * texHeight]; mOldItemBuffer = new unsigned char[texWidth * texHeight * 4]; for (int i = 0; i < texWidth * texHeight; ++ i) { mNewDepthBuffer[i] = 1; mOldDepthBuffer[i] = 1; mNewItemBuffer[i * 4] = 255; mNewItemBuffer[i * 4 + 1] = 255; mNewItemBuffer[i * 4 + 2] = 255; mNewItemBuffer[i * 4 + 3] = 255; mOldItemBuffer[i * 4] = 255; mOldItemBuffer[i * 4 + 1] = 255; mOldItemBuffer[i * 4 + 2] = 255; mOldItemBuffer[i * 4 + 3] = 255; } AxisAlignedBox3 bbox = globalLinesRenderer->mPreprocessor->mKdTree->GetBox(); Vector3 midPoint = bbox.Center(); const float sceneSize = Magnitude(bbox.Diagonal()); mViewPoint = midPoint + Vector3(0.5 * sceneSize, 0, 0); cout << "mid point: " << midPoint << endl; cout << "view point: " << mViewPoint << endl; cout << "scene: " << bbox << endl; mNear = 1; mFar = sceneSize; mWidth = sceneSize; mEyeVec = Normalize(midPoint - mViewPoint); mEyeVec.RightHandedBase(mUpVec, mLeftVec); /*gluLookAt(mViewPoint.x, mViewPoint.y, mViewPoint.z, midPoint.x, midPoint.y, midPoint.z, 0, 1, 0); */ gluLookAt(0, 0, 3, 0, 0, 0, 0, 1, 0); //glDisable(GL_CULL_FACE); glEnable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glClearColor(0.1, 0.2, 0.3, 1); // A square, mipmapped, anisotropically filtered 8-bit RGBA texture with // depth and stencil. // Note that RT_COPY_TO_TEXTURE is required for depth textures on ATI hardware mNewTexture = new RenderTexture(texWidth, texHeight, true, true); //mNewTexture->Initialize(true, true, false, true, true, 8, 8, 8, 8);//, RenderTexture::RT_COPY_TO_TEXTURE); mNewTexture->Initialize(true, true, false, true, true, 8, 8, 8, 8, RenderTexture::RT_COPY_TO_TEXTURE); mOldTexture = new RenderTexture(texWidth, texHeight, true, true); //mOldTexture ->Initialize(true, true, false, true, true, 8, 8, 8, 8);//, RenderTexture::RT_COPY_TO_TEXTURE); mOldTexture ->Initialize(true, true, false, true, true, 8, 8, 8, 8, RenderTexture::RT_COPY_TO_TEXTURE); // Setup Cg cgSetErrorCallback(cgErrorCallback); // Create cgContext. sCgContext = cgCreateContext(); // get the best profile for this hardware sCgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); //assert(sCgFragmentProfile != CG_PROFILE_UNKNOWN); cgGLSetOptimalOptions(sCgFragmentProfile); sCgDepthPeelingProgram = cgCreateProgramFromFile(sCgContext, CG_SOURCE, mNewTexture->IsRectangleTexture() ? "../src/depth_peelingRect.cg" : "../src/depth_peeling2d.cg", GLEW_ARB_fragment_program ? CG_PROFILE_ARBFP1 : CG_PROFILE_FP30, NULL, NULL); if(sCgDepthPeelingProgram != NULL) { cgGLLoadProgram(sCgDepthPeelingProgram); sTextureParam = cgGetNamedParameter(sCgDepthPeelingProgram, "depthTex"); } sCgPassThroughProgram = cgCreateProgramFromFile(sCgContext, CG_SOURCE, "../src/passthrough.cg", GLEW_ARB_fragment_program ? CG_PROFILE_ARBFP1 : CG_PROFILE_FP30, NULL, NULL); if(sCgPassThroughProgram != NULL) { cgGLLoadProgram(sCgPassThroughProgram); } // setup the rendering context for the RenderTexture mNewTexture->BeginCapture(); { //Reshape(texWidth, texHeight); glViewport(0, 0, texWidth, texHeight); SetFrustum(mWidth, mWidth, mNear, mFar); // for item buffer: white means no color glClearColor(1, 1, 1, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glFrontFace(GL_CCW); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); //glEnable(GL_CULL_FACE); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(mViewPoint.x, mViewPoint.y, mViewPoint.z, midPoint.x, midPoint.y, midPoint.z, 0, 1, 0); } mNewTexture->EndCapture(); // setup the rendering context for the other depth buffer mOldTexture->BeginCapture(); { // for item buffer: white means no color glClearColor(1, 1, 1, 1); //Reshape(texWidth, texHeight); glViewport(0, 0, texWidth, texHeight); SetFrustum(mWidth, mWidth, mNear, mFar); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glFrontFace(GL_CCW); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); //glEnable(GL_CULL_FACE); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); gluLookAt(mViewPoint.x, mViewPoint.y, mViewPoint.z, midPoint.x, midPoint.y, midPoint.z, 0, 1, 0); //SetFrustum(sceneSize, sceneSize, 1, sceneSize); } mOldTexture->EndCapture(); PrintGLerror("init"); } Intersectable *GlobalLinesRenderer::ExtractSamplePoint(float *depthBuffer, unsigned char *itemBuffer, const int x, const int y, Vector3 &hitPoint, const bool isFrontBuffer) const { const int depthIndex = x + texWidth * y; const int itemIndex = 4 * depthIndex; const float depth = depthBuffer[depthIndex]; const float eyeDist = mNear + (mFar - mNear) * depth; const float leftDist = 0.5f * mWidth - mWidth * ((float)x + 0.5f) / texWidth; //const float upDist = 0.5f * mWidth - (float)mWidth * ((float)y + 0.5f) / texHeight; const float upDist = -0.5f * mWidth + mWidth * ((float)y + 0.5f) / texHeight; hitPoint = mViewPoint + eyeDist * mEyeVec + leftDist * mUpVec + upDist * mLeftVec; unsigned char r = itemBuffer[itemIndex]; unsigned char g = itemBuffer[itemIndex + 1]; unsigned char b = itemBuffer[itemIndex + 2]; // 3 times 255 means no valid object if ((r == 255) && (g == 255) && (b == 255)) return NULL; const int id = mRenderer->GetId(r, g, b); //cout << "r: " << (int)r << "g: " << (int)g << " b: " << (int)b << " id: " << id << "|"; Intersectable *intersect = mPreprocessor->GetObjectById(id); const Vector3 dir = isFrontBuffer ? mEyeVec : -mEyeVec; // HACK: assume triangle intersectable const Vector3 norm = intersect->GetNormal(0); // test for invalid view space if (DotProd(dir, norm) >= -Limits::Small) return NULL; return intersect; } void GlobalLinesRenderer::ProcessDepthBuffer(VssRayContainer &vssRays, const bool oldBufferInitialised) { GrabDepthBuffer(mNewDepthBuffer, mNewTexture); GrabItemBuffer(mNewItemBuffer, mNewTexture); if (oldBufferInitialised) { GrabDepthBuffer(mOldDepthBuffer, mOldTexture); GrabItemBuffer(mOldItemBuffer, mOldTexture); } else { for (int i = 0; i < texWidth * texHeight; ++ i) { mOldDepthBuffer[i] = 0; mOldItemBuffer[i * 4] = 255; mOldItemBuffer[i * 4 + 1] = 255; mOldItemBuffer[i * 4 + 2] = 255; mOldItemBuffer[i * 4 + 3] = 255; } } cout << "vp: " << "eye: " << mEyeVec << " left: " << mLeftVec << " up: " << mUpVec << endl; for (int y = 0; y < texHeight; ++ y) { for (int x = 0; x < texWidth; ++ x) { Vector3 newPt, oldPt; Intersectable *termObj1 = ExtractSamplePoint(mNewDepthBuffer, mNewItemBuffer, x, y, newPt, true); Intersectable *termObj2 = ExtractSamplePoint(mOldDepthBuffer, mOldItemBuffer, x, y, oldPt, false); // create rays in both directions if (termObj1) { vssRays.push_back(new VssRay(oldPt, newPt, NULL, termObj1)); //cout << "new pt: " << newPt << endl; } if (termObj2) { vssRays.push_back(new VssRay(newPt, oldPt, NULL, termObj2)); //cout << "old pt: " << oldPt << endl; } } } } void GlobalLinesRenderer::Run() { glutMainLoop(); } void SetupFalseColor(const unsigned int id, unsigned char &r, unsigned char &g, unsigned char &b ) { // swap bits of the color r = id & 255; g = (id >> 8) & 255; b = (id >> 16) & 255; } void GlobalLinesRenderer::Visualize(const VssRayContainer &vssRays) { Exporter *exporter = Exporter::GetExporter("globalLines.wrl"); if (!exporter) return; exporter->SetWireframe(); //exporter->ExportGeometry(preprocessor->mObjects); exporter->SetFilled(); VssRayContainer::const_iterator vit, vit_end = vssRays.end(); for (vit = vssRays.begin(); vit != vit_end; ++ vit) { VssRay *ray = *vit; Intersectable *obj = (*vit)->mTerminationObject; exporter->ExportIntersectable(obj); } // exporter->ExportRays(vssRays); delete exporter; } void GlobalLinesRenderer::GrabDepthBuffer(float *data, RenderTexture *rt) { rt->BindDepth(); rt->EnableTextureTarget(); cout << "depth: " << mNewTexture->GetDepthBits() << endl; const int texFormat = GL_DEPTH_COMPONENT; glGetTexImage(mNewTexture->GetTextureTarget(), 0, texFormat, GL_FLOAT, data); mNewTexture->DisableTextureTarget(); } void GlobalLinesRenderer::GrabItemBuffer(unsigned char *data, RenderTexture *rt) { rt->Bind(); rt->EnableTextureTarget(); //cout << "depth: " << mNewTexture->GetDepthBits() << endl; const int texFormat = GL_RGBA; glGetTexImage(mNewTexture->GetTextureTarget(), 0, texFormat, GL_UNSIGNED_BYTE, data); mNewTexture->DisableTextureTarget(); } void GlobalLinesRenderer::ExportDepthBuffer() { mNewTexture->BindDepth(); mNewTexture->EnableTextureTarget(); cout << "depth: " << mNewTexture->GetDepthBits() << endl; const int components = 1;//mNewTexture->GetDepthBits() / 8; float *data = new float[texWidth * texHeight * components]; //const int texFormat = WGL_TEXTURE_DEPTH_COMPONENT_NV; const int texFormat = GL_DEPTH_COMPONENT; //const int texFormat = GL_RGBA; glGetTexImage(mNewTexture->GetTextureTarget(), 0, texFormat, GL_FLOAT, data); /*for (int i = texWidth * 123; i < texWidth * 124; ++ i) { cout << data[i] << " "; } cout << "Saving image " << texWidth << " " << texHeight << endl; */ string filename("depth.tga"); ilRegisterType(IL_FLOAT); const int depth = 1; const int bpp = components; ilTexImage(texWidth, texHeight, depth, bpp, IL_LUMINANCE, IL_FLOAT, data); ilSaveImage((char *const)filename.c_str()); cout << "finished" << endl; delete data; cout << "data deleted" << endl; mNewTexture->DisableTextureTarget(); PrintGLerror("grab texture"); } /* void GlobalLinesRenderer::ExportItemBuffer() { mNewTexture->Bind(); mNewTexture->EnableTextureTarget(); cout << "depth: " << mNewTexture->GetDepthBits() << endl; const int components = 4;//mNewTexture->GetDepthBits() / 8; float *data = new float[texWidth * texHeight * components*8]; const int texFormat = GL_RGBA; glGetTexImage(mNewTexture->GetTextureTarget(), 0, texFormat, GL_FLOAT, data); string filename("items.tga"); ilRegisterType(IL_FLOAT); const int depth = 1; const int bpp = components; cout << "saving items to file " << endl; ilTexImage(16, 16, depth, bpp, IL_RGBA, IL_FLOAT, data); ilSaveImage((char *const)filename.c_str()); cout << "finished" << endl; delete data; cout << "data deleted" << endl; mNewTexture->DisableTextureTarget(); PrintGLerror("grab texture"); } */ void GlobalLinesRenderer::ExportItemBuffer() { mNewTexture->Bind(); mNewTexture->EnableTextureTarget(); cout << "depth: " << mNewTexture->GetDepthBits() << endl; const int components = 4;//mNewTexture->GetDepthBits() / 8; unsigned char *data = new unsigned char [texWidth * texHeight * components]; //const int texFormat = WGL_TEXTURE_DEPTH_COMPONENT_NV; const int texFormat = GL_RGBA; glGetTexImage(mNewTexture->GetTextureTarget(), 0, texFormat, GL_UNSIGNED_BYTE, data); string filename("items.jpg"); ilRegisterType(IL_UNSIGNED_BYTE); const int depth = 1; const int bpp = components; ilTexImage(texWidth, texHeight, depth, bpp, IL_RGBA, IL_UNSIGNED_BYTE, data); ilSaveImage((char *const)filename.c_str()); cout << "finished" << endl; delete data; cout << "data deleted" << endl; mNewTexture->DisableTextureTarget(); PrintGLerror("grab texture"); } void GlobalLinesRenderer::ApplyDepthPeeling(VssRayContainer &rays, Beam &beam, const int samples) { mNewTexture->BeginCapture(); { //cgGLBindProgram(sCgPassThroughProgram); //cgGLEnableProfile(sCgFragmentProfile); DrawGeometry(); } mNewTexture->EndCapture(); PrintGLerror("firstpass"); if (mNewTexture->IsRectangleTexture()) cout << "rect" << endl; // process the buffers for the first layer ProcessDepthBuffer(rays, false); for(int i = 0; i < mMaxDepth; ++ i) { // Peel another layer SwitchRenderTextures(); // switch pointer between rendertextures mNewTexture->BeginCapture(); { //if (mNewTexture->IsDoubleBuffered()) // glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLBindProgram(sCgDepthPeelingProgram); cgGLEnableProfile(sCgFragmentProfile); cgGLSetTextureParameter(sTextureParam, mOldTexture->GetDepthTextureID()); cgGLEnableTextureParameter(sTextureParam); //glutSolidTorus(0.25, 1, 32, 64); DrawGeometry(); glPopMatrix(); cgGLDisableTextureParameter(sTextureParam); cgGLDisableProfile(sCgFragmentProfile); } mNewTexture->EndCapture(); // process the buffers for following layer ProcessDepthBuffer(rays, true); } PrintGLerror("endpeeling"); } }