1 #pragma once 2 3 #include "irender.h" 4 #include "OpenGLStateManager.h" 5 #include "container/cache.h" 6 #include "container/hashfunc.h" 7 8 class OpenGLShaderCache: public ShaderCache, 9 public TexturesCacheObserver, 10 public ModuleObserver, 11 public render::OpenGLStateManager 12 { 13 class CreateOpenGLShader 14 { 15 OpenGLShaderCache* m_cache; 16 public: 17 explicit CreateOpenGLShader (OpenGLShaderCache* cache = 0) : m_cache(cache)18 m_cache(cache) 19 { 20 } construct(const std::string & name)21 OpenGLShader* construct (const std::string& name) 22 { 23 OpenGLShader* shader = new OpenGLShader(*m_cache); 24 if (m_cache->realised()) { 25 shader->realise(name); 26 } 27 return shader; 28 } destroy(OpenGLShader * shader)29 void destroy (OpenGLShader* shader) 30 { 31 if (m_cache->realised()) { 32 shader->unrealise(); 33 } 34 delete shader; 35 } 36 }; 37 38 typedef HashedCache<std::string, OpenGLShader, HashString, std::equal_to<std::string>, CreateOpenGLShader> 39 Shaders; 40 Shaders m_shaders; 41 std::size_t m_unrealised; 42 43 render::OpenGLStates _state_sorted; 44 45 public: OpenGLShaderCache()46 OpenGLShaderCache () : 47 m_shaders(CreateOpenGLShader(this)), m_unrealised(3), // wait until shaders, gl-context and textures are realised before creating any render-states 48 m_traverseRenderablesMutex(false) 49 { 50 } ~OpenGLShaderCache()51 ~OpenGLShaderCache () 52 { 53 for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) { 54 globalOutputStream() << "leaked shader: " << makeQuoted(i->key) << "\n"; 55 } 56 } 57 insertSortedState(const render::OpenGLStates::value_type & val)58 void insertSortedState (const render::OpenGLStates::value_type& val) 59 { 60 _state_sorted.insert(val); 61 } 62 eraseSortedState(const render::OpenGLStates::key_type & key)63 void eraseSortedState (const render::OpenGLStates::key_type& key) 64 { 65 _state_sorted.erase(key); 66 } 67 68 /* Capture the given shader. 69 */ capture(const std::string & name)70 Shader* capture (const std::string& name) 71 { 72 return m_shaders.capture(name).get(); 73 } 74 75 /* Release the given shader. 76 */ release(const std::string & name)77 void release (const std::string& name) 78 { 79 m_shaders.release(name); 80 } 81 render(RenderStateFlags globalstate,const Matrix4 & modelview,const Matrix4 & projection,const Vector3 & viewer)82 void render (RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, 83 const Vector3& viewer) 84 { 85 glMatrixMode(GL_PROJECTION); 86 glLoadMatrixf(projection); 87 88 glMatrixMode(GL_MODELVIEW); 89 glLoadMatrixf(modelview); 90 91 ASSERT_MESSAGE(realised(), "render states are not realised"); 92 93 // global settings that are not set in renderstates 94 glFrontFace(GL_CW); 95 glCullFace(GL_BACK); 96 glPolygonOffset(-1, 1); 97 { 98 const GLubyte pattern[132] = { 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 99 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 100 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 101 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 102 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 103 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 104 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 105 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 106 0x55, 0x55, 0x55, 0x55 }; 107 glPolygonStipple(pattern); 108 } 109 glEnableClientState(GL_VERTEX_ARRAY); 110 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); 111 112 if (GlobalOpenGL().GL_1_3()) { 113 glActiveTexture(GL_TEXTURE0); 114 glClientActiveTexture(GL_TEXTURE0); 115 } 116 117 if (globalstate & RENDER_TEXTURE_2D) { 118 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 119 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 120 } 121 122 OpenGLState current; 123 current.constructDefault(); 124 current.m_sort = OpenGLState::eSortFirst; 125 126 // default renderstate settings 127 glLineStipple(current.m_linestipple_factor, current.m_linestipple_pattern); 128 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 129 glDisable(GL_LIGHTING); 130 glDisable(GL_TEXTURE_2D); 131 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 132 glDisableClientState(GL_COLOR_ARRAY); 133 glDisableClientState(GL_NORMAL_ARRAY); 134 glDisable(GL_BLEND); 135 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 136 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 137 glDisable(GL_CULL_FACE); 138 glShadeModel(GL_FLAT); 139 glDisable(GL_DEPTH_TEST); 140 glDepthMask(GL_FALSE); 141 glDisable(GL_ALPHA_TEST); 142 glDisable(GL_LINE_STIPPLE); 143 glDisable(GL_POLYGON_STIPPLE); 144 glDisable(GL_POLYGON_OFFSET_LINE); 145 glDisable(GL_POLYGON_OFFSET_FILL); // greebo: otherwise tiny gap lines between brushes are visible 146 147 glBindTexture(GL_TEXTURE_2D, 0); 148 glColor4f(1, 1, 1, 1); 149 glDepthFunc(GL_LESS); 150 glAlphaFunc(GL_ALWAYS, 0); 151 glLineWidth(1); 152 glPointSize(1); 153 154 // render brushes and entities 155 for (render::OpenGLStates::iterator i = _state_sorted.begin(); i != _state_sorted.end(); ++i) { 156 (*i).second->render(current, globalstate, viewer); 157 } 158 } realise()159 void realise () 160 { 161 if (--m_unrealised == 0) { 162 for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) { 163 if (!(*i).value.empty()) { 164 (*i).value->realise(i->key); 165 } 166 } 167 } 168 } unrealise()169 void unrealise () 170 { 171 if (++m_unrealised == 1) { 172 for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) { 173 if (!(*i).value.empty()) { 174 (*i).value->unrealise(); 175 } 176 } 177 } 178 } realised()179 bool realised () 180 { 181 return m_unrealised == 0; 182 } 183 184 typedef std::set<const Renderable*> Renderables; 185 Renderables m_renderables; 186 mutable bool m_traverseRenderablesMutex; 187 188 // renderables attachRenderable(const Renderable & renderable)189 void attachRenderable (const Renderable& renderable) 190 { 191 ASSERT_MESSAGE(!m_traverseRenderablesMutex, "attaching renderable during traversal"); 192 ASSERT_MESSAGE(m_renderables.find(&renderable) == m_renderables.end(), 193 "renderable could not be attached"); 194 m_renderables.insert(&renderable); 195 } detachRenderable(const Renderable & renderable)196 void detachRenderable (const Renderable& renderable) 197 { 198 ASSERT_MESSAGE(!m_traverseRenderablesMutex, "detaching renderable during traversal"); 199 ASSERT_MESSAGE(m_renderables.find(&renderable) != m_renderables.end(), 200 "renderable could not be detached"); 201 m_renderables.erase(&renderable); 202 } forEachRenderable(const RenderableCallback & callback)203 void forEachRenderable (const RenderableCallback& callback) const 204 { 205 ASSERT_MESSAGE(!m_traverseRenderablesMutex, "for-each during traversal"); 206 m_traverseRenderablesMutex = true; 207 for (Renderables::const_iterator i = m_renderables.begin(); i != m_renderables.end(); ++i) { 208 callback(*(*i)); 209 } 210 m_traverseRenderablesMutex = false; 211 } 212 }; 213