1 /* 2 Copyright (c) 2019-2023 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 deprecated("import dagon.graphics.texture instead") module dagon.graphics.cubemap; 29 30 /* 31 class Cubemap: Texture 32 { 33 this(Owner o) 34 { 35 super(o); 36 } 37 38 this(uint resolution, Owner o) 39 { 40 super(o); 41 initialize(resolution); 42 } 43 44 ~this() 45 { 46 release(); 47 } 48 49 void initialize() 50 { 51 releaseGLTexture(); 52 53 glActiveTexture(GL_TEXTURE0); 54 55 glGenTextures(1, &tex); 56 glBindTexture(GL_TEXTURE_CUBE_MAP, tex); 57 58 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 59 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 60 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 61 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 62 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 63 64 glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 65 } 66 67 void initialize(uint resolution) 68 { 69 initialize(); 70 71 width = resolution; 72 height = resolution; 73 74 glBindTexture(GL_TEXTURE_CUBE_MAP, tex); 75 76 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA16F, resolution, resolution, 0, GL_RGBA, GL_FLOAT, null); 77 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA16F, resolution, resolution, 0, GL_RGBA, GL_FLOAT, null); 78 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA16F, resolution, resolution, 0, GL_RGBA, GL_FLOAT, null); 79 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA16F, resolution, resolution, 0, GL_RGBA, GL_FLOAT, null); 80 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA16F, resolution, resolution, 0, GL_RGBA, GL_FLOAT, null); 81 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA16F, resolution, resolution, 0, GL_RGBA, GL_FLOAT, null); 82 83 glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 84 } 85 86 void setFaceImage(CubeFace face, SuperImage img) 87 { 88 if (img.width != img.height) 89 { 90 writefln("Cubemap face image must be square"); 91 return; 92 } 93 94 width = img.width; 95 height = img.height; 96 97 TextureFormat tf; 98 if (detectTextureFormat(img, tf)) 99 { 100 format = tf.format; 101 intFormat = tf.internalFormat; 102 type = tf.pixelType; 103 104 glBindTexture(GL_TEXTURE_CUBE_MAP, tex); 105 if (tf.compressed) 106 { 107 uint size = ((width + 3) / 4) * ((height + 3) / 4) * tf.blockSize; 108 glCompressedTexImage2D(face, 0, intFormat, width, height, 0, size, cast(void*)img.data.ptr); 109 } 110 else 111 { 112 glTexImage2D(face, 0, intFormat, width, height, 0, format, type, cast(void*)img.data.ptr); 113 } 114 glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 115 } 116 else 117 { 118 writefln("Unsupported pixel format %s", img.pixelFormat); 119 } 120 } 121 122 void fromEquirectangularMap(Texture tex) 123 { 124 fromEquirectangularMap(tex.image); 125 } 126 127 void fromEquirectangularMap(SuperImage envmap) 128 { 129 SuperImage faceImage = envmap.createSameFormat(width, width); 130 131 foreach(i, face; EnumMembers!CubeFace) 132 { 133 Matrix4x4f dirTransform = cubeFaceMatrix(face); 134 135 foreach(x; 0..width) 136 foreach(y; 0..width) 137 { 138 float cubex = (cast(float)x / cast(float)width) * 2.0f - 1.0f; 139 float cubey = (1.0f - cast(float)y / cast(float)width) * 2.0f - 1.0f; 140 Vector3f dir = Vector3f(cubex, cubey, 1.0f).normalized * dirTransform; 141 Vector2f uv = equirectProj(dir); 142 Color4f c = bilinearPixel(envmap, uv.x * envmap.width, uv.y * envmap.height); 143 faceImage[x, y] = c; 144 } 145 146 setFaceImage(face, faceImage); 147 } 148 149 faceImage.free(); 150 } 151 152 void fromContainerImage(ContainerImage img) 153 { 154 initialize(); 155 156 if (!img.isCubemap) 157 { 158 writefln("Image is not a cubemap"); 159 return; 160 } 161 162 TextureFormat tf; 163 if (!detectTextureFormat(img, tf)) 164 { 165 writefln("Unsupported pixel format %s for a cubemap", img.pixelFormat); 166 return; 167 } 168 else if (tf.compressed) 169 { 170 writefln("Unsupported pixel format %s for a cubemap", img.pixelFormat); 171 return; 172 } 173 174 width = img.width; 175 height = img.height; 176 numMipmapLevels = img.mipLevels; 177 178 format = tf.format; 179 intFormat = tf.internalFormat; 180 type = tf.pixelType; 181 182 uint pSize = pixelSize(img.pixelFormat); 183 184 glBindTexture(GL_TEXTURE_CUBE_MAP, tex); 185 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); 186 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, numMipmapLevels - 1); 187 188 ubyte* data = img.data.ptr; 189 uint offset = 0; 190 191 foreach(face; EnumMembers!CubeFace) 192 { 193 uint w = width; 194 uint h = height; 195 for (uint i = 0; i < numMipmapLevels; i++) 196 { 197 uint size = w * h * pSize; 198 glTexImage2D(face, i, intFormat, w, h, 0, format, type, cast(void*)(data + offset)); 199 offset += size; 200 w /= 2; 201 h /= 2; 202 if (offset >= img.data.length) 203 { 204 writeln("Incomplete data"); 205 break; 206 } 207 } 208 } 209 210 glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 211 } 212 213 void fromImage(SuperImage img, uint resolution = 512) 214 { 215 ContainerImage cImage = cast(ContainerImage)img; 216 if (cImage) 217 { 218 fromContainerImage(cImage); 219 } 220 else 221 { 222 initialize(resolution); 223 fromEquirectangularMap(img); 224 } 225 } 226 227 override void bind() 228 { 229 if (glIsTexture(tex)) 230 { 231 glBindTexture(GL_TEXTURE_CUBE_MAP, tex); 232 233 if (!mipmapGenerated && useMipmapFiltering) 234 { 235 glGenerateMipmap(GL_TEXTURE_CUBE_MAP); 236 mipmapGenerated = true; 237 } 238 } 239 } 240 241 override void unbind() 242 { 243 glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 244 } 245 246 void invalidateMipmap() 247 { 248 mipmapGenerated = false; 249 } 250 } 251 252 uint pixelSize(uint pixelFormat) 253 { 254 uint s = 0; 255 switch(pixelFormat) 256 { 257 case ContainerImageFormat.R8: s = 1; break; 258 case ContainerImageFormat.RG8: s = 2; break; 259 case ContainerImageFormat.RGB8: s = 3; break; 260 case ContainerImageFormat.RGBA8: s = 4; break; 261 case ContainerImageFormat.RGBAF32: s = 16; break; 262 case ContainerImageFormat.RGBAF16: s = 8; break; 263 default: break; 264 } 265 return s; 266 } 267 */ 268