#include "renderer_opengl.h" using namespace std; RendererOpenGL::RendererOpenGL(Core *core): Renderer(core), geomrun(false) { // this gets the projection matrix for our orthogonal view glMatrixMode(GL_PROJECTION); glPushMatrix(); glOrtho(0.0,(GLdouble)core->GetWidth(),(GLdouble)core->GetHeight(),0.0,-1.0,1.0); glGetDoublev(GL_PROJECTION_MATRIX,orthmat); glPopMatrix(); // initialize the OpenGL states UpdateGLState(); } static GLint geomtype_lookup[]= { GL_POINTS, //RAVEN_GEOMETRY_POINTS GL_LINES, //RAVEN_GEOMETRY_LINES GL_LINE_STRIP, //RAVEN_GEOMETRY_LINE_STRIP GL_LINE_LOOP, //RAVEN_GEOMETRY_LINE_LOOP GL_TRIANGLES, //RAVEN_GEOMETRY_TRIS GL_TRIANGLE_STRIP, //RAVEN_GEOMETRY_TRI_STRIP GL_TRIANGLE_FAN, //RAVEN_GEOMETRY_TRI_FAN GL_QUADS, //RAVEN_GEOMETRY_QUADS GL_QUAD_STRIP //RAVEN_GEOMETRY_QUAD_STRIP }; void RendererOpenGL::UpdateGLState() { glViewport((GLint)viewport.left,(GLint)viewport.top, (GLsizei)viewport.right-(GLint)viewport.left, (GLsizei)viewport.bottom-(GLint)viewport.top); switch (blend) { case RAVEN_BLEND_MASK_LOW: glDisable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL,blendmask); break; case RAVEN_BLEND_MASK_HI: glDisable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_LEQUAL,blendmask); break; case RAVEN_BLEND_ALPHA: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_ALPHA_TEST); break; case RAVEN_BLEND_ADD: glEnable(GL_BLEND); glBlendFunc(GL_ONE,GL_ONE); glDisable(GL_ALPHA_TEST); break; case RAVEN_BLEND_MULT: glEnable(GL_BLEND); glBlendFunc(GL_DST_COLOR,GL_ZERO); glDisable(GL_ALPHA_TEST); break; case RAVEN_BLEND_LIGHT: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE); glDisable(GL_ALPHA_TEST); break; default: glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); break; } glShadeModel(GL_SMOOTH); if (stateflags&RAVEN_STATE_WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); if (cullmode==RAVEN_CULL_NONE) { glDisable(GL_CULL_FACE); materialfaces=GL_FRONT_AND_BACK; } else { glEnable(GL_CULL_FACE); if (cullmode==RAVEN_CULL_BACK) { glCullFace(GL_BACK); materialfaces=GL_FRONT; } else if (cullmode==RAVEN_CULL_FRONT) { glCullFace(GL_FRONT); materialfaces=GL_BACK; } else { glDisable(GL_CULL_FACE); materialfaces=GL_FRONT_AND_BACK; } } if (stateflags&RAVEN_STATE_NODEPTH) glDisable(GL_DEPTH_TEST); else glEnable(GL_DEPTH_TEST); if (stateflags&RAVEN_STATE_LIGHT) { glEnable(GL_LIGHTING); glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,1); if (stateflags&RAVEN_STATE_MATERIAL) { if (material.UsingVertexColor()) { glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); Vector4 specular; material.GetComponent(RAVEN_OPTICS_SPECULAR_COMPONENT,specular); glMaterialfv(materialfaces,GL_SPECULAR,(float *)specular); glMaterialf(materialfaces,GL_SHININESS,material.Shininess()); } else { glDisable(GL_COLOR_MATERIAL); Vector4 ambient; Vector3 diffuse; Vector4 specular; material.GetComponent(RAVEN_OPTICS_AMBIENT_COMPONENT,ambient); material.GetComponent(RAVEN_OPTICS_DIFFUSE_COMPONENT,diffuse); material.GetComponent(RAVEN_OPTICS_SPECULAR_COMPONENT,specular); glMaterialfv(materialfaces,GL_AMBIENT,(float *)ambient); glMaterialfv(materialfaces,GL_DIFFUSE,(float *)Vector4(diffuse,material.Alpha())); glMaterialfv(materialfaces,GL_SPECULAR,(float *)specular); glMaterialf(materialfaces,GL_SHININESS,material.Shininess()); } if (stateflags&RAVEN_STATE_TEXTURE) { glEnable(GL_TEXTURE_2D); Texture *tex=material.Tex(); if (tex) tex->Bind(0); } else glDisable(GL_TEXTURE_2D); } else { glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); } } else { glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); if (stateflags&RAVEN_STATE_MATERIAL) { if (stateflags&RAVEN_STATE_TEXTURE) { glEnable(GL_TEXTURE_2D); Texture *tex=material.Tex(); if (tex) tex->Bind(0); } else glDisable(GL_TEXTURE_2D); } } if ((stateflags&RAVEN_STATE_GPU_PROGRAM)&&(stateflags&RAVEN_STATE_MATERIAL)) { ShaderProgram *shader=material.Shader(); if (shader) shader->Bind(); else glUseProgramObjectARB(0); } else glUseProgramObjectARB(0); } void RendererOpenGL::TargetViewport(const Viewport &vp) { viewport=vp; UpdateGLState(); } Viewport RendererOpenGL::TargetViewport() { return viewport; } void RendererOpenGL::PushProjection() { glMatrixMode(GL_PROJECTION); glPushMatrix(); Renderer::PushProjection(); } void RendererOpenGL::PopProjection() { glMatrixMode(GL_PROJECTION); glPopMatrix(); Renderer::PopProjection(); } void RendererOpenGL::LoadProjection(const Matrix4x4 &mat) { proj_stack[proj_stack_ptr]=mat; glMatrixMode(GL_PROJECTION); glLoadMatrixf((const float *)transpose(mat)); } void RendererOpenGL::LoadProjection(const Projection &proj) { Matrix4x4 mat; Projection _proj(proj); _proj.ToMatrix(mat); proj_stack[proj_stack_ptr]=mat; glMatrixMode(GL_PROJECTION); glLoadMatrixf((const float *)transpose(mat)); } void RendererOpenGL::MultProjection(Matrix4x4 &mat) { proj_stack[proj_stack_ptr]=proj_stack[proj_stack_ptr]*mat; glMatrixMode(GL_PROJECTION); glLoadMatrixf((const float *)transpose(proj_stack[proj_stack_ptr])); } void RendererOpenGL::PushModelView() { glMatrixMode(GL_MODELVIEW); glPushMatrix(); Renderer::PushModelView(); } void RendererOpenGL::PopModelView() { glMatrixMode(GL_MODELVIEW); glPopMatrix(); Renderer::PopModelView(); } void RendererOpenGL::LoadModelView(const Matrix4x4 &mat) { mdvw_stack[mdvw_stack_ptr]=mat; glMatrixMode(GL_MODELVIEW); glLoadMatrixf((const float *)transpose(mat)); } void RendererOpenGL::MultModelView(const Matrix4x4 &mat) { mdvw_stack[mdvw_stack_ptr]=mdvw_stack[mdvw_stack_ptr]*mat; glMatrixMode(GL_MODELVIEW); glLoadMatrixf((const float *)transpose(mdvw_stack[mdvw_stack_ptr])); } bool RendererOpenGL::BeginScene(bool clearcolor,bool cleardepth,Vector4 color) { glClearColor(color.x,color.y,color.z,color.w); glClear((clearcolor?GL_COLOR_BUFFER_BIT:0)|(cleardepth?GL_DEPTH_BUFFER_BIT:0)); glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadMatrixf((const float *)transpose(proj_stack[0])); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadMatrixf((const float *)transpose(mdvw_stack[0])); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); UpdateGLState(); //EnableDrawStates(); return true; } bool RendererOpenGL::EndScene(bool flip) { //DisableDrawStates(); glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPopAttrib(); glFinish(); if (flip) { if (!core->Update()) return false; } return true; } void RendererOpenGL::SetCullMode(CullMode mode) { cullmode=mode; UpdateGLState(); } CullMode RendererOpenGL::GetCullMode() { return cullmode; } void RendererOpenGL::State(int state,bool on) { if (on) stateflags|=state; else stateflags&=~state; UpdateGLState(); } void RendererOpenGL::Blend(BlendMode mode,float mask) { blend=mode; blendmask=mask; UpdateGLState(); } void RendererOpenGL::BlendMask(float mask) { blendmask=mask; UpdateGLState(); } void RendererOpenGL::Material(const RenderMaterial &material) { this->material=material; UpdateGLState(); } bool RendererOpenGL::EnableLight(int slot,Light *light) { int maxgllights; glGetIntegerv(GL_MAX_LIGHTS,&maxgllights); if (min(RAVEN_MAXIMUM_LIGHTS,maxgllights)GetComponent(RAVEN_OPTICS_AMBIENT_COMPONENT,ambient); active_lights[slot]->GetComponent(RAVEN_OPTICS_DIFFUSE_COMPONENT,diffuse); active_lights[slot]->GetComponent(RAVEN_OPTICS_SPECULAR_COMPONENT,specular); if (active_lights[slot]->GetType()==RAVEN_LIGHT_DIRECTIONAL) { Vector3 pos=active_lights[slot]->Direction(); position=Vector4(pos,0.0f); } else { Vector3 pos=active_lights[slot]->Position(); position=Vector4(pos,1.0f); } glLightfv(GL_LIGHT0+slot,GL_AMBIENT,(float *)ambient); glLightfv(GL_LIGHT0+slot,GL_DIFFUSE,(float *)diffuse); glLightfv(GL_LIGHT0+slot,GL_SPECULAR,(float *)specular); glLightfv(GL_LIGHT0+slot,GL_POSITION,(float *)position); glLightf(GL_LIGHT0+slot,GL_LINEAR_ATTENUATION,active_lights[slot]->Attenuation()); return true; } bool RendererOpenGL::DisableLight(int slot) { if (active_lights[slot]==NULL) return false; glDisable(GL_LIGHT0+slot); active_lights[slot]=NULL; return true; } VertexBuffer *RendererOpenGL::CreateVertexBuffer(int attribs) { if (stateflags&RAVEN_STATE_USE_HW_VERTEX_MEMORY) { if (GLEE_ARB_vertex_buffer_object) return new VertexBufferVBO(attribs); else { cerr<<"Vertex Buffer Objects not supported by this graphics card or driver!"<Get(RAVEN_GEOMETRY_FLAG_INDICES,0,(void **)&indices); buf->Get(RAVEN_GEOMETRY_FLAG_VERTICES,0,(void **)&verts); buf->Get(RAVEN_GEOMETRY_FLAG_NORMALS,0,(void **)&norms); buf->Get(RAVEN_GEOMETRY_FLAG_COLORS,0,(void **)&colors); if (buf->NumTextures()==1) buf->Get(RAVEN_GEOMETRY_FLAG_TEXCOORDS,0,(void **)&texcoords); glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); int attribs=buf->GetBufAttribs(); if (attribs&RAVEN_GEOMETRY_FLAG_VERTICES) glEnableClientState(GL_VERTEX_ARRAY); if (attribs&RAVEN_GEOMETRY_FLAG_NORMALS) glEnableClientState(GL_NORMAL_ARRAY); if (attribs&RAVEN_GEOMETRY_FLAG_COLORS) glEnableClientState(GL_COLOR_ARRAY); if (attribs&RAVEN_GEOMETRY_FLAG_TEXCOORDS) glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (attribs&RAVEN_GEOMETRY_FLAG_VERTICES) glVertexPointer(3,GL_FLOAT,0,verts); if (attribs&RAVEN_GEOMETRY_FLAG_NORMALS) glNormalPointer(GL_FLOAT,0,norms); if (attribs&RAVEN_GEOMETRY_FLAG_COLORS) glColorPointer(4,GL_FLOAT,0,colors); if (buf->NumTextures()==1) glTexCoordPointer(2,GL_FLOAT,0,texcoords); if (attribs&RAVEN_GEOMETRY_FLAG_INDICES) glDrawElements(geomtype_lookup[geomtype],buf->NumIndices(),GL_UNSIGNED_INT,indices); else glDrawArrays(geomtype_lookup[geomtype],0,buf->NumVerts()); glPopClientAttrib(); return true; } bool RendererOpenGL::RenderVertexBuffer(VertexBuffer *buf,GeometryType geomtype) { if (!buf) return false; bool result; if (buf->IsSoftBuffer()) result=render_soft_vertex_buffer(buf,geomtype); else result=buf->Render(geomtype); return result; } bool RendererOpenGL::BeginGeometry(int attribs,int numtextures,GeometryType geomtype) { if (geomrun) return false; glBegin(geomtype_lookup[geomtype]); geomattrib=attribs; geomtexdef=numtextures; cd=nd=td=false; return geomrun=true; } void RendererOpenGL::GeometryVertex(const Vector3 &vert) { if ((geomattrib&RAVEN_GEOMETRY_FLAG_COLORS)&&(!cd)) glColor4fv((float *)Vector4(0.0f)); if ((geomattrib&RAVEN_GEOMETRY_FLAG_NORMALS)&&(!nd)) glNormal3fv((float *)Vector3(0.0f)); if ((geomattrib&RAVEN_GEOMETRY_FLAG_TEXCOORDS)&&(!td)) glTexCoord2f(0.0f,0.0f); glVertex3fv((float *)vert); cd=nd=td=false; } void RendererOpenGL::GeometryNormal(const Vector3 &norm) { if (!(geomattrib&RAVEN_GEOMETRY_FLAG_NORMALS)) return; glNormal3fv((float *)norm); nd=true; } void RendererOpenGL::GeometryColor(const Vector4 &color) { if (!(geomattrib&RAVEN_GEOMETRY_FLAG_COLORS)) return; glColor4fv((float *)color); cd=true; } void RendererOpenGL::GeometryTexCoord(const Vector2 &texcoord,int idx) { if (!(geomattrib&RAVEN_GEOMETRY_FLAG_TEXCOORDS)) return; glMultiTexCoord2fvARB(GL_TEXTURE0+idx,(float *)texcoord); td=true; } bool RendererOpenGL::EndGeometry() { if (!geomrun) return false; glEnd(); geomrun=false; return true; } Texture *RendererOpenGL::CreateTexture(Pixelmap *image,SamplerState samp,unsigned int flags) { TextureOpenGL *tex=new TextureOpenGL(image,samp,flags); if (!tex->IsValid()) { delete tex; return NULL; } return tex; } FontBase *RendererOpenGL::LoadFont(const char *file,int pt) { TrueTypeFont *ttf=new TrueTypeFont(file,pt); if (!ttf->IsValid()) { delete ttf; return NULL; } FontOpenGL *glfont=new FontOpenGL(ttf); delete ttf; if (!glfont->IsValid()) { delete glfont; return NULL; } return glfont; } RenderTarget *RendererOpenGL::CreateRenderTargetColorTexture(SamplerState samp,int po2lev,bool floatformat) { if (!GLEE_EXT_framebuffer_object) return NULL; RenderTarget *rt=new RenderTargetFBO(samp,po2lev,floatformat); if (rt->IsValid()) return rt; else { delete rt; return NULL; } } bool RendererOpenGL::BindRenderTarget(RenderTarget *target) { if (!target) return false; if (target->IsMainFrameBuffer()) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glOrtho(0.0,(GLdouble)core->GetWidth(),(GLdouble)core->GetHeight(),0.0,-1.0,1.0); glGetDoublev(GL_PROJECTION_MATRIX,orthmat); glPopMatrix(); curr_target=target; UpdateGLState(); } else { glMatrixMode(GL_PROJECTION); glPushMatrix(); glOrtho(0.0, target->GetWidth(), target->GetHeight(), 0.0,-1.0,1.0); glGetDoublev(GL_PROJECTION_MATRIX,orthmat); glPopMatrix(); bool result=target->BindTarget(); if (!result) return result; else { UpdateGLState(); curr_target=target; return result; } } return true; } // nothin' here yet FontBase *RendererOpenGL::LoadFont(const char *file) { cerr<<"No support for bitmap fonts yet!"<IsValid()) { delete shader; return NULL; } return shader; } bool RendererOpenGL::RenderText(FontBase *font,int x,int y,const char *text) { if (!dynamic_cast(font)) return false; glUseProgramObjectARB(0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadMatrixd(orthmat); font->Render(x,y,text); glPopMatrix(); UpdateGLState(); return true; }