1 // glcontext.h
2 //
3 // Copyright (C) 2003, Chris Laurel <claurel@shatters.net>
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 
10 #include <algorithm>
11 #include <celutil/debug.h>
12 #include "gl.h"
13 #include "glext.h"
14 #include "glcontext.h"
15 
16 using namespace std;
17 
18 
19 static VertexProcessor* vpNV = NULL;
20 static VertexProcessor* vpARB = NULL;
21 static FragmentProcessor* fpNV = NULL;
22 
23 
GLContext()24 GLContext::GLContext() :
25     renderPath(GLPath_Basic),
26     vertexPath(VPath_Basic),
27     vertexProc(NULL),
28     maxSimultaneousTextures(1)
29 {
30 }
31 
~GLContext()32 GLContext::~GLContext()
33 {
34 }
35 
36 
init(const vector<string> & ignoreExt)37 void GLContext::init(const vector<string>& ignoreExt)
38 {
39     char* extensionsString = (char*) glGetString(GL_EXTENSIONS);
40     if (extensionsString != NULL)
41     {
42         char* next = extensionsString;
43 
44         while (*next != '\0')
45         {
46             while (*next != '\0' && *next != ' ')
47                 next++;
48 
49             string ext(extensionsString, next - extensionsString);
50 
51             // scan the ignore list
52             bool shouldIgnore = false;
53             for (vector<string>::const_iterator iter = ignoreExt.begin();
54                  iter != ignoreExt.end(); iter++)
55             {
56                 if (*iter == ext)
57                 {
58                     shouldIgnore = true;
59                     break;
60                 }
61             }
62 
63             if (!shouldIgnore)
64                 extensions.insert(extensions.end(), ext);
65 
66             if (*next == '\0')
67                 break;
68             next++;
69             extensionsString = next;
70         }
71     }
72 
73     // Initialize all extensions used
74     for (vector<string>::const_iterator iter = extensions.begin();
75          iter != extensions.end(); iter++)
76     {
77         InitExtension(iter->c_str());
78     }
79 
80     if (extensionSupported("GL_ARB_multitexture") &&
81         glx::glActiveTextureARB != NULL)
82     {
83         glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,
84                       (GLint*) &maxSimultaneousTextures);
85     }
86 
87     if (extensionSupported("GL_ARB_vertex_program") &&
88         glx::glGenProgramsARB)
89     {
90         DPRINTF(1, "Renderer: ARB vertex programs supported.\n");
91         if (vpARB == NULL)
92             vpARB = vp::initARB();
93         vertexProc = vpARB;
94     }
95     else if (extensionSupported("GL_NV_vertex_program") &&
96              glx::glGenProgramsNV)
97     {
98         DPRINTF(1, "Renderer: nVidia vertex programs supported.\n");
99         if (vpNV == NULL)
100             vpNV = vp::initNV();
101         vertexProc = vpNV;
102     }
103 
104     if (extensionSupported("GL_NV_fragment_program") &&
105         glx::glGenProgramsNV)
106     {
107         DPRINTF(1, "Renderer: nVidia fragment programs supported.\n");
108         if (fpNV == NULL)
109             fpNV = fp::initNV();
110         fragmentProc = fpNV;
111     }
112 
113     // Initialize GLX_SGI_video_sync blindly. At most, it will be null.
114     InitExtension("GLX_SGI_video_sync");
115 }
116 
117 
setRenderPath(GLRenderPath path)118 bool GLContext::setRenderPath(GLRenderPath path)
119 {
120     if (!renderPathSupported(path))
121         return false;
122 
123     switch (path)
124     {
125     case GLPath_Basic:
126     case GLPath_Multitexture:
127     case GLPath_NvCombiner:
128         vertexPath = VPath_Basic;
129         break;
130     case GLPath_NvCombiner_NvVP:
131         vertexPath = VPath_NV;
132         break;
133     case GLPath_DOT3_ARBVP:
134     case GLPath_NvCombiner_ARBVP:
135     case GLPath_ARBFP_ARBVP:
136     case GLPath_NV30:
137     case GLPath_GLSL:
138         vertexPath = VPath_ARB;
139         break;
140     default:
141         return false;
142     }
143 
144     renderPath = path;
145 
146     return true;
147 }
148 
149 
renderPathSupported(GLRenderPath path) const150 bool GLContext::renderPathSupported(GLRenderPath path) const
151 {
152     switch (path)
153     {
154     case GLPath_Basic:
155         return true;
156 
157     case GLPath_Multitexture:
158         return (maxSimultaneousTextures > 1 &&
159                ( extensionSupported("GL_EXT_texture_env_combine") ||
160                  extensionSupported("GL_ARB_texture_env_combine")) );
161 
162     case GLPath_NvCombiner:
163         return false;
164         /*
165         // No longer supported; all recent NVIDIA drivers also support
166         // the vertex_program extension, so the combiners-only path
167         // isn't necessary.
168         return extensionSupported("GL_NV_register_combiners");
169         */
170 
171     case GLPath_DOT3_ARBVP:
172         return (extensionSupported("GL_ARB_texture_env_dot3") &&
173                 extensionSupported("GL_ARB_vertex_program") &&
174                 vertexProc != NULL);
175 
176     case GLPath_NvCombiner_NvVP:
177         // If ARB_vertex_program is supported, don't report support for
178         // this render path.
179         return (extensionSupported("GL_NV_register_combiners") &&
180                 extensionSupported("GL_NV_vertex_program") &&
181                 !extensionSupported("GL_ARB_vertex_program") &&
182                 vertexProc != NULL);
183 
184     case GLPath_NvCombiner_ARBVP:
185         return (extensionSupported("GL_NV_register_combiners") &&
186                 extensionSupported("GL_ARB_vertex_program") &&
187                 vertexProc != NULL);
188 
189     case GLPath_ARBFP_ARBVP:
190         return false;
191         /*
192         return (extensionSupported("GL_ARB_vertex_program") &&
193                 extensionSupported("GL_ARB_fragment_program") &&
194                 vertexProc != NULL);
195         */
196 
197     case GLPath_NV30:
198 		/* This render path is deprecated; GLSL is now preferred */
199 		return false;
200 		/*
201         return (extensionSupported("GL_ARB_vertex_program") &&
202                 extensionSupported("GL_NV_fragment_program"));
203 		*/
204 
205     case GLPath_GLSL:
206         return (extensionSupported("GL_ARB_shader_objects") &&
207                 extensionSupported("GL_ARB_shading_language_100") &&
208                 extensionSupported("GL_ARB_vertex_shader") &&
209                 extensionSupported("GL_ARB_fragment_shader"));
210 
211     default:
212         return false;
213     }
214 }
215 
216 
nextRenderPath()217 GLContext::GLRenderPath GLContext::nextRenderPath()
218 {
219     GLContext::GLRenderPath newPath = renderPath;
220 
221     do {
222         newPath = (GLRenderPath) ((int) newPath + 1);;
223         if (newPath > GLPath_GLSL)
224             newPath = GLPath_Basic;
225     } while (newPath != renderPath && !renderPathSupported(newPath));
226 
227     renderPath = newPath;
228 
229     return renderPath;
230 }
231 
232 
extensionSupported(const string & ext) const233 bool GLContext::extensionSupported(const string& ext) const
234 {
235     return (find(extensions.begin(), extensions.end(), ext) != extensions.end());
236 }
237 
238 
bumpMappingSupported() const239 bool GLContext::bumpMappingSupported() const
240 {
241     return renderPath > GLPath_Multitexture;
242 }
243 
244 
getVertexPath() const245 GLContext::VertexPath GLContext::getVertexPath() const
246 {
247     return vertexPath;
248 }
249 
250 
getVertexProcessor() const251 VertexProcessor* GLContext::getVertexProcessor() const
252 {
253     return vertexPath == VPath_Basic ? NULL : vertexProc;
254 }
255 
256 
getFragmentProcessor() const257 FragmentProcessor* GLContext::getFragmentProcessor() const
258 {
259     if (renderPath == GLPath_NV30 /* || renderPath == GLPath_ARGFP_ARBVP */ )
260         return fragmentProc;
261     else
262         return NULL;
263 }
264