/** * $Id$ * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ #include #include #include "RAS_OpenGLRasterizer.h" #include "GL/glew.h" #include "RAS_Rect.h" #include "RAS_TexVert.h" #include "MT_CmMatrix4x4.h" #include "RAS_IRenderTools.h" // rendering text /** * 32x32 bit masks for vinterlace stereo mode */ static GLuint left_eye_vinterlace_mask[32]; static GLuint right_eye_vinterlace_mask[32]; /** * 32x32 bit masks for hinterlace stereo mode. * Left eye = &hinterlace_mask[0] * Right eye = &hinterlace_mask[1] */ static GLuint hinterlace_mask[33]; RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas) :RAS_IRasterizer(canvas), m_2DCanvas(canvas), m_fogenabled(false), m_time(0.0), m_stereomode(RAS_STEREO_NOSTEREO), m_curreye(RAS_STEREO_LEFTEYE), m_eyeseparation(0.0), m_seteyesep(false), m_focallength(0.0), m_setfocallength(false), m_noOfScanlines(32), m_motionblur(0), m_motionblurvalue(-1.0), m_texco_num(0), m_attrib_num(0), m_materialCachingInfo(0) { m_viewmatrix.Identity(); for (int i = 0; i < 32; i++) { left_eye_vinterlace_mask[i] = 0x55555555; right_eye_vinterlace_mask[i] = 0xAAAAAAAA; hinterlace_mask[i] = (i&1)*0xFFFFFFFF; } hinterlace_mask[32] = 0; } RAS_OpenGLRasterizer::~RAS_OpenGLRasterizer() { } static 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); glFrontFace(GL_CCW); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); } bool RAS_OpenGLRasterizer::Init() { Myinit_gl_stuff(); m_redback = 0.4375; m_greenback = 0.4375; m_blueback = 0.4375; m_alphaback = 0.0; m_ambr = 0.0f; m_ambg = 0.0f; m_ambb = 0.0f; glClearColor(m_redback,m_greenback,m_blueback,m_alphaback); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glShadeModel(GL_SMOOTH); return true; } void RAS_OpenGLRasterizer::SetAmbientColor(float red, float green, float blue) { m_ambr = red; m_ambg = green; m_ambb = blue; } void RAS_OpenGLRasterizer::SetAlphaTest(bool enable) { if (enable) { glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.6f); } else glDisable(GL_ALPHA_TEST); } void RAS_OpenGLRasterizer::SetAmbient(float factor) { float ambient[] = { m_ambr*factor, m_ambg*factor, m_ambb*factor, 1.0f }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); } 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); } } bool RAS_OpenGLRasterizer::SetMaterial(const RAS_IPolyMaterial& mat) { return mat.Activate(this, m_materialCachingInfo); } void RAS_OpenGLRasterizer::Exit() { glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glClearDepth(1.0); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 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_POLYGON_STIPPLE); glDisable(GL_LIGHTING); if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); EndFrame(); } bool RAS_OpenGLRasterizer::InterlacedStereo() const { return m_stereomode == RAS_STEREO_VINTERLACE || m_stereomode == RAS_STEREO_INTERLACED; } bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time) { m_time = time; m_drawingmode = drawingmode; if (!InterlacedStereo() || m_curreye == RAS_STEREO_LEFTEYE) { 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(DepthMask depthmask) { glDepthMask(depthmask == KX_DEPTHMASK_DISABLED ? GL_FALSE : GL_TRUE); } void RAS_OpenGLRasterizer::ClearDepthBuffer() { m_2DCanvas->ClearBuffer(RAS_ICanvas::DEPTH_BUFFER); } void RAS_OpenGLRasterizer::ClearCachingInfo(void) { m_materialCachingInfo = 0; } void RAS_OpenGLRasterizer::EndFrame() { glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); //DrawDebugLines glBegin(GL_LINES); for (unsigned int i=0;iEndFrame(); } void RAS_OpenGLRasterizer::SetRenderArea() { // only above/below stereo method needs viewport adjustment switch (m_stereomode) { case 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; } break; case RAS_STEREO_SIDEBYSIDE: switch (m_curreye) { case RAS_STEREO_LEFTEYE: // Left half of window m_2DCanvas->GetDisplayArea().SetLeft(0); m_2DCanvas->GetDisplayArea().SetBottom(0); m_2DCanvas->GetDisplayArea().SetRight(m_2DCanvas->GetWidth()/2); m_2DCanvas->GetDisplayArea().SetTop(m_2DCanvas->GetHeight()); break; case RAS_STEREO_RIGHTEYE: // Right half of window m_2DCanvas->GetDisplayArea().SetLeft(m_2DCanvas->GetWidth()/2); m_2DCanvas->GetDisplayArea().SetBottom(0); m_2DCanvas->GetDisplayArea().SetRight(m_2DCanvas->GetWidth()); m_2DCanvas->GetDisplayArea().SetTop(m_2DCanvas->GetHeight()); break; } break; default: // 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())); break; } } void RAS_OpenGLRasterizer::SetStereoMode(const StereoMode stereomode) { m_stereomode = stereomode; } bool RAS_OpenGLRasterizer::Stereo() { if(m_stereomode == RAS_STEREO_NOSTEREO) return false; else return true; } void RAS_OpenGLRasterizer::SetEye(const StereoEye eye) { m_curreye = eye; switch (m_stereomode) { case RAS_STEREO_QUADBUFFERED: glDrawBuffer(m_curreye == RAS_STEREO_LEFTEYE ? GL_BACK_LEFT : GL_BACK_RIGHT); break; case RAS_STEREO_ANAGLYPH: if (m_curreye == RAS_STEREO_LEFTEYE) { glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE); } else { //glAccum(GL_LOAD, 1.0); glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); ClearDepthBuffer(); } break; case RAS_STEREO_VINTERLACE: { glEnable(GL_POLYGON_STIPPLE); glPolygonStipple((const GLubyte*) ((m_curreye == RAS_STEREO_LEFTEYE) ? left_eye_vinterlace_mask : right_eye_vinterlace_mask)); if (m_curreye == RAS_STEREO_RIGHTEYE) ClearDepthBuffer(); break; } case RAS_STEREO_INTERLACED: { glEnable(GL_POLYGON_STIPPLE); glPolygonStipple((const GLubyte*) &hinterlace_mask[m_curreye == RAS_STEREO_LEFTEYE?0:1]); if (m_curreye == RAS_STEREO_RIGHTEYE) ClearDepthBuffer(); break; } default: break; } } RAS_IRasterizer::StereoEye RAS_OpenGLRasterizer::GetEye() { return m_curreye; } void RAS_OpenGLRasterizer::SetEyeSeparation(const float eyeseparation) { m_eyeseparation = eyeseparation; m_seteyesep = true; } float RAS_OpenGLRasterizer::GetEyeSeparation() { return m_eyeseparation; } void RAS_OpenGLRasterizer::SetFocalLength(const float focallength) { m_focallength = focallength; m_setfocallength = true; } float RAS_OpenGLRasterizer::GetFocalLength() { return m_focallength; } void RAS_OpenGLRasterizer::SwapBuffers() { m_2DCanvas->SwapBuffers(); } void RAS_OpenGLRasterizer::GetViewMatrix(MT_Matrix4x4 &mat) const { float viewmat[16]; glGetFloatv(GL_MODELVIEW_MATRIX, viewmat); mat.setValue(viewmat); } 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, class KX_ListSlot** slot ) { 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 ; unsigned int numindices,vt; for (vt=0;vtRenderText(polymat->GetDrawingMode(),polymat,v1,v2,v3,v4); ClearCachingInfo(); } break; } case 0: { glBegin(GL_TRIANGLES); vindex=0; for (unsigned int i=0;iRenderText(polymat->GetDrawingMode(),polymat,v1,v2,v3,NULL); ClearCachingInfo(); } glEnd(); break; } default: { } } //switch } //for each vertexarray } void RAS_OpenGLRasterizer::SetTexCoordNum(int num) { m_texco_num = num; if(m_texco_num > RAS_MAX_TEXCO) m_texco_num = RAS_MAX_TEXCO; } void RAS_OpenGLRasterizer::SetAttribNum(int num) { m_attrib_num = num; if(m_attrib_num > RAS_MAX_ATTRIB) m_attrib_num = RAS_MAX_ATTRIB; } void RAS_OpenGLRasterizer::SetTexCoord(TexCoGen coords, int unit) { // this changes from material to material if(unit < RAS_MAX_TEXCO) m_texco[unit] = coords; } void RAS_OpenGLRasterizer::SetAttrib(TexCoGen coords, int unit) { // this changes from material to material if(unit < RAS_MAX_ATTRIB) m_attrib[unit] = coords; } void RAS_OpenGLRasterizer::TexCoord(const RAS_TexVert &tv) { int unit; if(GLEW_ARB_multitexture) { for(unit=0; unit