| 68 | | Another issue is presented by |
|---|
| 69 | | Windows operating systems. The default opengl32.dll on Windows systems prior to Vista |
|---|
| 70 | | only provides exports for OpenGL 1.1. It has not been updated since it was first realeased |
|---|
| 71 | | on Windows 95. Furthermore, this DLL is a (rather poor) software implementation. Vista |
|---|
| 72 | | ships with the software implementation, but also includes an OpenGL DLL that supports |
|---|
| 73 | | up to core OpenGL 1.4 and is implemented on top of Direct3D. This DLL provides hardware |
|---|
| 74 | | acceleration, but all of the calls first go through a translation layer to convert |
|---|
| 75 | | them to D3D calls. The system can load the implementation provided by the |
|---|
| 76 | | graphics card driver, but there is no way to know which implementation the |
|---|
| 77 | | application is actually using, or which version a graphics card driver supports, |
|---|
| 78 | | until the context is created. |
|---|
| | 68 | Another issue is presented by Windows operating systems. The default opengl32.dll |
|---|
| | 69 | on Windows systems prior to Vista only provides exports for OpenGL 1.1. It has |
|---|
| | 70 | not been updated since it was first realeased on Windows 95. Furthermore, this |
|---|
| | 71 | DLL is a (rather poor) software implementation. Vista ships with the software |
|---|
| | 72 | implementation, but also includes an OpenGL DLL that supports up to core OpenGL |
|---|
| | 73 | 1.4 and is implemented on top of Direct3D. This DLL provides hardware acceleration, |
|---|
| | 74 | but all of the calls first go through a translation layer to convert them to D3D |
|---|
| | 75 | calls. The system can load the implementation provided by the graphics card |
|---|
| | 76 | driver, but there is no way to know which implementation the application is |
|---|
| | 77 | actually using, or which version a graphics card driver supports, until the |
|---|
| | 78 | context is created. |
|---|
| | 217 | <h3>Loading OpenGL Extensions</h3> |
|---|
| | 218 | |
|---|
| | 219 | As an added convenience, DerelictGL includes support for the easy detection and |
|---|
| | 220 | loading of several OpenGL extensions. In the <tt>derelict.opengl.extension</tt> |
|---|
| | 221 | package are several subpackages. Each subpackage contains loaders for a group |
|---|
| | 222 | of extensions. For example, loaders for <span class='bold'>GL_EXT</span> |
|---|
| | 223 | extensions are found in <tt>derelict.opengl.extension.ext</tt>, loaders for |
|---|
| | 224 | <span class='bold'>GL_ARB</span> extensions in <tt>derelict.opengl.extension.arb</tt>, |
|---|
| | 225 | loaders for <span class='bold'GL_NV extensions in</span> |
|---|
| | 226 | <tt>derelict.opengl.extension.nv</tt>, and so on. |
|---|
| | 227 | |
|---|
| | 228 | <h4>Naming Conventions</h4> |
|---|
| | 229 | It's important to understand the difference between extension |
|---|
| | 230 | <span class='emph'>names</span> and <span class='emph'>name strings</span>. |
|---|
| | 231 | A name string is an extension name prefixed with <span class='bold'>GL_</span> |
|---|
| | 232 | (for core OpenGL extensions), or a platform-specific prefix (such as |
|---|
| | 233 | <span class='bold'>WGL_</span> on Windows and <span class='bold'>GLX_</span> on |
|---|
| | 234 | Linux) for platform-specific extensions. For example, <span class='bold'>ARB_shadow |
|---|
| | 235 | </span> is an extension name and <span class='bold'>GL_ARB_shadow</span> is a |
|---|
| | 236 | name string. |
|---|
| | 237 | <p> |
|---|
| | 238 | In DerelictGL, each supported extension has its own loader. The name of the |
|---|
| | 239 | loader's module is identical to the extension name, minus the prefix. The prefix |
|---|
| | 240 | is the name of the package in which the module can be found. For example, the |
|---|
| | 241 | loader for the extension <span class='bold'>ARB_shadow_objects</span> resides in |
|---|
| | 242 | the module <tt>derelict.opengl.extension.arb.shadow_objects</tt></span>. |
|---|
| | 243 | </p> |
|---|
| | 244 | <div class='note'> |
|---|
| | 245 | The one exception to this rule is the extension |
|---|
| | 246 | <span class='bold'>EXT_422_pixels</span>. In D, module names cannot begin with |
|---|
| | 247 | a number. For this extension, the module is |
|---|
| | 248 | <tt>derelict.opengl.extension.ext.four22_pixels</tt>. However, the name of the |
|---|
| | 249 | loader for this extension follows the convention outlined below. |
|---|
| | 250 | </div> |
|---|
| | 251 | |
|---|
| | 252 | <p> |
|---|
| | 253 | The name of each loader is a modified form of the extension name. Essentially, |
|---|
| | 254 | each lowercase word separated by an underscore is capitalized and the underscores |
|---|
| | 255 | removed, resulting in a camel-case name. Here are some examples: |
|---|
| | 256 | </p> |
|---|
| | 257 | <ul> |
|---|
| | 258 | <li>ARB_shadow => ARBShadow</li> |
|---|
| | 259 | <li>NV_float_buffer => NVFloatBuffer</li> |
|---|
| | 260 | <li>EXT_bgra => EXTBgra</li> |
|---|
| | 261 | <li>EXT_422_pixels =>EXT422Pixels</li> |
|---|
| | 262 | <li>ATI_texture_compression_3dc => ATITextureCompression3dc</li> |
|---|
| | 263 | </ul> |
|---|
| | 264 | <p> |
|---|
| | 265 | Take special notice of EXTBgra. It's tempting to write EXTBGRA instead, but in any |
|---|
| | 266 | case where acronyms are part of an extension name, the name of the loader |
|---|
| | 267 | will only capitalize the first letter of the acronym. |
|---|
| | 268 | </p> |
|---|
| | 269 | |
|---|
| | 270 | <h4>Loading Extensions</h4> |
|---|
| | 271 | |
|---|
| | 272 | On some operating systems, it may be possible to load extensions without first |
|---|
| | 273 | creating an OpenGL context. Unfortunately, on Windows, this is not the case. |
|---|
| | 274 | As such, in order to maintain a consistent interface DerelictGL requires that |
|---|
| | 275 | a valid OpenGL context exist before extensions can be loaded. Any attempt to |
|---|
| | 276 | load extensions when no context has been created will cause an exception to |
|---|
| | 277 | be thrown. |
|---|
| | 278 | |
|---|
| | 279 | <p> |
|---|
| | 280 | Once DerelictGL has been loaded and a context created, you can load all extensions |
|---|
| | 281 | used by your application with one method call: <tt>DerelictGL.loadExtensions</tt>. |
|---|
| | 282 | Extensions not used by your application will not be loaded. Internally, DerelictGL |
|---|
| | 283 | uses module constructors to track which extensions need to be loaded. So all you |
|---|
| | 284 | need do is to import the extension loader modules you intend you use. There is |
|---|
| | 285 | no requirement that you import them in the same module in which you load them -- |
|---|
| | 286 | you can import them anywhere in your application: |
|---|
| | 287 | </p> |
|---|
| | 288 | <pre> |
|---|
| | 289 | // render.d |
|---|
| | 290 | module myapp.render; |
|---|
| | 291 | |
|---|
| | 292 | import derelict.opengl.extension.arb.point_sprite; |
|---|
| | 293 | import derelict.opengl.extension.nv.texture_rectangle; |
|---|
| | 294 | |
|---|
| | 295 | ... |
|---|
| | 296 | |
|---|
| | 297 | // init.d |
|---|
| | 298 | module myapp.init |
|---|
| | 299 | |
|---|
| | 300 | void loadOpenGL() |
|---|
| | 301 | { |
|---|
| | 302 | // load DerelictGL |
|---|
| | 303 | DerelictGL.load(); |
|---|
| | 304 | |
|---|
| | 305 | // create the OpenGL context here (via SDL, Win32, or some other API) |
|---|
| | 306 | ... |
|---|
| | 307 | |
|---|
| | 308 | // load all of the extensions you use (in this case ARB_point_sprite and NV_texture_rectangle) |
|---|
| | 309 | DerelictGL.loadExtensions(); |
|---|
| | 310 | } |
|---|
| | 311 | </pre> |
|---|
| | 312 | <p> |
|---|
| | 313 | This is a fine compromise between the two techniques often used in the C world: |
|---|
| | 314 | loading each extension individually, or using a third-party library that loads |
|---|
| | 315 | all available extensions. |
|---|
| | 316 | </p><p> |
|---|
| | 317 | The <tt>load</tt> method of each extension loader is publicly exposed, so you |
|---|
| | 318 | can call it directly if you prefer. It's much simpler, however, to use the |
|---|
| | 319 | <tt>loadExtensions</tt> method of DerelictGL instead. |
|---|
| | 320 | </p> |
|---|
| | 321 | |
|---|
| | 322 | <h4>Using Extensions</h4> |
|---|
| | 323 | |
|---|
| | 324 | Because all extensions used by the application are loaded at once, and because |
|---|
| | 325 | failure to load an extension rarely indicates that an application should terminate, |
|---|
| | 326 | no exceptions are thrown when an extension is not present or fails to load. It |
|---|
| | 327 | would have been possible to use Derelict's selective loading mechanism with |
|---|
| | 328 | extension loading, but the decision was made not to do so simply because it is |
|---|
| | 329 | not an exceptional circumstance for an extension to be unavailable on a user's |
|---|
| | 330 | machine. In fact, it is often expected that some extensions will not be present. |
|---|
| | 331 | Therefore, before attempting to use an extension it is important to check |
|---|
| | 332 | whether or not the extension is available. |
|---|
| | 333 | <p> |
|---|
| | 334 | Alternate code paths are the norm in OpenGL programming. Typically, developers |
|---|
| | 335 | determine a mimimal OpenGL version and/or extension set to support. If the minimum |
|---|
| | 336 | is not available on the user's machine, the application aborts. Many OpenGL |
|---|
| | 337 | applications also support more advanced features if they are available. For example, |
|---|
| | 338 | some advanced lighting technniques can be implemented with GLSL shaders, but |
|---|
| | 339 | when GLSL is unavailable the application can fall back to a different technique |
|---|
| | 340 | using the fixed-function pipeline for a degraded effect. Some applications may |
|---|
| | 341 | provide for three or four different ways of achieving a single effect. |
|---|
| | 342 | </p><p> |
|---|
| | 343 | With this in mind, each extension loader in Derelict exposes the following |
|---|
| | 344 | method: <tt>bool isEnabled()</tt>. You can call this method to determine if |
|---|
| | 345 | an extension is available and take appropriate action if it is not. Here is |
|---|
| | 346 | an example: |
|---|
| | 347 | </p> |
|---|
| | 348 | <pre> |
|---|
| | 349 | import derelict.extension.arb.vertex_shader; |
|---|
| | 350 | |
|---|
| | 351 | void doSomethingWithVertexShaderExtension |
|---|
| | 352 | { |
|---|
| | 353 | if(ARBVertexShader.isEnabled()) |
|---|
| | 354 | { |
|---|
| | 355 | // use extension here |
|---|
| | 356 | } |
|---|
| | 357 | else |
|---|
| | 358 | { |
|---|
| | 359 | // use fallback, exit program, or whatever you need to do |
|---|
| | 360 | } |
|---|
| | 361 | } |
|---|
| | 362 | </pre> |
|---|
| | 363 | |
|---|