diff options
| -rw-r--r-- | gfx/include/gfx/render_backend.h | 1 | ||||
| -rw-r--r-- | gfx/src/render/texture.c | 24 | ||||
| -rw-r--r-- | gfx/src/util/ibl.c | 176 |
3 files changed, 109 insertions, 92 deletions
diff --git a/gfx/include/gfx/render_backend.h b/gfx/include/gfx/render_backend.h index 167cf8a..e037f78 100644 --- a/gfx/include/gfx/render_backend.h +++ b/gfx/include/gfx/render_backend.h | |||
| @@ -159,6 +159,7 @@ typedef enum { | |||
| 159 | TextureRG16, | 159 | TextureRG16, |
| 160 | TextureRG16F, | 160 | TextureRG16F, |
| 161 | TextureRGB8, | 161 | TextureRGB8, |
| 162 | TextureR11G11B10F, | ||
| 162 | TextureRGBA8, | 163 | TextureRGBA8, |
| 163 | TextureSRGB8, | 164 | TextureSRGB8, |
| 164 | TextureSRGBA8 | 165 | TextureSRGBA8 |
diff --git a/gfx/src/render/texture.c b/gfx/src/render/texture.c index 691f3f8..31bf636 100644 --- a/gfx/src/render/texture.c +++ b/gfx/src/render/texture.c | |||
| @@ -29,8 +29,8 @@ bool gfx_init_texture(Texture* texture, const TextureDesc* desc) { | |||
| 29 | switch (texture->target) { | 29 | switch (texture->target) { |
| 30 | case GL_TEXTURE_2D: | 30 | case GL_TEXTURE_2D: |
| 31 | case GL_TEXTURE_CUBE_MAP: | 31 | case GL_TEXTURE_CUBE_MAP: |
| 32 | glTexStorage2D(texture->target, levels, internal_format, desc->width, | 32 | glTexStorage2D( |
| 33 | desc->height); | 33 | texture->target, levels, internal_format, desc->width, desc->height); |
| 34 | break; | 34 | break; |
| 35 | default: | 35 | default: |
| 36 | assert(false && "Unhandled texture dimension"); | 36 | assert(false && "Unhandled texture dimension"); |
| @@ -40,13 +40,13 @@ bool gfx_init_texture(Texture* texture, const TextureDesc* desc) { | |||
| 40 | 40 | ||
| 41 | // glTexSubImageXD | 41 | // glTexSubImageXD |
| 42 | const GLenum format = to_GL_format(desc->format); | 42 | const GLenum format = to_GL_format(desc->format); |
| 43 | const GLenum type = to_GL_type(desc->format); | 43 | const GLenum type = to_GL_type(desc->format); |
| 44 | switch (texture->target) { | 44 | switch (texture->target) { |
| 45 | case GL_TEXTURE_2D: | 45 | case GL_TEXTURE_2D: |
| 46 | if (desc->pixels) { | 46 | if (desc->pixels) { |
| 47 | glTexSubImage2D(GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/0, | 47 | glTexSubImage2D( |
| 48 | /*yoffset=*/0, desc->width, desc->height, format, type, | 48 | GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/0, |
| 49 | desc->pixels); | 49 | /*yoffset=*/0, desc->width, desc->height, format, type, desc->pixels); |
| 50 | } | 50 | } |
| 51 | break; | 51 | break; |
| 52 | case GL_TEXTURE_CUBE_MAP: | 52 | case GL_TEXTURE_CUBE_MAP: |
| @@ -72,10 +72,10 @@ bool gfx_init_texture(Texture* texture, const TextureDesc* desc) { | |||
| 72 | 72 | ||
| 73 | // Texture filtering. | 73 | // Texture filtering. |
| 74 | const bool linear = desc->filtering == LinearFiltering; | 74 | const bool linear = desc->filtering == LinearFiltering; |
| 75 | GLenum min = desc->mipmaps ? (linear ? GL_LINEAR_MIPMAP_LINEAR | 75 | GLenum min = desc->mipmaps ? (linear ? GL_LINEAR_MIPMAP_LINEAR |
| 76 | : GL_NEAREST_MIPMAP_NEAREST) | 76 | : GL_NEAREST_MIPMAP_NEAREST) |
| 77 | : (linear ? GL_LINEAR : GL_NEAREST); | 77 | : (linear ? GL_LINEAR : GL_NEAREST); |
| 78 | GLenum mag = linear ? GL_LINEAR : GL_NEAREST; | 78 | GLenum mag = linear ? GL_LINEAR : GL_NEAREST; |
| 79 | glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, min); | 79 | glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, min); |
| 80 | glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, mag); | 80 | glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, mag); |
| 81 | 81 | ||
| @@ -126,6 +126,8 @@ GLenum to_GL_internal_format(TextureFormat format) { | |||
| 126 | return GL_RG16F; | 126 | return GL_RG16F; |
| 127 | case TextureRGB8: | 127 | case TextureRGB8: |
| 128 | return GL_RGB8; | 128 | return GL_RGB8; |
| 129 | case TextureR11G11B10F: | ||
| 130 | return GL_R11F_G11F_B10F; | ||
| 129 | case TextureRGBA8: | 131 | case TextureRGBA8: |
| 130 | return GL_RGBA8; | 132 | return GL_RGBA8; |
| 131 | case TextureSRGB8: | 133 | case TextureSRGB8: |
| @@ -146,6 +148,7 @@ GLenum to_GL_format(TextureFormat format) { | |||
| 146 | case TextureRG16F: | 148 | case TextureRG16F: |
| 147 | return GL_RG; | 149 | return GL_RG; |
| 148 | case TextureRGB8: | 150 | case TextureRGB8: |
| 151 | case TextureR11G11B10F: | ||
| 149 | case TextureSRGB8: | 152 | case TextureSRGB8: |
| 150 | return GL_RGB; | 153 | return GL_RGB; |
| 151 | case TextureRGBA8: | 154 | case TextureRGBA8: |
| @@ -161,6 +164,7 @@ GLenum to_GL_type(TextureFormat format) { | |||
| 161 | switch (format) { | 164 | switch (format) { |
| 162 | case TextureDepth: | 165 | case TextureDepth: |
| 163 | case TextureRG16F: | 166 | case TextureRG16F: |
| 167 | case TextureR11G11B10F: | ||
| 164 | return GL_FLOAT; | 168 | return GL_FLOAT; |
| 165 | case TextureRG16: | 169 | case TextureRG16: |
| 166 | case TextureRGB8: | 170 | case TextureRGB8: |
diff --git a/gfx/src/util/ibl.c b/gfx/src/util/ibl.c index 704cf08..c9bef43 100644 --- a/gfx/src/util/ibl.c +++ b/gfx/src/util/ibl.c | |||
| @@ -9,13 +9,13 @@ | |||
| 9 | #include <stdlib.h> | 9 | #include <stdlib.h> |
| 10 | 10 | ||
| 11 | typedef struct IBL { | 11 | typedef struct IBL { |
| 12 | Geometry* quad; | 12 | Geometry* quad; |
| 13 | ShaderProgram* brdf_integration_map_shader; | 13 | ShaderProgram* brdf_integration_map_shader; |
| 14 | ShaderProgram* irradiance_map_shader; | 14 | ShaderProgram* irradiance_map_shader; |
| 15 | ShaderProgram* prefiltered_environment_map_shader; | 15 | ShaderProgram* prefiltered_environment_map_shader; |
| 16 | Texture* brdf_integration_map; | 16 | Texture* brdf_integration_map; |
| 17 | FrameBuffer* framebuffer; | 17 | FrameBuffer* framebuffer; |
| 18 | mat4 rotations[6]; | 18 | mat4 rotations[6]; |
| 19 | } IBL; | 19 | } IBL; |
| 20 | 20 | ||
| 21 | static const CubemapFace faces[6] = { | 21 | static const CubemapFace faces[6] = { |
| @@ -71,29 +71,35 @@ IBL* gfx_make_ibl(RenderBackend* render_backend) { | |||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | // Right. | 73 | // Right. |
| 74 | ibl->rotations[0] = mat4_lookat(/*position=*/vec3_make(0, 0, 0), | 74 | ibl->rotations[0] = mat4_lookat( |
| 75 | /*target=*/vec3_make(1, 0, 0), | 75 | /*position=*/vec3_make(0, 0, 0), |
| 76 | /*up=*/vec3_make(0, 1, 0)); | 76 | /*target=*/vec3_make(1, 0, 0), |
| 77 | /*up=*/vec3_make(0, 1, 0)); | ||
| 77 | // Left. | 78 | // Left. |
| 78 | ibl->rotations[1] = mat4_lookat(/*position=*/vec3_make(0, 0, 0), | 79 | ibl->rotations[1] = mat4_lookat( |
| 79 | /*target=*/vec3_make(-1, 0, 0), | 80 | /*position=*/vec3_make(0, 0, 0), |
| 80 | /*up=*/vec3_make(0, 1, 0)); | 81 | /*target=*/vec3_make(-1, 0, 0), |
| 82 | /*up=*/vec3_make(0, 1, 0)); | ||
| 81 | // Up. | 83 | // Up. |
| 82 | ibl->rotations[2] = mat4_lookat(/*position=*/vec3_make(0, 0, 0), | 84 | ibl->rotations[2] = mat4_lookat( |
| 83 | /*target=*/vec3_make(0, 1, 0), | 85 | /*position=*/vec3_make(0, 0, 0), |
| 84 | /*up=*/vec3_make(0, 0, 1)); | 86 | /*target=*/vec3_make(0, 1, 0), |
| 87 | /*up=*/vec3_make(0, 0, 1)); | ||
| 85 | // Down. | 88 | // Down. |
| 86 | ibl->rotations[3] = mat4_lookat(/*position=*/vec3_make(0, 0, 0), | 89 | ibl->rotations[3] = mat4_lookat( |
| 87 | /*target=*/vec3_make(0, -1, 0), | 90 | /*position=*/vec3_make(0, 0, 0), |
| 88 | /*up=*/vec3_make(0, 0, -1)); | 91 | /*target=*/vec3_make(0, -1, 0), |
| 92 | /*up=*/vec3_make(0, 0, -1)); | ||
| 89 | // Back. | 93 | // Back. |
| 90 | ibl->rotations[4] = mat4_lookat(/*position=*/vec3_make(0, 0, 0), | 94 | ibl->rotations[4] = mat4_lookat( |
| 91 | /*target=*/vec3_make(0, 0, 1), | 95 | /*position=*/vec3_make(0, 0, 0), |
| 92 | /*up=*/vec3_make(0, 1, 0)); | 96 | /*target=*/vec3_make(0, 0, 1), |
| 97 | /*up=*/vec3_make(0, 1, 0)); | ||
| 93 | // Forward. | 98 | // Forward. |
| 94 | ibl->rotations[5] = mat4_lookat(/*position=*/vec3_make(0, 0, 0), | 99 | ibl->rotations[5] = mat4_lookat( |
| 95 | /*target=*/vec3_make(0, 0, -1), | 100 | /*position=*/vec3_make(0, 0, 0), |
| 96 | /*up=*/vec3_make(0, 1, 0)); | 101 | /*target=*/vec3_make(0, 0, -1), |
| 102 | /*up=*/vec3_make(0, 1, 0)); | ||
| 97 | 103 | ||
| 98 | return ibl; | 104 | return ibl; |
| 99 | 105 | ||
| @@ -110,15 +116,15 @@ void gfx_destroy_ibl(RenderBackend* render_backend, IBL** ibl) { | |||
| 110 | gfx_destroy_geometry(render_backend, &(*ibl)->quad); | 116 | gfx_destroy_geometry(render_backend, &(*ibl)->quad); |
| 111 | } | 117 | } |
| 112 | if ((*ibl)->brdf_integration_map_shader) { | 118 | if ((*ibl)->brdf_integration_map_shader) { |
| 113 | gfx_destroy_shader_program(render_backend, | 119 | gfx_destroy_shader_program( |
| 114 | &(*ibl)->brdf_integration_map_shader); | 120 | render_backend, &(*ibl)->brdf_integration_map_shader); |
| 115 | } | 121 | } |
| 116 | if ((*ibl)->irradiance_map_shader) { | 122 | if ((*ibl)->irradiance_map_shader) { |
| 117 | gfx_destroy_shader_program(render_backend, &(*ibl)->irradiance_map_shader); | 123 | gfx_destroy_shader_program(render_backend, &(*ibl)->irradiance_map_shader); |
| 118 | } | 124 | } |
| 119 | if ((*ibl)->prefiltered_environment_map_shader) { | 125 | if ((*ibl)->prefiltered_environment_map_shader) { |
| 120 | gfx_destroy_shader_program(render_backend, | 126 | gfx_destroy_shader_program( |
| 121 | &(*ibl)->prefiltered_environment_map_shader); | 127 | render_backend, &(*ibl)->prefiltered_environment_map_shader); |
| 122 | } | 128 | } |
| 123 | if ((*ibl)->brdf_integration_map) { | 129 | if ((*ibl)->brdf_integration_map) { |
| 124 | gfx_destroy_texture(render_backend, &(*ibl)->brdf_integration_map); | 130 | gfx_destroy_texture(render_backend, &(*ibl)->brdf_integration_map); |
| @@ -130,8 +136,8 @@ void gfx_destroy_ibl(RenderBackend* render_backend, IBL** ibl) { | |||
| 130 | *ibl = 0; | 136 | *ibl = 0; |
| 131 | } | 137 | } |
| 132 | 138 | ||
| 133 | Texture* gfx_make_brdf_integration_map(IBL* ibl, RenderBackend* render_backend, | 139 | Texture* gfx_make_brdf_integration_map( |
| 134 | int width, int height) { | 140 | IBL* ibl, RenderBackend* render_backend, int width, int height) { |
| 135 | assert(ibl); | 141 | assert(ibl); |
| 136 | assert(render_backend); | 142 | assert(render_backend); |
| 137 | 143 | ||
| @@ -142,14 +148,15 @@ Texture* gfx_make_brdf_integration_map(IBL* ibl, RenderBackend* render_backend, | |||
| 142 | bool success = false; | 148 | bool success = false; |
| 143 | 149 | ||
| 144 | if (!(ibl->brdf_integration_map = gfx_make_texture( | 150 | if (!(ibl->brdf_integration_map = gfx_make_texture( |
| 145 | render_backend, &(TextureDesc){.width = width, | 151 | render_backend, &(TextureDesc){ |
| 146 | .height = height, | 152 | .width = width, |
| 147 | .depth = 1, | 153 | .height = height, |
| 148 | .dimension = Texture2D, | 154 | .depth = 1, |
| 149 | .format = TextureRG16, | 155 | .dimension = Texture2D, |
| 150 | .filtering = LinearFiltering, | 156 | .format = TextureRG16F, |
| 151 | .wrap = ClampToEdge, | 157 | .filtering = LinearFiltering, |
| 152 | .mipmaps = false}))) { | 158 | .wrap = ClampToEdge, |
| 159 | .mipmaps = false}))) { | ||
| 153 | goto cleanup; | 160 | goto cleanup; |
| 154 | } | 161 | } |
| 155 | 162 | ||
| @@ -157,10 +164,10 @@ Texture* gfx_make_brdf_integration_map(IBL* ibl, RenderBackend* render_backend, | |||
| 157 | gfx_framebuffer_set_viewport(ibl->framebuffer, 0, 0, width, height); | 164 | gfx_framebuffer_set_viewport(ibl->framebuffer, 0, 0, width, height); |
| 158 | gfx_activate_shader_program(ibl->brdf_integration_map_shader); | 165 | gfx_activate_shader_program(ibl->brdf_integration_map_shader); |
| 159 | if (!gfx_framebuffer_attach_colour( | 166 | if (!gfx_framebuffer_attach_colour( |
| 160 | ibl->framebuffer, | 167 | ibl->framebuffer, &(FrameBufferAttachment){ |
| 161 | &(FrameBufferAttachment){.type = FrameBufferTexture, | 168 | .type = FrameBufferTexture, |
| 162 | .texture.texture = ibl->brdf_integration_map, | 169 | .texture.texture = ibl->brdf_integration_map, |
| 163 | .texture.mip_level = 0})) { | 170 | .texture.mip_level = 0})) { |
| 164 | goto cleanup; | 171 | goto cleanup; |
| 165 | } | 172 | } |
| 166 | gfx_render_geometry(ibl->quad); | 173 | gfx_render_geometry(ibl->quad); |
| @@ -178,27 +185,32 @@ cleanup: | |||
| 178 | } | 185 | } |
| 179 | } | 186 | } |
| 180 | 187 | ||
| 181 | Texture* gfx_make_irradiance_map(IBL* ibl, RenderBackend* render_backend, | 188 | Texture* gfx_make_irradiance_map( |
| 182 | const Texture* environment_map, int width, | 189 | IBL* ibl, RenderBackend* render_backend, const Texture* environment_map, |
| 183 | int height) { | 190 | int width, int height) { |
| 184 | assert(ibl); | 191 | assert(ibl); |
| 185 | assert(render_backend); | 192 | assert(render_backend); |
| 186 | assert(environment_map); | 193 | assert(environment_map); |
| 187 | 194 | ||
| 188 | Texture* irradiance_map = 0; | ||
| 189 | bool success = false; | 195 | bool success = false; |
| 190 | 196 | ||
| 197 | Texture* irradiance_map = 0; | ||
| 198 | |||
| 191 | // TODO: Could define colour-renderable texture formats separately to make | 199 | // TODO: Could define colour-renderable texture formats separately to make |
| 192 | // framebuffer creation less error-prone. Or, at the very least, validate the | 200 | // framebuffer creation less error-prone. Or, at the very least, validate the |
| 193 | // choice at runtime. | 201 | // choice at runtime. |
| 202 | // | ||
| 203 | // Make sure to use a float colour format to avoid [0,1] clamping when the | ||
| 204 | // irradiance values are computed! | ||
| 194 | if (!(irradiance_map = gfx_make_texture( | 205 | if (!(irradiance_map = gfx_make_texture( |
| 195 | render_backend, &(TextureDesc){.width = width, | 206 | render_backend, &(TextureDesc){ |
| 196 | .height = height, | 207 | .width = width, |
| 197 | .depth = 1, | 208 | .height = height, |
| 198 | .dimension = TextureCubeMap, | 209 | .depth = 1, |
| 199 | .format = TextureRGBA8, | 210 | .dimension = TextureCubeMap, |
| 200 | .filtering = NearestFiltering, | 211 | .format = TextureR11G11B10F, |
| 201 | .mipmaps = false}))) { | 212 | .filtering = LinearFiltering, |
| 213 | .mipmaps = false}))) { | ||
| 202 | goto cleanup; | 214 | goto cleanup; |
| 203 | } | 215 | } |
| 204 | 216 | ||
| @@ -208,14 +220,14 @@ Texture* gfx_make_irradiance_map(IBL* ibl, RenderBackend* render_backend, | |||
| 208 | gfx_set_texture_uniform(ibl->irradiance_map_shader, "Sky", environment_map); | 220 | gfx_set_texture_uniform(ibl->irradiance_map_shader, "Sky", environment_map); |
| 209 | for (int i = 0; i < 6; ++i) { | 221 | for (int i = 0; i < 6; ++i) { |
| 210 | if (!gfx_framebuffer_attach_colour( | 222 | if (!gfx_framebuffer_attach_colour( |
| 211 | ibl->framebuffer, | 223 | ibl->framebuffer, &(FrameBufferAttachment){ |
| 212 | &(FrameBufferAttachment){.type = FrameBufferCubemapTexture, | 224 | .type = FrameBufferCubemapTexture, |
| 213 | .cubemap.face = faces[i], | 225 | .cubemap.face = faces[i], |
| 214 | .cubemap.texture = irradiance_map})) { | 226 | .cubemap.texture = irradiance_map})) { |
| 215 | goto cleanup; | 227 | goto cleanup; |
| 216 | } | 228 | } |
| 217 | gfx_set_mat4_uniform(ibl->irradiance_map_shader, "Modelview", | 229 | gfx_set_mat4_uniform( |
| 218 | &ibl->rotations[i]); | 230 | ibl->irradiance_map_shader, "Modelview", &ibl->rotations[i]); |
| 219 | gfx_apply_uniforms(ibl->irradiance_map_shader); | 231 | gfx_apply_uniforms(ibl->irradiance_map_shader); |
| 220 | gfx_render_geometry(ibl->quad); | 232 | gfx_render_geometry(ibl->quad); |
| 221 | } | 233 | } |
| @@ -233,62 +245,62 @@ cleanup: | |||
| 233 | } | 245 | } |
| 234 | } | 246 | } |
| 235 | 247 | ||
| 236 | Texture* gfx_make_prefiltered_environment_map(IBL* ibl, | 248 | Texture* gfx_make_prefiltered_environment_map( |
| 237 | RenderBackend* render_backend, | 249 | IBL* ibl, RenderBackend* render_backend, const Texture* environment_map, |
| 238 | const Texture* environment_map, | 250 | int width, int height, int* max_mip_level) { |
| 239 | int width, int height, | ||
| 240 | int* max_mip_level) { | ||
| 241 | assert(ibl); | 251 | assert(ibl); |
| 242 | assert(render_backend); | 252 | assert(render_backend); |
| 243 | assert(environment_map); | 253 | assert(environment_map); |
| 244 | assert(max_mip_level); | 254 | assert(max_mip_level); |
| 245 | 255 | ||
| 246 | Texture* prefiltered_env_map = 0; | ||
| 247 | bool success = false; | 256 | bool success = false; |
| 248 | 257 | ||
| 249 | // TODO: Use 16 bits for more precision and a floating-point format, e.g. | 258 | Texture* prefiltered_env_map = 0; |
| 250 | // RGB16F. | 259 | |
| 251 | if (!(prefiltered_env_map = gfx_make_texture( | 260 | if (!(prefiltered_env_map = gfx_make_texture( |
| 252 | render_backend, &(TextureDesc){.width = width, | 261 | render_backend, &(TextureDesc){ |
| 253 | .height = height, | 262 | .width = width, |
| 254 | .depth = 1, | 263 | .height = height, |
| 255 | .dimension = TextureCubeMap, | 264 | .depth = 1, |
| 256 | .format = TextureRGBA8, | 265 | .dimension = TextureCubeMap, |
| 257 | .filtering = LinearFiltering, | 266 | .format = TextureR11G11B10F, |
| 258 | .mipmaps = true}))) { | 267 | .filtering = LinearFiltering, |
| 268 | .mipmaps = true}))) { | ||
| 259 | goto cleanup; | 269 | goto cleanup; |
| 260 | } | 270 | } |
| 261 | 271 | ||
| 262 | gfx_activate_framebuffer(ibl->framebuffer); | 272 | gfx_activate_framebuffer(ibl->framebuffer); |
| 263 | gfx_activate_shader_program(ibl->prefiltered_environment_map_shader); | 273 | gfx_activate_shader_program(ibl->prefiltered_environment_map_shader); |
| 264 | gfx_set_texture_uniform(ibl->prefiltered_environment_map_shader, "Sky", | 274 | gfx_set_texture_uniform( |
| 265 | environment_map); | 275 | ibl->prefiltered_environment_map_shader, "Sky", environment_map); |
| 266 | const int max_mip = (int)(rlog2(min(width, height))); | 276 | const int max_mip = (int)(rlog2(min(width, height))); |
| 267 | for (int mip = 0; mip <= max_mip; ++mip) { | 277 | for (int mip = 0; mip <= max_mip; ++mip) { |
| 268 | const int mip_width = width >> mip; | 278 | const int mip_width = width >> mip; |
| 269 | const int mip_height = height >> mip; | 279 | const int mip_height = height >> mip; |
| 270 | const float roughness = (float)mip / (float)(max_mip); | 280 | const float roughness = (float)mip / (float)(max_mip); |
| 271 | gfx_framebuffer_set_viewport(ibl->framebuffer, 0, 0, mip_width, mip_height); | 281 | gfx_framebuffer_set_viewport(ibl->framebuffer, 0, 0, mip_width, mip_height); |
| 272 | gfx_set_float_uniform(ibl->prefiltered_environment_map_shader, "Roughness", | 282 | gfx_set_float_uniform( |
| 273 | roughness); | 283 | ibl->prefiltered_environment_map_shader, "Roughness", roughness); |
| 274 | 284 | ||
| 275 | for (int i = 0; i < 6; ++i) { | 285 | for (int i = 0; i < 6; ++i) { |
| 276 | if (!gfx_framebuffer_attach_colour( | 286 | if (!gfx_framebuffer_attach_colour( |
| 277 | ibl->framebuffer, &(FrameBufferAttachment){ | 287 | ibl->framebuffer, &(FrameBufferAttachment){ |
| 278 | .type = FrameBufferCubemapTexture, | 288 | .type = FrameBufferCubemapTexture, |
| 279 | .cubemap.face = faces[i], | 289 | .cubemap.face = faces[i], |
| 280 | .cubemap.mip_level = mip, | 290 | .cubemap.mip_level = mip, |
| 281 | .cubemap.texture = prefiltered_env_map})) { | 291 | .cubemap.texture = prefiltered_env_map})) { |
| 282 | goto cleanup; | 292 | goto cleanup; |
| 283 | } | 293 | } |
| 284 | gfx_set_mat4_uniform(ibl->prefiltered_environment_map_shader, "Modelview", | 294 | gfx_set_mat4_uniform( |
| 285 | &ibl->rotations[i]); | 295 | ibl->prefiltered_environment_map_shader, "Modelview", |
| 296 | &ibl->rotations[i]); | ||
| 286 | gfx_apply_uniforms(ibl->prefiltered_environment_map_shader); | 297 | gfx_apply_uniforms(ibl->prefiltered_environment_map_shader); |
| 287 | gfx_render_geometry(ibl->quad); | 298 | gfx_render_geometry(ibl->quad); |
| 288 | } | 299 | } |
| 289 | } | 300 | } |
| 290 | 301 | ||
| 291 | *max_mip_level = max_mip; | 302 | *max_mip_level = max_mip; |
| 303 | |||
| 292 | success = true; | 304 | success = true; |
| 293 | 305 | ||
| 294 | cleanup: | 306 | cleanup: |
