├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── LICENSE.txt ├── Makefile ├── README.md ├── compile_flags.txt ├── ggx.h ├── impl ├── gl_helpers.cpp ├── gl_helpers.h ├── glsl.h ├── inline_glsl.cpp ├── inline_glsl.h ├── shader_types.h └── ssgl.h ├── main.cpp ├── math_helpers.h ├── ssgl.sln ├── ssgl.vcxproj └── utils ├── gl_timing.h ├── glext.h ├── loadgl46.cpp ├── loadgl46.h ├── mesh.cpp ├── mesh.h ├── wglext.h ├── window.cpp └── window.h /.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | x64 3 | .vs 4 | build 5 | *.filters 6 | *.user 7 | *.bin 8 | *.pdb 9 | *.o 10 | /shader_cache 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "(gdb) Launch", 9 | "type": "lldb", 10 | "request": "launch", 11 | "program": "build/debug", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${fileDirname}", 15 | "externalConsole": false, 16 | "setupCommands": [ 17 | { 18 | "description": "Enable pretty-printing for gdb", 19 | "text": "-enable-pretty-printing", 20 | "ignoreFailures": true 21 | } 22 | ] 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clang-cl Debug", 6 | "type": "shell", 7 | "command": "clang-cl", 8 | "args": [ 9 | "main.cpp", 10 | "impl/gl_helpers.cpp", "impl/inline_glsl.cpp", 11 | "utils/window.cpp", "utils/loadgl46.cpp", "utils/mesh.cpp", 12 | "/Z7", 13 | "/EHsc", 14 | "/MTd", 15 | "/std:c++17", 16 | "/Iimpl", 17 | "/Iutils", 18 | "/Od", 19 | "/o", "build/debug", 20 | "/link", "User32.lib", "Gdi32.lib" 21 | ], 22 | "group": { 23 | "kind": "build", 24 | "isDefault": true 25 | } 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Pauli Kemppinen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CFLAGS = -c -std=c++17 -I. -Iimpl -Iutils 3 | GLSL_DEPS = impl/inline_glsl.h impl/glsl.h impl/shader_types.h impl/gl_helpers.h 4 | 5 | all: program 6 | ./program 7 | 8 | obj: 9 | mkdir -p obj 10 | 11 | obj/window.o: utils/window.cpp utils/window.h impl/glsl.h|obj 12 | $(CXX) $(CFLAGS) -o obj/window.o utils/window.cpp 13 | obj/loadgl46.o: utils/loadgl46.cpp utils/loadgl46.h|obj 14 | $(CXX) $(CFLAGS) -o obj/loadgl46.o utils/loadgl46.cpp 15 | obj/gl_helpers.o: impl/gl_helpers.cpp impl/gl_helpers.h|obj 16 | $(CXX) $(CFLAGS) -o obj/gl_helpers.o impl/gl_helpers.cpp 17 | obj/inline_glsl.o: impl/inline_glsl.cpp $(GLSL_DEPS)|obj 18 | $(CXX) $(CFLAGS) -o obj/inline_glsl.o impl/inline_glsl.cpp 19 | obj/main.o: main.cpp $(GLSL_DEPS)|obj 20 | $(CXX) $(CFLAGS) -o obj/main.o main.cpp 21 | obj/mesh.o: utils/mesh.cpp utils/mesh.h impl/glsl.h|obj 22 | $(CXX) $(CFLAGS) -o obj/mesh.o utils/mesh.cpp 23 | 24 | program: obj/window.o obj/loadgl46.o obj/gl_helpers.o obj/inline_glsl.o obj/main.o obj/mesh.o 25 | $(CXX) -o program obj/*.o -lm -ldl -lpthread -lX11 -lEGL -lGL -lpng 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # single source gl 2 | 3 | single source gl (ssgl) lets you write GLSL shaders as C++ lambdas that automatically capture shader inputs and outputs. This unifies code, brings powerful C++ tools into shader development, and removes code that just passes objects around. All of this makes it extremely fast to prototype ideas and iterate on them. 4 | 5 | To illustrate, the following is a program that uses a compute shader to fill a buffer with a running count. Note how the whole program sits in a single file, and calling `useShader` is all that's required to set up the drawcall. The shader is the lambda `fill`, and the main body of the shader is in `glsl_main`. `useShader` sets up the program and binds the buffer as instructed by the `bind_block` macro. 6 | ```C++ 7 | #include 8 | #include "ssgl.h" 9 | 10 | int main() { 11 | // init OpenGL 12 | OpenGL context(640, 480, "iota_example", false, false); 13 | 14 | // reserve space 15 | Buffer iota; 16 | glNamedBufferData(iota, 1024 * 1024 * sizeof(uint32_t), nullptr, GL_STATIC_DRAW); 17 | 18 | // the shader itself 19 | auto fill = [&] { 20 | layout (local_size_x = 256) in; 21 | buffer bind_block(iota) { 22 | uint result[]; 23 | }; 24 | void glsl_main() { 25 | result[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x; 26 | } 27 | }; 28 | 29 | // call the shader 30 | useShader(fill()); 31 | glDispatchCompute(1024*4, 1, 1); 32 | 33 | // display results 34 | std::vector result(1024 * 1024); 35 | glGetNamedBufferSubData(iota, 0, sizeof(uint32_t) * result.size(), result.data()); 36 | for (int i = 0; i<1024*1024; i+=64*1024) 37 | printf("%u\n", result[i]); 38 | } 39 | ``` 40 | 41 | The project aims to make shader development smoother with this injection of GLSL into C++. There are several factors that go into this: 42 | * shaders are brought right next to the code that calls them 43 | * shaders can be edited like any C++ code: with intellisense, auto-complete, syntax highlighting, and so on 44 | * shaders are hot reloadable so interactive editing is possible 45 | * shader inputs and outputs such as uniforms and framebuffer targets are automatically captured, removing a bunch of supporting code 46 | * the GLSL vector and matrix types are available on the host side 47 | * free functions can be called from shader code; you can implement functions once and call them both on the CPU and the GPU 48 | * no custom extensions are required, thus all major compilers are supported (tested on MSVC, GCC, and clang) 49 | 50 | Since the code is C++ under the hood, IDE features like Intellisense work properly with shaders. This efficiently prevents making trivial type or syntax mistakes, as they're caught already while writing the code: 51 | 52 | ![](https://i.imgur.com/QnwMIau.png) 53 | 54 | To be clear, the project is **not** about adding C++ features to shaders, or being able to run shaders on the CPU (even though the latter is possible to an extent). All of the shader code will be standard GLSL and run on the GPU. The point is that GLSL now sits within C++, improving the development experience by making shaders nicer to write and reducing the need for uninteresting code. 55 | 56 | The project is written against C++17 and OpenGL 4.6. The C++17 features are strictly necessary, but OpenGL could be ported back at least to 3.0 -- the main hurdle would be to convert all DSA code to the old model. This will happen at some point to enable Mac and potentially OpenGL ES support. 57 | 58 | The implementation is split into two folders: `impl` contains everything you need for the library to work, and that's all you need if you want to use your own windowing/OpenGL environment. `utils` contains some extra helpers and a sample windowing/GL extension loading system to keep the repository self-contained. On Linux, this windowing system requires GLFW 3. A Visual Studio project and a Makefile are provided, there's also a rudimentary VSCode setup that's still work in progress but should get you started. 59 | 60 | ## documentation 61 | - [examples](#examples) 62 | - [simple compute shader](#simple-compute-shader) 63 | - [rotating rgb triangle](#rotating-rgb-triangle) 64 | - [simple global illumination and subsurface scattering](#simple-global-illumination-and-subsurface-scattering) 65 | - [Shadertoy adapter](#shadertoy-adapter) 66 | - [reference](#reference) 67 | - [bind macros](#bind-macros) 68 | - [global values and functions](#global-values-and-functions) 69 | - [wrapper types](#wrapper-types) 70 | - [misc](#misc) 71 | 72 | ## examples 73 | 74 | Let's look at a few usage examples in more detail. This is not a tutorial on C++, GPU programming, or graphics, so a certain level of proficiency in each is expected. The interest is not in what we compute, but how we do it. Focusing on form over function here will let you do the opposite in your actual projects. 75 | 76 | ### simple compute shader 77 | 78 | ![](https://user-images.githubusercontent.com/1880715/150009227-71b83b32-0033-4e7b-aa08-79465e41e135.png) 79 | 80 | We'll first go through the simple compute shader already shown above. There are more comments this time around; all crucial information is there, but some things are further explained below. 81 | 82 | ```C++ 83 | #include 84 | // include ssgl.h last; it defines many iffy macros that will break some other headers 85 | #include "ssgl.h" 86 | 87 | int main() { 88 | 89 | // An OpenGL object creates and stores a window and its OpenGL context; 90 | // after it goes out of scope, OpenGL is released and the window destroyed. 91 | OpenGL context(640, 480, "iota_example", false, false); 92 | 93 | // A Buffer creates and stores an OpenGL buffer object. It's similar to 94 | // std::unique_ptr but for an OpenGL object instead of system memory. 95 | Buffer iota; 96 | 97 | // a Buffer is implicitly castable to GLuint so you can use it with OpenGL functions: 98 | glNamedBufferData(iota, 1024 * 1024 * sizeof(uint32_t), nullptr, GL_STATIC_DRAW); 99 | 100 | // The shader itself. Do remember to capture everything with the &! 101 | auto fill = [&] { 102 | 103 | // This scope is the global scope of the shader; nothing can be executed here. 104 | // Instead, here we declare inputs, outputs, and parameters of the shader. 105 | 106 | // first, since this is a compute shader, we define the local workgroup size: 107 | layout (local_size_x = 256) in; // (this is standard GLSL syntax) 108 | 109 | // SSBOs and UBOs are bound using "bind_block", as their contents are defined 110 | // in a block following the declaration. bind_block takes the Buffer object 111 | // with the same name ("iota") from the scope above and passes it to the shader. 112 | buffer bind_block(iota) { 113 | // The GLSL dynamic array syntax ("uint result[];") is not legal C++ here, 114 | // so we define dynamic arrays like this instead: 115 | dynamic_array(uint, result); 116 | }; 117 | 118 | // We already have a main in C++, so we'll use "glsl_main" as the GLSL entry point: 119 | void glsl_main() { 120 | // This is where the GPU will start running our code! 121 | 122 | // For this example, we'll write the index of the current thread to the array. 123 | // GLSL programs can be arbitrarily complex, this is just for the sake of brevity. 124 | result[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x; 125 | } 126 | }; 127 | 128 | // useShader sets our shader as the current shader and binds all of the required objects: 129 | useShader(fill()); // Note that we're *calling* the lambda here, not just passing it in! 130 | 131 | // This is the actual call to the shader. The arguments give the global size; 132 | // the local size is defined in the shader and all other arguments are handled by useShader. 133 | glDispatchCompute(1024*4, 1, 1); 134 | 135 | // display some of the results to check that something actually happened 136 | std::vector result(1024 * 1024); 137 | glGetNamedBufferSubData(iota, 0, sizeof(uint32_t) * result.size(), result.data()); 138 | for (int i = 0; i<1024*1024; i+=64*1024) 139 | printf("%u\n", result[i]); 140 | } 141 | ``` 142 | 143 | Another rationale for `dynamic_array` is that C++ flexible arrays don't have the `.length()` member that GLSL dynamic arrays do. In this example, you could call `result.length()` in the shader, but there's no way to make this work if we just wrote `uint result[];`. The GLSL syntax also doesn't compile under GCC, as the implementation of `bind_block` actually introduces the block as a union. 144 | 145 | If you wish to manually bind anything to the shader or otherwise change its state, you can do so between `useShader()` and your draw call. 146 | 147 | You should **not** store the `Shader` object returned by a shader lambda: call the lambda every time you call `useShader()`. The values of the binds are updated by calling the lambda, so using the old `Shader` might mess things up when objects change names or names change objects. 148 | 149 | 150 | ### rotating rgb triangle 151 | 152 | ![](https://user-images.githubusercontent.com/1880715/150008489-79662388-f997-4f29-b10a-48279413fc9b.png) 153 | 154 | This one is a classic OpenGL example. We'll use it to illustrate how vertex attributes and uniforms work. 155 | 156 | ```C++ 157 | #include "ssgl.h" 158 | // the headers in this repo are built to respect ssgl.h, so order doesn't matter 159 | #include "gl_timing.h" 160 | 161 | // We use the keyword "glsl_function" to define global functions with GLSL support. 162 | // Necessary C++ keywords and specifiers can be placed before "glsl_function". 163 | inline glsl_function mat2 get_rotation(float angle) { 164 | // get a 2D rotation matrix based on an angle (in radians) 165 | float c = cos(angle), s = sin(angle); 166 | return mat2(c, s, -s, c); 167 | } 168 | 169 | int main() { 170 | // init OpenGL, create window 171 | OpenGL context(1280, 720, "Triangle"); 172 | 173 | // define some vertices as a CPU-side array 174 | struct Vertex { vec2 position; vec3 color; }; 175 | Vertex verts[] = { 176 | {vec2(.5f, .0f), vec3(1.f, .0f, .0f)}, 177 | {vec2(-.4f, .5f), vec3(.0f, 1.f, .0f)}, 178 | {vec2(-.4f,-.5f), vec3(.0f, .0f, 1.f)} 179 | }; 180 | 181 | // send the vertices array to the GPU 182 | Buffer b; glNamedBufferData(b, sizeof(Vertex) * 3, verts, GL_STATIC_DRAW); 183 | 184 | // Here we set up attributes corresponding to the values. These are wrapper objects that act 185 | // as a view to the given Buffer; the arguments mostly match those of glVertexAttribPointer: 186 | // (buffer, stride, offset=0, type=-1, normalized=false), where typically stride is the size 187 | // of the vertex and offset is how many bytes into the struct the corresponding field is. 188 | // The template argument of Attribute is the desired shader-side type; if this doesn't match 189 | // the data in the buffer (say, your data is uint8_t), you can manually override the type. 190 | Attribute position(b, sizeof(Vertex), 0); 191 | Attribute color(b, sizeof(Vertex), sizeof(vec2)); 192 | 193 | // TimeStamp stores both CPU- and GPU-side timing events so you can query the difference 194 | // between two stamps. It has some overhead, but it's OK for testing and performance tuning. 195 | TimeStamp start; 196 | 197 | // loop() returns true while the window is open and ESC has not been pressed 198 | while (loop()) { 199 | TimeStamp now; 200 | // cpuTime() gets time in milliseconds between two stamps, whereas 201 | // gpuTime() would get total render operation time between the stamps. 202 | float t = .001f*(float)cpuTime(start, now); 203 | 204 | // define the shaders 205 | auto vertex = [&] { 206 | // Uniforms are bound with bind(name), this means basic types (including vec* and mat*) 207 | // and textures/images which are bound as uniforms. 208 | uniform float bind(t); 209 | // Attributes are bound with bind_attribute; note that you don't bind the buffer directly! 210 | in vec2 bind_attribute(position); // These do type checking; try changing the type! 211 | in vec3 bind_attribute(color); 212 | out vec3 col; 213 | void glsl_main() { 214 | col = color; 215 | 216 | // Shaders are hot reloadable! Try changing "t" to "0.5f*t" or "-t" 217 | // and saving the file while the program is running. 218 | float angle = t; 219 | 220 | // Here we call get_rotation() defined in the beginning. 221 | vec2 pos = get_rotation(angle)*position.xy; 222 | 223 | // GLSL's built-in variables are pre-defined: 224 | gl_Position = vec4(pos*vec2(9.f/16.f,1.f), .0f, 1.f); 225 | } 226 | }; 227 | auto fragment = [&] { 228 | in vec3 col; 229 | // Screen is a special texture output that writes to the window sufrace. 230 | out vec3 bind_target(screen); 231 | void glsl_main() { 232 | // just output the interpolated value 233 | screen = col; 234 | } 235 | }; 236 | 237 | // set up the shader and draw 238 | useShader(vertex(), fragment()); 239 | glDrawArrays(GL_TRIANGLES, 0, 3); 240 | 241 | // show the frame on the screen 242 | swapBuffers(); 243 | // clear the screen for the next iteration 244 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 245 | } 246 | } 247 | ``` 248 | 249 | Crucially, there are no Vertex Array Objects (VAO) or Framebuffer Objects (FBO). The only extra abstraction for turning a buffer into a vertex attribute is the `Attribute` class that defines where the attribute values are to be read from, and rendering into textures is performed by binding the desired texture directly without an intermediate object. Here we only drew to the screen which requires no FBOs in standard GL either, but rendering to textures in ssgl looks exactly the same (see the next example). Naturally VAOs and FBOs exist behind the scenes, as OpenGL requires them to be used. Automating their use can incur a performance cost, as it reduces the opportunities to reuse objects and avoid state changes. Still, the uplift in convenience is difficult to overstate. 250 | 251 | Also notice how we use `f` postfixes for `float`s like C++ and unlike GLSL. They get removed before compiling the shader so no GLSL compiler gets confused. It's not strictly necessary but good practice to use the `f`s, since it keeps the C++ compiler from emitting loads of warnings about conversions between `float` and `double`. 252 | 253 | It's important to keep in mind that the hot reload feature only works for the parts of the shader that run on the GPU; notably, input and output binds do **not** update live. This is because the `bind` macros work by producing OpenGL code on the C++ side, and this changes only when the project is recompiled. However, global functions (even ones from headers) do update whenever their containing file is saved. 254 | 255 | ### simple global illumination and subsurface scattering 256 | 257 | ![image](https://user-images.githubusercontent.com/1880715/151415036-80650b16-c8c0-4229-ad4f-9f2407a14e93.png) 258 | 259 | This is a slightly more complicated example that lets us explore the rest of the key features in ssgl. The basic gist is we define some geometry procedurally and use [reflective shadow maps](http://www.klayge.org/material/3_12/GI/rsm.pdf) and [depth map based absorption](https://developer.download.nvidia.com/books/HTML/gpugems/gpugems_ch16.html) to light it nicely. The graphics techniques aren't the point here and will only be skimmed over, the key thing is in rendering to multiple targets simultaneously and using the results in a second pass. 260 | 261 | ```C++ 262 | #include "ssgl.h" 263 | #include "gl_timing.h" 264 | #include "math_helpers.h" // for pi, perspective(), lookat(), and rnd() 265 | 266 | // glsl_global is equivalent to glsl_function but for variables. 267 | glsl_global vec3 ldir = normalize(vec3(1.f, 2.f, 1.f)); 268 | 269 | int main() { 270 | // init OpenGL, create window 271 | OpenGL context(1280, 720, "Cubes"); 272 | glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); 273 | 274 | // create a vertex attribute and index list for a cube 275 | vec3 verts[8]; 276 | for (int i = 0; i < 8; ++i) 277 | verts[i] = vec3(i & 1, (i/2)&1, (i/4)&1)*2.f - 1.f; 278 | uvec3 inds[] = { 279 | {0,2,1}, {1,2,3}, {0,4,2}, {2,4,6}, {0,1,4}, {4,1,5}, 280 | {2,6,3}, {3,6,7}, {1,3,5}, {5,3,7}, {4,5,6}, {6,5,7} 281 | }; 282 | 283 | Buffer vertexBuffer, indexBuffer; 284 | glNamedBufferData(vertexBuffer, sizeof(verts), verts, GL_STATIC_DRAW); 285 | glNamedBufferData(indexBuffer, sizeof(inds), inds, GL_STATIC_DRAW); 286 | Attribute position(vertexBuffer, sizeof(vec3), 0); 287 | 288 | // Create textures to render to. For reflective shadow maps we need to have an 289 | // enriched shadow map with normal and color information. 290 | Texture color, normal, depth; 291 | glTextureStorage2D(color, 1, GL_RGB32F, 2048, 2048); 292 | glTextureStorage2D(normal, 1, GL_RGB32F, 2048, 2048); 293 | glTextureStorage2D(depth, 1, GL_DEPTH24_STENCIL8, 2048, 2048); 294 | 295 | TimeStamp start; 296 | 297 | int instances = 800; 298 | 299 | // while window open and ESC not pressed 300 | while (loop()) { 301 | // get elapsed time 302 | TimeStamp now; 303 | float t = .00005f*(float)cpuTime(start, now); 304 | 305 | // compute matrices to transform between world, camera, and light spaces 306 | mat4 cameraToWorld = lookAt(vec3(cos(t), .4f, sin(t))*12.f, vec3(.0f)); 307 | mat4 worldToClip = perspective(.5f, 16.f/9.f, .1f, 30.f) * inverse(cameraToWorld); 308 | mat4 worldToLight = ortho(12.f, 1.f, -7.f, 7.f) * inverse(lookAt(ldir, vec3(.0f))); 309 | 310 | // This vertex shader will be used for both the shadow map and the final pass, 311 | // but with different matrices; for this to work, we have to rename the input 312 | // by passing it as an argument. As the shaders themselves can only capture 313 | // inputs, we need to introduce an extra scope, here done by wrapping the shader 314 | // in an outer generator lambda. 315 | auto vertex = [&](mat4 matrix) { 316 | return [&] { 317 | uniform float bind(t); 318 | uniform mat4 bind(matrix); 319 | in vec3 bind_attribute(position); 320 | out vec3 col, p; 321 | 322 | // a local function is introduced using the glsl_func() macro. 323 | // local functions are useful as they automatically get access to uniforms 324 | // and such, unlike global functions, like gl_InstanceID here. 325 | // the "arg_out" macro corresponds to "out vec3" and "vec3&". 326 | // "arg_inout" and "arg_in" are also available. 327 | vec3 glsl_func(get_position)(vec3 p, arg_out(vec3) col, float t) { 328 | // this function repositions a bunch of cubes to generate the scene 329 | if (gl_InstanceID == 0) { 330 | p = vec3(p.x*4.f, -1.f + p.y * .1f, p.z*4.f); 331 | col = vec3(.8f); 332 | } 333 | else { 334 | srnd(gl_InstanceID); 335 | float angle = rnd() * 2.f * pi + t * 10.f; 336 | float c = cos(angle), s = sin(angle); 337 | p.xy = p.xy*.05f + vec2(2.f + rnd(),.0f); 338 | mat3 B = basis(normalize(vec3(rnd() - .5f, 2.f, rnd() - .5f))); 339 | p.xyz = mat3(B[1], B[2], B[0]) * mat3(c, .0f, s, .0f, 1.f, .0f, -s, .0f, c) * p.xyz; 340 | col = mix(vec3(.2f, .1f, .05f), vec3(.8f, .4f, .1f), rnd()); 341 | } 342 | return p; 343 | }; // <-- since glsl_func() maps to a lambda under the hood, we need a semicolon here! 344 | 345 | void glsl_main() { 346 | p = get_position(position, col, t); 347 | gl_Position = matrix * vec4(p, 1.f); 348 | } 349 | }(); 350 | }; 351 | // the first fragment shader will populate the shadow maps (with color+normal instead of just depth) 352 | auto lightFragment = [&] { 353 | // It's up to the user to make sure that the render target sizes match; 354 | // viewport will be set to (0,0,w,h) automatically. 355 | out vec3 bind_target(color, normal); 356 | out float bind_depth(depth); // you can write to this, default is the rasterized depth 357 | in vec3 col, p; 358 | void glsl_main() { 359 | // just copy the outputs 360 | color = col; 361 | normal = normalize(cross(dFdx(p), dFdy(p))); 362 | } 363 | }; 364 | 365 | // set up the shader and draw 366 | useShader(vertex(worldToLight), lightFragment()); 367 | 368 | // Here's the time to setup extra stuff like an index buffer: 369 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 370 | 371 | // useShader() binds the targets so we can clear them here: 372 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 373 | 374 | // glViewport(...) // we could set the viewport manually here if desired 375 | 376 | glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0, instances); 377 | 378 | // actually draw to the screen 379 | auto fragment = [&] { 380 | uniform mat4 bind(worldToLight); 381 | uniform float bind(t); 382 | in vec3 col, p; 383 | // Samplers are bound just like any uniform. 384 | // Remember, depth is in the x channel only. 385 | uniform sampler2D bind(color, normal, depth); 386 | 387 | // If we don't bind the output, we always write to the screen and can choose any variable name. 388 | // Using the "screen" target seems somewhat cleaner, but this is also an option. 389 | out vec3 out_color; 390 | 391 | void glsl_main() { 392 | vec3 n = normalize(cross(dFdx(p), dFdy(p))); 393 | 394 | // compute the light space coordinate of our screen fragment 395 | vec4 lNDC = worldToLight * vec4(p, 1.f); 396 | lNDC.xyz = (lNDC.xyz/lNDC.w)*.5f+.5f; 397 | 398 | float shadow = .0f; 399 | vec3 scatter = vec3(.0f); 400 | 401 | // a different seed for each pixel every frame 402 | srnd(uint(gl_FragCoord.x) + 1280 * uint(gl_FragCoord.y) + floatBitsToUint(t)); 403 | 404 | // loop for shadow filtering and the shadow map based subsurface scattering 405 | for (int i = 0; i < 8; ++i) { 406 | vec2 jitter = (vec2(rnd(), rnd()) - .5f) / vec2(textureSize(depth, 0))*2.f; 407 | // difference between shadow map and current fragment depth from the light 408 | float penetration = texture(depth, lNDC.xy + jitter).x - lNDC.z; 409 | // shadow mapping 410 | if (penetration > -.001f) 411 | shadow += 1.f; 412 | // Scattering: Beer's law and a bunch of magic constants. 413 | if (col.b < .2f) { 414 | float irradiance = max(.0f, dot(texture(normal, lNDC.xy + jitter).xyz, ldir)); 415 | vec3 optical_length = 60.f * penetration / texture(color, lNDC.xy + jitter).xyz; 416 | scatter += .2f * col * irradiance * exp(min(vec3(.0f), optical_length)); 417 | } 418 | } 419 | shadow /= 8.f; 420 | scatter /= 8.f; 421 | 422 | // Reflective shadow mapping: each shadow map texel is treated as a virtual point light (VPL) and 423 | // the total contribution of all VPLs is stochastically evaluated by taking the average 424 | // of the colors of a set of random trials. To make this fast, we don't care if the current 425 | // fragment and the VPL are actually mutually visible or not. 426 | vec3 indirect = vec3(.0f); 427 | for (int i = 0; i < 16; ++i) { 428 | // pick a texel 429 | float angle = rnd() * 2.f * pi; 430 | vec2 offset = lNDC.xy+vec2(cos(angle), sin(angle)) * sqrt(float(i) + rnd())*.02f; 431 | 432 | // backproject the VPL location 433 | vec4 vpl_pos = inverse(worldToLight)*vec4(offset*2.f-1.f, texture(depth, offset).x*2.f-1.f, 1.0f); 434 | vpl_pos.xyz /= vpl_pos.w; 435 | vec3 diff = p - vpl_pos.xyz; 436 | 437 | // read normal and color of VPL 438 | vec3 vpl_normal = texture(normal, offset).xyz; 439 | vec3 vpl_col = texture(color, offset).xyz; 440 | 441 | // limit the normalization factor to avoid bright splotches 442 | float lensq = max(dot(diff, diff), .4f); 443 | 444 | // the geometric term between the VPL and the receiver 445 | diff = normalize(diff); 446 | float G = max(.0f, dot(-diff, n)) * max(.0f, dot(diff, vpl_normal)) / lensq; 447 | indirect += col * vpl_col * G; 448 | } 449 | indirect /= 16.f; 450 | 451 | vec3 direct = shadow * col * max(.0f, dot(n, ldir)); 452 | out_color = direct + indirect + scatter; 453 | } 454 | }; 455 | 456 | // set up the shader and draw 457 | useShader(vertex(worldToClip), fragment()); 458 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 459 | glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0, instances); 460 | 461 | // show the frame and clear the screen 462 | swapBuffers(); 463 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 464 | } 465 | } 466 | ``` 467 | 468 | That's it! The tour is over; that's how you use ssgl. Towards the bottom of this document is a reference with slightly longer explanations and a couple of more obscure features that we skipped. 469 | 470 | ### Shadertoy adapter 471 | 472 | ![image](https://user-images.githubusercontent.com/1880715/151568002-1718ca77-b7f1-49c8-870a-7580c63d669f.png) 473 | 474 | Just for fun, here's a snippet that lets you run most [Shadertoys](https://www.shadertoy.com/) in ssgl, you just need to prepend functions and globals with `glsl_function` and `glsl_global`. Be wary that the more esoteric syntax that some Shadertoys contain (passing swizzles as inout parameters, swizzling the result of a `*=` operation, using #defines inside a function, ...) might need to be simplified a bit. 475 | 476 | Note that this makes the `mainImage` function a standard C++ function that you can call (and **debug**) on the CPU! 477 | 478 | ```C++ 479 | #include "ssgl.h" 480 | #include "gl_timing.h" 481 | 482 | glsl_global vec3 iResolution; // viewport resolution (in pixels) 483 | glsl_global float iTime; // shader playback time (in seconds) 484 | glsl_global float iTimeDelta; // render time (in seconds) 485 | glsl_global int iFrame; // shader playback frame 486 | glsl_global vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click (actually spacebar) 487 | 488 | // Shadertoy goes here: 489 | glsl_function void mainImage(out vec4 fragColor, in vec2 fragCoord) 490 | { 491 | // Normalized pixel coordinates (from 0 to 1) 492 | vec2 uv = fragCoord / iResolution.xy; 493 | 494 | // Time varying pixel color 495 | vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0, 2, 4)); 496 | 497 | // Output to screen 498 | fragColor = vec4(col, 1.0); 499 | } 500 | 501 | int main() { 502 | // init OpenGL, create window 503 | OpenGL context(1280, 720, "Shadertoy"); 504 | 505 | // start timing 506 | TimeStamp start; 507 | 508 | int frame = 0; 509 | float old_t = .0f; 510 | // while window open and ESC not pressed 511 | while (loop()) { 512 | frame++; 513 | // get elapsed time 514 | TimeStamp now; 515 | float t = .001f*(float)cpuTime(start, now); 516 | float dt = t - old_t; 517 | old_t = t; 518 | 519 | // generate a triangle large enough to cover the screen 520 | auto vertex = [&] { 521 | void glsl_main() { 522 | gl_Position = vec4(gl_VertexID == 0 ? 4.f : -1.0f, gl_VertexID == 1 ? 4.f : -1.0f, .5f, 1.f); 523 | } 524 | }; 525 | 526 | ivec2 resolution = windowSize(); 527 | ivec4 mouse = ivec4(getMouse(), keyDown(VK_SPACE), keyHit(VK_SPACE)); 528 | 529 | // just pass everything along to mainImage() 530 | auto fragment = [&] { 531 | out vec3 screen; 532 | uniform float bind(t, dt); 533 | uniform ivec2 bind(resolution); 534 | uniform ivec4 bind(mouse); 535 | uniform int bind(frame); 536 | 537 | void glsl_main() { 538 | iResolution.xy = vec2(resolution); 539 | iTime = t; 540 | iTimeDelta = dt; 541 | iMouse = vec4(mouse); 542 | iFrame = frame; 543 | vec4 color; 544 | mainImage(color, gl_FragCoord.xy); 545 | screen = color.rgb; 546 | } 547 | }; 548 | 549 | // set up the shader and draw 550 | useShader(vertex(), fragment()); 551 | glDrawArrays(GL_TRIANGLES, 0, 3); 552 | 553 | // show the frame and clear the screen 554 | swapBuffers(); 555 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 556 | } 557 | } 558 | ``` 559 | 560 | ## reference 561 | 562 | This is a listing of all the types and macros in single source gl. 563 | 564 | ### bind macros 565 | 566 | The `bind` macros significantly reduce boiler plate code around drawcalls. 567 | 568 | ```C++ 569 | bind(uniform_1, uniform_2, ...) 570 | uniform float bind(a, b, c); 571 | 572 | bind_attribute(attribute_1, attribute_2, ...) 573 | in vec3 bind_attribute(a, b, c); 574 | 575 | bind_target(target_1, target_2, ...) 576 | out vec4 bind_target(a, b, c); 577 | 578 | bind_depth(depth_map) 579 | out float bind_depth(shadow_map); 580 | 581 | bind_block(b) 582 | buffer bind_block(buff) { /*SSBO contents*/ }; 583 | uniform bind_block(buff) { /*UBO contents*/ }; 584 | ``` 585 | 586 | The `bind` macro family is the main difference in single source gl to typical shader programming. Instead of declaring values to be passed directly, we'll use the corresponding macro: `bind` for uniforms, `bind_attribute` for vertex attributes, `bind_target` for render targets, `bind_depth` for depth maps, and `bind_block` for SSBOs and UBOs. These take the object or value in the scope above and pass it to the shader **with the same name**, so there's no need to specify any indices or explicitly match objects to their names. The implementation relies on variable shadowing to produce a correctly typed local object; as such, you cannot just pass the object as a differently named argument. If you wish to call the same shader with multiple objects, you should place it in a function where the argument name is used as the name of the object: 587 | 588 | ```C++ 589 | Shader wrapper(Buffer b) { 590 | return [&] { 591 | buffer bind_block(b) {/*whatever b contains*/}; 592 | void glsl_main() {/*whatever you wanted to do with b*/} 593 | }(); 594 | } 595 | ``` 596 | which can now be set as the current shader with `useShader(wrapper(any_buffer))`, where `any_buffer` can indeed be any buffer you want. `wrapper` could also be a lambda. In fact, you could just add a redundant extra scope to your original shader function, but this looks somewhat confusing. 597 | 598 | Note that some of the `bind` macros can take multiple arguments: this is purely a convenience feature, you can also declare each (for example) uniform in its own statement. As usual, to be able to declare the objects on the same line, they'll need to be of the same type. 599 | 600 | ```C++ 601 | dynamic_array(type, name) 602 | ``` 603 | Since flexible arrays inside unions are not valid C++, an SSBO can't contain an array of the form `type name[]`; this GLSL construct is replaced by this macro. With some compilers you can use the GLSL syntax, but this doesn't let you query the length of the array; using `dynamic_array(type, name)` you can call `name.length()` in the shader, just as you typically would in GLSL. 604 | 605 | ### global values and functions 606 | 607 | single source gl also lets you use functions and variables declared outside of the shader scope. 608 | 609 | ```C++ 610 | glsl_function 611 | inline glsl_function float test() {return .0f;} 612 | glsl_global 613 | static glsl_global uint random_seed = 0; 614 | ``` 615 | 616 | These two are straight forward, but very useful. `glsl_function` lets you write a function in the global scope, and makes it visible to both CPU and GPU side code. The system also supports includes, so you can place your functions in a header. Note that any specifiers before `glsl_function` are ignored, as the `inline` in the example above. `glsl_global` is basically the same, but introduces variables instead of functions. This is useful for global values such as mathematical constants and state required by global functions (GLSL doesn't have a static keyword, so for example random seeds have to be stored this way.) 617 | 618 | ```C++ 619 | return_type glsl_func(name)(arguments) {/*function body*/}; 620 | float glsl_func(twice)(float x) {return 2.f * x;}; 621 | ``` 622 | 623 | `glsl_func` is almost the same as `glsl_function`, but is for functions inside the shader body. Since C++ doesn't support local functions, this actually maps to a lambda; notice the necessary semicolon after the function body. This is most convenient when you want to, for example, read from an SSBO in a specific way multiple times and want to wrap the read in a function -- you can't pass an SSBO to a function in GLSL and you won't have access to one on the global scope, so a local function is necessary. (Note that actually reading from an SSBO in a `glsl_func` requires the newest version of VS2022 and compiling as c++20, older ones will give an "internal compiler error"; other compilers are fine with it.) 624 | 625 | ```C++ 626 | arg_in(type) 627 | arg_out(type) 628 | arg_inout(type) 629 | glsl_function void test(arg_in(float) a, arg_out(int) b, arg_inout(mat4) c) {} 630 | ``` 631 | 632 | These macros are used to wrap `out` and `inout` argument types for `glsl_function`s and `glsl_func`s; `arg_in` should not be necessary but is provided for completeness' sake. This form is required to allow using proper out/inout arguments on both the CPU and the GPU. 633 | 634 | ### wrapper types 635 | 636 | ```C++ 637 | struct OpenGL; 638 | Opengl(width, height, title, fullscreen, show); 639 | ``` 640 | `OpenGL` is a RAII wrapper for an OpenGL context; constructing the object opens a context and makes it current, and it remains current until the object is destructed, at which point both the OpenGL context and the window are destroyed. The constructor takes the parameters of the window: its size and title, if it's fullscreen, and if it should be shown at all. The last option is to support CLI programs where you don't want a window at all. 641 | 642 | ```C++ 643 | struct Buffer; 644 | template struct Texture; 645 | ``` 646 | 647 | `Buffer` and `Texture` are RAII wrappers for OpenGL buffers and textures. They store a single object at a time and destroy it when the lifetime ends (similar to `unique_ptr`), or the object is replaced. The object is automatically constructed if no arguments are given, and the objects are implicitly convertible to their underlying GLuint values; so for example, you can pass a `Buffer` to `glNamedBufferStorage` to set up its storage. The type is also used to deduce bindings, so using these classes is required for the shader system to work. If you wish to track your lifetimes manually or with some other system, you can construct a non-owning `Buffer` or `Texture` by just passing the `GLuint` to the constructor (or the `GLuint` and `true` to pass ownership to the class). The `target` in `Texture` refers to the texture target (such as `GL_TEXTURE_2D`) -- to write a generic function that can take in any type, you should use `Texture<>` which stores the target dynamically. 648 | 649 | ```C++ 650 | template 651 | Texture<> Level(const Texture& t, int level); 652 | template 653 | Texture<> Layer(const Texture& t, int layer); 654 | ``` 655 | 656 | `Level` and `Layer` take the MIP level or the 2D layer of the given `Texture`, and return a corresponding dynamically-targeted texture. This is so it's possible to write a shader that operates on a 2D texture, and pass in a specific MIP level or a layer of a 3D texture. 657 | 658 | ```C++ 659 | template 660 | struct Attribute; 661 | // to construct: 662 | Attribute(const Buffer& b, int stride, int offset = 0, GLuint type = -1, bool normalized = false) 663 | ``` 664 | 665 | `Attribute` is an adapter for vertex buffers: it's where you define how the buffer is read to produce vertex inputs. The template argument `T` is the shader-side type of the attribute. The only things you can do with `Attribute` instances are construct them and bind them to shaders. In the constructor you specify the buffer to be read, and all of the information typically given to `glVertexAttribPointer`. The type of the attribute is typically determined by the template argument, but for example a vec3 attribute can be backed up by `GL_BYTE` data, so you can also give the type manually. 666 | 667 | ### misc 668 | 669 | ```C++ 670 | void useShader(const Shader& compute); 671 | void useShader(const Shader& vertex, const Shader& fragment); 672 | void useShader(const Shader& vertex, const Shader& geometry, const Shader& fragment); 673 | void useShader(const Shader& vertex, const Shader& control, const Shader& evaluation, const Shader& fragment); 674 | void useShader(const Shader& vertex, const Shader& geometry, const Shader& control, const Shader& evaluation, const Shader& fragment); 675 | ``` 676 | `useShader` basically replaces `glUseProgram()` and most of the binding code. You give it the shaders corresponding to the shader stages you require. The OpenGL side shader programs themselves are cached, so compilation only happens on the first call to that specific combination of shaders. 677 | 678 | ```C++ 679 | bool loop(); 680 | void swapBuffers(); 681 | void setTitle(const char* title); 682 | void showWindow(); 683 | void hideWindow(); 684 | 685 | bool keyDown(uint vk_code); 686 | bool keyHit(uint vk_code); 687 | void resetHits(); 688 | 689 | ivec2 getMouse(); 690 | void setMouse(ivec2); 691 | 692 | ivec2 windowSize(); 693 | ``` 694 | These functions manage the window. Calling them might do something weird if there's no OpenGL context active. Going in order, `loop()` handles window messages and returns false if the program should quit (so your default main loop should be `while(loop())`). `swapBuffers()` presents the rendered frame from the default framebuffer on the screen. `setTitle()` changes the window title. `showWindow()` and `hideWindow()` make the window appear and disappear. `keyDown()` returns if the given key is currently held down, and `keyHit()` if it's been pressed down during this frame. `resetHits()` (automatically called by `loop()`) resets key hit status. `getMouse()` gets screen-relative mouse location in pixels (origin is top left of the window, x is to the right and y is down). `setMouse()` warps the pointer to the desired pixel (coordinates match `getMouse()`). `windowSize()` gets the current window resolution. 695 | 696 | ```C++ 697 | glsl_extension(name, behavior) 698 | glsl_version(version) 699 | ``` 700 | 701 | These macros are used inside a shader to specify the required extensions and the GLSL version to compile against. The default is no extensions and GLSL 4.60. 702 | -------------------------------------------------------------------------------- /compile_flags.txt: -------------------------------------------------------------------------------- 1 | -Iimpl 2 | -Iutils 3 | -std=c++17 -------------------------------------------------------------------------------- /ggx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inline_glsl.h" 4 | 5 | // Schlick, 1994, Fresnel, 1823 6 | inline glsl_function float schlick_fresnel(float ior, vec3 out_dir, vec3 half_vector) { 7 | float R0 = (1.f - ior) / (1.f + ior); 8 | return mix(R0 * R0, 1.f, pow(1.f - abs(dot(out_dir, half_vector)), 5.f)); 9 | } 10 | 11 | // Tokuyoshi, 2021 12 | inline glsl_function float tokuyoshi_G1(vec3 v, vec3 half_vector, float alpha_x, float alpha_y) { 13 | if (dot(v, half_vector) < .0f) return .0f; 14 | return 2.f * abs(v.z) / (v.z + sqrt(alpha_x * alpha_x * v.x * v.x + alpha_y * alpha_y * v.y * v.y + v.z * v.z)); 15 | } 16 | 17 | // Smith, 1967 18 | inline glsl_function float smith_G1(vec3 v, vec3 half_vector, float alpha_x, float alpha_y) { 19 | if (dot(v, half_vector) < .0f) return .0f; 20 | const float lambda = .5f * (-1.f + sqrt(1.f + (alpha_x * alpha_x * v.x * v.x + alpha_y * alpha_y * v.y * v.y) / (v.z * v.z))); 21 | return 1.f / (1.f + lambda); 22 | } 23 | 24 | // Walter, 2007 25 | inline glsl_function float D(vec3 n, float alpha_x, float alpha_y) { 26 | const float denom = (n.x * n.x) / (alpha_x * alpha_x) + (n.y * n.y) / (alpha_y * alpha_y) + n.z * n.z; 27 | return 1.f / (pi * alpha_x * alpha_y * denom * denom); 28 | } 29 | 30 | // Cook and Torrance, 1982 31 | inline glsl_function float GGX(vec3 in_dir, vec3 out_dir, float alpha_x, float alpha_y, float ior) { 32 | const vec3 half_vector = normalize(in_dir + out_dir); 33 | const float fresnel = schlick_fresnel(ior, out_dir, half_vector); 34 | const float distribution = D(half_vector, alpha_x, alpha_y); 35 | const float view_mask = smith_G1(in_dir, half_vector, alpha_x, alpha_y); 36 | const float light_mask = smith_G1(out_dir, half_vector, alpha_x, alpha_y); 37 | const float normalization = 4.f * dot(in_dir, half_vector) * dot(out_dir, half_vector); 38 | return fresnel * distribution * view_mask * light_mask / normalization; 39 | } 40 | 41 | // Heitz, 2018 42 | inline glsl_function vec3 sampleGGX(vec3 Ve, float alpha_x, float alpha_y, float U1, float U2) { 43 | vec3 Vh = normalize(vec3(alpha_x * Ve.x, alpha_y * Ve.y, Ve.z)); 44 | float lensq = Vh.x * Vh.x + Vh.y * Vh.y; 45 | vec3 T1 = lensq > .0f ? vec3(-Vh.y, Vh.x, .0f) / sqrt(lensq) : vec3(1.f, 0.f, 0.f); 46 | vec3 T2 = cross(Vh, T1); 47 | float r = sqrt(U1); 48 | float phi = 2.f * pi * U2; 49 | float t1 = r * cos(phi); 50 | float t2 = r * sin(phi); 51 | float s = 0.5f * (1.0f + Vh.z); 52 | t2 = (1.0f - s) * sqrt(1.0f - t1 * t1) + s * t2; 53 | vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(.0f, 1.f - t1 * t1 - t2 * t2)) * Vh; 54 | vec3 Ne = normalize(vec3(alpha_x * Nh.x, alpha_y * Nh.y, max(.0f, Nh.z))); 55 | return Ne; 56 | } 57 | 58 | inline glsl_function float probGGX(vec3 Ve, vec3 Ne, float alpha_x, float alpha_y) { 59 | float dot_ = dot(Ve, Ne); 60 | if (dot_ <= .0f) return .0f; 61 | return tokuyoshi_G1(Ve, Ne, alpha_x, alpha_y) * D(Ne, alpha_x, alpha_y) / (4.f * dot_); 62 | } 63 | -------------------------------------------------------------------------------- /impl/gl_helpers.cpp: -------------------------------------------------------------------------------- 1 | 2 | #ifdef _WIN32 3 | #include 4 | 5 | #include "gl_helpers.h" 6 | 7 | #include 8 | #pragma comment(lib, "gdiplus.lib") 9 | #include 10 | #include 11 | 12 | Texture loadImage(const wchar_t* path) { 13 | using namespace Gdiplus; 14 | ULONG_PTR token; 15 | GdiplusStartupInput startupInput; 16 | GdiplusStartup(&token, &startupInput, nullptr); 17 | 18 | Texture result; 19 | // new scope so RAII objects are released before gdi+ shutdown 20 | { 21 | Image image(path); 22 | image.RotateFlip(RotateNoneFlipY); 23 | const Rect r(0, 0, image.GetWidth(), image.GetHeight()); 24 | BitmapData data; 25 | ((Bitmap*)&image)->LockBits(&r, ImageLockModeRead, PixelFormat32bppARGB, &data); 26 | 27 | glBindTexture(GL_TEXTURE_2D, result); 28 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.GetWidth(), image.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_BYTE, data.Scan0); 29 | glGenerateMipmap(GL_TEXTURE_2D); 30 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 31 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 32 | 33 | ((Bitmap*)&image)->UnlockBits(&data); 34 | } 35 | GdiplusShutdown(token); 36 | return result; 37 | } 38 | 39 | Texture loadImage(const char* path) { 40 | wchar_t str[1024]; 41 | MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, str, 1024); 42 | return loadImage(str); 43 | } 44 | #else 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include "gl_helpers.h" 52 | 53 | Texture loadImage(const wchar_t* path) {} 54 | Texture loadImage(const char* path) { 55 | unsigned char header[8]; 56 | 57 | FILE* fp = fopen(path, "rb"); 58 | fread(header, 1, 8, fp); 59 | assert(!png_sig_cmp(header, 0, 8)); 60 | 61 | png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 62 | 63 | png_infop info = png_create_info_struct(png); 64 | 65 | setjmp(png_jmpbuf(png)); 66 | 67 | png_init_io(png, fp); 68 | png_set_sig_bytes(png, 8); 69 | 70 | png_read_info(png, info); 71 | 72 | int width = png_get_image_width(png, info); 73 | int height = png_get_image_height(png, info); 74 | png_byte color_type = png_get_color_type(png, info); 75 | png_byte bit_depth = png_get_bit_depth(png, info); 76 | assert(bit_depth == 8); // let's just support this 77 | 78 | int number_of_passes = png_set_interlace_handling(png); 79 | png_read_update_info(png, info); 80 | 81 | 82 | setjmp(png_jmpbuf(png)); 83 | 84 | png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); 85 | size_t stride = png_get_rowbytes(png, info); 86 | for (int i = 0; i < height; i++) 87 | row_pointers[i] = (png_byte*)malloc(stride); 88 | 89 | png_read_image(png, row_pointers); 90 | 91 | unsigned char* contiguous = (unsigned char*)malloc(stride * height); 92 | 93 | for (int i = 0; i < height; i++) 94 | memcpy(contiguous + stride * (height-1-i), row_pointers[i], stride); 95 | 96 | GLenum format = GL_INVALID_ENUM, order; 97 | if (PNG_COLOR_TYPE_GRAY == color_type) { format = GL_R8; order = GL_RED; } 98 | if (PNG_COLOR_TYPE_RGB == color_type) { format = GL_RGB8; order = GL_RGB; } 99 | if (PNG_COLOR_TYPE_RGB_ALPHA == color_type) { format = GL_RGBA8; order = GL_RGBA; } 100 | assert(format != GL_INVALID_ENUM); 101 | 102 | Texture result; 103 | glBindTexture(GL_TEXTURE_2D, result); 104 | glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, order, GL_UNSIGNED_BYTE, contiguous); 105 | glGenerateMipmap(GL_TEXTURE_2D); 106 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 107 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 108 | 109 | free(row_pointers); 110 | fclose(fp); 111 | 112 | return result; 113 | } 114 | #endif 115 | 116 | -------------------------------------------------------------------------------- /impl/gl_helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define GL_GLEXT_LEGACY 4 | #include 5 | #undef GL_VERSION_1_3 6 | #include "glext.h" 7 | 8 | #include "loadgl46.h" 9 | 10 | #include 11 | // RAII lifetime handlers for GLuint-based buffers and textures; in principle, very close to unique pointers (with GLuint playing the role of a raw pointer). 12 | 13 | struct Buffer { 14 | public: 15 | void destroy() { if (object != 0 && owning) { glDeleteBuffers(1, &object); object = 0; } } 16 | Buffer() : owning(true) { glCreateBuffers(1, &object); } 17 | Buffer(size_t size, void* data = nullptr, bool immutable = false, GLenum usage_or_flags = GL_STATIC_DRAW) : owning(true) { 18 | glCreateBuffers(1, &object); 19 | if(immutable) 20 | glNamedBufferStorage(object, size, data, usage_or_flags); 21 | else 22 | glNamedBufferData(object, size, data, usage_or_flags); 23 | } 24 | template 25 | Buffer(const std::vector& v, bool immutable = false, GLenum usage_or_flags = GL_STATIC_DRAW) : owning(true) { 26 | glCreateBuffers(1, &object); 27 | if(immutable) 28 | glNamedBufferStorage(object, v.size()*sizeof(T), v.data(), usage_or_flags); 29 | else 30 | glNamedBufferData(object, v.size()*sizeof(T), v.data(), usage_or_flags); 31 | } 32 | template 33 | operator std::vector() const { 34 | GLint64 size; 35 | glGetNamedBufferParameteri64v(object, GL_BUFFER_SIZE, &size); 36 | if (size % sizeof(T)) printf("warning: buffer and vector types don't align"); 37 | std::vector result(size/sizeof(T)); 38 | glGetNamedBufferSubData(object, 0, result.size()*sizeof(T), result.data()); 39 | return result; 40 | } 41 | ~Buffer() { destroy(); } 42 | Buffer(const Buffer& other) : object(other.object), owning(false) { } 43 | Buffer(GLuint object, bool owning = false) : object(object), owning(owning) { } 44 | Buffer(Buffer&& other) : object(other.object), owning(other.owning) { other.owning = false; } 45 | auto& operator=(const Buffer& other) { object = other.object; owning = false; return *this; } 46 | auto& operator=(Buffer&& other) { object = other.object; owning = other.owning; other.owning = false; return *this; } 47 | operator GLuint() const { return object; } 48 | operator bool() const { return object != 0; } 49 | private: 50 | GLuint object = 0; bool owning; 51 | }; 52 | 53 | template struct Texture; 54 | 55 | template<> 56 | struct Texture { 57 | public: 58 | void destroy() { 59 | if (handle != 0) glMakeTextureHandleNonResident(handle); 60 | if (object && owning) { glDeleteTextures(1, &object); object = 0; } 61 | } 62 | Texture() : object(0), target(GL_INVALID_INDEX) {} 63 | Texture(GLuint target, bool owning = false) : target(target), owning(owning) { glCreateTextures(target, 1, &object); } 64 | ~Texture() { if (object != 0 && owning) destroy(); } 65 | template 66 | Texture(const Texture& other) : object(other.object), level(other.level), layer(other.layer), target(other.target), owning(false) { } 67 | Texture(GLuint object, GLuint target, bool owning = false) : object(object), target(target), owning(owning) { } 68 | template 69 | Texture(Texture&& other) : object(other.object), level(other.level), layer(other.layer), target(other.target), owning(other.owning) { other.owning = false; } 70 | template 71 | auto& operator=(const Texture& other) { 72 | destroy(); 73 | object = other.object; level = other.level; layer = other.layer; target = other.target; 74 | owning = false; 75 | return *this; 76 | } 77 | template 78 | auto& operator=(Texture&& other) { 79 | destroy(); 80 | object = other.object; level = other.level; layer = other.layer; target = other.target; 81 | owning = other.owning; 82 | other.owning = false; 83 | return *this; 84 | } 85 | operator GLuint() const { return object; } 86 | operator bool() const { return object != 0; } 87 | GLuint level = 0, layer = GL_INVALID_INDEX, target; 88 | GLuint64 getBindless() { 89 | if (handle == 0) { 90 | handle = glGetTextureHandle(object); 91 | glMakeTextureHandleResident(handle); 92 | } 93 | return handle; 94 | } 95 | private: 96 | GLuint object; bool owning; GLuint64 handle = 0; 97 | }; 98 | 99 | template 100 | struct Texture { 101 | public: 102 | void destroy() { 103 | if (handle != 0) glMakeTextureHandleNonResident(handle); 104 | if (object && owning) { glDeleteTextures(1, &object); object = 0; } 105 | } 106 | Texture() : owning(true) { glCreateTextures(T, 1, &object); } 107 | ~Texture() { destroy(); } 108 | Texture(GLuint other, bool owning = false) : object(other), owning(owning) {} 109 | Texture(const Texture& other) : object(other.object), owning(false) { } 110 | Texture(Texture&& other) : object(other.object), owning(other.owning) { other.owning = false; } 111 | Texture& operator=(const Texture& other) { destroy(); object = other.object; owning = false; return *this; } 112 | Texture& operator=(Texture&& other) { destroy(); object = other.object; owning = other.owning; other.owning = false; return *this; } 113 | operator GLuint() const { return object; } 114 | operator bool() const { return object != 0; } 115 | static constexpr GLuint level = 0, layer = GL_INVALID_INDEX; 116 | friend Texture<>; 117 | static constexpr GLuint target = T; 118 | GLuint64 getBindless() { 119 | if (handle == 0) { 120 | handle = glGetTextureHandle(object); 121 | glMakeTextureHandleResident(handle); 122 | } 123 | return handle; 124 | } 125 | private: 126 | GLuint object = 0; bool owning; GLuint64 handle = 0; 127 | }; 128 | 129 | template 130 | Texture<> Level(const Texture& t, int level) { 131 | Texture<> result(t); 132 | result.level = level; 133 | return result; 134 | } 135 | 136 | template 137 | Texture<> Layer(const Texture& t, int layer) { 138 | Texture<> result(t); 139 | result.layer = layer; 140 | return result; 141 | } 142 | 143 | Texture loadImage(const char* path); 144 | Texture loadImage(const wchar_t* path); 145 | -------------------------------------------------------------------------------- /impl/inline_glsl.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "inline_glsl.h" 3 | #ifdef _WIN32 4 | #include 5 | #endif 6 | 7 | ivec2 windowSize(); 8 | 9 | namespace inline_glsl { 10 | #ifdef _WIN32 11 | long ShaderStore::id_counter = 1; // 0 reserved for non-existing shaders 12 | inline ULONGLONG lastAccess(const char* path) { 13 | HANDLE file = CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 14 | FILETIME writeTime; 15 | GetFileTime(file, nullptr, nullptr, &writeTime); 16 | CloseHandle(file); 17 | return ULARGE_INTEGER{ writeTime.dwLowDateTime, writeTime.dwHighDateTime }.QuadPart; 18 | } 19 | #else 20 | std::atomic ShaderStore::id_counter{1}; 21 | inline auto lastAccess(const char* path) { 22 | return last_write_time(std::filesystem::path(path)); 23 | } 24 | #endif 25 | 26 | inline bool alphanum_(char input) { 27 | return 'a' <= input && input <= 'z' || 'A' <= input && input <= 'Z' || '0' <= input && input <= '9' || input == '_'; 28 | } 29 | 30 | inline void remove_bind_calls(char* input) { 31 | char* output = input; 32 | bool inside = false; 33 | const char* needle = " bind"; 34 | 35 | while (*input != '\0') { 36 | *output = *input; 37 | if (!alphanum_(*input)) { 38 | for (int i = 1;; i++) { 39 | if (needle[i] == '\0') { 40 | while (*input != '(' && *input != '\0') input++; 41 | inside = true; 42 | break; 43 | } 44 | if (input[i] != needle[i]) break; 45 | } 46 | } 47 | output++; input++; 48 | if (inside && *input == ')') { 49 | input++; 50 | inside = false; 51 | } 52 | } 53 | *output = '\0'; 54 | } 55 | 56 | inline char* search(char* input, const char* needle, int& line) { 57 | while (*input != '\0') { 58 | if (*input == '\n') line++; 59 | for (int i = 0;; i++) { 60 | if (needle[i] == '\0') return input; 61 | else if (input[i] != needle[i]) break; 62 | } 63 | input++; 64 | } 65 | return input; 66 | } 67 | 68 | void remove_comments(char* source_in, uint* lines_in) { 69 | char* source_out = source_in; 70 | uint* lines_out = lines_in; 71 | bool multi_comment = false, single_comment = false; 72 | 73 | while(*source_in!='\0') { 74 | if (multi_comment) { 75 | if (*source_in == '\n') { // keep commented \ns to preserve lines 76 | *(source_out++) = '\n'; 77 | *(lines_out++) = *lines_in; 78 | } 79 | else if (*source_in == '/' && *(source_in-1) == '*') 80 | multi_comment = false; 81 | } 82 | else if (single_comment && *source_in == '\n') { 83 | *(source_out++) = '\n'; 84 | *(lines_out++) = *lines_in; 85 | single_comment = false; 86 | } 87 | else { 88 | if (*source_in == '/') { 89 | if (*(source_in+1) == '/') 90 | single_comment = true; 91 | else if (*(source_in + 1) == '*') 92 | multi_comment = true; 93 | } 94 | if (!single_comment && !multi_comment) { 95 | *(source_out++) = *source_in; 96 | *(lines_out++) = *lines_in; 97 | } 98 | } 99 | source_in++; 100 | lines_in++; 101 | } 102 | *source_out = '\0'; 103 | *lines_out = *lines_in; 104 | } 105 | 106 | void remove_float_suffixes(char* source_in, uint* lines_in) { 107 | char* source_out = source_in; 108 | uint* lines_out = lines_in; 109 | bool number = false; 110 | while (*source_in!='\0') { 111 | bool keep = true; 112 | if (number) { 113 | if (*source_in == 'f') 114 | keep = number = false; 115 | if (!('0'<=*source_in && *source_in<='9') && *source_in != '.') 116 | number = false; 117 | } 118 | if (!alphanum_(*source_in) && ('0' <= *(source_in+1) && *(source_in+1) <= '9')) 119 | number = true; 120 | if (keep) { 121 | *(source_out++) = *source_in; 122 | *(lines_out++) = *lines_in; 123 | } 124 | source_in++; 125 | lines_in++; 126 | } 127 | *source_out = '\0'; 128 | *lines_out = *lines_in; 129 | } 130 | 131 | bool is_same(const char* a, const char* b) { 132 | while (*a == *b) { 133 | if (*a == '\0') return true; 134 | a++; b++; 135 | } 136 | return false; 137 | } 138 | 139 | bool SourceStore::update(const char* path) { 140 | this->path = path; 141 | 142 | auto latestUpdate = lastAccess(path); 143 | for (auto include : includes) { 144 | //printf("checking include %s\n", include); 145 | auto includeUpdate = lastAccess(include); 146 | if (includeUpdate > latestUpdate) 147 | latestUpdate = includeUpdate; 148 | } 149 | 150 | if (latestUpdate == currentUpdate) 151 | return false; 152 | 153 | FILE* file = fopen(path, "rb"); 154 | if(!file) return false; 155 | 156 | fseek(file, 0, SEEK_END); 157 | size_t size = size_t(ftell(file)) + 1; 158 | if(size == 0) return false; 159 | 160 | iteration++; 161 | 162 | currentUpdate = latestUpdate; 163 | 164 | contents.resize(size); 165 | contents.back() = '\0'; 166 | fseek(file, 0, SEEK_SET); 167 | fread(contents.data(), 1, contents.size() - 1, file); 168 | fclose(file); 169 | 170 | lines.resize(contents.size()); 171 | int line = 1; 172 | for (int i = 0; i < contents.size(); ++i) { 173 | lines[i] = line; 174 | if (contents[i] == '\n') line++; 175 | } 176 | remove_comments(contents.data(), lines.data()); 177 | remove_float_suffixes(contents.data(), lines.data()); 178 | 179 | char* search = contents.data(); 180 | 181 | for (auto a : includes) delete[] a; 182 | includes.clear(); 183 | 184 | // add include files (absolutely beautiful code I know) 185 | while (true) { 186 | int dummy; 187 | //printf("%s", contents.data()); 188 | search = inline_glsl::search(search, "#in", dummy); 189 | 190 | if (*search != '\0') { 191 | char* include_begin = search; 192 | while (*search != '\"' && *search != '<' && *search != '\0') search++; 193 | if (*search == '\"' || *search == '<') { 194 | char* path = ++search; 195 | 196 | while (*search != '\"' && *search != '>' && *search != '\0') search++; 197 | int64_t path_length = search - path + 1; 198 | char* filePath = new char[path_length]; 199 | for (int i = 0; path < search; ++i) 200 | filePath[i] = *(path++); 201 | filePath[path_length - 1] = '\0'; 202 | 203 | search++; 204 | int64_t begin_ind = include_begin - contents.data(), search_ind = search - contents.data(); 205 | 206 | bool already_included = false; 207 | for (auto& a : includes) 208 | if (is_same(a, filePath)) 209 | already_included = true; 210 | 211 | if (!already_included && !is_same(filePath, "glext.h") && !is_same(filePath, "window.h") && !is_same(filePath, "loadgl46.h") && !is_same(filePath, "inline_glsl.h")) { 212 | 213 | //printf("%s\n", filePath); 214 | FILE* includeFile = fopen(filePath, "rb"); 215 | if (includeFile) { 216 | fseek(includeFile, 0, SEEK_END); 217 | size_t size = size_t(ftell(includeFile)); 218 | includes.push_back(filePath); 219 | if(size>0) { 220 | uint includeMask = uint(includes.size()) << 20; 221 | if (includes.size() >= 4096) 222 | printf("too many includes, errors may be reported in incorrect files\n"); 223 | 224 | size_t copy_length = contents.size() - search_ind; 225 | contents.resize(contents.size() + size - (search_ind - begin_ind) - 1); 226 | lines.resize(contents.size()); 227 | memcpy(&contents[contents.size() - copy_length], &contents[search_ind], copy_length); 228 | memcpy(&lines[lines.size() - copy_length], &lines[search_ind], copy_length * sizeof(int)); 229 | 230 | fseek(includeFile, 0, SEEK_SET); 231 | fread(&contents[begin_ind], 1, size, includeFile); 232 | fclose(includeFile); 233 | line = 1; 234 | for (int i = 0; i < size; ++i) { 235 | lines[begin_ind + i] = includeMask | line; 236 | if (contents[begin_ind + i] == '\n') line++; 237 | } 238 | remove_comments(contents.data(), lines.data()); 239 | remove_float_suffixes(contents.data(), lines.data()); 240 | } 241 | } 242 | else delete[] filePath; 243 | } 244 | else delete[] filePath; 245 | search = &contents[search_ind]; 246 | } 247 | else 248 | search++; 249 | } 250 | else break; 251 | } 252 | contents.resize(search + 1 - contents.data()); 253 | lines.resize(contents.size()); 254 | 255 | /*int lineBegin = 0; 256 | for (int i = 0; i < contents.size(); ++i) { 257 | if (contents[i] == '\n' || contents[i] == '\0') { 258 | printf("%d: %.*s", lines[lineBegin], i - lineBegin + 1, &contents[lineBegin]); 259 | lineBegin = i + 1; 260 | } 261 | } 262 | for (int i = 0; i < 5; ++i) { 263 | printf("%d, ", lines[lines.size() - 1 - i]); 264 | }*/ 265 | 266 | glsl_mains.clear(); 267 | glsl_main_lines.clear(); 268 | glsl_functions.clear(); 269 | 270 | search = contents.data(); 271 | 272 | while (true) { 273 | search = inline_glsl::search(search, "glsl_main", line); 274 | if (*search != '\0') { 275 | glsl_mains.push_back(search); 276 | glsl_main_lines.push_back(lines[search-contents.data()]); 277 | search++; 278 | } 279 | else break; 280 | } 281 | search = contents.data(); 282 | while (true) { 283 | search = inline_glsl::search(search + 1, "#define", line); 284 | if (*search != '\0') { 285 | glsl_functions.push_back(search); 286 | search++; 287 | } 288 | else break; 289 | } 290 | search = contents.data(); 291 | while (true) { 292 | search = inline_glsl::search(search + 1, "glsl_global", line); 293 | if (*search != '\0') { 294 | glsl_functions.push_back(search + 11); 295 | search++; 296 | } 297 | else break; 298 | } 299 | search = contents.data(); 300 | while (true) { 301 | search = inline_glsl::search(search + 1, "glsl_function", line); 302 | if (*search != '\0') { 303 | glsl_functions.push_back(search + 13); 304 | search++; 305 | } 306 | else break; 307 | } 308 | search = contents.data(); 309 | while (true) { 310 | search = inline_glsl::search(search + 1, "glsl_func(", line); 311 | if (*search != '\0') { 312 | for (int i = 0; i < 3; ++i) { 313 | char open = i < 2 ? '(' : '{', close = i < 2 ? ')' : '}'; 314 | while (*search != open && *search != '\0') search++; 315 | int inside = 1; 316 | while (inside > 0 && *(++search)!='\0') { 317 | if (*search == open) inside++; 318 | if (*search == close) inside--; 319 | } 320 | } 321 | /*if (*(search + 1) != ';') 322 | printf("wrong character..?\n"); 323 | else 324 | printf("semicolon removed!\n");*/ 325 | *(search+1) = ' '; 326 | } 327 | else break; 328 | } 329 | 330 | glsl_begin_lines = glsl_main_lines; 331 | for (int i = 0; i < glsl_mains.size(); i++) { 332 | char*& c = glsl_mains[i]; 333 | int inside = 1; 334 | char* k = c; 335 | while (inside > 0 && *k != '\0') { 336 | if (*k == '{') inside++; 337 | if (*k == '}') inside--; 338 | k++; 339 | } 340 | *(k - 1) = '\0'; 341 | inside = 1; 342 | while (inside > 0 && c != contents.data()) { 343 | c--; 344 | if (*c == '}') inside++; 345 | if (*c == '{') inside--; 346 | if (*c == '\n') glsl_begin_lines[i]--; 347 | } 348 | c++; 349 | 350 | remove_bind_calls(c); 351 | } 352 | for (char* c : glsl_functions) { 353 | if (*c == '#') { 354 | while (*c != '\n' && *c != '\0') c++; 355 | *c = '\0'; 356 | continue; 357 | } 358 | while (*c != ';' && *c != '{' && *c != '(' && *c != '\0') c++; 359 | if (*c == '{') { 360 | c++; 361 | // struct 362 | int inside = 1; 363 | while (inside>0 && *c != '\0') { 364 | if (*c == '{') inside++; 365 | if (*c == '}') inside--; 366 | c++; 367 | } 368 | } 369 | if (*c == ';') *(c + 1) = '\0'; // variable 370 | else { 371 | // function 372 | c++; 373 | int inside = 1; 374 | while (inside > 0 && *c!='\0') { 375 | if (*c == '(') inside++; 376 | if (*c == ')') inside--; 377 | c++; 378 | } 379 | while (*c != '{' && *c!=';' && *c != '\0') c++; 380 | if (*c == ';') 381 | *(c+1) = '\0'; 382 | else { 383 | c++; 384 | inside = 1; 385 | while (inside > 0 && *c != '\0') { 386 | if (*c == '{') inside++; 387 | if (*c == '}') inside--; 388 | c++; 389 | } 390 | *c = '\0'; 391 | } 392 | } 393 | } 394 | for (const char* c : includes) { 395 | while (*c != '\"' && *c != '>' && *c != '\0') ++c; 396 | *const_cast(c) = '\0'; 397 | } 398 | 399 | return true; 400 | } 401 | 402 | void write_line(char* target, int line, int file) { 403 | for (int i = 0; i < 7; ++i) target[i] = "\n#line "[i]; 404 | sprintf(target + 7, "%u %u\n", line, file); 405 | } 406 | 407 | bool add_shader(GLuint program, GLenum type, const char* name, const Shader& shader_obj, SourceStore& store) { 408 | 409 | GLuint shader = glCreateShader(type); 410 | 411 | if (!shader_obj.store->cached) { 412 | 413 | const char* stub = "\ 414 | #extension GL_ARB_gpu_shader_int64 : enable\n\ 415 | #define glsl_main() main()\n\ 416 | #define glsl_func(a) a\n\ 417 | #define dynamic_array(t, a) t a[]\n\ 418 | #define arg_in(a) in a\n\ 419 | #define arg_out(a) out a\n\ 420 | #define arg_inout(a) inout a\n\ 421 | #define arg_layout layout\n\ 422 | #define glsl_extension(a,b) int _##a = 1\n\ 423 | #define glsl_version(a) int glsl_version = a\n\ 424 | #define glsl_subgroup(a) \n\ 425 | #define not_(a) not(a)\n"; 426 | 427 | size_t extensions = shader_obj.store->extensions.size(); 428 | size_t functions = store.glsl_functions.size(); 429 | const char** sources = const_cast(new char* [4 + extensions + 2 * functions]); 430 | 431 | sources[0] = shader_obj.store->version ? shader_obj.store->version : "#version 460\n"; 432 | for (int i = 0; i < extensions; ++i) 433 | sources[1 + i] = shader_obj.store->extensions[i]; 434 | sources[extensions + 1] = stub; 435 | 436 | uint mask = 0xffffffffu << 20u; 437 | for (int i = 0; i < functions; ++i) { 438 | char* k = new char[32]; 439 | uint line_file = store.lines[store.glsl_functions[i] - store.contents.data()]; 440 | write_line(k, line_file & ~mask, (line_file & mask) >> 20u); 441 | sources[i * 2 + 2 + extensions] = k; 442 | sources[i * 2 + 3 + extensions] = store.glsl_functions[i]; 443 | } 444 | char* l = new char[32]; 445 | write_line(l, store.glsl_begin_lines[shader_obj.store->nth_in_file], 0); 446 | sources[2 + 2 * functions + extensions] = l; 447 | sources[3 + 2 * functions + extensions] = store.glsl_mains[shader_obj.store->nth_in_file]; 448 | 449 | //printf("source: \n"); 450 | //for (int i = 0; i < 4 + extensions + 2 * store.glsl_functions.size(); ++i) 451 | // printf("%s", sources[i]); 452 | 453 | #ifdef _WIN32 454 | (void)_mkdir("shader_cache"); 455 | #else 456 | std::filesystem::create_directory("shader_cache"); 457 | #endif 458 | 459 | char cache_name[256]; 460 | get_cache_name(cache_name, store.path, shader_obj.store->line); 461 | FILE* cache = fopen(cache_name, "wb"); 462 | for (auto& include : store.includes) { 463 | int count = 0; 464 | while (include[count] != '\0') count++; 465 | fwrite(include, 1, count, cache); 466 | fwrite(",", 1, 1, cache); 467 | } 468 | fwrite("\n", 1, 1, cache); 469 | for (int i = 0; i < 4 + extensions + 2 * store.glsl_functions.size(); ++i) { 470 | int count = 0; 471 | while (sources[i][count] != '\0') count++; 472 | fwrite(sources[i], 1, count, cache); 473 | } 474 | fclose(cache); 475 | 476 | glShaderSource(shader, GLsizei(4 + extensions + 2 * functions), sources, nullptr); 477 | 478 | delete[] l; 479 | for (int i = 0; i < functions; ++i) 480 | delete[] const_cast(sources[i * 2 + 2 + extensions]); 481 | delete[] sources; 482 | } 483 | else 484 | glShaderSource(shader, 1, &shader_obj.store->cached, nullptr); 485 | 486 | glCompileShader(shader); 487 | GLint status; 488 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 489 | if (status != GL_TRUE) { 490 | GLint length; 491 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); 492 | std::vector info_log(length); 493 | glGetShaderInfoLog(shader, length, nullptr, info_log.data()); 494 | const GLubyte* vendor = glGetString(GL_VENDOR); 495 | 496 | if(vendor[0] == 'N' && vendor[1] == 'V') // should be enough :^) 497 | for (int i = 0; i < info_log.size(); ++i) { 498 | uint file_number, line_number; 499 | if ((i==0||info_log[i-1] == '\n') && 2 == sscanf(info_log.data() + i, "%u(%u)", &file_number, &line_number)) { 500 | int j = 0; while (i+j < info_log.size() && info_log[i+j] != ')') j++; j++; 501 | 502 | const char* path = (file_number == 0) ? shader_obj.store->path : shader_obj.store->include_files[file_number-1]; 503 | 504 | int last_dir = 0; 505 | for (int k = 0; path[k] != '\0'; k++) 506 | if (path[k] == '\\' || path[k] == '/') 507 | last_dir = k; 508 | if(last_dir) 509 | path += last_dir + 1; 510 | 511 | int k = 0; while (path[k] != '\0')k++; 512 | int t = int(ceil(log10(line_number))); 513 | // ", line " 514 | size_t copy_size = info_log.size() - i - j; 515 | info_log.resize(info_log.size()-j+k+t+7); 516 | memcpy(info_log.data() + i + k + t + 7, info_log.data() + i + j, copy_size); 517 | for (int p = 0; p < k; ++p) 518 | info_log[i + p] = path[p]; 519 | for (int p = 0; p < 7; ++p) 520 | info_log[i + k + p] = ", line "[p]; 521 | info_log[i+k+7+sprintf(info_log.data() + i + k + 7, "%u", line_number)] = ' '; 522 | i += k + t + 7; 523 | } 524 | } 525 | // TODO: AMD, Intel, ...? some vendors may have different error reporting schemes for different generations? 526 | printf("\n%s failed: \n%s", name, info_log.data()); 527 | glDeleteShader(shader); 528 | return false; 529 | } 530 | glAttachShader(program, shader); 531 | glDeleteShader(shader); 532 | return true; 533 | } 534 | 535 | // maybe make this O(log n) at some point 536 | inline Program& find_or_insert(int64_t ids[6], std::vector& programs) { 537 | for (int i = 0; i < programs.size(); ++i) { 538 | for (int j = 0; j < 6; ++j) { 539 | if (programs[i].ids[j] != ids[j]) break; 540 | else if (j == 5) return programs[i].p; 541 | } 542 | } 543 | programs.resize(programs.size() + 1); 544 | size_t location = programs.size() - 1; 545 | programs[location].p = Program(); 546 | for (int i = 0; i < 6; ++i) 547 | programs[location].ids[i] = (long)ids[i]; 548 | return programs[location].p; 549 | } 550 | 551 | std::vector draw_buffers; 552 | 553 | void useShader(const Shader& compute, const Shader& vertex, const Shader& geometry, const Shader& control, const Shader& evaluation, const Shader& fragment, std::vector& programs, ShaderState& shader_state, SourceStore& store) { 554 | 555 | int64_t ids[] = { compute.unique_id, vertex.unique_id, fragment.unique_id, geometry.unique_id, control.unique_id, evaluation.unique_id }; 556 | Program& program = find_or_insert(ids, programs); 557 | 558 | shader_state.rebuilt = false; 559 | if (program.obj == 0 || compute.changed || vertex.changed || fragment.changed || geometry.changed || control.changed || evaluation.changed) { 560 | printf("compiling... "); 561 | GLuint newProgram = glCreateProgram(); 562 | 563 | bool csuccess = !compute.unique_id || add_shader(newProgram, GL_COMPUTE_SHADER, "compute", compute, store); 564 | bool vsuccess = !vertex.unique_id || add_shader(newProgram, GL_VERTEX_SHADER, "vertex", vertex, store); 565 | bool gsuccess = !geometry.unique_id || add_shader(newProgram, GL_GEOMETRY_SHADER, "geometry", geometry, store); 566 | bool tsuccess = !control.unique_id || add_shader(newProgram, GL_TESS_CONTROL_SHADER, "control", control, store); 567 | bool esuccess = !evaluation.unique_id || add_shader(newProgram, GL_TESS_EVALUATION_SHADER, "evaluation", evaluation, store); 568 | bool fsuccess = !fragment.unique_id || add_shader(newProgram, GL_FRAGMENT_SHADER, "fragment", fragment, store); 569 | 570 | bool success = csuccess && vsuccess && gsuccess && tsuccess && esuccess && fsuccess; 571 | 572 | if (success) { 573 | glLinkProgram(newProgram); 574 | 575 | GLint status; 576 | glGetProgramiv(newProgram, GL_LINK_STATUS, &status); 577 | if (status != GL_TRUE) { 578 | GLint length; 579 | glGetProgramiv(newProgram, GL_INFO_LOG_LENGTH, &length); 580 | std::vector info_log(length); 581 | glGetProgramInfoLog(newProgram, length, nullptr, info_log.data()); 582 | printf("\ncouldn't link shader: \n%s\n", info_log.data()); 583 | glDeleteProgram(newProgram); 584 | success = false; 585 | } 586 | } 587 | else printf("\n"); 588 | if (success) { 589 | printf("success! \n"); 590 | if (program.obj != 0) 591 | glDeleteProgram(program.obj); 592 | program.obj = newProgram; 593 | 594 | if (program.vao != 0) 595 | glDeleteVertexArrays(1, &program.vao); 596 | glCreateVertexArrays(1, &program.vao); 597 | 598 | shader_state.rebuilt = true; 599 | } 600 | } 601 | 602 | glBindVertexArray(program.vao); 603 | 604 | glUseProgram(program.obj); 605 | 606 | if (draw_buffers.size() == 0) { 607 | GLint maxBuffers; 608 | glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxBuffers); 609 | draw_buffers.resize(maxBuffers); 610 | } 611 | for (auto& b : draw_buffers) 612 | b = GL_NONE; 613 | 614 | shader_state.fbo = program.fbo; 615 | shader_state.program = program.obj; 616 | shader_state.texture_unit = shader_state.image_unit = shader_state.fbo_width = shader_state.fbo_height = 0; 617 | 618 | shader_state.use_fbo = false; 619 | 620 | if (compute.unique_id) for (auto& f : compute.store->callbacks) f(shader_state); 621 | if (vertex.unique_id) for (auto& f : vertex.store->callbacks) f(shader_state); 622 | if (geometry.unique_id) for (auto& f : geometry.store->callbacks) f(shader_state); 623 | if (control.unique_id) for (auto& f : control.store->callbacks) f(shader_state); 624 | if (evaluation.unique_id) for (auto& f : evaluation.store->callbacks) f(shader_state); 625 | if (fragment.unique_id) for (auto& f : fragment.store->callbacks) f(shader_state); 626 | 627 | program.fbo = shader_state.fbo; 628 | 629 | if (shader_state.use_fbo) { 630 | glViewport(0, 0, shader_state.fbo_width, shader_state.fbo_height); 631 | //auto test = glCheckFramebufferStatus(GL_FRAMEBUFFER); 632 | //if (test != GL_FRAMEBUFFER_COMPLETE) 633 | // printf("framebuffer status %X\n", test); 634 | 635 | glDrawBuffers(draw_buffers.size(), draw_buffers.data()); 636 | } 637 | else { 638 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 639 | auto size = windowSize(); 640 | glViewport(0, 0, size.x, size.y); 641 | } 642 | } 643 | 644 | void Arg::findLocation(ShaderState& shader_state, ArgStore& store) { 645 | //printf("find location of SSBO '%s'\n", store.name); 646 | store.location = glGetProgramResourceIndex(shader_state.program, GL_SHADER_STORAGE_BLOCK, store.name); 647 | if (store.location != GL_INVALID_INDEX) 648 | glShaderStorageBlockBinding(shader_state.program, store.location, store.location); 649 | } 650 | void Arg::findLocation(ShaderState& shader_state, ArgStore& store) { 651 | //printf("find location of UBO '%s'\n", store.name); 652 | store.location = glGetProgramResourceIndex(shader_state.program, GL_UNIFORM_BLOCK, store.name); 653 | if (store.location != GL_INVALID_INDEX) 654 | glUniformBlockBinding(shader_state.program, store.location, store.location); 655 | } 656 | void Arg::findLocation(ShaderState& shader_state, ArgStore& store) { 657 | //printf("find location of color attachment '%s'\n", store.name); 658 | store.location = glGetProgramResourceIndex(shader_state.program, GL_PROGRAM_OUTPUT, store.name); 659 | } 660 | void Arg::findLocation(ShaderState& shader_state, ArgStore& store) { 661 | //printf("'location' of depth attachment '%s' is obvious\n", store.name); 662 | } 663 | 664 | #undef bind 665 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 666 | //printf("set uniform float '%s' to %g\n", store.name, store.item); 667 | glUniform1f(store.location, store.item); 668 | } 669 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 670 | //printf("set uniform int '%s' to %i\n", store.name, store.item); 671 | glUniform1i(store.location, store.item); 672 | } 673 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 674 | //printf("set uniform uint '%s' to %ui\n", store.name, store.item); 675 | glUniform1ui(store.location, store.item); 676 | } 677 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 678 | //printf("set uniform uint '%s' to %ui\n", store.name, store.item); 679 | glUniform1ui64(store.location, store.item); 680 | } 681 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 682 | //printf("set uniform vec2 '%s'\n", store.name); 683 | glUniform2fv(store.location, 1, store.item.data); 684 | } 685 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 686 | //printf("set uniform ivec2 '%s'\n", store.name); 687 | glUniform2iv(store.location, 1, store.item.data); 688 | } 689 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 690 | //printf("set uniform uvec2 '%s'\n", store.name); 691 | glUniform2uiv(store.location, 1, (const GLuint*)store.item.data); 692 | } 693 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 694 | //printf("set uniform vec3 '%s'\n", store.name); 695 | glUniform3fv(store.location, 1, store.item.data); 696 | } 697 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 698 | //printf("set uniform ivec3 '%s'\n", store.name); 699 | glUniform3iv(store.location, 1, store.item.data); 700 | } 701 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 702 | //printf("set uniform uvec3 '%s'\n", store.name); 703 | glUniform3uiv(store.location, 1, (const GLuint*)store.item.data); 704 | } 705 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 706 | //printf("set uniform vec4 '%s'\n", store.name); 707 | glUniform4fv(store.location, 1, store.item.data); 708 | } 709 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 710 | //printf("set uniform ivec4 '%s'\n", store.name); 711 | glUniform4iv(store.location, 1, store.item.data); 712 | } 713 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 714 | //printf("set uniform uvec4 '%s'\n", store.name); 715 | glUniform4uiv(store.location, 1, (const GLuint*)store.item.data); 716 | } 717 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 718 | //printf("set uniform mat2 '%s'\n", store.name); 719 | glUniformMatrix2fv(store.location, 1, false, store.item.data); 720 | } 721 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 722 | //printf("set uniform mat3 '%s'\n", store.name); 723 | glUniformMatrix3fv(store.location, 1, false, store.item.data); 724 | } 725 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 726 | //printf("set uniform mat4 '%s'\n", store.name); 727 | glUniformMatrix4fv(store.location, 1, false, store.item.data); 728 | } 729 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 730 | //printf("set uniform mat3x2 '%s'\n", store.name); 731 | glUniformMatrix3x2fv(store.location, 1, false, store.item.data); 732 | } 733 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 734 | //printf("set uniform mat4x2 '%s'\n", store.name); 735 | glUniformMatrix4x2fv(store.location, 1, false, store.item.data); 736 | } 737 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 738 | //printf("set uniform mat2x3 '%s'\n", store.name); 739 | glUniformMatrix2x3fv(store.location, 1, false, store.item.data); 740 | } 741 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 742 | //printf("set uniform mat4x3 '%s'\n", store.name); 743 | glUniformMatrix4x3fv(store.location, 1, false, store.item.data); 744 | } 745 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 746 | //printf("set uniform mat2x4 '%s'\n", store.name); 747 | glUniformMatrix2x4fv(store.location, 1, false, store.item.data); 748 | } 749 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 750 | //printf("set uniform mat3x4 '%s'\n", store.name); 751 | glUniformMatrix3x4fv(store.location, 1, false, store.item.data); 752 | } 753 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 754 | //printf("bind SSBO '%s'\n", store.name); 755 | glBindBufferBase(GL_SHADER_STORAGE_BUFFER, store.location, store.item); 756 | } 757 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 758 | //printf("bind UBO '%s'\n", store.name); 759 | glBindBufferBase(GL_UNIFORM_BUFFER, store.location, store.item); 760 | } 761 | 762 | void set_fbo_size(GLuint texture, GLint level, ShaderState& state) { 763 | glGetTextureLevelParameteriv(texture, level, GL_TEXTURE_WIDTH, &state.fbo_width); 764 | glGetTextureLevelParameteriv(texture, level, GL_TEXTURE_HEIGHT, &state.fbo_height); 765 | } 766 | 767 | bool layered(GLenum type) { 768 | return type == GL_TEXTURE_2D_ARRAY || type == GL_TEXTURE_3D || type == GL_TEXTURE_CUBE_MAP || type == GL_TEXTURE_CUBE_MAP_ARRAY || type == GL_TEXTURE_2D_MULTISAMPLE_ARRAY; 769 | } 770 | 771 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 772 | //printf("attach color '%s'\n", store.name); 773 | if (store.item == 0) return; 774 | if (shader_state.fbo == 0) 775 | glGenFramebuffers(1, &shader_state.fbo); 776 | if(!shader_state.use_fbo) 777 | glBindFramebuffer(GL_FRAMEBUFFER, shader_state.fbo); 778 | shader_state.use_fbo = true; 779 | if (shader_state.fbo_width == 0) set_fbo_size(store.item, store.item.level, shader_state); 780 | if (layered(store.item.type)) 781 | glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + store.location, store.item, store.item.level, store.item.layer); 782 | else 783 | glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + store.location, store.item, store.item.level); 784 | draw_buffers[store.location] = GL_COLOR_ATTACHMENT0 + store.location; 785 | } 786 | void Arg::bind(ShaderState& shader_state, ArgStore& store) { 787 | //printf("attach %s to depth\n", store.name); 788 | if (store.item == 0) return; 789 | if (shader_state.fbo == 0) 790 | glGenFramebuffers(1, &shader_state.fbo); 791 | if (!shader_state.use_fbo) 792 | glBindFramebuffer(GL_FRAMEBUFFER, shader_state.fbo); 793 | shader_state.use_fbo = true; 794 | if (shader_state.fbo_width == 0) set_fbo_size(store.item, store.item.level, shader_state); 795 | if (layered(store.item.type)) 796 | glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, store.item, store.item.level, store.item.layer); 797 | else 798 | glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, store.item, store.item.level); 799 | } 800 | } 801 | -------------------------------------------------------------------------------- /impl/inline_glsl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef _WIN32 6 | #define VC_EXTRALEAN 7 | #define WIN32_LEAN_AND_MEAN 8 | #define NOMINMAX 9 | #include 10 | #else 11 | #include 12 | #endif 13 | 14 | #include "glsl.h" 15 | #include "shader_types.h" 16 | 17 | #ifndef _WIN32 18 | #include 19 | #include 20 | #endif 21 | 22 | namespace inline_glsl { 23 | 24 | struct SourceStore { 25 | std::vector contents; 26 | std::vector glsl_mains; 27 | std::vector glsl_functions; 28 | std::vector glsl_main_lines, glsl_begin_lines; 29 | std::vector includes; 30 | char const* path; 31 | std::vector lines; 32 | #ifdef _WIN32 33 | ULONGLONG currentUpdate = 0; 34 | #else 35 | std::filesystem::file_time_type currentUpdate = {}; 36 | #endif 37 | uint iteration = 0; 38 | bool update(const char* path); 39 | ~SourceStore() { 40 | for (auto include : includes) delete[] include; 41 | } 42 | }; 43 | 44 | static SourceStore store; 45 | 46 | // filled prior to invoking a program 47 | struct ShaderState { 48 | GLuint program; 49 | GLuint fbo; 50 | GLuint image_format, image_access; 51 | GLubyte texture_unit; 52 | GLubyte image_unit; 53 | GLint fbo_width, fbo_height; 54 | bool rebuilt, use_fbo; 55 | } static shader_state; 56 | 57 | struct Function { 58 | virtual void operator()(ShaderState&) = 0; 59 | virtual ~Function() {} 60 | }; 61 | 62 | template 63 | struct Specific : Function { 64 | T func; 65 | Specific(T func) : func(func) {} 66 | virtual void operator()(ShaderState& state) { func(state); } 67 | }; 68 | 69 | struct Func { 70 | Function* func = nullptr; 71 | template 72 | Func(T func) : func(new Specific(func)) {} 73 | Func(Func&& other) : func(other.func) { other.func = nullptr; } 74 | void operator()(ShaderState& state) { (*func)(state); } 75 | ~Func() { if (func) delete func; } 76 | }; 77 | 78 | using ShaderSetup = std::vector; 79 | inline ShaderSetup* current_callbacks; 80 | inline std::vector* extensions; 81 | inline const char** version; 82 | 83 | inline void get_cache_name(char* result, const char* path, int line) { 84 | 85 | const char* path_name = path; 86 | while (*path_name != '\0') path_name++; 87 | while (*path_name != '\\' && *path_name != '/' && path_name > path)path_name--; 88 | if (path_name > path) path_name++; 89 | 90 | int i = 0; 91 | for (i = 0; i < 13; ++i) 92 | result[i] = "shader_cache/"[i]; 93 | while (*path_name != '.' && *path_name != '\0') 94 | result[i++] = *path_name++; 95 | result[i++] = '_'; 96 | 97 | i += sprintf(result+i, "%d", line); 98 | 99 | for (int j = 0; j < 6; ++j) 100 | result[i++] = ".glsl"[j]; 101 | } 102 | 103 | struct ShaderStore { 104 | ShaderSetup callbacks; 105 | std::vector extensions, include_files; 106 | const char* version; 107 | const char* path; int line; 108 | const char* cached = nullptr; 109 | uint nth_in_file, iteration = 0; 110 | long unique_id; 111 | #ifdef _WIN32 112 | static long id_counter; 113 | #else 114 | static std::atomic id_counter; 115 | #endif 116 | ShaderStore(const char* path, int line, SourceStore& store) : path(path), line(line) { 117 | #ifdef _WIN32 118 | unique_id = InterlockedAdd(&id_counter, 1); 119 | #else 120 | unique_id = id_counter++; 121 | #endif 122 | FILE* test = fopen(path, "r"); 123 | if (test) { 124 | fclose(test); 125 | store.update(path); 126 | include_files = store.includes; 127 | for (nth_in_file = 0; nth_in_file < store.glsl_main_lines.size() && store.glsl_main_lines[nth_in_file] != line; ++nth_in_file); 128 | //printf("glsl_main %d at line %d\n", nth_in_file, line); 129 | } 130 | else { 131 | char name_buffer[256]; 132 | get_cache_name(name_buffer, path, line); 133 | FILE* file = fopen(name_buffer, "rb"); 134 | fseek(file, 0, SEEK_END); 135 | size_t size = size_t(ftell(file)) + 1; 136 | char* cache = new char[size]; 137 | cache[size - 1] = '\0'; 138 | 139 | fseek(file, 0, SEEK_SET); 140 | fread(cache, 1, size - 1, file); 141 | fclose(file); 142 | 143 | while (*cache != '\0' && *cache != '\n') { 144 | include_files.push_back(cache); 145 | while (*cache != '\0' && *cache != ',') cache++; 146 | if (*cache != '\0') { 147 | *cache = '\0'; 148 | cache++; 149 | } 150 | } 151 | 152 | cached = cache+1; 153 | } 154 | } 155 | 156 | bool update(SourceStore& store) { 157 | callbacks.clear(); 158 | extensions.clear(); 159 | version = nullptr; 160 | inline_glsl::current_callbacks = &callbacks; 161 | inline_glsl::extensions = &extensions; 162 | inline_glsl::version = &version; 163 | if (cached) return false; 164 | store.update(path); 165 | uint old_iteration = iteration; 166 | iteration = store.iteration; 167 | return old_iteration != iteration; 168 | } 169 | ~ShaderStore() { delete[] cached; } 170 | }; 171 | 172 | struct Extension { 173 | const char* ext; 174 | Extension(const char* ext) : ext(ext) {} 175 | ~Extension() { inline_glsl::extensions->push_back(ext); } 176 | }; 177 | struct Version { 178 | const char* version; 179 | Version(const char* version) : version(version) {} 180 | ~Version() { *inline_glsl::version = version; } 181 | }; 182 | } 183 | struct Shader { 184 | uint unique_id = 0; bool changed = false; 185 | inline_glsl::ShaderStore* store = nullptr; 186 | Shader() {} 187 | Shader(inline_glsl::ShaderStore& shader, inline_glsl::SourceStore& source) { 188 | changed = shader.update(source); 189 | unique_id = shader.unique_id; 190 | store = &shader; 191 | } 192 | }; 193 | 194 | namespace inline_glsl { 195 | struct Program { 196 | GLuint obj = 0, vao = 0, fbo = 0; 197 | }; 198 | 199 | struct ProgramEntry { 200 | long ids[6] = { 0 }; 201 | Program p; 202 | }; 203 | 204 | static std::vector programs; 205 | void useShader(const Shader& compute, const Shader& vertex, const Shader& geometry, const Shader& control, const Shader& evaluation, const Shader& fragment, std::vector& programs, ShaderState& shader_state, SourceStore& store); 206 | 207 | 208 | template 209 | struct ArgStore { 210 | const char* name; 211 | GLuint location, program; 212 | T item; 213 | ArgStore(const char* name, T i) : name(name), item(i) { 214 | //printf("retainer for %s\n", name); 215 | } 216 | }; 217 | 218 | using glsl::same, glsl::Field, glsl::Rows; 219 | 220 | template 221 | constexpr bool is_image = false; 222 | template 223 | constexpr bool is_image> = true; 224 | 225 | struct Arg { 226 | template 227 | void findLocation(ShaderState& shader_state, ArgStore& store) { 228 | //printf("glGetUniformLocation(%s)\n", store.name); 229 | store.location = glGetUniformLocation(shader_state.program, store.name); 230 | } 231 | template 232 | void findLocation(ShaderState& shader_state, ArgStore>& store) { 233 | //printf("glGetUniformLocation(%s)\n", store.name); 234 | store.location = glGetUniformLocation(shader_state.program, store.name); 235 | if (store.location != GL_INVALID_INDEX) 236 | glUniform1i(store.location, shader_state.texture_unit); 237 | if constexpr (shadow) { 238 | glTextureParameteri(store.item, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); 239 | glTextureParameteri(store.item, GL_TEXTURE_COMPARE_FUNC, GL_LESS); 240 | } 241 | } 242 | template 243 | void findLocation(ShaderState& shader_state, ArgStore>& store) { 244 | store.location = glGetUniformLocation(shader_state.program, store.name); 245 | if (store.location != GL_INVALID_INDEX) 246 | glUniform1i(store.location, shader_state.image_unit); 247 | } 248 | void findLocation(ShaderState& shader_state, ArgStore& store); 249 | void findLocation(ShaderState& shader_state, ArgStore& store); 250 | template 251 | void findLocation(ShaderState& shader_state, ArgStore>& store) { 252 | //printf("find location of vertex attribute '%s'\n", store.name); 253 | store.location = glGetAttribLocation(shader_state.program, store.name); 254 | if(store.location!= GL_INVALID_INDEX) 255 | glEnableVertexAttribArray(store.location); 256 | } 257 | void findLocation(ShaderState& shader_state, ArgStore& store); 258 | void findLocation(ShaderState& shader_state, ArgStore& store); 259 | 260 | void bind(ShaderState& shader_state, ArgStore& store); 261 | void bind(ShaderState& shader_state, ArgStore& store); 262 | void bind(ShaderState& shader_state, ArgStore& store); 263 | void bind(ShaderState& shader_state, ArgStore& store); 264 | void bind(ShaderState& shader_state, ArgStore& store); 265 | void bind(ShaderState& shader_state, ArgStore& store); 266 | void bind(ShaderState& shader_state, ArgStore& store); 267 | void bind(ShaderState& shader_state, ArgStore& store); 268 | void bind(ShaderState& shader_state, ArgStore& store); 269 | void bind(ShaderState& shader_state, ArgStore& store); 270 | void bind(ShaderState& shader_state, ArgStore& store); 271 | void bind(ShaderState& shader_state, ArgStore& store); 272 | void bind(ShaderState& shader_state, ArgStore& store); 273 | void bind(ShaderState& shader_state, ArgStore& store); 274 | void bind(ShaderState& shader_state, ArgStore& store); 275 | void bind(ShaderState& shader_state, ArgStore& store); 276 | void bind(ShaderState& shader_state, ArgStore& store); 277 | void bind(ShaderState& shader_state, ArgStore& store); 278 | void bind(ShaderState& shader_state, ArgStore& store); 279 | void bind(ShaderState& shader_state, ArgStore& store); 280 | void bind(ShaderState& shader_state, ArgStore& store); 281 | void bind(ShaderState& shader_state, ArgStore& store); 282 | void bind(ShaderState& shader_state, ArgStore& store); 283 | void bind(ShaderState& shader_state, ArgStore& store); 284 | template 285 | void bind(ShaderState& shader_state, ArgStore>& store) { 286 | //printf("bind vertex attribute '%s'\n", store.name); 287 | glBindBuffer(GL_ARRAY_BUFFER, store.item); 288 | 289 | static_assert(same, float> || same, int> || same,uint>, "attribute base type not supported"); 290 | if constexpr (same, float>) 291 | glVertexAttribPointer(store.location, Rows, store.item.type, store.item.normalized, store.item.stride, (void*)(size_t)store.item.offset); 292 | else 293 | glVertexAttribIPointer(store.location, Rows, store.item.type, store.item.stride, (void*)(size_t)store.item.offset); 294 | } 295 | 296 | void bind(ShaderState& shader_state, ArgStore& store); 297 | void bind(ShaderState& shader_state, ArgStore& store); 298 | 299 | template 300 | void bind(ShaderState& shader_state, ArgStore>& store) { 301 | //printf("bind sampler2D '%s'\n", store.name); 302 | glBindTextureUnit(shader_state.texture_unit, store.item); 303 | shader_state.texture_unit++; 304 | } 305 | template 306 | void bind(ShaderState& shader_state, ArgStore>& store, GLuint access, GLuint format) { 307 | //printf("bind image2D '%s'\n", store.name); 308 | if (access == 1) access = GL_READ_ONLY; 309 | else if (access == 2) access = GL_WRITE_ONLY; 310 | else access = GL_READ_WRITE; 311 | 312 | bool layered = store.item.layer == GL_INVALID_INDEX; 313 | GLint tex_format, tex_size, bind_size; 314 | glGetTextureLevelParameteriv(store.item, store.item.level, GL_TEXTURE_INTERNAL_FORMAT, &tex_format); 315 | glGetInternalformativ(type, tex_format, GL_IMAGE_TEXEL_SIZE, 1, &tex_size); 316 | glGetInternalformativ(type, format, GL_IMAGE_TEXEL_SIZE, 1, &bind_size); 317 | if (tex_size != bind_size) { 318 | printf("warning: texture and shader image have different texel sizes\n"); 319 | #ifdef _WIN32 320 | __debugbreak(); 321 | #endif 322 | } 323 | glBindImageTexture(shader_state.image_unit, store.item, store.item.level, layered, layered ? 0 : store.item.layer, access, format); 324 | shader_state.image_unit++; 325 | } 326 | 327 | Func func; 328 | template 329 | Arg(volatile ArgStore& store_, const U& j) : func([&, j, state = shader_state](ShaderState& shader_state) { 330 | ArgStore& store = const_cast&>(store_); // volatile is a legit keyword for images and buffers; the variable is not actually volatile so we cast it away 331 | 332 | if (shader_state.rebuilt || store.program != shader_state.program) { 333 | store.program = shader_state.program; 334 | findLocation(shader_state, store); 335 | } 336 | 337 | store.item = j; 338 | if (store.location != -1) 339 | if constexpr (!is_image) 340 | bind(shader_state, store); 341 | else 342 | bind(shader_state, store, state.image_access, state.image_format); 343 | }) {} 344 | 345 | ~Arg() { current_callbacks->push_back(std::move(func)); } 346 | }; 347 | } 348 | 349 | #define UNIQUE_(a, b) ___ ## a ## b 350 | #define UNIQUE(a, b) UNIQUE_(a, b) 351 | 352 | #define REPEAT1(m, a) m(a) 353 | #define REPEAT2(m, a, b) m(a), m(b) 354 | #define REPEAT3(m, a, b, c) m(a), m(b), m(c) 355 | #define REPEAT4(m, a, b, c, d) m(a), m(b), m(c), m(d) 356 | #define REPEAT5(m, a, b, c, d, e) m(a), m(b), m(c), m(d), m(e) 357 | #define REPEAT6(m, a, b, c, d, e, f) m(a), m(b), m(c), m(d), m(e), m(f) 358 | #define REPEAT7(m, a, b, c, d, e, f, g) m(a), m(b), m(c), m(d), m(e), m(f), m(g) 359 | #define REPEAT8(m, a, b, c, d, e, f, g, h) m(a), m(b), m(c), m(d), m(e), m(f), m(g), m(h) 360 | 361 | #define SELECT(a, b, c, d, e, f, g, h, macro, ...) macro 362 | #define REPEAT(...) SELECT(__VA_ARGS__, REPEAT8, REPEAT7, REPEAT6, REPEAT5, REPEAT4, REPEAT3, REPEAT2, REPEAT1) 363 | 364 | 365 | #define STORE(a) UNIQUE(a,0)(#a, a) 366 | #define ARG(a) UNIQUE(a##_,0)(UNIQUE(a, 0), (decltype(UNIQUE(a,0).item))a) 367 | #define SHADOW(a) a = {} 368 | 369 | #define UNIFORM static inline_glsl::ArgStore< 370 | #define BUFFER static inline_glsl::ArgStore REPEAT(__VA_ARGS__)(STORE, __VA_ARGS__); inline_glsl::Arg REPEAT(__VA_ARGS__)(ARG, __VA_ARGS__); const FIRSTTYPE(__VA_ARGS__, 0) REPEAT(__VA_ARGS__)(SHADOW, __VA_ARGS__); inline_glsl::shader_state.image_access = 0 380 | #define BIND_BLOCK(a) > UNIQUE(a,0)(#a, a); inline_glsl::Arg UNIQUE(a##_,0)(UNIQUE(a,0), (decltype(UNIQUE(a,0).item))a); inline_glsl::shader_state.image_access = 0; union 381 | 382 | // bind(uniform_1, uniform_2, ...) 383 | #define bind(...) BIND(__VA_ARGS__) 384 | 385 | // bind_block(ssbo/ubo) {...}; 386 | #define bind_block(a) BIND_BLOCK(a) 387 | 388 | #define DECL_TARGET_(a) UNIQUE(a##_,0)(#a, a) 389 | #define SELECT_TARGET_DECLARE_(...) REPEAT(__VA_ARGS__)(DECL_TARGET_, __VA_ARGS__) 390 | 391 | #define DECL_TARGET(a) UNIQUE(a,0)(#a, a) 392 | #define SELECT_TARGET_DECLARE(...) REPEAT(__VA_ARGS__)(DECL_TARGET, __VA_ARGS__) 393 | 394 | #define TARGET_SETTER(a) UNIQUE(a##_,0)(UNIQUE(a, 0), Target(a)) 395 | #define SELECT_TARGET_SET(...) REPEAT(__VA_ARGS__)(TARGET_SETTER, __VA_ARGS__) 396 | 397 | #define SET_ATTR(a) UNIQUE(a##_,0)(UNIQUE(a, 0), Attribute(a)) 398 | #define SELECT_ATTRIB_SET(...) REPEAT(__VA_ARGS__)(SET_ATTR, __VA_ARGS__) 399 | 400 | 401 | #define BIND_ATTRIBUTE(...) UNIQUE(type, __LINE__);(void)UNIQUE(type, __LINE__); static inline_glsl::ArgStore> SELECT_TARGET_DECLARE(__VA_ARGS__); inline_glsl::Arg SELECT_ATTRIB_SET(__VA_ARGS__); const decltype(UNIQUE(type, __LINE__)) REPEAT(__VA_ARGS__)(SHADOW, __VA_ARGS__) 402 | #define BIND_TARGET(...) UNIQUE(type, __LINE__);(void)UNIQUE(type, __LINE__); static inline_glsl::ArgStore SELECT_TARGET_DECLARE(__VA_ARGS__); inline_glsl::Arg SELECT_TARGET_SET(__VA_ARGS__); decltype(UNIQUE(type, __LINE__)) REPEAT(__VA_ARGS__)(SHADOW, __VA_ARGS__) 403 | 404 | // bind_attribute(attribute_1, attribute_2, ...) 405 | #define bind_attribute(...) BIND_ATTRIBUTE(__VA_ARGS__) 406 | 407 | // bind_target(texture_1, texture_2, ...) 408 | #define bind_target(...) BIND_TARGET(__VA_ARGS__) 409 | 410 | #define glsl_func(name) *UNIQUE(type, __LINE__); (void)(UNIQUE(type, __LINE__)); auto name = [&] 411 | 412 | #define in 413 | #define out 414 | 415 | #define arg_in(type) type 416 | #define arg_out(type) type& 417 | #define arg_inout(type) type& 418 | 419 | #define flat 420 | #define noperspective 421 | #define smooth 422 | 423 | #define layout(...) __VA_ARGS__; 424 | 425 | #define std140 0 426 | #define std430 0 427 | 428 | #define shared 429 | 430 | #define glsl_extension(name, behavior) inline_glsl::Extension _##name("#extension " #name " : " #behavior "\n") 431 | #define glsl_version(version) inline_glsl::Version glsl_version("#version " #version "\n") 432 | #define glsl_subgroup(behavior) \ 433 | glsl_extension(GL_KHR_shader_subgroup_basic, behavior);\ 434 | glsl_extension(GL_KHR_shader_subgroup_vote, behavior);\ 435 | glsl_extension(GL_KHR_shader_subgroup_ballot, behavior);\ 436 | glsl_extension(GL_KHR_shader_subgroup_arithmetic, behavior);\ 437 | glsl_extension(GL_KHR_shader_subgroup_shuffle, behavior);\ 438 | glsl_extension(GL_KHR_shader_subgroup_shuffle_relative, behavior);\ 439 | glsl_extension(GL_KHR_shader_subgroup_clustered, behavior);\ 440 | glsl_extension(GL_KHR_shader_subgroup_quad, behavior) 441 | 442 | inline unsigned location, binding, component, offset, vertices, max_vertices, primitive, invocations, local_size_x, local_size_y, local_size_z; 443 | inline unsigned points, lines, lines_adjacency, triangles, triangles_adjacency, line_strip, triangle_strip; 444 | 445 | #define IMAGE_FORMAT(a) inline_glsl::shader_state.image_format = a 446 | template 447 | struct DynamicArray { 448 | T val; 449 | T& operator[](int){ return val; } 450 | int length() { return 0; } 451 | }; 452 | #define dynamic_array(type, name) DynamicArray name; 453 | 454 | #define arg_layout(...) 455 | 456 | #define r11f_g11f_b10f IMAGE_FORMAT(GL_R11F_G11F_B10F) 457 | #define rgb10_a2 IMAGE_FORMAT(GL_RGB10_A2) 458 | #define rgba32f IMAGE_FORMAT(GL_RGBA32F) 459 | #define rgba16f IMAGE_FORMAT(GL_RGBA16F) 460 | #define rgba16 IMAGE_FORMAT(GL_RGBA16) 461 | #define rgba8 IMAGE_FORMAT(GL_RGBA8) 462 | #define rg32f IMAGE_FORMAT(GL_RG32F) 463 | #define rg16f IMAGE_FORMAT(GL_RG16F) 464 | #define rg16 IMAGE_FORMAT(GL_RG16) 465 | #define rg8 IMAGE_FORMAT(GL_RG8) 466 | #define r32f IMAGE_FORMAT(GL_R32F) 467 | #define r16f IMAGE_FORMAT(GL_R16F) 468 | #define r16 IMAGE_FORMAT(GL_R16) 469 | #define r8 IMAGE_FORMAT(GL_R8) 470 | #define rgba16_snorm IMAGE_FORMAT(GL_RGBA16_SNORM) 471 | #define rgba8_snorm IMAGE_FORMAT(GL_RGBA8_SNORM) 472 | #define rg16_snorm IMAGE_FORMAT(GL_RG16_SNORM) 473 | #define rg8_snorm IMAGE_FORMAT(GL_RG8_SNORM) 474 | #define r16_snorm IMAGE_FORMAT(GL_R16_SNORM) 475 | #define r8_snorm IMAGE_FORMAT(GL_R8_SNORM) 476 | 477 | #define rgba32i IMAGE_FORMAT(GL_RGBA32I) 478 | #define rgba16i IMAGE_FORMAT(GL_RGBA16I) 479 | #define rgba8i IMAGE_FORMAT(GL_RGBA8I) 480 | #define rg32i IMAGE_FORMAT(GL_RG32I) 481 | #define rg16i IMAGE_FORMAT(GL_RG16I) 482 | #define rg8i IMAGE_FORMAT(GL_RG8I) 483 | #define r32i IMAGE_FORMAT(GL_R32I) 484 | #define r16i IMAGE_FORMAT(GL_R16I) 485 | #define r8i IMAGE_FORMAT(GL_R8I) 486 | 487 | 488 | #define rgb10_a2ui IMAGE_FORMAT(GL_RGB10_A2UI) 489 | #define rgba32ui IMAGE_FORMAT(GL_RGBA32UI) 490 | #define rgba16ui IMAGE_FORMAT(GL_RGBA16UI) 491 | #define rgba8ui IMAGE_FORMAT(GL_RGBA8UI) 492 | #define rg32ui IMAGE_FORMAT(GL_RG32UI) 493 | #define rg16ui IMAGE_FORMAT(GL_RG16UI) 494 | #define rg8ui IMAGE_FORMAT(GL_RG8UI) 495 | #define r32ui IMAGE_FORMAT(GL_R32UI) 496 | #define r16ui IMAGE_FORMAT(GL_R16UI) 497 | #define r8ui IMAGE_FORMAT(GL_R8UI) 498 | 499 | #define READONLY inline_glsl::shader_state.image_access |= 1; 500 | #define readonly READONLY 501 | #define WRITEONLY inline_glsl::shader_state.image_access |= 2; 502 | #define writeonly WRITEONLY 503 | 504 | #define coherent 505 | #define restrict 506 | 507 | #define early_fragment_tests 508 | 509 | #define glsl_function 510 | #define glsl_global 511 | 512 | #define EmitVertex() 513 | #define EndPrimitive() 514 | #define EmitStreamVertex() 515 | 516 | #define GLSL_MAIN ();static inline_glsl::ShaderStore __s(__FILE__, __LINE__, inline_glsl::store); return Shader(__s, inline_glsl::store); if constexpr(false) 517 | #define glsl_main() GLSL_MAIN 518 | 519 | #define BIND_DEPTH(a) ();static inline_glsl::ArgStore UNIQUE(a,__LINE__)(#a, a); inline_glsl::Arg UNIQUE(a##_,__LINE__)(UNIQUE(a, __LINE__), DepthTarget(a)) 520 | // bind_depth(texture) 521 | #define bind_depth(a) BIND_DEPTH(a) 522 | 523 | static void useShader(const Shader& compute) { 524 | inline_glsl::useShader(compute, Shader{}, Shader{}, Shader{}, Shader{}, Shader{}, inline_glsl::programs, inline_glsl::shader_state, inline_glsl::store); 525 | } 526 | static void useShader(const Shader& vertex, const Shader& fragment) { 527 | inline_glsl::useShader(Shader{}, vertex, Shader{}, Shader{}, Shader{}, fragment, inline_glsl::programs, inline_glsl::shader_state, inline_glsl::store); 528 | } 529 | static void useShader(const Shader& vertex, const Shader& geometry, const Shader& fragment) { 530 | inline_glsl::useShader(Shader{}, vertex, geometry, Shader{}, Shader{}, fragment, inline_glsl::programs, inline_glsl::shader_state, inline_glsl::store); 531 | } 532 | static void useShader(const Shader& vertex, const Shader& control, const Shader& evaluation, const Shader& fragment) { 533 | inline_glsl::useShader(Shader{}, vertex, Shader{}, control, evaluation, fragment, inline_glsl::programs, inline_glsl::shader_state, inline_glsl::store); 534 | } 535 | static void useShader(const Shader& vertex, const Shader& geometry, const Shader& control, const Shader& evaluation, const Shader& fragment) { 536 | inline_glsl::useShader(Shader{}, vertex, geometry, control, evaluation, fragment, inline_glsl::programs, inline_glsl::shader_state, inline_glsl::store); 537 | } 538 | 539 | inline const Texture<> screen = {}; 540 | inline const Texture<> screen_depth = {}; 541 | -------------------------------------------------------------------------------- /impl/shader_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "gl_helpers.h" 5 | 6 | template 7 | struct Image { 8 | GLuint obj, level, layer; 9 | Image() : obj(0) { } 10 | template 11 | Image(const Texture& t) : obj(t), level(t.level), layer(t.layer) { } 12 | operator int() { return obj; } 13 | bool operator !=(const Image& other) { 14 | return obj != other.obj; 15 | } 16 | }; 17 | 18 | #define IMAGEBASIC(name, sizetype, prefix, ...)\ 19 | inline sizetype imageSize(prefix##name image) { return {}; }\ 20 | inline prefix##vec4 imageLoad(prefix##name image, __VA_ARGS__) { return {}; }\ 21 | inline void imageStore(prefix##name image, __VA_ARGS__, prefix##vec4 data) { }\ 22 | 23 | #define IMAGEATOMIC(func, name, ...)\ 24 | inline int func(i##name, __VA_ARGS__, int data){ return {}; }\ 25 | inline uint func(u##name, __VA_ARGS__, uint data){ return {}; } 26 | 27 | #define IMAGEDEF(name, glenum, sizetype, ...)\ 28 | using name = Image < glenum, float>;\ 29 | using i ## name = Image < glenum, int>;\ 30 | using u ## name = Image < glenum, uint>;\ 31 | IMAGEBASIC(name, sizetype, , __VA_ARGS__)\ 32 | IMAGEBASIC(name, sizetype, i, __VA_ARGS__)\ 33 | IMAGEBASIC(name, sizetype, u, __VA_ARGS__)\ 34 | IMAGEATOMIC(imageAtomicAdd, name, __VA_ARGS__)\ 35 | IMAGEATOMIC(imageAtomicMin, name, __VA_ARGS__)\ 36 | IMAGEATOMIC(imageAtomicMax, name, __VA_ARGS__)\ 37 | IMAGEATOMIC(imageAtomicAnd, name, __VA_ARGS__)\ 38 | IMAGEATOMIC(imageAtomicOr, name, __VA_ARGS__)\ 39 | IMAGEATOMIC(imageAtomicXor, name, __VA_ARGS__)\ 40 | IMAGEATOMIC(imageAtomicExchange, name, __VA_ARGS__)\ 41 | IMAGEATOMIC(imageAtomicCompSwap, name, __VA_ARGS__) 42 | 43 | IMAGEDEF(image1D, GL_TEXTURE_1D, int, int P) 44 | IMAGEDEF(image2D, GL_TEXTURE_2D, ivec2, ivec2 P) 45 | IMAGEDEF(image3D, GL_TEXTURE_3D, ivec3, ivec3 P) 46 | IMAGEDEF(imageCube, GL_TEXTURE_CUBE_MAP, ivec2, ivec3 P) 47 | IMAGEDEF(image2DRect, GL_TEXTURE_RECTANGLE, ivec2, ivec2 P) 48 | IMAGEDEF(image1DArray, GL_TEXTURE_1D_ARRAY, ivec2, ivec2 P) 49 | IMAGEDEF(image2DArray, GL_TEXTURE_2D_ARRAY, ivec3, ivec3 P) 50 | IMAGEDEF(imageCubeArray, GL_TEXTURE_CUBE_MAP_ARRAY, ivec3, ivec3 P) 51 | IMAGEDEF(imageBuffer, GL_TEXTURE_BUFFER, int, int P) 52 | IMAGEDEF(image2DMS, GL_TEXTURE_2D_MULTISAMPLE, ivec2, ivec2 P, int sample) 53 | IMAGEDEF(image2DMSArray, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, ivec3, ivec3 P, int sample) 54 | 55 | inline int imageSamples(image2DMS image) { return 0; } 56 | inline int imageSamples(iimage2DMS image) { return 0; } 57 | inline int imageSamples(uimage2DMS image) { return 0; } 58 | inline int imageSamples(image2DMSArray image) { return 0; } 59 | inline int imageSamples(iimage2DMSArray image) { return 0; } 60 | inline int imageSamples(uimage2DMSArray image) { return 0; } 61 | 62 | #undef IMAGEBASIC 63 | #undef IMAGEATOMIC 64 | #undef IMAGEDEF 65 | 66 | template 67 | struct Sampler { 68 | GLuint obj; 69 | Sampler() : obj(0) { } 70 | Sampler(uint64_t) : obj(0) { } 71 | template 72 | Sampler(const Texture& t) : obj(t) {} 73 | operator int() { return obj; } 74 | bool operator !=(const Sampler& other) { 75 | return obj != other.obj; 76 | } 77 | }; 78 | 79 | #define COMMA , 80 | 81 | #define SAMPLEFUNC(func, name, params)\ 82 | inline vec4 func(name sampler params) {return {};}\ 83 | inline ivec4 func(i##name sampler params) {return {};}\ 84 | inline uvec4 func(u##name sampler params) {return {};} 85 | 86 | #define TEXFUNC(func, name, params)\ 87 | inline func(name sampler params) { return {}; }\ 88 | inline func(i##name sampler params) { return {}; }\ 89 | inline func(u##name sampler params) { return {}; } 90 | 91 | #define MIPPABLE(name, glenum, sizetype)\ 92 | using name = Sampler;\ 93 | using i ## name= Sampler;\ 94 | using u ## name = Sampler;\ 95 | TEXFUNC(sizetype textureSize, name,COMMA int lod)\ 96 | TEXFUNC(int textureQueryLevels, name,) 97 | 98 | #define UNMIPPABLE(name, glenum, sizetype)\ 99 | using name = Sampler;\ 100 | using i ## name= Sampler;\ 101 | using u ## name = Sampler;\ 102 | TEXFUNC(sizetype textureSize, name,) 103 | 104 | MIPPABLE(sampler1D, GL_TEXTURE_1D, int) 105 | MIPPABLE(sampler2D, GL_TEXTURE_2D, ivec2) 106 | MIPPABLE(sampler3D, GL_TEXTURE_3D, ivec3) 107 | MIPPABLE(samplerCube, GL_TEXTURE_CUBE_MAP, ivec2) 108 | MIPPABLE(sampler1DArray, GL_TEXTURE_1D_ARRAY, ivec2) 109 | MIPPABLE(sampler2DArray, GL_TEXTURE_2D_ARRAY, ivec3) 110 | MIPPABLE(samplerCubeArray, GL_TEXTURE_CUBE_MAP_ARRAY, ivec3) 111 | 112 | UNMIPPABLE(sampler2DRect, GL_TEXTURE_RECTANGLE, ivec2) 113 | UNMIPPABLE(samplerBuffer, GL_TEXTURE_BUFFER, int) 114 | UNMIPPABLE(sampler2DMS, GL_TEXTURE_2D_MULTISAMPLE, ivec2) 115 | UNMIPPABLE(sampler2DMSArray, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, ivec3) 116 | 117 | inline int textureSamples(sampler2DMS image) { return 0; } 118 | inline int textureSamples(isampler2DMS image) { return 0; } 119 | inline int textureSamples(usampler2DMS image) { return 0; } 120 | inline int textureSamples(sampler2DMSArray image) { return 0; } 121 | inline int textureSamples(isampler2DMSArray image) { return 0; } 122 | inline int textureSamples(usampler2DMSArray image) { return 0; } 123 | 124 | #define MIPPABLE_SHADOW(name, glenum, sizetype)\ 125 | using name = Sampler;\ 126 | inline sizetype textureSize(name sampler, int lod) {return {};}\ 127 | inline int textureQueryLevels(name sampler) {return 0;} 128 | 129 | MIPPABLE_SHADOW(sampler1DShadow, GL_TEXTURE_1D, int) 130 | MIPPABLE_SHADOW(sampler2DShadow, GL_TEXTURE_2D, ivec2) 131 | MIPPABLE_SHADOW(samplerCubeShadow, GL_TEXTURE_CUBE_MAP, ivec2) 132 | MIPPABLE_SHADOW(sampler1DArrayShadow, GL_TEXTURE_1D_ARRAY, ivec2) 133 | MIPPABLE_SHADOW(sampler2DArrayShadow, GL_TEXTURE_2D_ARRAY, ivec3) 134 | MIPPABLE_SHADOW(samplerCubeArrayShadow, GL_TEXTURE_CUBE_MAP_ARRAY, ivec3) 135 | using sampler2DRectShadow = Sampler; 136 | inline ivec2 textureSize(sampler2DRectShadow sampler) { return {}; } 137 | 138 | 139 | SAMPLEFUNC(texelFetch, sampler1D, COMMA int P COMMA int lod) 140 | SAMPLEFUNC(texelFetch, sampler2D, COMMA ivec2 P COMMA int lod) 141 | SAMPLEFUNC(texelFetch, sampler3D, COMMA ivec3 P COMMA int lod) 142 | SAMPLEFUNC(texelFetch, sampler2DRect, COMMA ivec2 P) 143 | SAMPLEFUNC(texelFetch, sampler1DArray, COMMA ivec2 P COMMA int lod) 144 | SAMPLEFUNC(texelFetch, sampler2DArray, COMMA ivec3 P COMMA int lod) 145 | SAMPLEFUNC(texelFetch, samplerBuffer, COMMA int P) 146 | SAMPLEFUNC(texelFetch, sampler2DMS, COMMA ivec2 P COMMA int sample) 147 | SAMPLEFUNC(texelFetch, sampler2DMSArray, COMMA ivec3 P COMMA int sample) 148 | 149 | SAMPLEFUNC(texelFetchOffset, sampler1D, COMMA int P COMMA int lod COMMA int offset) 150 | SAMPLEFUNC(texelFetchOffset, sampler2D, COMMA ivec2 P COMMA int lod COMMA ivec2 offset) 151 | SAMPLEFUNC(texelFetchOffset, sampler3D, COMMA ivec3 P COMMA int lod COMMA ivec3 offset) 152 | SAMPLEFUNC(texelFetchOffset, sampler2DRect, COMMA ivec2 P COMMA ivec2 offset) 153 | SAMPLEFUNC(texelFetchOffset, sampler1DArray, COMMA ivec2 P COMMA int lod COMMA ivec2 offset) 154 | SAMPLEFUNC(texelFetchOffset, sampler2DArray, COMMA ivec3 P COMMA int lod COMMA ivec3 offset) 155 | 156 | SAMPLEFUNC(texture, sampler1D, COMMA float P COMMA float bias = .0f) 157 | SAMPLEFUNC(texture, sampler2D, COMMA vec2 P COMMA float bias = .0f) 158 | SAMPLEFUNC(texture, sampler3D, COMMA vec3 P COMMA float bias = .0f) 159 | SAMPLEFUNC(texture, samplerCube, COMMA vec3 P COMMA float bias = .0f) 160 | SAMPLEFUNC(texture, sampler1DArray, COMMA vec2 P COMMA float bias = .0f) 161 | SAMPLEFUNC(texture, sampler2DArray, COMMA vec3 P COMMA float bias = .0f) 162 | SAMPLEFUNC(texture, samplerCubeArray, COMMA vec4 P COMMA float bias = .0f) 163 | SAMPLEFUNC(texture, sampler2DRect, COMMA vec2 P) 164 | inline float texture(sampler1DShadow sampler, vec3 P, float bias = .0f) { return {}; } // ... why does this take in a vec3??? 165 | inline float texture(sampler2DShadow sampler, vec3 P, float bias = .0f) { return {}; } 166 | inline float texture(samplerCubeShadow sampler, vec4 P, float bias = .0f) { return {}; } 167 | inline float texture(sampler1DArrayShadow sampler, vec3 P, float bias = .0f) { return {}; } 168 | inline float texture(sampler2DArrayShadow sampler, vec4 P, float bias = .0f) { return {}; } 169 | inline float texture(sampler2DRectShadow sampler, vec3 P) { return {}; } 170 | inline float texture(samplerCubeArrayShadow sampler, vec4 P, float compare) { return {}; } 171 | 172 | SAMPLEFUNC(textureGather, sampler2D, COMMA vec2 P COMMA int comp = 0) 173 | SAMPLEFUNC(textureGather, sampler2DArray, COMMA vec3 P COMMA int comp = 0) 174 | SAMPLEFUNC(textureGather, samplerCube, COMMA vec3 P COMMA int comp = 0) 175 | SAMPLEFUNC(textureGather, samplerCubeArray, COMMA vec4 P COMMA int comp = 0) 176 | SAMPLEFUNC(textureGather, sampler2DRect, COMMA vec2 P COMMA int comp = 0) 177 | inline float textureGather(sampler2DShadow sampler, vec2 P, float refZ) { return {}; } 178 | inline float textureGather(sampler2DArrayShadow sampler, vec3 P, float refZ) { return {}; } 179 | inline float textureGather(samplerCubeShadow sampler, vec3 P, float refZ) { return {}; } 180 | inline float textureGather(samplerCubeArrayShadow sampler, vec4 P, float refZ) { return {}; } 181 | inline float textureGather(sampler2DRectShadow sampler, vec2 P, float refZ) { return {}; } 182 | 183 | SAMPLEFUNC(textureGatherOffset, sampler2D, COMMA vec2 P COMMA ivec2 offset COMMA int comp = 0) 184 | SAMPLEFUNC(textureGatherOffset, sampler2DArray, COMMA vec3 P COMMA ivec2 offset COMMA int comp = 0) 185 | SAMPLEFUNC(textureGatherOffset, sampler2DRect, COMMA vec2 P COMMA ivec2 offset COMMA int comp = 0) 186 | inline float textureGatherOffset(sampler2DShadow sampler, vec2 P, float refZ, ivec2 offset) { return {}; } 187 | inline float textureGatherOffset(sampler2DArrayShadow sampler, vec3 P, float refZ, ivec2 offset) { return {}; } 188 | inline float textureGatherOffset(sampler2DRectShadow sampler, vec2 P, float refZ, ivec2 offset) { return {}; } 189 | 190 | 191 | SAMPLEFUNC(textureGatherOffsets, sampler2D, COMMA vec2 P COMMA ivec2 offsets[4] COMMA int comp = 0) 192 | SAMPLEFUNC(textureGatherOffsets, sampler2DArray, COMMA vec3 P COMMA ivec2 offsets[4] COMMA int comp = 0) 193 | SAMPLEFUNC(textureGatherOffsets, sampler2DRect, COMMA vec2 P COMMA ivec2 offsets[4] COMMA int comp = 0) 194 | inline float textureGatherOffsets(sampler2DShadow sampler, vec2 P, float refZ, ivec2 offsets[4]) { return {}; } 195 | inline float textureGatherOffsets(sampler2DArrayShadow sampler, vec3 P, float refZ, ivec2 offsets[4]) { return {}; } 196 | inline float textureGatherOffsets(sampler2DRectShadow sampler, vec2 P, float refZ, ivec2 offsets[4]) { return {}; } 197 | 198 | SAMPLEFUNC(textureGrad, sampler1D, COMMA float P COMMA float dPdx COMMA float dPdy) 199 | SAMPLEFUNC(textureGrad, sampler2D, COMMA vec2 P COMMA vec2 dPdx COMMA vec2 dPdy) 200 | SAMPLEFUNC(textureGrad, sampler3D, COMMA vec3 P COMMA vec3 dPdx COMMA vec3 dPdy) 201 | SAMPLEFUNC(textureGrad, samplerCube, COMMA vec3 P COMMA vec3 dPdx COMMA vec3 dPdy) 202 | SAMPLEFUNC(textureGrad, sampler1DArray, COMMA vec2 P COMMA float dPdx COMMA float dPdy) 203 | SAMPLEFUNC(textureGrad, sampler2DArray, COMMA vec3 P COMMA vec2 dPdx COMMA vec2 dPdy) 204 | SAMPLEFUNC(textureGrad, samplerCubeArray, COMMA vec4 P COMMA vec3 dPdx COMMA vec3 dPdy) 205 | SAMPLEFUNC(textureGrad, sampler2DRect, COMMA vec2 P COMMA vec2 dPdx COMMA vec2 dPdy) 206 | inline float textureGrad(sampler1DShadow sampler, vec3 P, float dPdx, float dPdy) { return {}; } 207 | inline float textureGrad(sampler2DShadow sampler, vec3 P, vec2 dPdx, vec2 dPdy) { return {}; } 208 | inline float textureGrad(samplerCubeShadow sampler, vec4 P, vec3 dPdx, vec3 dPdy) { return {}; } 209 | inline float textureGrad(sampler1DArrayShadow sampler, vec3 P, float dPdx, float dPdy) { return {}; } 210 | inline float textureGrad(sampler2DArrayShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy) { return {}; } 211 | inline float textureGrad(sampler2DRectShadow sampler, vec3 P, vec2 dPdx, vec2 dPdy) { return {}; } 212 | 213 | SAMPLEFUNC(textureGradOffset, sampler1D, COMMA float P COMMA float dPdx COMMA float dPdy COMMA int offset) 214 | SAMPLEFUNC(textureGradOffset, sampler2D, COMMA vec2 P COMMA vec2 dPdx COMMA vec2 dPdy COMMA ivec2 offset) 215 | SAMPLEFUNC(textureGradOffset, sampler3D, COMMA vec3 P COMMA vec3 dPdx COMMA vec3 dPdy COMMA ivec3 offset) 216 | SAMPLEFUNC(textureGradOffset, sampler1DArray, COMMA vec2 P COMMA float dPdx COMMA float dPdy COMMA int offset) 217 | SAMPLEFUNC(textureGradOffset, sampler2DArray, COMMA vec3 P COMMA vec2 dPdx COMMA vec2 dPdy COMMA ivec2 offset) 218 | SAMPLEFUNC(textureGradOffset, sampler2DRect, COMMA vec2 P COMMA vec2 dPdx COMMA vec2 dPdy COMMA ivec2 offset) 219 | inline float textureGradOffset(sampler1DShadow sampler, vec3 P, float dPdx, float dPdy, int offset) { return {}; } 220 | inline float textureGradOffset(sampler2DShadow sampler, vec3 P, vec2 dPdx, vec2 dPdy, ivec2 offset) { return {}; } 221 | inline float textureGradOffset(sampler1DArrayShadow sampler, vec3 P, float dPdx, float dPdy, int offset) { return {}; } 222 | inline float textureGradOffset(sampler2DArrayShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy, ivec2 offset) { return {}; } 223 | inline float textureGradOffset(sampler2DRectShadow sampler, vec3 P, vec2 dPdx, vec2 dPdy, ivec2 offset) { return {}; } 224 | 225 | SAMPLEFUNC(textureLod, sampler1D, COMMA float P COMMA float lod) 226 | SAMPLEFUNC(textureLod, sampler2D, COMMA vec2 P COMMA float lod) 227 | SAMPLEFUNC(textureLod, sampler3D, COMMA vec3 P COMMA float lod) 228 | SAMPLEFUNC(textureLod, samplerCube, COMMA vec3 P COMMA float lod) 229 | SAMPLEFUNC(textureLod, sampler1DArray, COMMA vec2 P COMMA float lod) 230 | SAMPLEFUNC(textureLod, sampler2DArray, COMMA vec3 P COMMA float lod) 231 | SAMPLEFUNC(textureLod, samplerCubeArray, COMMA vec4 P COMMA float lod) 232 | inline float textureLod(sampler1DShadow sampler, vec3 P, float lod) { return {}; } 233 | inline float textureLod(sampler2DShadow sampler, vec3 P, float lod) { return {}; } 234 | inline float textureLod(sampler1DArrayShadow sampler, vec3 P, float lod) { return {}; } 235 | 236 | SAMPLEFUNC(textureLodOffset, sampler1D, COMMA float P COMMA float lod COMMA int offset) 237 | SAMPLEFUNC(textureLodOffset, sampler2D, COMMA vec2 P COMMA float lod COMMA ivec2 offset) 238 | SAMPLEFUNC(textureLodOffset, sampler3D, COMMA vec3 P COMMA float lod COMMA ivec3 offset) 239 | SAMPLEFUNC(textureLodOffset, sampler1DArray, COMMA vec2 P COMMA float lod COMMA int offset) 240 | SAMPLEFUNC(textureLodOffset, sampler2DArray, COMMA vec3 P COMMA float lod COMMA ivec2 offset) 241 | inline float textureLodOffset(sampler1DShadow sampler, vec3 P, float lod, int offset) { return {}; } 242 | inline float textureLodOffset(sampler2DShadow sampler, vec3 P, float lod, ivec2 offset) { return {}; } 243 | inline float textureLodOffset(sampler1DArrayShadow sampler, vec3 P, float lod, int offset) { return {}; } 244 | 245 | SAMPLEFUNC(textureProjLod, sampler1D, COMMA vec2 P COMMA float lod) 246 | SAMPLEFUNC(textureProjLod, sampler1D, COMMA vec4 P COMMA float lod) 247 | SAMPLEFUNC(textureProjLod, sampler2D, COMMA vec3 P COMMA float lod) 248 | SAMPLEFUNC(textureProjLod, sampler2D, COMMA vec4 P COMMA float lod) 249 | SAMPLEFUNC(textureProjLod, sampler3D, COMMA vec4 P COMMA float lod) 250 | inline float textureProjLod(sampler1DShadow sampler, vec4 P, float lod) { return {}; } 251 | inline float textureProjLod(sampler2DShadow sampler, vec4 P, float lod) { return {}; } 252 | 253 | SAMPLEFUNC(textureProjLodOffset, sampler1D, COMMA vec2 P COMMA float lod COMMA int offset) 254 | SAMPLEFUNC(textureProjLodOffset, sampler1D, COMMA vec4 P COMMA float lod COMMA int offset) 255 | SAMPLEFUNC(textureProjLodOffset, sampler2D, COMMA vec3 P COMMA float lod COMMA ivec2 offset) 256 | SAMPLEFUNC(textureProjLodOffset, sampler2D, COMMA vec4 P COMMA float lod COMMA ivec2 offset) 257 | SAMPLEFUNC(textureProjLodOffset, sampler3D, COMMA vec4 P COMMA float lod COMMA ivec3 offset) 258 | inline float textureProjLodOffset(sampler1DShadow sampler, vec4 P, float lod, int offset) { return {}; } 259 | inline float textureProjLodOffset(sampler2DShadow sampler, vec4 P, float lod, ivec2 offset) { return {}; } 260 | 261 | SAMPLEFUNC(textureProj, sampler1D, COMMA vec2 P COMMA float bias = .0f) 262 | SAMPLEFUNC(textureProj, sampler1D, COMMA vec4 P COMMA float bias = .0f) 263 | SAMPLEFUNC(textureProj, sampler2D, COMMA vec3 P COMMA float bias = .0f) 264 | SAMPLEFUNC(textureProj, sampler2D, COMMA vec4 P COMMA float bias = .0f) 265 | SAMPLEFUNC(textureProj, sampler3D, COMMA vec4 P COMMA float bias = .0f) 266 | SAMPLEFUNC(textureProj, sampler2DRect, COMMA vec3 P) 267 | SAMPLEFUNC(textureProj, sampler2DRect, COMMA vec4 P) 268 | inline float textureProj(sampler1DShadow sampler, vec4 P, float bias = .0f) { return {}; } 269 | inline float textureProj(sampler2DShadow sampler, vec4 P, float bias = .0f) { return {}; } 270 | inline float textureProj(sampler2DRectShadow sampler, vec4 P) { return {}; } 271 | 272 | SAMPLEFUNC(textureOffset, sampler1D, COMMA float P COMMA int offset COMMA float bias = .0f) 273 | SAMPLEFUNC(textureOffset, sampler2D, COMMA vec2 P COMMA ivec2 offset COMMA float bias = .0f) 274 | SAMPLEFUNC(textureOffset, sampler3D, COMMA vec3 P COMMA ivec3 offset COMMA float bias = .0f) 275 | SAMPLEFUNC(textureOffset, sampler1DArray, COMMA vec2 P COMMA int offset COMMA float bias = .0f) 276 | SAMPLEFUNC(textureOffset, sampler2DArray, COMMA vec3 P COMMA ivec2 offset COMMA float bias = .0f) 277 | SAMPLEFUNC(textureOffset, sampler2DRect, COMMA vec2 P COMMA ivec2 offset) 278 | inline float textureOffset(sampler1DShadow sampler, vec3 P, int offset, float bias = .0f) { return {}; } // ... why does this take in a vec3??? 279 | inline float textureOffset(sampler2DShadow sampler, vec3 P, ivec2 offset, float bias = .0f) { return {}; } 280 | inline float textureOffset(sampler1DArrayShadow sampler, vec3 P, int offset, float bias = .0f) { return {}; } 281 | inline float textureOffset(sampler2DArrayShadow sampler, vec4 P, ivec2 offset, float bias = .0f) { return {}; } 282 | inline float textureOffset(sampler2DRectShadow sampler, vec3 P, ivec2 offset) { return {}; } 283 | 284 | SAMPLEFUNC(textureProjGrad, sampler1D, COMMA vec2 P COMMA float dPdx COMMA float dPdy) 285 | SAMPLEFUNC(textureProjGrad, sampler1D, COMMA vec4 P COMMA float dPdx COMMA float dPdy) 286 | SAMPLEFUNC(textureProjGrad, sampler2D, COMMA vec3 P COMMA vec2 dPdx COMMA vec2 dPdy) 287 | SAMPLEFUNC(textureProjGrad, sampler2D, COMMA vec4 P COMMA vec2 dPdx COMMA vec2 dPdy) 288 | SAMPLEFUNC(textureProjGrad, sampler3D, COMMA vec4 P COMMA vec3 dPdx COMMA vec3 dPdy) 289 | SAMPLEFUNC(textureProjGrad, sampler2DRect, COMMA vec3 P COMMA vec2 dPdx COMMA vec2 dPdy) 290 | SAMPLEFUNC(textureProjGrad, sampler2DRect, COMMA vec4 P COMMA vec2 dPdx COMMA vec2 dPdy) 291 | inline float textureProjGrad(sampler1DShadow sampler, vec4 P, float dPdx, float dPdy) { return {}; } 292 | inline float textureProjGrad(sampler2DShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy) { return {}; } 293 | inline float textureProjGrad(sampler2DRectShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy) { return {}; } 294 | 295 | SAMPLEFUNC(textureProjGradOffset, sampler1D, COMMA vec2 P COMMA float dPdx COMMA float dPdy COMMA int offset) 296 | SAMPLEFUNC(textureProjGradOffset, sampler1D, COMMA vec4 P COMMA float dPdx COMMA float dPdy COMMA int offset) 297 | SAMPLEFUNC(textureProjGradOffset, sampler2D, COMMA vec3 P COMMA vec2 dPdx COMMA vec2 dPdy COMMA ivec2 offset) 298 | SAMPLEFUNC(textureProjGradOffset, sampler2D, COMMA vec4 P COMMA vec2 dPdx COMMA vec2 dPdy COMMA ivec2 offset) 299 | SAMPLEFUNC(textureProjGradOffset, sampler3D, COMMA vec4 P COMMA vec3 dPdx COMMA vec3 dPdy COMMA ivec3 offset) 300 | SAMPLEFUNC(textureProjGradOffset, sampler2DRect, COMMA vec3 P COMMA vec2 dPdx COMMA vec2 dPdy COMMA ivec2 offset) 301 | SAMPLEFUNC(textureProjGradOffset, sampler2DRect, COMMA vec4 P COMMA vec2 dPdx COMMA vec2 dPdy COMMA ivec2 offset) 302 | inline float textureProjGradOffset(sampler1DShadow sampler, vec4 P, float dPdx, float dPdy, int offset) { return {}; } 303 | inline float textureProjGradOffset(sampler2DShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy, ivec2 offset) { return {}; } 304 | inline float textureProjGradOffset(sampler2DRectShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy, ivec2 offset) { return {}; } 305 | 306 | SAMPLEFUNC(textureProjOffset, sampler1D, COMMA vec2 P COMMA int offset COMMA float bias = .0f) 307 | SAMPLEFUNC(textureProjOffset, sampler1D, COMMA vec4 P COMMA int offset COMMA float bias = .0f) 308 | SAMPLEFUNC(textureProjOffset, sampler2D, COMMA vec3 P COMMA ivec2 offset COMMA float bias = .0f) 309 | SAMPLEFUNC(textureProjOffset, sampler2D, COMMA vec4 P COMMA ivec2 offset COMMA float bias = .0f) 310 | SAMPLEFUNC(textureProjOffset, sampler3D, COMMA vec4 P COMMA ivec3 offset COMMA float bias = .0f) 311 | SAMPLEFUNC(textureProjOffset, sampler2DRect, COMMA vec3 P COMMA ivec2 offset) 312 | SAMPLEFUNC(textureProjOffset, sampler2DRect, COMMA vec4 P COMMA ivec2 offset) 313 | inline float textureProjOffset(sampler1DShadow sampler, vec4 P, int offset, float bias = .0f) { return {}; } 314 | inline float textureProjOffset(sampler2DShadow sampler, vec4 P, ivec2 offset, float bias = .0f) { return {}; } 315 | inline float textureProjOffset(sampler2DRectShadow sampler, vec4 P, ivec2 offset) { return {}; } 316 | 317 | TEXFUNC(vec2 textureQueryLod, sampler1D, COMMA float P) 318 | TEXFUNC(vec2 textureQueryLod, sampler2D, COMMA vec2 P) 319 | TEXFUNC(vec2 textureQueryLod, sampler3D, COMMA vec3 P) 320 | TEXFUNC(vec2 textureQueryLod, samplerCube, COMMA vec3 P) 321 | TEXFUNC(vec2 textureQueryLod, sampler1DArray, COMMA float P) 322 | TEXFUNC(vec2 textureQueryLod, sampler2DArray, COMMA vec2 P) 323 | TEXFUNC(vec2 textureQueryLod, samplerCubeArray, COMMA vec3 P) 324 | inline vec2 textureQueryLod(sampler1DShadow sampler, float P) { return {}; } // ... why does this take in a vec3??? 325 | inline vec2 textureQueryLod(sampler2DShadow sampler, vec2 P) { return {}; } 326 | inline vec2 textureQueryLod(samplerCubeShadow sampler, vec3 P) { return {}; } 327 | inline vec2 textureQueryLod(sampler1DArrayShadow sampler, float P) { return {}; } 328 | inline vec2 textureQueryLod(sampler2DArrayShadow sampler, vec2 P) { return {}; } 329 | inline vec2 textureQueryLod(samplerCubeArrayShadow sampler, vec3 P) { return {}; } 330 | 331 | #undef COMMA 332 | #undef SAMPLEFUNC 333 | #undef TEXFUNC 334 | #undef MIPPABLE 335 | #undef UNMIPPABLE 336 | #undef MIPPABLE_SHADOW 337 | 338 | struct Target { 339 | GLuint obj, level, layer, type; 340 | Target() : obj(0) {} 341 | template 342 | Target(const Texture& t) : obj(t), level(t.level), layer(t.layer), type(t.target) { } 343 | operator int() { return obj; } 344 | bool operator !=(const Target& other) { 345 | return obj != other.obj; 346 | } 347 | }; 348 | 349 | struct DepthTarget { 350 | GLuint obj, level, layer, type; 351 | template 352 | DepthTarget(const Texture& t) : obj(t), level(t.level), layer(t.layer), type(t.target) { } 353 | operator int() { return obj; } 354 | bool operator !=(const DepthTarget& other) { 355 | return obj != other.obj; 356 | } 357 | }; 358 | 359 | struct UBO { 360 | GLuint obj; 361 | UBO(const Buffer& t) : obj(t) {} 362 | operator int() { return obj; }; 363 | bool operator!=(const UBO& other) { 364 | return obj != other.obj; 365 | } 366 | }; 367 | struct SSBO { 368 | GLuint obj; 369 | SSBO(const Buffer& t) : obj(t) {} 370 | operator int() { return obj; }; 371 | bool operator!=(const SSBO& other) { 372 | return obj != other.obj; 373 | } 374 | }; 375 | 376 | template 377 | struct Attribute { 378 | GLuint obj, stride, offset, type; 379 | bool normalized; 380 | Attribute(const Buffer& b, int stride, int offset = 0, GLuint type = -1, bool normalized = false) 381 | : obj(b), stride(stride), offset(offset), type(type), normalized(normalized) 382 | { 383 | if (this->type == -1) { 384 | if constexpr (glsl::same, float>) 385 | this->type = GL_FLOAT; 386 | else if constexpr (glsl::same, int>) 387 | this->type = GL_INT; 388 | else if constexpr (glsl::same, uint>) 389 | this->type = GL_UNSIGNED_INT; 390 | else 391 | printf("vertex attribute type not given and couldn't be deduced from T in Attribute\n"); 392 | } 393 | } 394 | 395 | operator int() { return obj; } 396 | bool operator!=(const Attribute& other) { 397 | return obj != other.obj || stride != other.stride || offset != other.offset || type != other.type || normalized != other.normalized; 398 | } 399 | }; 400 | -------------------------------------------------------------------------------- /impl/ssgl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "window.h" 4 | #include "inline_glsl.h" 5 | #include "gl_timing.h" 6 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ssgl.h" 3 | #include "gl_timing.h" 4 | 5 | int main() { 6 | // init OpenGL, create window 7 | OpenGL context(1280, 720, "Triangle"); 8 | 9 | // define some vertices as a CPU array 10 | struct Vertex { vec2 position; vec3 color; }; 11 | Vertex verts[] = { 12 | {vec2(.5f, .0f), vec3(1.f, .0f, .0f)}, 13 | {vec2(-.4f, .5f), vec3(.0f, 1.f, .0f)}, 14 | {vec2(-.4f,-.5f), vec3(.0f, .0f, 1.f)} 15 | }; 16 | 17 | // send the vertices to the GPU 18 | Buffer b; glNamedBufferData(b, sizeof(Vertex) * 3, verts, GL_STATIC_DRAW); 19 | // set up attributes corresponding to the values 20 | Attribute position(b, sizeof(Vertex), 0); 21 | Attribute color(b, sizeof(Vertex), sizeof(vec2)); 22 | 23 | // start timing 24 | TimeStamp start; 25 | 26 | // while window open and ESC not pressed 27 | while (loop()) { 28 | // get time elapsed 29 | TimeStamp now; 30 | float t = .001f*(float)cpuTime(start, now); 31 | 32 | // define the shaders 33 | auto vertex = [&] { 34 | uniform float bind(t); 35 | in vec2 bind_attribute(position); 36 | in vec3 bind_attribute(color); 37 | out vec3 col; 38 | void glsl_main() { 39 | col = color; 40 | float c = cos(t), s = sin(t); 41 | gl_Position = vec4(mat2(c, s, -s, c) *position.xy*vec2(9.f/16.f,1.f), .0f, 1.f); 42 | } 43 | }; 44 | auto fragment = [&] { 45 | in vec3 col; 46 | out vec3 bind_target(screen); // screen is the special name 47 | void glsl_main() { 48 | screen = col; 49 | } 50 | }; 51 | 52 | // set up the shader and draw 53 | useShader(vertex(), fragment()); 54 | glDrawArrays(GL_TRIANGLES, 0, 3); 55 | 56 | // show the frame and clear the screen 57 | swapBuffers(); 58 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 59 | } 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /math_helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inline_glsl.h" 4 | 5 | inline glsl_global const float pi = 3.14159265358979323f; 6 | 7 | // see Song Ho Ahns page for derivations and details 8 | inline glsl_function mat4 perspective(float fov_rad, float width_over_height, float near_plane = .1f, float far_plane = 10.f) { 9 | mat4 result = mat4(1.f); 10 | result[0].x = 1.f / (width_over_height * tan(fov_rad*.5f)); 11 | result[1].y = 1.f / tan(fov_rad * .5f); 12 | result[2].zw = vec2(-(far_plane + near_plane) / (far_plane - near_plane), -1.f); 13 | result[3].zw = vec2(-2.f * far_plane * near_plane / (far_plane - near_plane), .0f); 14 | return result; 15 | } 16 | inline glsl_function mat4 ortho(float size, float width_over_height, float near_plane = .0f, float far_plane = 10.f) { 17 | mat4 result = mat4(1.f); 18 | result[0].x = 1.f / (width_over_height * size * .5f); 19 | result[1].y = 1.f / (size * .5f); 20 | result[2].z = -2.f / (far_plane - near_plane); 21 | result[3].z = -(far_plane + near_plane) / (far_plane - near_plane); 22 | return result; 23 | } 24 | inline glsl_function mat4 lookAt(vec3 camera_position, vec3 camera_target, vec3 up = vec3(.0f, 1.f, .0f)) { 25 | mat4 result = mat4(1.f); 26 | result[2].xyz = normalize(camera_position - camera_target); 27 | result[0].xyz = normalize(cross(up, result[2].xyz)); 28 | result[1].xyz = cross(result[2].xyz, result[0].xyz); 29 | result[3].xyz = camera_position; 30 | return result; 31 | } 32 | 33 | // Jarzynski and Olano, 2020 34 | static glsl_global uint rnd_seed = 0; 35 | inline glsl_function uint rnd_uint() { 36 | uint x = rnd_seed; 37 | rnd_seed = rnd_seed * 747796405u + 2891336453u; 38 | return ((x >> ((x >> 28u) + 4u)) ^ x) * 277803737u; 39 | } 40 | inline glsl_function float rnd() { 41 | return float(rnd_uint())/float(0xffffffffu); 42 | } 43 | inline glsl_function void srnd(uint seed) { 44 | rnd_seed = seed; rnd(); 45 | } 46 | 47 | // Duff, 2017 48 | inline glsl_function mat3 basis(vec3 n){ 49 | float sign = uintBitsToFloat((floatBitsToUint(n.z)&(1u<<31u))|floatBitsToUint(1.f)); 50 | const float a = -1.0f / (sign + n.z); 51 | const float b = n.x * n.y * a; 52 | return mat3( 53 | vec3(1.0f + sign * n.x * n.x * a, sign * b, -sign * n.x), 54 | vec3(b, sign + n.y * n.y * a, -n.y), 55 | n); 56 | } 57 | 58 | // as per the sRGB standard 59 | inline glsl_function vec3 srgb_to_linear(vec3 x) { 60 | return mix(x / 12.92f, pow((x + .055f) / 1.055f, vec3(2.4f)), step(.04045f, x)); 61 | } 62 | 63 | inline glsl_function vec3 linear_to_srgb(vec3 x) { 64 | return mix(x * 12.92f, pow(x, vec3(1.f/2.4f))*1.055f - .055f, step(.0031308f, x)); 65 | } 66 | 67 | // convert floating points to uints and back, preserving order. 68 | // mostly useful for performing atomicMax/Min on floats (map float to sortable uint -> uint atomic -> map result back to float). 69 | inline glsl_function uint convert_sortable(float f) { 70 | uint result = ~floatBitsToUint(f); 71 | return result ^ (0x7fffffff * (result >> 31)); 72 | } 73 | 74 | inline glsl_function float convert_sortable(uint f) { 75 | return uintBitsToFloat(~(f ^ (0x7fffffff * (f >> 31)))); 76 | } -------------------------------------------------------------------------------- /ssgl.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.32106.194 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssgl", "ssgl.vcxproj", "{BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}.Debug|x64.ActiveCfg = Debug|x64 17 | {BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}.Debug|x64.Build.0 = Debug|x64 18 | {BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}.Debug|x86.ActiveCfg = Debug|Win32 19 | {BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}.Debug|x86.Build.0 = Debug|Win32 20 | {BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}.Release|x64.ActiveCfg = Release|x64 21 | {BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}.Release|x64.Build.0 = Release|x64 22 | {BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}.Release|x86.ActiveCfg = Release|Win32 23 | {BF0752E3-D4D2-4E1D-813A-BCBC51D747D1}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {2F8D12E3-98B6-494C-B582-75B0B658E7CB} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /ssgl.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 16.0 46 | Win32Proj 47 | {bf0752e3-d4d2-4e1d-813a-bcbc51d747d1} 48 | ssgl 49 | 10.0 50 | 51 | 52 | 53 | Application 54 | true 55 | v143 56 | Unicode 57 | 58 | 59 | Application 60 | false 61 | v143 62 | true 63 | Unicode 64 | 65 | 66 | Application 67 | true 68 | v143 69 | Unicode 70 | 71 | 72 | Application 73 | false 74 | v143 75 | true 76 | Unicode 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | true 98 | 99 | 100 | false 101 | 102 | 103 | true 104 | 105 | 106 | false 107 | 108 | 109 | 110 | Level3 111 | true 112 | _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 113 | true 114 | $(SolutionDir)utils;$(SolutionDir)impl;$(SolutionDir);%(AdditionalIncludeDirectories) 115 | stdcpp17 116 | true 117 | 118 | 119 | Console 120 | true 121 | 122 | 123 | 124 | 125 | Level3 126 | true 127 | true 128 | true 129 | _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 130 | true 131 | $(SolutionDir)utils;$(SolutionDir)impl;$(SolutionDir);%(AdditionalIncludeDirectories) 132 | stdcpp17 133 | true 134 | 135 | 136 | Console 137 | true 138 | true 139 | true 140 | 141 | 142 | 143 | 144 | Level3 145 | true 146 | _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 147 | true 148 | $(SolutionDir)utils;$(SolutionDir)impl;$(SolutionDir);%(AdditionalIncludeDirectories) 149 | stdcpp17 150 | true 151 | 152 | 153 | Console 154 | true 155 | 156 | 157 | 158 | 159 | Level3 160 | true 161 | true 162 | true 163 | _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 164 | true 165 | $(SolutionDir)utils;$(SolutionDir)impl;$(SolutionDir);%(AdditionalIncludeDirectories) 166 | stdcpp17 167 | true 168 | 169 | 170 | Console 171 | true 172 | true 173 | true 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /utils/gl_timing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include "glext.h" 7 | #include "loadgl46.h" 8 | 9 | // GPU timing object 10 | struct TimeStamp { 11 | // todo: move construct, etc? might want map of string to stamp for global use 12 | GLint64 asynchronous; 13 | GLuint synchronousObject; 14 | mutable GLuint available = GL_FALSE; 15 | mutable GLint64 synchronous; 16 | TimeStamp() { 17 | // create GPU query 18 | glCreateQueries(GL_TIMESTAMP, 1, &synchronousObject); 19 | glQueryCounter(synchronousObject, GL_TIMESTAMP); 20 | // query CPU counter directly 21 | glGetInteger64v(GL_TIMESTAMP, &asynchronous); 22 | } 23 | void check() const { 24 | while (available == GL_FALSE) { 25 | glGetQueryObjectuiv(synchronousObject, GL_QUERY_RESULT_AVAILABLE, &available); 26 | if(available == GL_TRUE) 27 | glGetQueryObjecti64v(synchronousObject, GL_QUERY_RESULT, &synchronous); 28 | } 29 | } 30 | // latency between CPU call and GPU execution, in ms 31 | double latency() const { 32 | check(); 33 | return double(synchronous - asynchronous)*1.0e-6; 34 | } 35 | ~TimeStamp() { 36 | glDeleteQueries(1, &synchronousObject); 37 | } 38 | }; 39 | 40 | // GPU time between two stamps, ms 41 | inline double operator-(const TimeStamp& end, const TimeStamp& begin) { 42 | begin.check(); 43 | end.check(); 44 | return double(end.synchronous - begin.synchronous)*1.0e-6; 45 | } 46 | 47 | // GPU time between two stamps, ms 48 | inline double gpuTime(const TimeStamp& begin, const TimeStamp& end) { 49 | return end - begin; 50 | } 51 | 52 | // CPU-side time between two stamps, ms 53 | inline double cpuTime(const TimeStamp& begin, const TimeStamp& end) { 54 | return double(end.asynchronous - begin.asynchronous)*1.0e-6; 55 | } 56 | -------------------------------------------------------------------------------- /utils/mesh.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "mesh.h" 10 | #include "math_helpers.h" 11 | 12 | struct ind_type { uint32_t position, uv, normal, material; }; 13 | 14 | bool operator==(const ind_type& a, const ind_type& b) { 15 | return a.position == b.position && a.uv == b.uv && a.normal == b.normal && a.material == b.material; 16 | } 17 | 18 | namespace std { 19 | template<> 20 | struct hash { 21 | size_t operator()(const ind_type& i) const { 22 | size_t result = 0; 23 | for (uint32_t k : {i.position, i.uv, i.normal, i.material}) { 24 | srnd(k); rnd(); 25 | result ^= rnd_seed + 0x9e3779b9 + (result << 6) + (result >> 2); 26 | } 27 | return result; 28 | } 29 | }; 30 | } 31 | 32 | void get_mesh(const char* filename, void* meshPtr, bool smooth_shaded) { 33 | 34 | using namespace std; 35 | 36 | struct binary_header { 37 | uint32_t position_count, uv_count, normal_count, material_count, triangle_count; 38 | }; 39 | 40 | vector positions; 41 | vector uvs; 42 | vector normals; 43 | vector material_albedos; 44 | vector indices; 45 | 46 | filesystem::path path(filename); 47 | 48 | path.replace_extension(".bin"); 49 | if (!filesystem::exists(path)) { 50 | 51 | path.replace_extension(".mtl"); 52 | FILE* mtlFile = fopen(path.string().c_str(), "rb"); 53 | fseek(mtlFile, 0, SEEK_END); 54 | const size_t mtlSize = size_t(ftell(mtlFile)) + 1; 55 | 56 | vector mtlContents(mtlSize); 57 | mtlContents.back() = '\0'; 58 | fseek(mtlFile, 0, SEEK_SET); 59 | fread(mtlContents.data(), 1, mtlSize - 1, mtlFile); 60 | fclose(mtlFile); 61 | 62 | vector mtlNameIndices; 63 | vec3 color(1.f); 64 | int i = 0; 65 | while (i < mtlSize - 1) { 66 | if (mtlContents[i] == 'n') { 67 | i += 7; // skip "newmtl " 68 | while (mtlContents[i] == ' ' || mtlContents[i] == '\t') i++; 69 | 70 | if (mtlNameIndices.size() > 0) 71 | material_albedos.push_back(color); 72 | mtlNameIndices.push_back(i); 73 | } 74 | else if (mtlContents[i] == 'K' && mtlContents[i+1] == 'd') 75 | sscanf(mtlContents.data() + i + 2, " %g %g %g", color.data, color.data+1, color.data+2); 76 | while (i < mtlSize - 1 && mtlContents[i++] != '\n'); 77 | } 78 | material_albedos.push_back(color); 79 | 80 | path.replace_extension(".obj"); 81 | 82 | FILE* objFile = fopen(path.string().c_str(), "rb"); 83 | fseek(objFile, 0, SEEK_END); 84 | const size_t objSize = size_t(ftell(objFile)) + 1; 85 | 86 | vector objContents(objSize); 87 | objContents.back() = '\0'; 88 | fseek(objFile, 0, SEEK_SET); 89 | fread(objContents.data(), 1, objSize - 1, objFile); 90 | fclose(objFile); 91 | 92 | int use_mtl_index = 0; 93 | i = 0; 94 | while (i= 2) 140 | for(int k = 0; k<3; ++k) 141 | indices.push_back(sweep_inds[k]); 142 | 143 | sweep_inds[1] = sweep_inds[2]; 144 | j++; write_index = 2; 145 | 146 | while (objContents[i] == ' ' || objContents[i] == '\t') i++; 147 | } 148 | } 149 | else if (objContents[i] == 'u' && objContents[i+1] == 's') { 150 | use_mtl_index = -1; 151 | i += 7; // skip "usemtl " 152 | while (objContents[i] == ' ' || objContents[i] == '\t') i++; 153 | for (auto j: mtlNameIndices) { 154 | use_mtl_index++; 155 | int k = i; 156 | bool match = false; 157 | while (objContents[k] == mtlContents[j] && objContents[k] != '\0') { 158 | if (objContents[k] == ' ' || objContents[k] == '\t' || objContents[k] == '\n' || objContents[k] == '\0') { 159 | match = true; 160 | break; 161 | } 162 | k++; j++; 163 | } 164 | if (match) break; 165 | } 166 | } 167 | while (i < objSize - 1 && objContents[i] != '\n') i++; 168 | i++; 169 | } 170 | path.replace_extension(".bin"); 171 | FILE* binFile = fopen(path.string().c_str(), "wb"); 172 | binary_header header = { uint32_t(positions.size()), uint32_t(uvs.size()), uint32_t(normals.size()), uint32_t(material_albedos.size()), uint32_t(indices.size()) }; 173 | fwrite(&header, sizeof(header), 1, binFile); 174 | fwrite(positions.data(), sizeof(positions[0]), positions.size(), binFile); 175 | fwrite(uvs.data(), sizeof(uvs[0]), uvs.size(), binFile); 176 | fwrite(normals.data(), sizeof(normals[0]), normals.size(), binFile); 177 | fwrite(material_albedos.data(), sizeof(material_albedos[0]), material_albedos.size(), binFile); 178 | fwrite(indices.data(), sizeof(indices[0]), indices.size(), binFile); 179 | fclose(binFile); 180 | } 181 | else { 182 | FILE* binFile = fopen(path.string().c_str(), "rb"); 183 | binary_header header; 184 | fread(&header, sizeof(header), 1, binFile); 185 | positions.resize(header.position_count); uvs.resize(header.uv_count); normals.resize(header.normal_count); 186 | material_albedos.resize(header.material_count); indices.resize(header.triangle_count); 187 | fread(positions.data(), sizeof(positions[0]), positions.size(), binFile); 188 | fread(uvs.data(), sizeof(uvs[0]), uvs.size(), binFile); 189 | fread(normals.data(), sizeof(normals[0]), normals.size(), binFile); 190 | fread(material_albedos.data(), sizeof(material_albedos[0]), material_albedos.size(), binFile); 191 | fread(indices.data(), sizeof(indices[0]), indices.size(), binFile); 192 | fclose(binFile); 193 | } 194 | 195 | if (!smooth_shaded) { 196 | FlatMesh* mesh = (FlatMesh*)meshPtr; 197 | mesh->triangle_count = int(indices.size()/3); 198 | #ifdef _WIN32 199 | mesh->triangles = (FlatMesh::triangle*)_aligned_malloc(mesh->triangle_count * sizeof(FlatMesh::triangle), 16); 200 | #else // see how the arguments are flipped? pretty funny joke by whoever defined these :) 201 | mesh->triangles = (FlatMesh::triangle*)aligned_alloc(16, mesh->triangle_count * sizeof(FlatMesh::triangle)); 202 | #endif 203 | for (int i = 0; i < mesh->triangle_count; ++i) { 204 | vec3 color = material_albedos[indices[i * 3].material]; 205 | for (int j = 0; j < 3; ++j) { 206 | const auto ind = indices[i * 3 + j]; 207 | vec3 position = positions[ind.position]; 208 | 209 | mesh->triangles[i].vertices[j].position = _mm_setr_ps(position.x, position.y, position.z, 1.f); 210 | vec3 normal = normals[ind.normal]; 211 | mesh->triangles[i].vertices[j].normal = _mm_setr_ps(normal.x, normal.y, normal.z, 1.f); 212 | mesh->triangles[i].vertices[j].color = _mm_setr_ps(color.r, color.g, color.b, 1.f); 213 | } 214 | } 215 | } 216 | else { 217 | Mesh* mesh = (Mesh*)meshPtr; 218 | mesh->triangle_count = int(indices.size() / 3); 219 | mesh->vertex_count = int(positions.size()); 220 | 221 | std::unordered_map ind_to_vert; 222 | std::vector verts; 223 | std::vector inds; 224 | 225 | for (ind_type i : indices) { 226 | if(i.position > mesh->vertex_count) continue; 227 | if (!ind_to_vert.count(i)) { 228 | ind_to_vert[i] = verts.size(); 229 | verts.push_back({}); 230 | verts.back().position = vec4(positions[i.position], 1.f); 231 | verts.back().normal = i.normal < normals.size() ? vec4(normals[i.normal], 1.f) : vec4(.0f); 232 | verts.back().uv = i.uvvertex_count = verts.size(); 239 | mesh->verts = new Mesh::vertex[mesh->vertex_count]; 240 | memcpy(mesh->verts, verts.data(), sizeof(Mesh::vertex)*verts.size()); 241 | mesh->indices = new uint32_t[mesh->triangle_count * 3]; 242 | memcpy(mesh->indices, inds.data(), sizeof(uint32_t)*inds.size()); 243 | } 244 | } 245 | 246 | -------------------------------------------------------------------------------- /utils/mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | 6 | void get_mesh(const char* filename, void* mesh, bool smooth_shaded); 7 | 8 | struct FlatMesh { 9 | struct vertex { 10 | __m128 position, normal, color; 11 | }; 12 | struct triangle { 13 | vertex vertices[3]; 14 | } *triangles = nullptr; 15 | int triangle_count = 0; 16 | 17 | FlatMesh(const char* filename) { 18 | get_mesh(filename, this, false); 19 | } 20 | ~FlatMesh() { 21 | #ifdef _WIN32 22 | _aligned_free(triangles); 23 | #else 24 | free(triangles); 25 | #endif 26 | } 27 | }; 28 | 29 | #include "glsl.h" 30 | 31 | struct Mesh { 32 | struct vertex { 33 | vec4 position, normal, color; 34 | vec2 uv; 35 | } *verts = nullptr; 36 | uint32_t* indices = nullptr; 37 | int vertex_count = 0, triangle_count = 0; 38 | 39 | Mesh(const char* filename) { 40 | get_mesh(filename, this, true); 41 | } 42 | ~Mesh() { delete[] verts; delete[] indices; } 43 | }; 44 | -------------------------------------------------------------------------------- /utils/wglext.h: -------------------------------------------------------------------------------- 1 | #ifndef __wglext_h_ 2 | #define __wglext_h_ 1 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /* 9 | ** Copyright (c) 2013-2017 The Khronos Group Inc. 10 | ** 11 | ** Permission is hereby granted, free of charge, to any person obtaining a 12 | ** copy of this software and/or associated documentation files (the 13 | ** "Materials"), to deal in the Materials without restriction, including 14 | ** without limitation the rights to use, copy, modify, merge, publish, 15 | ** distribute, sublicense, and/or sell copies of the Materials, and to 16 | ** permit persons to whom the Materials are furnished to do so, subject to 17 | ** the following conditions: 18 | ** 19 | ** The above copyright notice and this permission notice shall be included 20 | ** in all copies or substantial portions of the Materials. 21 | ** 22 | ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 26 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 27 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 29 | */ 30 | /* 31 | ** This header is generated from the Khronos OpenGL / OpenGL ES XML 32 | ** API Registry. The current version of the Registry, generator scripts 33 | ** used to make the header, and the header can be found at 34 | ** https://github.com/KhronosGroup/OpenGL-Registry 35 | */ 36 | 37 | #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) 38 | #define WIN32_LEAN_AND_MEAN 1 39 | #include 40 | #endif 41 | 42 | #define WGL_WGLEXT_VERSION 20170817 43 | 44 | /* Generated C header for: 45 | * API: wgl 46 | * Versions considered: .* 47 | * Versions emitted: _nomatch_^ 48 | * Default extensions included: wgl 49 | * Additional extensions included: _nomatch_^ 50 | * Extensions removed: _nomatch_^ 51 | */ 52 | 53 | #ifndef WGL_ARB_buffer_region 54 | #define WGL_ARB_buffer_region 1 55 | #define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 56 | #define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 57 | #define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 58 | #define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 59 | typedef HANDLE(WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); 60 | typedef VOID(WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); 61 | typedef BOOL(WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); 62 | typedef BOOL(WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); 63 | #ifdef WGL_WGLEXT_PROTOTYPES 64 | HANDLE WINAPI wglCreateBufferRegionARB(HDC hDC, int iLayerPlane, UINT uType); 65 | VOID WINAPI wglDeleteBufferRegionARB(HANDLE hRegion); 66 | BOOL WINAPI wglSaveBufferRegionARB(HANDLE hRegion, int x, int y, int width, int height); 67 | BOOL WINAPI wglRestoreBufferRegionARB(HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); 68 | #endif 69 | #endif /* WGL_ARB_buffer_region */ 70 | 71 | #ifndef WGL_ARB_context_flush_control 72 | #define WGL_ARB_context_flush_control 1 73 | #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 74 | #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 75 | #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 76 | #endif /* WGL_ARB_context_flush_control */ 77 | 78 | #ifndef WGL_ARB_create_context 79 | #define WGL_ARB_create_context 1 80 | #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 81 | #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 82 | #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 83 | #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 84 | #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 85 | #define WGL_CONTEXT_FLAGS_ARB 0x2094 86 | #define ERROR_INVALID_VERSION_ARB 0x2095 87 | typedef HGLRC(WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); 88 | #ifdef WGL_WGLEXT_PROTOTYPES 89 | HGLRC WINAPI wglCreateContextAttribsARB(HDC hDC, HGLRC hShareContext, const int *attribList); 90 | #endif 91 | #endif /* WGL_ARB_create_context */ 92 | 93 | #ifndef WGL_ARB_create_context_no_error 94 | #define WGL_ARB_create_context_no_error 1 95 | #define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 96 | #endif /* WGL_ARB_create_context_no_error */ 97 | 98 | #ifndef WGL_ARB_create_context_profile 99 | #define WGL_ARB_create_context_profile 1 100 | #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 101 | #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 102 | #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 103 | #define ERROR_INVALID_PROFILE_ARB 0x2096 104 | #endif /* WGL_ARB_create_context_profile */ 105 | 106 | #ifndef WGL_ARB_create_context_robustness 107 | #define WGL_ARB_create_context_robustness 1 108 | #define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 109 | #define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 110 | #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 111 | #define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 112 | #endif /* WGL_ARB_create_context_robustness */ 113 | 114 | #ifndef WGL_ARB_extensions_string 115 | #define WGL_ARB_extensions_string 1 116 | typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); 117 | #ifdef WGL_WGLEXT_PROTOTYPES 118 | const char *WINAPI wglGetExtensionsStringARB(HDC hdc); 119 | #endif 120 | #endif /* WGL_ARB_extensions_string */ 121 | 122 | #ifndef WGL_ARB_framebuffer_sRGB 123 | #define WGL_ARB_framebuffer_sRGB 1 124 | #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 125 | #endif /* WGL_ARB_framebuffer_sRGB */ 126 | 127 | #ifndef WGL_ARB_make_current_read 128 | #define WGL_ARB_make_current_read 1 129 | #define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 130 | #define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 131 | typedef BOOL(WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); 132 | typedef HDC(WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); 133 | #ifdef WGL_WGLEXT_PROTOTYPES 134 | BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc); 135 | HDC WINAPI wglGetCurrentReadDCARB(void); 136 | #endif 137 | #endif /* WGL_ARB_make_current_read */ 138 | 139 | #ifndef WGL_ARB_multisample 140 | #define WGL_ARB_multisample 1 141 | #define WGL_SAMPLE_BUFFERS_ARB 0x2041 142 | #define WGL_SAMPLES_ARB 0x2042 143 | #endif /* WGL_ARB_multisample */ 144 | 145 | #ifndef WGL_ARB_pbuffer 146 | #define WGL_ARB_pbuffer 1 147 | DECLARE_HANDLE(HPBUFFERARB); 148 | #define WGL_DRAW_TO_PBUFFER_ARB 0x202D 149 | #define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E 150 | #define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F 151 | #define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 152 | #define WGL_PBUFFER_LARGEST_ARB 0x2033 153 | #define WGL_PBUFFER_WIDTH_ARB 0x2034 154 | #define WGL_PBUFFER_HEIGHT_ARB 0x2035 155 | #define WGL_PBUFFER_LOST_ARB 0x2036 156 | typedef HPBUFFERARB(WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); 157 | typedef HDC(WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); 158 | typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); 159 | typedef BOOL(WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); 160 | typedef BOOL(WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); 161 | #ifdef WGL_WGLEXT_PROTOTYPES 162 | HPBUFFERARB WINAPI wglCreatePbufferARB(HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); 163 | HDC WINAPI wglGetPbufferDCARB(HPBUFFERARB hPbuffer); 164 | int WINAPI wglReleasePbufferDCARB(HPBUFFERARB hPbuffer, HDC hDC); 165 | BOOL WINAPI wglDestroyPbufferARB(HPBUFFERARB hPbuffer); 166 | BOOL WINAPI wglQueryPbufferARB(HPBUFFERARB hPbuffer, int iAttribute, int *piValue); 167 | #endif 168 | #endif /* WGL_ARB_pbuffer */ 169 | 170 | #ifndef WGL_ARB_pixel_format 171 | #define WGL_ARB_pixel_format 1 172 | #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 173 | #define WGL_DRAW_TO_WINDOW_ARB 0x2001 174 | #define WGL_DRAW_TO_BITMAP_ARB 0x2002 175 | #define WGL_ACCELERATION_ARB 0x2003 176 | #define WGL_NEED_PALETTE_ARB 0x2004 177 | #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 178 | #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 179 | #define WGL_SWAP_METHOD_ARB 0x2007 180 | #define WGL_NUMBER_OVERLAYS_ARB 0x2008 181 | #define WGL_NUMBER_UNDERLAYS_ARB 0x2009 182 | #define WGL_TRANSPARENT_ARB 0x200A 183 | #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 184 | #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 185 | #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 186 | #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A 187 | #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B 188 | #define WGL_SHARE_DEPTH_ARB 0x200C 189 | #define WGL_SHARE_STENCIL_ARB 0x200D 190 | #define WGL_SHARE_ACCUM_ARB 0x200E 191 | #define WGL_SUPPORT_GDI_ARB 0x200F 192 | #define WGL_SUPPORT_OPENGL_ARB 0x2010 193 | #define WGL_DOUBLE_BUFFER_ARB 0x2011 194 | #define WGL_STEREO_ARB 0x2012 195 | #define WGL_PIXEL_TYPE_ARB 0x2013 196 | #define WGL_COLOR_BITS_ARB 0x2014 197 | #define WGL_RED_BITS_ARB 0x2015 198 | #define WGL_RED_SHIFT_ARB 0x2016 199 | #define WGL_GREEN_BITS_ARB 0x2017 200 | #define WGL_GREEN_SHIFT_ARB 0x2018 201 | #define WGL_BLUE_BITS_ARB 0x2019 202 | #define WGL_BLUE_SHIFT_ARB 0x201A 203 | #define WGL_ALPHA_BITS_ARB 0x201B 204 | #define WGL_ALPHA_SHIFT_ARB 0x201C 205 | #define WGL_ACCUM_BITS_ARB 0x201D 206 | #define WGL_ACCUM_RED_BITS_ARB 0x201E 207 | #define WGL_ACCUM_GREEN_BITS_ARB 0x201F 208 | #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 209 | #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 210 | #define WGL_DEPTH_BITS_ARB 0x2022 211 | #define WGL_STENCIL_BITS_ARB 0x2023 212 | #define WGL_AUX_BUFFERS_ARB 0x2024 213 | #define WGL_NO_ACCELERATION_ARB 0x2025 214 | #define WGL_GENERIC_ACCELERATION_ARB 0x2026 215 | #define WGL_FULL_ACCELERATION_ARB 0x2027 216 | #define WGL_SWAP_EXCHANGE_ARB 0x2028 217 | #define WGL_SWAP_COPY_ARB 0x2029 218 | #define WGL_SWAP_UNDEFINED_ARB 0x202A 219 | #define WGL_TYPE_RGBA_ARB 0x202B 220 | #define WGL_TYPE_COLORINDEX_ARB 0x202C 221 | typedef BOOL(WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); 222 | typedef BOOL(WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); 223 | typedef BOOL(WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); 224 | #ifdef WGL_WGLEXT_PROTOTYPES 225 | BOOL WINAPI wglGetPixelFormatAttribivARB(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); 226 | BOOL WINAPI wglGetPixelFormatAttribfvARB(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); 227 | BOOL WINAPI wglChoosePixelFormatARB(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); 228 | #endif 229 | #endif /* WGL_ARB_pixel_format */ 230 | 231 | #ifndef WGL_ARB_pixel_format_float 232 | #define WGL_ARB_pixel_format_float 1 233 | #define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 234 | #endif /* WGL_ARB_pixel_format_float */ 235 | 236 | #ifndef WGL_ARB_render_texture 237 | #define WGL_ARB_render_texture 1 238 | #define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 239 | #define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 240 | #define WGL_TEXTURE_FORMAT_ARB 0x2072 241 | #define WGL_TEXTURE_TARGET_ARB 0x2073 242 | #define WGL_MIPMAP_TEXTURE_ARB 0x2074 243 | #define WGL_TEXTURE_RGB_ARB 0x2075 244 | #define WGL_TEXTURE_RGBA_ARB 0x2076 245 | #define WGL_NO_TEXTURE_ARB 0x2077 246 | #define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 247 | #define WGL_TEXTURE_1D_ARB 0x2079 248 | #define WGL_TEXTURE_2D_ARB 0x207A 249 | #define WGL_MIPMAP_LEVEL_ARB 0x207B 250 | #define WGL_CUBE_MAP_FACE_ARB 0x207C 251 | #define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D 252 | #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E 253 | #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F 254 | #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 255 | #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 256 | #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 257 | #define WGL_FRONT_LEFT_ARB 0x2083 258 | #define WGL_FRONT_RIGHT_ARB 0x2084 259 | #define WGL_BACK_LEFT_ARB 0x2085 260 | #define WGL_BACK_RIGHT_ARB 0x2086 261 | #define WGL_AUX0_ARB 0x2087 262 | #define WGL_AUX1_ARB 0x2088 263 | #define WGL_AUX2_ARB 0x2089 264 | #define WGL_AUX3_ARB 0x208A 265 | #define WGL_AUX4_ARB 0x208B 266 | #define WGL_AUX5_ARB 0x208C 267 | #define WGL_AUX6_ARB 0x208D 268 | #define WGL_AUX7_ARB 0x208E 269 | #define WGL_AUX8_ARB 0x208F 270 | #define WGL_AUX9_ARB 0x2090 271 | typedef BOOL(WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); 272 | typedef BOOL(WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); 273 | typedef BOOL(WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); 274 | #ifdef WGL_WGLEXT_PROTOTYPES 275 | BOOL WINAPI wglBindTexImageARB(HPBUFFERARB hPbuffer, int iBuffer); 276 | BOOL WINAPI wglReleaseTexImageARB(HPBUFFERARB hPbuffer, int iBuffer); 277 | BOOL WINAPI wglSetPbufferAttribARB(HPBUFFERARB hPbuffer, const int *piAttribList); 278 | #endif 279 | #endif /* WGL_ARB_render_texture */ 280 | 281 | #ifndef WGL_ARB_robustness_application_isolation 282 | #define WGL_ARB_robustness_application_isolation 1 283 | #define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 284 | #endif /* WGL_ARB_robustness_application_isolation */ 285 | 286 | #ifndef WGL_ARB_robustness_share_group_isolation 287 | #define WGL_ARB_robustness_share_group_isolation 1 288 | #endif /* WGL_ARB_robustness_share_group_isolation */ 289 | 290 | #ifndef WGL_3DFX_multisample 291 | #define WGL_3DFX_multisample 1 292 | #define WGL_SAMPLE_BUFFERS_3DFX 0x2060 293 | #define WGL_SAMPLES_3DFX 0x2061 294 | #endif /* WGL_3DFX_multisample */ 295 | 296 | #ifndef WGL_3DL_stereo_control 297 | #define WGL_3DL_stereo_control 1 298 | #define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 299 | #define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 300 | #define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 301 | #define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 302 | typedef BOOL(WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState); 303 | #ifdef WGL_WGLEXT_PROTOTYPES 304 | BOOL WINAPI wglSetStereoEmitterState3DL(HDC hDC, UINT uState); 305 | #endif 306 | #endif /* WGL_3DL_stereo_control */ 307 | 308 | #ifndef WGL_AMD_gpu_association 309 | #define WGL_AMD_gpu_association 1 310 | #define WGL_GPU_VENDOR_AMD 0x1F00 311 | #define WGL_GPU_RENDERER_STRING_AMD 0x1F01 312 | #define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 313 | #define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 314 | #define WGL_GPU_RAM_AMD 0x21A3 315 | #define WGL_GPU_CLOCK_AMD 0x21A4 316 | #define WGL_GPU_NUM_PIPES_AMD 0x21A5 317 | #define WGL_GPU_NUM_SIMD_AMD 0x21A6 318 | #define WGL_GPU_NUM_RB_AMD 0x21A7 319 | #define WGL_GPU_NUM_SPI_AMD 0x21A8 320 | typedef UINT(WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids); 321 | typedef INT(WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data); 322 | typedef UINT(WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc); 323 | typedef HGLRC(WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id); 324 | typedef HGLRC(WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList); 325 | typedef BOOL(WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc); 326 | typedef BOOL(WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc); 327 | typedef HGLRC(WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void); 328 | typedef VOID(WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); 329 | #ifdef WGL_WGLEXT_PROTOTYPES 330 | UINT WINAPI wglGetGPUIDsAMD(UINT maxCount, UINT *ids); 331 | INT WINAPI wglGetGPUInfoAMD(UINT id, int property, GLenum dataType, UINT size, void *data); 332 | UINT WINAPI wglGetContextGPUIDAMD(HGLRC hglrc); 333 | HGLRC WINAPI wglCreateAssociatedContextAMD(UINT id); 334 | HGLRC WINAPI wglCreateAssociatedContextAttribsAMD(UINT id, HGLRC hShareContext, const int *attribList); 335 | BOOL WINAPI wglDeleteAssociatedContextAMD(HGLRC hglrc); 336 | BOOL WINAPI wglMakeAssociatedContextCurrentAMD(HGLRC hglrc); 337 | HGLRC WINAPI wglGetCurrentAssociatedContextAMD(void); 338 | VOID WINAPI wglBlitContextFramebufferAMD(HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); 339 | #endif 340 | #endif /* WGL_AMD_gpu_association */ 341 | 342 | #ifndef WGL_ATI_pixel_format_float 343 | #define WGL_ATI_pixel_format_float 1 344 | #define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 345 | #endif /* WGL_ATI_pixel_format_float */ 346 | 347 | #ifndef WGL_EXT_colorspace 348 | #define WGL_EXT_colorspace 1 349 | #define WGL_COLORSPACE_EXT 0x3087 350 | #define WGL_COLORSPACE_SRGB_EXT 0x3089 351 | #define WGL_COLORSPACE_LINEAR_EXT 0x308A 352 | #endif /* WGL_EXT_colorspace */ 353 | 354 | #ifndef WGL_EXT_create_context_es2_profile 355 | #define WGL_EXT_create_context_es2_profile 1 356 | #define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 357 | #endif /* WGL_EXT_create_context_es2_profile */ 358 | 359 | #ifndef WGL_EXT_create_context_es_profile 360 | #define WGL_EXT_create_context_es_profile 1 361 | #define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 362 | #endif /* WGL_EXT_create_context_es_profile */ 363 | 364 | #ifndef WGL_EXT_depth_float 365 | #define WGL_EXT_depth_float 1 366 | #define WGL_DEPTH_FLOAT_EXT 0x2040 367 | #endif /* WGL_EXT_depth_float */ 368 | 369 | #ifndef WGL_EXT_display_color_table 370 | #define WGL_EXT_display_color_table 1 371 | typedef GLboolean(WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); 372 | typedef GLboolean(WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); 373 | typedef GLboolean(WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); 374 | typedef VOID(WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); 375 | #ifdef WGL_WGLEXT_PROTOTYPES 376 | GLboolean WINAPI wglCreateDisplayColorTableEXT(GLushort id); 377 | GLboolean WINAPI wglLoadDisplayColorTableEXT(const GLushort *table, GLuint length); 378 | GLboolean WINAPI wglBindDisplayColorTableEXT(GLushort id); 379 | VOID WINAPI wglDestroyDisplayColorTableEXT(GLushort id); 380 | #endif 381 | #endif /* WGL_EXT_display_color_table */ 382 | 383 | #ifndef WGL_EXT_extensions_string 384 | #define WGL_EXT_extensions_string 1 385 | typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); 386 | #ifdef WGL_WGLEXT_PROTOTYPES 387 | const char *WINAPI wglGetExtensionsStringEXT(void); 388 | #endif 389 | #endif /* WGL_EXT_extensions_string */ 390 | 391 | #ifndef WGL_EXT_framebuffer_sRGB 392 | #define WGL_EXT_framebuffer_sRGB 1 393 | #define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 394 | #endif /* WGL_EXT_framebuffer_sRGB */ 395 | 396 | #ifndef WGL_EXT_make_current_read 397 | #define WGL_EXT_make_current_read 1 398 | #define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 399 | typedef BOOL(WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); 400 | typedef HDC(WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); 401 | #ifdef WGL_WGLEXT_PROTOTYPES 402 | BOOL WINAPI wglMakeContextCurrentEXT(HDC hDrawDC, HDC hReadDC, HGLRC hglrc); 403 | HDC WINAPI wglGetCurrentReadDCEXT(void); 404 | #endif 405 | #endif /* WGL_EXT_make_current_read */ 406 | 407 | #ifndef WGL_EXT_multisample 408 | #define WGL_EXT_multisample 1 409 | #define WGL_SAMPLE_BUFFERS_EXT 0x2041 410 | #define WGL_SAMPLES_EXT 0x2042 411 | #endif /* WGL_EXT_multisample */ 412 | 413 | #ifndef WGL_EXT_pbuffer 414 | #define WGL_EXT_pbuffer 1 415 | DECLARE_HANDLE(HPBUFFEREXT); 416 | #define WGL_DRAW_TO_PBUFFER_EXT 0x202D 417 | #define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E 418 | #define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F 419 | #define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 420 | #define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 421 | #define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 422 | #define WGL_PBUFFER_LARGEST_EXT 0x2033 423 | #define WGL_PBUFFER_WIDTH_EXT 0x2034 424 | #define WGL_PBUFFER_HEIGHT_EXT 0x2035 425 | typedef HPBUFFEREXT(WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); 426 | typedef HDC(WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); 427 | typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); 428 | typedef BOOL(WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); 429 | typedef BOOL(WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); 430 | #ifdef WGL_WGLEXT_PROTOTYPES 431 | HPBUFFEREXT WINAPI wglCreatePbufferEXT(HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); 432 | HDC WINAPI wglGetPbufferDCEXT(HPBUFFEREXT hPbuffer); 433 | int WINAPI wglReleasePbufferDCEXT(HPBUFFEREXT hPbuffer, HDC hDC); 434 | BOOL WINAPI wglDestroyPbufferEXT(HPBUFFEREXT hPbuffer); 435 | BOOL WINAPI wglQueryPbufferEXT(HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); 436 | #endif 437 | #endif /* WGL_EXT_pbuffer */ 438 | 439 | #ifndef WGL_EXT_pixel_format 440 | #define WGL_EXT_pixel_format 1 441 | #define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 442 | #define WGL_DRAW_TO_WINDOW_EXT 0x2001 443 | #define WGL_DRAW_TO_BITMAP_EXT 0x2002 444 | #define WGL_ACCELERATION_EXT 0x2003 445 | #define WGL_NEED_PALETTE_EXT 0x2004 446 | #define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 447 | #define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 448 | #define WGL_SWAP_METHOD_EXT 0x2007 449 | #define WGL_NUMBER_OVERLAYS_EXT 0x2008 450 | #define WGL_NUMBER_UNDERLAYS_EXT 0x2009 451 | #define WGL_TRANSPARENT_EXT 0x200A 452 | #define WGL_TRANSPARENT_VALUE_EXT 0x200B 453 | #define WGL_SHARE_DEPTH_EXT 0x200C 454 | #define WGL_SHARE_STENCIL_EXT 0x200D 455 | #define WGL_SHARE_ACCUM_EXT 0x200E 456 | #define WGL_SUPPORT_GDI_EXT 0x200F 457 | #define WGL_SUPPORT_OPENGL_EXT 0x2010 458 | #define WGL_DOUBLE_BUFFER_EXT 0x2011 459 | #define WGL_STEREO_EXT 0x2012 460 | #define WGL_PIXEL_TYPE_EXT 0x2013 461 | #define WGL_COLOR_BITS_EXT 0x2014 462 | #define WGL_RED_BITS_EXT 0x2015 463 | #define WGL_RED_SHIFT_EXT 0x2016 464 | #define WGL_GREEN_BITS_EXT 0x2017 465 | #define WGL_GREEN_SHIFT_EXT 0x2018 466 | #define WGL_BLUE_BITS_EXT 0x2019 467 | #define WGL_BLUE_SHIFT_EXT 0x201A 468 | #define WGL_ALPHA_BITS_EXT 0x201B 469 | #define WGL_ALPHA_SHIFT_EXT 0x201C 470 | #define WGL_ACCUM_BITS_EXT 0x201D 471 | #define WGL_ACCUM_RED_BITS_EXT 0x201E 472 | #define WGL_ACCUM_GREEN_BITS_EXT 0x201F 473 | #define WGL_ACCUM_BLUE_BITS_EXT 0x2020 474 | #define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 475 | #define WGL_DEPTH_BITS_EXT 0x2022 476 | #define WGL_STENCIL_BITS_EXT 0x2023 477 | #define WGL_AUX_BUFFERS_EXT 0x2024 478 | #define WGL_NO_ACCELERATION_EXT 0x2025 479 | #define WGL_GENERIC_ACCELERATION_EXT 0x2026 480 | #define WGL_FULL_ACCELERATION_EXT 0x2027 481 | #define WGL_SWAP_EXCHANGE_EXT 0x2028 482 | #define WGL_SWAP_COPY_EXT 0x2029 483 | #define WGL_SWAP_UNDEFINED_EXT 0x202A 484 | #define WGL_TYPE_RGBA_EXT 0x202B 485 | #define WGL_TYPE_COLORINDEX_EXT 0x202C 486 | typedef BOOL(WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); 487 | typedef BOOL(WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); 488 | typedef BOOL(WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); 489 | #ifdef WGL_WGLEXT_PROTOTYPES 490 | BOOL WINAPI wglGetPixelFormatAttribivEXT(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); 491 | BOOL WINAPI wglGetPixelFormatAttribfvEXT(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); 492 | BOOL WINAPI wglChoosePixelFormatEXT(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); 493 | #endif 494 | #endif /* WGL_EXT_pixel_format */ 495 | 496 | #ifndef WGL_EXT_pixel_format_packed_float 497 | #define WGL_EXT_pixel_format_packed_float 1 498 | #define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 499 | #endif /* WGL_EXT_pixel_format_packed_float */ 500 | 501 | #ifndef WGL_EXT_swap_control 502 | #define WGL_EXT_swap_control 1 503 | typedef BOOL(WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); 504 | typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); 505 | #ifdef WGL_WGLEXT_PROTOTYPES 506 | BOOL WINAPI wglSwapIntervalEXT(int interval); 507 | int WINAPI wglGetSwapIntervalEXT(void); 508 | #endif 509 | #endif /* WGL_EXT_swap_control */ 510 | 511 | #ifndef WGL_EXT_swap_control_tear 512 | #define WGL_EXT_swap_control_tear 1 513 | #endif /* WGL_EXT_swap_control_tear */ 514 | 515 | #ifndef WGL_I3D_digital_video_control 516 | #define WGL_I3D_digital_video_control 1 517 | #define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 518 | #define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 519 | #define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 520 | #define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 521 | typedef BOOL(WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); 522 | typedef BOOL(WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); 523 | #ifdef WGL_WGLEXT_PROTOTYPES 524 | BOOL WINAPI wglGetDigitalVideoParametersI3D(HDC hDC, int iAttribute, int *piValue); 525 | BOOL WINAPI wglSetDigitalVideoParametersI3D(HDC hDC, int iAttribute, const int *piValue); 526 | #endif 527 | #endif /* WGL_I3D_digital_video_control */ 528 | 529 | #ifndef WGL_I3D_gamma 530 | #define WGL_I3D_gamma 1 531 | #define WGL_GAMMA_TABLE_SIZE_I3D 0x204E 532 | #define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F 533 | typedef BOOL(WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); 534 | typedef BOOL(WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); 535 | typedef BOOL(WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); 536 | typedef BOOL(WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); 537 | #ifdef WGL_WGLEXT_PROTOTYPES 538 | BOOL WINAPI wglGetGammaTableParametersI3D(HDC hDC, int iAttribute, int *piValue); 539 | BOOL WINAPI wglSetGammaTableParametersI3D(HDC hDC, int iAttribute, const int *piValue); 540 | BOOL WINAPI wglGetGammaTableI3D(HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); 541 | BOOL WINAPI wglSetGammaTableI3D(HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); 542 | #endif 543 | #endif /* WGL_I3D_gamma */ 544 | 545 | #ifndef WGL_I3D_genlock 546 | #define WGL_I3D_genlock 1 547 | #define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 548 | #define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045 549 | #define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046 550 | #define WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047 551 | #define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 552 | #define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 553 | #define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A 554 | #define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B 555 | #define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C 556 | typedef BOOL(WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); 557 | typedef BOOL(WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); 558 | typedef BOOL(WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); 559 | typedef BOOL(WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); 560 | typedef BOOL(WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); 561 | typedef BOOL(WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); 562 | typedef BOOL(WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); 563 | typedef BOOL(WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); 564 | typedef BOOL(WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); 565 | typedef BOOL(WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); 566 | typedef BOOL(WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); 567 | typedef BOOL(WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); 568 | #ifdef WGL_WGLEXT_PROTOTYPES 569 | BOOL WINAPI wglEnableGenlockI3D(HDC hDC); 570 | BOOL WINAPI wglDisableGenlockI3D(HDC hDC); 571 | BOOL WINAPI wglIsEnabledGenlockI3D(HDC hDC, BOOL *pFlag); 572 | BOOL WINAPI wglGenlockSourceI3D(HDC hDC, UINT uSource); 573 | BOOL WINAPI wglGetGenlockSourceI3D(HDC hDC, UINT *uSource); 574 | BOOL WINAPI wglGenlockSourceEdgeI3D(HDC hDC, UINT uEdge); 575 | BOOL WINAPI wglGetGenlockSourceEdgeI3D(HDC hDC, UINT *uEdge); 576 | BOOL WINAPI wglGenlockSampleRateI3D(HDC hDC, UINT uRate); 577 | BOOL WINAPI wglGetGenlockSampleRateI3D(HDC hDC, UINT *uRate); 578 | BOOL WINAPI wglGenlockSourceDelayI3D(HDC hDC, UINT uDelay); 579 | BOOL WINAPI wglGetGenlockSourceDelayI3D(HDC hDC, UINT *uDelay); 580 | BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D(HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); 581 | #endif 582 | #endif /* WGL_I3D_genlock */ 583 | 584 | #ifndef WGL_I3D_image_buffer 585 | #define WGL_I3D_image_buffer 1 586 | #define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 587 | #define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 588 | typedef LPVOID(WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); 589 | typedef BOOL(WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); 590 | typedef BOOL(WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); 591 | typedef BOOL(WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); 592 | #ifdef WGL_WGLEXT_PROTOTYPES 593 | LPVOID WINAPI wglCreateImageBufferI3D(HDC hDC, DWORD dwSize, UINT uFlags); 594 | BOOL WINAPI wglDestroyImageBufferI3D(HDC hDC, LPVOID pAddress); 595 | BOOL WINAPI wglAssociateImageBufferEventsI3D(HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); 596 | BOOL WINAPI wglReleaseImageBufferEventsI3D(HDC hDC, const LPVOID *pAddress, UINT count); 597 | #endif 598 | #endif /* WGL_I3D_image_buffer */ 599 | 600 | #ifndef WGL_I3D_swap_frame_lock 601 | #define WGL_I3D_swap_frame_lock 1 602 | typedef BOOL(WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); 603 | typedef BOOL(WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); 604 | typedef BOOL(WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); 605 | typedef BOOL(WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); 606 | #ifdef WGL_WGLEXT_PROTOTYPES 607 | BOOL WINAPI wglEnableFrameLockI3D(void); 608 | BOOL WINAPI wglDisableFrameLockI3D(void); 609 | BOOL WINAPI wglIsEnabledFrameLockI3D(BOOL *pFlag); 610 | BOOL WINAPI wglQueryFrameLockMasterI3D(BOOL *pFlag); 611 | #endif 612 | #endif /* WGL_I3D_swap_frame_lock */ 613 | 614 | #ifndef WGL_I3D_swap_frame_usage 615 | #define WGL_I3D_swap_frame_usage 1 616 | typedef BOOL(WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); 617 | typedef BOOL(WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); 618 | typedef BOOL(WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); 619 | typedef BOOL(WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); 620 | #ifdef WGL_WGLEXT_PROTOTYPES 621 | BOOL WINAPI wglGetFrameUsageI3D(float *pUsage); 622 | BOOL WINAPI wglBeginFrameTrackingI3D(void); 623 | BOOL WINAPI wglEndFrameTrackingI3D(void); 624 | BOOL WINAPI wglQueryFrameTrackingI3D(DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); 625 | #endif 626 | #endif /* WGL_I3D_swap_frame_usage */ 627 | 628 | #ifndef WGL_NV_DX_interop 629 | #define WGL_NV_DX_interop 1 630 | #define WGL_ACCESS_READ_ONLY_NV 0x00000000 631 | #define WGL_ACCESS_READ_WRITE_NV 0x00000001 632 | #define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 633 | typedef BOOL(WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle); 634 | typedef HANDLE(WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice); 635 | typedef BOOL(WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice); 636 | typedef HANDLE(WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); 637 | typedef BOOL(WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject); 638 | typedef BOOL(WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access); 639 | typedef BOOL(WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); 640 | typedef BOOL(WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); 641 | #ifdef WGL_WGLEXT_PROTOTYPES 642 | BOOL WINAPI wglDXSetResourceShareHandleNV(void *dxObject, HANDLE shareHandle); 643 | HANDLE WINAPI wglDXOpenDeviceNV(void *dxDevice); 644 | BOOL WINAPI wglDXCloseDeviceNV(HANDLE hDevice); 645 | HANDLE WINAPI wglDXRegisterObjectNV(HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); 646 | BOOL WINAPI wglDXUnregisterObjectNV(HANDLE hDevice, HANDLE hObject); 647 | BOOL WINAPI wglDXObjectAccessNV(HANDLE hObject, GLenum access); 648 | BOOL WINAPI wglDXLockObjectsNV(HANDLE hDevice, GLint count, HANDLE *hObjects); 649 | BOOL WINAPI wglDXUnlockObjectsNV(HANDLE hDevice, GLint count, HANDLE *hObjects); 650 | #endif 651 | #endif /* WGL_NV_DX_interop */ 652 | 653 | #ifndef WGL_NV_DX_interop2 654 | #define WGL_NV_DX_interop2 1 655 | #endif /* WGL_NV_DX_interop2 */ 656 | 657 | #ifndef WGL_NV_copy_image 658 | #define WGL_NV_copy_image 1 659 | typedef BOOL(WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); 660 | #ifdef WGL_WGLEXT_PROTOTYPES 661 | BOOL WINAPI wglCopyImageSubDataNV(HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); 662 | #endif 663 | #endif /* WGL_NV_copy_image */ 664 | 665 | #ifndef WGL_NV_delay_before_swap 666 | #define WGL_NV_delay_before_swap 1 667 | typedef BOOL(WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds); 668 | #ifdef WGL_WGLEXT_PROTOTYPES 669 | BOOL WINAPI wglDelayBeforeSwapNV(HDC hDC, GLfloat seconds); 670 | #endif 671 | #endif /* WGL_NV_delay_before_swap */ 672 | 673 | #ifndef WGL_NV_float_buffer 674 | #define WGL_NV_float_buffer 1 675 | #define WGL_FLOAT_COMPONENTS_NV 0x20B0 676 | #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 677 | #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 678 | #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 679 | #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 680 | #define WGL_TEXTURE_FLOAT_R_NV 0x20B5 681 | #define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 682 | #define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 683 | #define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 684 | #endif /* WGL_NV_float_buffer */ 685 | 686 | #ifndef WGL_NV_gpu_affinity 687 | #define WGL_NV_gpu_affinity 1 688 | DECLARE_HANDLE(HGPUNV); 689 | struct _GPU_DEVICE { 690 | DWORD cb; 691 | CHAR DeviceName[32]; 692 | CHAR DeviceString[128]; 693 | DWORD Flags; 694 | RECT rcVirtualScreen; 695 | }; 696 | typedef struct _GPU_DEVICE *PGPU_DEVICE; 697 | #define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 698 | #define ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 699 | typedef BOOL(WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu); 700 | typedef BOOL(WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); 701 | typedef HDC(WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList); 702 | typedef BOOL(WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); 703 | typedef BOOL(WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc); 704 | #ifdef WGL_WGLEXT_PROTOTYPES 705 | BOOL WINAPI wglEnumGpusNV(UINT iGpuIndex, HGPUNV *phGpu); 706 | BOOL WINAPI wglEnumGpuDevicesNV(HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); 707 | HDC WINAPI wglCreateAffinityDCNV(const HGPUNV *phGpuList); 708 | BOOL WINAPI wglEnumGpusFromAffinityDCNV(HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); 709 | BOOL WINAPI wglDeleteDCNV(HDC hdc); 710 | #endif 711 | #endif /* WGL_NV_gpu_affinity */ 712 | 713 | #ifndef WGL_NV_multisample_coverage 714 | #define WGL_NV_multisample_coverage 1 715 | #define WGL_COVERAGE_SAMPLES_NV 0x2042 716 | #define WGL_COLOR_SAMPLES_NV 0x20B9 717 | #endif /* WGL_NV_multisample_coverage */ 718 | 719 | #ifndef WGL_NV_present_video 720 | #define WGL_NV_present_video 1 721 | DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); 722 | #define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 723 | typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); 724 | typedef BOOL(WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); 725 | typedef BOOL(WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue); 726 | #ifdef WGL_WGLEXT_PROTOTYPES 727 | int WINAPI wglEnumerateVideoDevicesNV(HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); 728 | BOOL WINAPI wglBindVideoDeviceNV(HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); 729 | BOOL WINAPI wglQueryCurrentContextNV(int iAttribute, int *piValue); 730 | #endif 731 | #endif /* WGL_NV_present_video */ 732 | 733 | #ifndef WGL_NV_render_depth_texture 734 | #define WGL_NV_render_depth_texture 1 735 | #define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 736 | #define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 737 | #define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 738 | #define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 739 | #define WGL_DEPTH_COMPONENT_NV 0x20A7 740 | #endif /* WGL_NV_render_depth_texture */ 741 | 742 | #ifndef WGL_NV_render_texture_rectangle 743 | #define WGL_NV_render_texture_rectangle 1 744 | #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 745 | #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 746 | #define WGL_TEXTURE_RECTANGLE_NV 0x20A2 747 | #endif /* WGL_NV_render_texture_rectangle */ 748 | 749 | #ifndef WGL_NV_swap_group 750 | #define WGL_NV_swap_group 1 751 | typedef BOOL(WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); 752 | typedef BOOL(WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); 753 | typedef BOOL(WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier); 754 | typedef BOOL(WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); 755 | typedef BOOL(WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count); 756 | typedef BOOL(WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC); 757 | #ifdef WGL_WGLEXT_PROTOTYPES 758 | BOOL WINAPI wglJoinSwapGroupNV(HDC hDC, GLuint group); 759 | BOOL WINAPI wglBindSwapBarrierNV(GLuint group, GLuint barrier); 760 | BOOL WINAPI wglQuerySwapGroupNV(HDC hDC, GLuint *group, GLuint *barrier); 761 | BOOL WINAPI wglQueryMaxSwapGroupsNV(HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); 762 | BOOL WINAPI wglQueryFrameCountNV(HDC hDC, GLuint *count); 763 | BOOL WINAPI wglResetFrameCountNV(HDC hDC); 764 | #endif 765 | #endif /* WGL_NV_swap_group */ 766 | 767 | #ifndef WGL_NV_vertex_array_range 768 | #define WGL_NV_vertex_array_range 1 769 | typedef void *(WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); 770 | typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); 771 | #ifdef WGL_WGLEXT_PROTOTYPES 772 | void *WINAPI wglAllocateMemoryNV(GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); 773 | void WINAPI wglFreeMemoryNV(void *pointer); 774 | #endif 775 | #endif /* WGL_NV_vertex_array_range */ 776 | 777 | #ifndef WGL_NV_video_capture 778 | #define WGL_NV_video_capture 1 779 | DECLARE_HANDLE(HVIDEOINPUTDEVICENV); 780 | #define WGL_UNIQUE_ID_NV 0x20CE 781 | #define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF 782 | typedef BOOL(WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); 783 | typedef UINT(WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); 784 | typedef BOOL(WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); 785 | typedef BOOL(WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); 786 | typedef BOOL(WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); 787 | #ifdef WGL_WGLEXT_PROTOTYPES 788 | BOOL WINAPI wglBindVideoCaptureDeviceNV(UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); 789 | UINT WINAPI wglEnumerateVideoCaptureDevicesNV(HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); 790 | BOOL WINAPI wglLockVideoCaptureDeviceNV(HDC hDc, HVIDEOINPUTDEVICENV hDevice); 791 | BOOL WINAPI wglQueryVideoCaptureDeviceNV(HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); 792 | BOOL WINAPI wglReleaseVideoCaptureDeviceNV(HDC hDc, HVIDEOINPUTDEVICENV hDevice); 793 | #endif 794 | #endif /* WGL_NV_video_capture */ 795 | 796 | #ifndef WGL_NV_video_output 797 | #define WGL_NV_video_output 1 798 | DECLARE_HANDLE(HPVIDEODEV); 799 | #define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 800 | #define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 801 | #define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 802 | #define WGL_VIDEO_OUT_COLOR_NV 0x20C3 803 | #define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 804 | #define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 805 | #define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 806 | #define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 807 | #define WGL_VIDEO_OUT_FRAME 0x20C8 808 | #define WGL_VIDEO_OUT_FIELD_1 0x20C9 809 | #define WGL_VIDEO_OUT_FIELD_2 0x20CA 810 | #define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB 811 | #define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC 812 | typedef BOOL(WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); 813 | typedef BOOL(WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice); 814 | typedef BOOL(WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); 815 | typedef BOOL(WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer); 816 | typedef BOOL(WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); 817 | typedef BOOL(WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); 818 | #ifdef WGL_WGLEXT_PROTOTYPES 819 | BOOL WINAPI wglGetVideoDeviceNV(HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); 820 | BOOL WINAPI wglReleaseVideoDeviceNV(HPVIDEODEV hVideoDevice); 821 | BOOL WINAPI wglBindVideoImageNV(HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); 822 | BOOL WINAPI wglReleaseVideoImageNV(HPBUFFERARB hPbuffer, int iVideoBuffer); 823 | BOOL WINAPI wglSendPbufferToVideoNV(HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); 824 | BOOL WINAPI wglGetVideoInfoNV(HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); 825 | #endif 826 | #endif /* WGL_NV_video_output */ 827 | 828 | #ifndef WGL_OML_sync_control 829 | #define WGL_OML_sync_control 1 830 | typedef BOOL(WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); 831 | typedef BOOL(WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); 832 | typedef INT64(WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); 833 | typedef INT64(WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); 834 | typedef BOOL(WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); 835 | typedef BOOL(WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); 836 | #ifdef WGL_WGLEXT_PROTOTYPES 837 | BOOL WINAPI wglGetSyncValuesOML(HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); 838 | BOOL WINAPI wglGetMscRateOML(HDC hdc, INT32 *numerator, INT32 *denominator); 839 | INT64 WINAPI wglSwapBuffersMscOML(HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); 840 | INT64 WINAPI wglSwapLayerBuffersMscOML(HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); 841 | BOOL WINAPI wglWaitForMscOML(HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); 842 | BOOL WINAPI wglWaitForSbcOML(HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); 843 | #endif 844 | #endif /* WGL_OML_sync_control */ 845 | 846 | #ifdef __cplusplus 847 | } 848 | #endif 849 | 850 | #endif -------------------------------------------------------------------------------- /utils/window.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "window.h" 3 | 4 | #ifndef _WIN32 5 | #include 6 | #endif 7 | 8 | void APIENTRY glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, void*) { 9 | 10 | // format the message nicely 11 | auto output = printf("OpenGL "); 12 | 13 | switch (type) { 14 | case GL_DEBUG_TYPE_ERROR: printf("error"); break; 15 | case GL_DEBUG_TYPE_PORTABILITY: printf("portability issue"); break; 16 | case GL_DEBUG_TYPE_PERFORMANCE: printf("performance issue"); break; 17 | case GL_DEBUG_TYPE_OTHER: printf("issue"); break; 18 | case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: printf("undefined behavior"); break; 19 | case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: printf("deprecated behavior"); break; 20 | default: printf("issue(?)"); break; 21 | } 22 | switch (source) { 23 | case GL_DEBUG_SOURCE_API: break; 24 | case GL_DEBUG_SOURCE_WINDOW_SYSTEM: printf(" in the window system"); break; 25 | case GL_DEBUG_SOURCE_SHADER_COMPILER: printf(" in the shader compiler"); break; 26 | case GL_DEBUG_SOURCE_THIRD_PARTY: printf(" in third party code"); break; 27 | case GL_DEBUG_SOURCE_APPLICATION: printf(" in this program"); break; 28 | case GL_DEBUG_SOURCE_OTHER: printf(" in an undefined source"); break; 29 | default: printf(" nowhere(?)"); break; 30 | } 31 | 32 | printf(", id %u:\n%.*s\n", id, length, message); 33 | // this is invaluable; you can directly see where any opengl error originated by checking the call stack at this breakpoint 34 | if (type == GL_DEBUG_TYPE_ERROR) 35 | #ifdef _WIN32 36 | __debugbreak(); 37 | #else 38 | raise(SIGTRAP); 39 | #endif 40 | } 41 | 42 | void setupDebug() { 43 | // enable debug output 44 | glEnable(GL_DEBUG_OUTPUT); 45 | // debug output from main thread: get the correct stack frame when breaking 46 | glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 47 | 48 | glDebugMessageCallback((GLDEBUGPROC)glDebugCallback, 0); 49 | 50 | // query everything about errors, deprecated and undefined things 51 | glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, 0, GL_TRUE); 52 | glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_TRUE); 53 | glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_TRUE); 54 | 55 | // disable misc info. might want to check these from time to time! 56 | glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE, 0, 0, GL_FALSE); 57 | glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE, GL_DONT_CARE, 0, 0, GL_FALSE); 58 | } 59 | 60 | #ifdef _WIN32 61 | 62 | #include "wglext.h" 63 | 64 | #pragma comment(lib, "opengl32.lib") 65 | 66 | const int GL_WINDOW_ATTRIBUTES[] = { 67 | WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, 68 | WGL_SUPPORT_OPENGL_ARB, GL_TRUE, 69 | WGL_DOUBLE_BUFFER_ARB, GL_TRUE, 70 | WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE, 71 | //WGL_SAMPLES_ARB, 8, // MSAA 72 | 73 | WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, 74 | WGL_COLOR_BITS_ARB, 32, 75 | WGL_DEPTH_BITS_ARB, 24, 76 | 0 }; 77 | 78 | const int GL_CONTEXT_ATTRIBUTES[] = { 79 | WGL_CONTEXT_MAJOR_VERSION_ARB, 4, 80 | WGL_CONTEXT_MINOR_VERSION_ARB, 6, 81 | WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 82 | //WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, 83 | 0 }; 84 | 85 | HWND wnd = nullptr; 86 | HDC dc; 87 | HGLRC rc; 88 | 89 | // update the frame onto screen 90 | void swapBuffers() { 91 | SwapBuffers(dc); 92 | } 93 | 94 | void setTitle(const char* title) { 95 | SetWindowTextA(wnd, title); 96 | } 97 | 98 | ivec2 getMouse() { 99 | POINT mouse; 100 | GetCursorPos(&mouse); 101 | ScreenToClient(wnd, &mouse); 102 | return ivec2(mouse.x, mouse.y); 103 | } 104 | 105 | void setMouse(ivec2 p) { 106 | POINT p_{ p.x, p.y }; 107 | ClientToScreen(wnd, &p_); 108 | SetCursorPos(p_.x, p_.y); 109 | } 110 | 111 | ivec2 windowSize() { 112 | RECT r; 113 | GetClientRect(wnd, &r); 114 | return { r.right - r.left, r.bottom - r.top }; 115 | } 116 | 117 | WPARAM down[256]; int downptr = 0; 118 | WPARAM hit[256]; int hitptr = 0; 119 | 120 | bool keyDown(uint vk_code) { 121 | for (int i = 0; i < downptr; ++i) 122 | if (vk_code == down[i]) 123 | return true; 124 | return false; 125 | } 126 | 127 | bool keyHit(uint vk_code) { 128 | for (int i = 0; i < hitptr; ++i) 129 | if (vk_code == hit[i]) 130 | return true; 131 | return false; 132 | } 133 | 134 | void resetHits() { 135 | hitptr = 0; 136 | } 137 | 138 | inline WPARAM mapExtended(WPARAM wParam, LPARAM lParam) { 139 | int ext = (lParam>>24)&1; 140 | switch(wParam) { 141 | case VK_SHIFT: return MapVirtualKeyEx((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX, GetKeyboardLayout(0)); 142 | case VK_CONTROL: return VK_LCONTROL+ext; 143 | case VK_MENU: return VK_LMENU+ext; 144 | case VK_RETURN: return VK_RETURN + ext*(VK_SEPARATOR-VK_RETURN); 145 | default: return wParam; 146 | } 147 | } 148 | 149 | LRESULT CALLBACK wndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 150 | switch (uMsg) { 151 | case WM_CLOSE: 152 | PostQuitMessage(0); 153 | return 0; 154 | case WM_SYSKEYDOWN: 155 | case WM_KEYDOWN: 156 | wParam = mapExtended(wParam, lParam); 157 | if (!keyDown((UINT)wParam)) 158 | down[downptr++] = hit[hitptr++] = wParam; // todo: if mapNarrowed(wParam)!=wParam: also add mapNarrowed() 159 | if (wParam == VK_ESCAPE) 160 | PostQuitMessage(0); 161 | return 0; 162 | case WM_SYSKEYUP: 163 | case WM_KEYUP: 164 | wParam = mapExtended(wParam, lParam); 165 | for (int i = 0; i < downptr - 1; ++i) // todo: if mapNarrowed(wParam)!=wParam: also remove mapNarrowed() 166 | if (wParam == down[i]) { 167 | down[i] = down[downptr-1]; 168 | break; 169 | } 170 | if (downptr > 0) downptr--; 171 | return 0; 172 | case WM_KILLFOCUS: 173 | // hitptr = downptr = 0; 174 | return 0; 175 | } 176 | return DefWindowProc(hwnd, uMsg, wParam, lParam); 177 | } 178 | 179 | bool loop() { 180 | hitptr = 0; 181 | MSG msg; 182 | bool result = true; 183 | while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { 184 | TranslateMessage(&msg); 185 | DispatchMessage(&msg); 186 | if (msg.message == WM_QUIT) { 187 | result = false; 188 | break; 189 | } 190 | } 191 | return result; 192 | } 193 | 194 | void setupGL(int width, int height, const char* title, bool fullscreen, bool show) { 195 | 196 | if (glOpen()) return; 197 | 198 | WNDCLASSEX windowClass = { 0 }; 199 | windowClass.cbSize = sizeof(windowClass); 200 | windowClass.hInstance = GetModuleHandle(nullptr); 201 | windowClass.lpszClassName = TEXT("classy class"); 202 | windowClass.hCursor = LoadCursor(nullptr, IDC_ARROW); 203 | windowClass.style = CS_OWNDC; 204 | windowClass.lpfnWndProc = wndProc; 205 | RegisterClassEx(&windowClass); 206 | 207 | PIXELFORMATDESCRIPTOR formatDesc = { 0 }; 208 | formatDesc.nVersion = 1; 209 | formatDesc.nSize = sizeof(formatDesc); 210 | formatDesc.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; 211 | formatDesc.iLayerType = PFD_MAIN_PLANE; 212 | formatDesc.iPixelType = PFD_TYPE_RGBA; 213 | formatDesc.cColorBits = 32; 214 | formatDesc.cDepthBits = 24; 215 | formatDesc.cStencilBits = 8; 216 | 217 | // create a temporary window to have a functional opengl context in order to get some extension function pointers 218 | HWND tempWnd = CreateWindow(TEXT("classy class"), TEXT("windy window"), WS_POPUP, 0, 0, width, height, nullptr, nullptr, GetModuleHandle(nullptr), nullptr); 219 | HDC tempDC = GetDC(tempWnd); 220 | SetPixelFormat(tempDC, ChoosePixelFormat(tempDC, &formatDesc), &formatDesc); 221 | HGLRC tempRC = wglCreateContext(tempDC); 222 | wglMakeCurrent(tempDC, tempRC); 223 | 224 | // these are why we made the temporary context; can set more pixel format attributes (multisample, floating point etc.) and create debug/core/etc contexts 225 | auto wglChoosePixelFormat = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); 226 | auto wglCreateContextAttribs = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); 227 | 228 | // adjust the window borders away, center the window 229 | RECT area = { 0, 0, width, height }; 230 | const DWORD style = (fullscreen ? WS_POPUP : (WS_SYSMENU|WS_CAPTION|WS_MINIMIZEBOX)) | ((fullscreen||show)?WS_VISIBLE:0); 231 | if (fullscreen) { 232 | DEVMODE mode = { 0 }; 233 | mode.dmSize = sizeof(mode); 234 | mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; 235 | mode.dmPelsWidth = width; mode.dmPelsHeight = height; 236 | mode.dmBitsPerPel = 32; 237 | ChangeDisplaySettings(&mode, CDS_FULLSCREEN); 238 | } 239 | 240 | AdjustWindowRect(&area, style, false); 241 | int adjustedWidth = fullscreen ? width : area.right - area.left, adjustedHeight = fullscreen ? height : area.bottom - area.top; 242 | int centerX = (GetSystemMetrics(SM_CXSCREEN) - adjustedWidth) / 2, centerY = (GetSystemMetrics(SM_CYSCREEN) - adjustedHeight) / 2; 243 | if (fullscreen) 244 | centerX = centerY = 0; 245 | 246 | // create the final window and context 247 | dc = GetDC(wnd = CreateWindowA("classy class", title, style, centerX, centerY, adjustedWidth, adjustedHeight, nullptr, nullptr, GetModuleHandle(nullptr), nullptr)); 248 | 249 | int format; UINT numFormats; 250 | wglChoosePixelFormat(dc, GL_WINDOW_ATTRIBUTES, nullptr, 1, &format, &numFormats); 251 | 252 | SetPixelFormat(dc, format, &formatDesc); 253 | 254 | rc = wglCreateContextAttribs(dc, 0, GL_CONTEXT_ATTRIBUTES); 255 | 256 | wglMakeCurrent(dc, rc); 257 | glViewport(0, 0, width, height); 258 | 259 | // release the temporary window and context 260 | wglDeleteContext(tempRC); 261 | ReleaseDC(tempWnd, tempDC); 262 | DestroyWindow(tempWnd); 263 | 264 | // what GL did we get? 265 | printf("gl %s\non %s\nby %s\nsl %s\n", glGetString(GL_VERSION), glGetString(GL_RENDERER), glGetString(GL_VENDOR), glGetString(GL_SHADING_LANGUAGE_VERSION)); 266 | 267 | loadgl(); 268 | 269 | setupDebug(); 270 | glEnable(GL_FRAMEBUFFER_SRGB); 271 | ((PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"))(-1); // freesync 272 | } 273 | 274 | #include 275 | void closeGL() { 276 | if (!glOpen()) return; 277 | 278 | // release context, window 279 | ChangeDisplaySettings(nullptr, CDS_FULLSCREEN); 280 | wglMakeCurrent(0, 0); 281 | wglDeleteContext(rc); 282 | ReleaseDC(wnd, dc); 283 | DestroyWindow(wnd); 284 | wnd = nullptr; 285 | UnregisterClass(TEXT("classy class"), GetModuleHandle(nullptr)); 286 | _CrtDumpMemoryLeaks(); 287 | } 288 | 289 | bool glOpen() { 290 | return wnd != nullptr; 291 | } 292 | 293 | void showWindow() { 294 | ShowWindow(wnd, SW_SHOW); 295 | } 296 | 297 | void hideWindow() { 298 | ShowWindow(wnd, SW_HIDE); 299 | } 300 | 301 | #else 302 | 303 | #ifdef HEADLESS 304 | #define EGL_NO_X11 305 | #define MESA_EGL_NO_X11_HEADERS 306 | #else 307 | #include 308 | Display* xdisplay = nullptr; 309 | Window xwindow; 310 | #endif 311 | 312 | #include 313 | #include 314 | 315 | #define GLAPIENTRY 316 | 317 | #include 318 | 319 | EGLDisplay display; 320 | EGLContext context; 321 | 322 | EGLSurface surface = EGL_NO_SURFACE; 323 | 324 | ivec2 windowsize{}; 325 | 326 | void setupGL(int width, int height, const char* title, bool fullscreen, bool show) { 327 | windowsize = ivec2(width, height); 328 | #ifndef HEADLESS 329 | xdisplay = XOpenDisplay(nullptr); 330 | XSetWindowAttributes window_attributes = {0}; 331 | window_attributes.event_mask = ExposureMask | PointerMotionMask | KeyPressMask; 332 | xwindow = XCreateWindow(xdisplay, DefaultRootWindow(xdisplay), 0, 0, width, height, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask, &window_attributes); 333 | XStoreName(xdisplay, xwindow, title); 334 | XMapWindow(xdisplay, xwindow); 335 | display = eglGetDisplay((EGLNativeDisplayType)xdisplay); 336 | #else 337 | display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 338 | #endif 339 | EGLint major, minor; 340 | eglInitialize(display, &major, &minor); 341 | const EGLint config_attributes[] = { 342 | EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, 343 | EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8, 344 | EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, 345 | #ifdef HEADLESS 346 | EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, 347 | #endif 348 | EGL_NONE 349 | }; 350 | 351 | eglBindAPI(EGL_OPENGL_API); 352 | 353 | EGLConfig config; EGLint configCount; 354 | eglChooseConfig(display, config_attributes, &config, 1, &configCount); 355 | 356 | const EGLint context_attributes[] = { 357 | EGL_CONTEXT_MAJOR_VERSION, 4, 358 | EGL_CONTEXT_MINOR_VERSION, 6, 359 | EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, 360 | EGL_NONE 361 | }; 362 | context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes); 363 | #ifndef HEADLESS 364 | EGLint surface_attributes[] = { 365 | EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR, 366 | EGL_RENDER_BUFFER, EGL_BACK_BUFFER, 367 | EGL_NONE 368 | }; 369 | surface = eglCreateWindowSurface(display, config, xwindow, surface_attributes); 370 | #else 371 | EGLint surface_attributes[] = { 372 | //EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR, 373 | //EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, 374 | //EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, 375 | EGL_WIDTH, width, EGL_HEIGHT, height, 376 | EGL_NONE 377 | }; 378 | surface = eglCreatePbufferSurface(display, config, surface_attributes); 379 | #endif 380 | eglMakeCurrent(display, surface, surface, context); 381 | loadgl(); 382 | 383 | setupDebug(); 384 | glEnable(GL_FRAMEBUFFER_SRGB); 385 | } 386 | void closeGL() { 387 | eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 388 | eglDestroySurface(display, surface); 389 | eglDestroyContext(display, context); 390 | eglTerminate(display); 391 | #ifndef HEADLESS 392 | XDestroyWindow(xdisplay, xwindow); 393 | XCloseDisplay(xdisplay); 394 | #endif 395 | } 396 | bool loop() { 397 | #ifdef HEADLESS 398 | return false; 399 | #else 400 | return true; 401 | #endif 402 | } 403 | bool glOpen() { 404 | return surface!=EGL_NO_SURFACE; 405 | } 406 | void swapBuffers() { 407 | //printf("oh lord is it this\n"); 408 | eglSwapBuffers(display, surface); 409 | } 410 | void setTitle(const char* title) {} 411 | void showWindow() {} 412 | void hideWindow() {} 413 | 414 | int down[256]; int downptr = 0; 415 | int hit[256]; int hitptr = 0; 416 | 417 | bool keyDown(uint vk_code) { 418 | for (int i = 0; i < downptr; ++i) 419 | if (vk_code == down[i]) 420 | return true; 421 | return false; 422 | } 423 | 424 | bool keyHit(uint vk_code) { 425 | for (int i = 0; i < hitptr; ++i) 426 | if (vk_code == hit[i]) 427 | return true; 428 | return false; 429 | } 430 | 431 | void resetHits() { 432 | hitptr = 0; 433 | } 434 | 435 | ivec2 getMouse() { return {};} 436 | void setMouse(ivec2) {} 437 | 438 | ivec2 windowSize() { 439 | return windowsize; 440 | } 441 | 442 | #endif 443 | -------------------------------------------------------------------------------- /utils/window.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #ifdef _WIN32 5 | 6 | #define VC_EXTRALEAN 7 | #define WIN32_LEAN_AND_MEAN 8 | #define NOMINMAX 9 | #include 10 | #endif 11 | #include 12 | 13 | #define GL_GLEXT_LEGACY 14 | #include 15 | #undef GL_VERSION_1_3 16 | #include "glext.h" 17 | #include "loadgl46.h" 18 | 19 | void setupGL(int width, int height, const char* title, bool fullscreen, bool show); 20 | void closeGL(); 21 | bool loop(); 22 | bool glOpen(); 23 | void swapBuffers(); 24 | void setTitle(const char* title); 25 | void showWindow(); 26 | void hideWindow(); 27 | 28 | #include "glsl.h" 29 | 30 | bool keyDown(uint vk_code); 31 | bool keyHit(uint vk_code); 32 | void resetHits(); 33 | 34 | ivec2 getMouse(); 35 | void setMouse(ivec2); 36 | 37 | ivec2 windowSize(); 38 | 39 | // todo: make this a true class? or use some kind of "finally" for the close? 40 | // possible reasoning: don't really want singleton, but don't really want to support multiple contexts either 41 | // why not just global functions: to be nice, we want to free all RAII objects before closing the GL context, so this has to be RAII as well 42 | struct OpenGL { 43 | OpenGL( 44 | int width, int height, 45 | const char* title = "", 46 | bool fullscreen = false, 47 | bool show = true) 48 | { 49 | if (glOpen()) return; 50 | isOwning = true; 51 | setupGL(width, height, title, fullscreen, show); 52 | } 53 | ~OpenGL() { 54 | if(isOwning) 55 | closeGL(); 56 | } 57 | bool isOwning = false; 58 | }; 59 | --------------------------------------------------------------------------------