#include "RAS_OpenGLRasterizer.h" #ifdef WIN32 #include #endif // WIN32 #include "GL/gl.h" #include "RAS_Rect.h" #include "RAS_TexVert.h" #include "MT_CmMatrix4x4.h" #include "RAS_IRenderTools.h" // rendering text RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas) :RAS_IRasterizer(canvas), m_2DCanvas(canvas), m_fogenabled(false), m_materialCachingInfo(0), m_noOfScanlines(32) { m_viewmatrix.Identity(); m_stereomode = RAS_STEREO_NOSTEREO; } RAS_OpenGLRasterizer::~RAS_OpenGLRasterizer() { } void Myinit_gl_stuff(void) { float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 }; float mat_shininess[] = { 35.0 }; /* float one= 1.0; */ int a, x, y; GLubyte pat[32*32]; const GLubyte *patc= pat; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess); #if defined(__FreeBSD) || defined(__linux__) glDisable(GL_DITHER); /* op sgi/sun hardware && 12 bits */ #endif /* no local viewer, looks ugly in ortho mode */ /* glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, &one); */ glDepthFunc(GL_LEQUAL); /* scaling matrices */ glEnable(GL_NORMALIZE); glShadeModel(GL_FLAT); glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDisable(GL_FOG); glDisable(GL_LIGHTING); glDisable(GL_LOGIC_OP); glDisable(GL_STENCIL_TEST); glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); glPixelTransferi(GL_MAP_COLOR, GL_FALSE); glPixelTransferi(GL_RED_SCALE, 1); glPixelTransferi(GL_RED_BIAS, 0); glPixelTransferi(GL_GREEN_SCALE, 1); glPixelTransferi(GL_GREEN_BIAS, 0); glPixelTransferi(GL_BLUE_SCALE, 1); glPixelTransferi(GL_BLUE_BIAS, 0); glPixelTransferi(GL_ALPHA_SCALE, 1); glPixelTransferi(GL_ALPHA_BIAS, 0); a = 0; for(x=0; x<32; x++) { for(y=0; y<4; y++) { if( (x) & 1) pat[a++]= 0x88; else pat[a++]= 0x22; } } glPolygonStipple(patc); } bool RAS_OpenGLRasterizer::Init() { Myinit_gl_stuff(); m_redback = 0.4375; m_greenback = 0.4375; m_blueback = 0.4375; m_alphaback = 0.0; // enable both vertexcolor AND lighting color glEnable(GL_COLOR_MATERIAL); glClearColor(m_redback,m_greenback,m_blueback,m_alphaback); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glShadeModel(GL_SMOOTH); return true; } void RAS_OpenGLRasterizer::SetBackColor(float red, float green, float blue, float alpha) { m_redback = red; m_greenback = green; m_blueback = blue; m_alphaback = alpha; } void RAS_OpenGLRasterizer::SetFogColor(float r, float g, float b) { m_fogr = r; m_fogg = g; m_fogb = b; m_fogenabled = true; } void RAS_OpenGLRasterizer::SetFogStart(float start) { m_fogstart = start; m_fogenabled = true; } void RAS_OpenGLRasterizer::SetFogEnd(float fogend) { m_fogdist = fogend; m_fogenabled = true; } void RAS_OpenGLRasterizer::SetFog(float start, float dist, float r, float g, float b) { m_fogstart = start; m_fogdist = dist; m_fogr = r; m_fogg = g; m_fogb = b; m_fogenabled = true; } void RAS_OpenGLRasterizer::DisableFog() { m_fogenabled = false; } void RAS_OpenGLRasterizer::DisplayFog() { if ((m_drawingmode >= KX_SOLID) && m_fogenabled) { float params[5]; glFogi(GL_FOG_MODE, GL_LINEAR); glFogf(GL_FOG_DENSITY, 0.1f); glFogf(GL_FOG_START, m_fogstart); glFogf(GL_FOG_END, m_fogstart + m_fogdist); params[0]= m_fogr; params[1]= m_fogg; params[2]= m_fogb; params[3]= 0.0; glFogfv(GL_FOG_COLOR, params); glEnable(GL_FOG); } else { glDisable(GL_FOG); } } void RAS_OpenGLRasterizer::SetMaterial(const RAS_IPolyMaterial& mat) { if (mat.GetCachingInfo() != m_materialCachingInfo) { mat.Activate(this, m_materialCachingInfo); } } void RAS_OpenGLRasterizer::Exit() { glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glClearDepth(1.0); glClearColor(m_redback, m_greenback, m_blueback, m_alphaback); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDepthMask (GL_TRUE); glDepthFunc(GL_LEQUAL); glBlendFunc(GL_ONE, GL_ZERO); glDisable(GL_LIGHTING); EndFrame(); } bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time) { m_time = time; m_drawingmode = drawingmode; m_2DCanvas->ClearColor(m_redback,m_greenback,m_blueback,m_alphaback); m_2DCanvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER); // Blender camera routine destroys the settings if (m_drawingmode < KX_SOLID) { glDisable (GL_CULL_FACE); glDisable (GL_DEPTH_TEST); } else { glEnable(GL_DEPTH_TEST); glEnable (GL_CULL_FACE); } glShadeModel(GL_SMOOTH); m_2DCanvas->BeginFrame(); return true; } void RAS_OpenGLRasterizer::SetDrawingMode(int drawingmode) { m_drawingmode = drawingmode; switch (m_drawingmode) { case KX_BOUNDINGBOX: { } case KX_WIREFRAME: { glDisable (GL_CULL_FACE); break; } case KX_TEXTURED: { } case KX_SHADED: { } case KX_SOLID: { } default: { } } } int RAS_OpenGLRasterizer::GetDrawingMode() { return m_drawingmode; } void RAS_OpenGLRasterizer::SetDepthMask(int depthmask) { switch (depthmask) { case KX_DEPTHMASK_ENABLED: { glDepthMask(GL_TRUE); break; }; case KX_DEPTHMASK_DISABLED: { glDepthMask(GL_FALSE); break; }; default: { //printf("someone made a mistake, RAS_OpenGLRasterizer::SetDepthMask(int depthmask)\n"); exit(0); } } } void RAS_OpenGLRasterizer::ClearDepthBuffer() { m_2DCanvas->ClearBuffer(RAS_ICanvas::DEPTH_BUFFER); } void RAS_OpenGLRasterizer::ClearCachingInfo(void) { m_materialCachingInfo = 0; } void RAS_OpenGLRasterizer::EndFrame() { m_2DCanvas->EndFrame(); } void RAS_OpenGLRasterizer::SetRenderArea() { // only above/below stereo method needs viewport adjustment if(m_stereomode == RAS_STEREO_ABOVEBELOW) { switch(m_curreye) { case RAS_STEREO_LEFTEYE: // upper half of window m_2DCanvas->GetDisplayArea().SetLeft(0); m_2DCanvas->GetDisplayArea().SetBottom(m_2DCanvas->GetHeight() - int(m_2DCanvas->GetHeight() - m_noOfScanlines) / 2); m_2DCanvas->GetDisplayArea().SetRight(int(m_2DCanvas->GetWidth())); m_2DCanvas->GetDisplayArea().SetTop(int(m_2DCanvas->GetHeight())); break; case RAS_STEREO_RIGHTEYE: // lower half of window m_2DCanvas->GetDisplayArea().SetLeft(0); m_2DCanvas->GetDisplayArea().SetBottom(0); m_2DCanvas->GetDisplayArea().SetRight(int(m_2DCanvas->GetWidth())); m_2DCanvas->GetDisplayArea().SetTop(int(m_2DCanvas->GetHeight() - m_noOfScanlines) / 2); break; } } else { // every available pixel m_2DCanvas->GetDisplayArea().SetLeft(0); m_2DCanvas->GetDisplayArea().SetBottom(0); m_2DCanvas->GetDisplayArea().SetRight(int(m_2DCanvas->GetWidth())); m_2DCanvas->GetDisplayArea().SetTop(int(m_2DCanvas->GetHeight())); } } void RAS_OpenGLRasterizer::SetStereoMode(const int stereomode) { m_stereomode = stereomode; } bool RAS_OpenGLRasterizer::Stereo() { if(m_stereomode == RAS_STEREO_NOSTEREO) return false; else return true; } void RAS_OpenGLRasterizer::SetEye(int eye) { m_curreye = eye; if(m_stereomode == RAS_STEREO_QUADBUFFERED) { if(m_curreye == RAS_STEREO_LEFTEYE) glDrawBuffer(GL_BACK_LEFT); else glDrawBuffer(GL_BACK_RIGHT); } } void RAS_OpenGLRasterizer::SetEyeSeparation(float eyeseparation) { m_eyeseparation = eyeseparation; } void RAS_OpenGLRasterizer::SetFocalLength(float focallength) { m_focallength = focallength; } void RAS_OpenGLRasterizer::SwapBuffers() { m_2DCanvas->SwapBuffers(); } void RAS_OpenGLRasterizer::IndexPrimitives(const vecVertexArray & vertexarrays, const vecIndexArrays & indexarrays, int mode, class RAS_IPolyMaterial* polymat, class RAS_IRenderTools* rendertools, bool useObjectColor, const MT_Vector4& rgbacolor ) { static const GLsizei vtxstride = sizeof(RAS_TexVert); GLenum drawmode; switch (mode) { case 0: drawmode = GL_TRIANGLES; break; case 1: drawmode = GL_LINES; break; case 2: drawmode = GL_QUADS; break; default: drawmode = GL_LINES; break; } const RAS_TexVert* vertexarray ; int numindices,vt; for (vt=0;vtsize(); if (!numindices) break; int vindex=0; switch (mode) { case 1: { glBegin(GL_LINES); vindex=0; for (int i=0;isize(); if (!numindices) break; int vindex=0; switch (mode) { case 1: { glBegin(GL_LINES); vindex=0; for (int i=0;isize(); if (!numindices) break; int vindex=0; switch (mode) { case 1: { glBegin(GL_LINES); vindex=0; for (int i=0;iRenderText(polymat->GetDrawingMode(),polymat,v1,v2,v3,v4); ClearCachingInfo(); } break; } case 0: { glBegin(GL_TRIANGLES); vindex=0; for (int i=0;iRenderText(polymat->GetDrawingMode(),polymat,v1,v2,v3,NULL); ClearCachingInfo(); } glEnd(); break; } default: { } } //switch } //for each vertexarray } void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_CmMatrix4x4 &mat) { glMatrixMode(GL_PROJECTION); double* matrix = &mat(0,0); glLoadMatrixd(matrix); } void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_Matrix4x4 & mat) { glMatrixMode(GL_PROJECTION); double matrix[16]; /* Get into argument. Looks a bit dodgy, but it's ok. */ mat.getValue(matrix); /* Internally, MT_Matrix4x4 uses doubles (MT_Scalar). */ glLoadMatrixd(matrix); } MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix( float left, float right, float bottom, float top, float frustnear, float frustfar ){ MT_Matrix4x4 result; double mat[16]; // correction for stereo if(m_stereomode != RAS_STEREO_NOSTEREO) { float near_div_focallength; // next 2 params should be specified on command line and in Blender publisher m_focallength = 1.5 * right; // derived from example m_eyeseparation = 0.18 * right; // just a guess... near_div_focallength = frustnear / m_focallength; switch(m_curreye) { case RAS_STEREO_LEFTEYE: left += 0.5 * m_eyeseparation * near_div_focallength; right += 0.5 * m_eyeseparation * near_div_focallength; break; case RAS_STEREO_RIGHTEYE: left -= 0.5 * m_eyeseparation * near_div_focallength; right -= 0.5 * m_eyeseparation * near_div_focallength; break; } // leave bottom, top, bottom and top untouched } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(left, right, bottom, top, frustnear, frustfar); glGetDoublev(GL_PROJECTION_MATRIX, mat); result.setValue(mat); return result; } // next arguments probably contain redundant info, for later... void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vector3& campos, const MT_Point3 &camLoc, const MT_Quaternion &camOrientQuat) { MT_Matrix4x4 viewMat = mat; // correction for stereo if(m_stereomode != RAS_STEREO_NOSTEREO) { MT_Matrix3x3 camOrientMat3x3(camOrientQuat); MT_Vector3 unitViewDir(0.0, -1.0, 0.0); // minus y direction, Blender convention MT_Vector3 unitViewupVec(0.0, 0.0, 1.0); MT_Vector3 viewDir, viewupVec; MT_Vector3 eyeline; // actual viewDir viewDir = camOrientMat3x3 * unitViewDir; // this is the moto convention, vector on right hand side // actual viewup vec viewupVec = camOrientMat3x3 * unitViewupVec; // vector between eyes eyeline = viewDir.cross(viewupVec); switch(m_curreye) { case RAS_STEREO_LEFTEYE: { // translate to left by half the eye distance MT_Transform transform; transform.setIdentity(); transform.translate(-(eyeline * m_eyeseparation / 2.0)); viewMat *= transform; } break; case RAS_STEREO_RIGHTEYE: { // translate to right by half the eye distance MT_Transform transform; transform.setIdentity(); transform.translate(eyeline * m_eyeseparation / 2.0); viewMat *= transform; } break; } } // convert row major matrix 'viewMat' to column major for OpenGL MT_Scalar cammat[16]; viewMat.getValue(cammat); MT_CmMatrix4x4 viewCmmat = cammat; glMatrixMode(GL_MODELVIEW); m_viewmatrix = viewCmmat; glLoadMatrixd(&m_viewmatrix(0,0)); m_campos = campos; } const MT_Point3& RAS_OpenGLRasterizer::GetCameraPosition() { return m_campos; } void RAS_OpenGLRasterizer::LoadViewMatrix() { glLoadMatrixd(&m_viewmatrix(0,0)); } void RAS_OpenGLRasterizer::EnableTextures(bool enable) { } void RAS_OpenGLRasterizer::SetCullFace(bool enable) { if (enable) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); } void RAS_OpenGLRasterizer::SetSpecularity(float specX, float specY, float specZ, float specval) { GLfloat mat_specular[] = {specX, specY, specZ, specval}; glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); } void RAS_OpenGLRasterizer::SetShinyness(float shiny) { GLfloat mat_shininess[] = { shiny }; glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess); } void RAS_OpenGLRasterizer::SetDiffuse(float difX,float difY,float difZ,float diffuse) { GLfloat mat_diffuse [] = {difX, difY,difZ, diffuse}; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse); } double RAS_OpenGLRasterizer::GetTime() { return m_time; }