11#include " texture.h"
22
3- #include < unordered_map>
43#define STB_IMAGE_IMPLEMENTATION
54#include < stb_image.h>
65
@@ -44,7 +43,7 @@ namespace Resource::Loading {
4443 return ImageData{width, height, channelCount, imgData};
4544 }
4645
47- GLint getChannelCount (const int channelCount) {
46+ GLint getGLChannels (const int channelCount) {
4847 switch (channelCount) {
4948 case 1 : return GL_RED;
5049 case 3 : return GL_RGB;
@@ -57,7 +56,7 @@ namespace Resource::Loading {
5756 }
5857
5958 std::expected<unsigned int , Error> loadTexture (const ImageData& imgData) {
60- const GLint format = getChannelCount (imgData.channelCount );
59+ const GLint format = getGLChannels (imgData.channelCount );
6160
6261 unsigned int textureID;
6362 glGenTextures (1 , &textureID);
@@ -96,37 +95,162 @@ namespace Resource::Loading {
9695 return texture;
9796 }
9897
99- std::expected<unsigned int , Error> loadCubeMap (const std::string& filePath) {
98+ constexpr std::array<std::string, 6 > cubemapFaces = {" right" , " left" , " top" , " bottom" , " front" , " back" };
99+
100+ std::expected<unsigned int , Error> loadCubemap (const std::string& filePath) {
100101 unsigned int textureID;
101102 glGenTextures (1 , &textureID);
102103 glBindTexture (GL_TEXTURE_CUBE_MAP, textureID);
103104
104- const std::pmr::unordered_map<GLint, std::string> dirMap = {
105- {GL_TEXTURE_CUBE_MAP_POSITIVE_X, " right" },
106- {GL_TEXTURE_CUBE_MAP_NEGATIVE_X, " left" },
107- {GL_TEXTURE_CUBE_MAP_POSITIVE_Y, " top" },
108- {GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, " bottom" },
109- {GL_TEXTURE_CUBE_MAP_POSITIVE_Z, " front" },
110- {GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, " back" }
111- };
112-
113105 const auto extension_index = filePath.find_last_of (' .' );
106+ const auto pathPrefix = filePath.substr (0 , extension_index) + " _" ;
107+
108+ ImageData firstData = {};
114109 for (int i = 0 ; i < 6 ; i++) {
110+ const std::string path = pathPrefix + cubemapFaces[i] + filePath.substr (extension_index);
111+
112+ Expected<ImageData> imgData = loadImage (path.c_str ());
113+ if (!imgData) {
114+ glDeleteTextures (1 , &textureID);
115+ return std::unexpected (FW_ERROR (imgData.error (), " Failed to load cubemap texture" ));
116+ }
117+ if (imgData->width != imgData->height ) {
118+ glDeleteTextures (1 , &textureID);
119+ stbi_image_free (imgData->imgData );
120+ return std::unexpected (ERROR (" Cubemap texture must be square" ));
121+ }
122+ if (i == 0 )
123+ firstData = imgData.value ();
124+ else if (imgData->width != firstData.width || imgData->channelCount != firstData.channelCount ) {
125+ glDeleteTextures (1 , &textureID);
126+ stbi_image_free (imgData->imgData );
127+ return std::unexpected (ERROR (" Cubemap texture faces must have the same dimensions and channel counts" ));
128+ }
129+ SPDLOG_DEBUG (" Loaded cubemap %s texture \" %s\" with dimensions %dx%d" ,
130+ cubemapFaces[i].c_str (), path.c_str (), imgData->width , imgData->height );
131+
115132 const GLint faceDir = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
133+ assert (faceDir >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceDir <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
134+
135+ const GLint format = getGLChannels (imgData->channelCount );
136+ glTexImage2D (faceDir,
137+ 0 , format, imgData->width , imgData->height , 0 , format, GL_UNSIGNED_BYTE, imgData->imgData );
138+ stbi_image_free (imgData->imgData );
139+ }
140+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
141+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
142+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
143+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
144+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
116145
117- const auto path = filePath.substr (0 , extension_index) + " _" + dirMap.at (faceDir) + filePath.substr (extension_index);
146+ return textureID;
147+ }
148+ std::expected<unsigned int , Error> loadCubemap (const std::array<const unsigned char *, 6 >& data, const std::array<int , 6 >& sizes)
149+ {
150+ unsigned int textureID;
151+ glGenTextures (1 , &textureID);
152+ glBindTexture (GL_TEXTURE_CUBE_MAP, textureID);
118153
119- Expected<ImageData> imgData = loadImage (path.c_str ());
154+ ImageData firstData = {};
155+ for (int i = 0 ; i < 6 ; i++) {
156+ Expected<ImageData> imgData = loadImageMemory (data[i], sizes[i]);
120157 if (!imgData) {
121158 glDeleteTextures (1 , &textureID);
122159 return std::unexpected (FW_ERROR (imgData.error (), " Failed to load cubemap texture" ));
123160 }
124- SPDLOG_DEBUG (" Loaded cubemap %s texture \" %s\" with dimensions %dx%d" , dirMap.at (faceDir).c_str (), path.c_str (), imgData->width , imgData->height );
161+ if (imgData->width != imgData->height ) {
162+ glDeleteTextures (1 , &textureID);
163+ stbi_image_free (imgData->imgData );
164+ return std::unexpected (ERROR (" Cubemap texture must be square" ));
165+ }
166+ if (i == 0 )
167+ firstData = imgData.value ();
168+ else if (imgData->width != firstData.width || imgData->channelCount != firstData.channelCount ) {
169+ glDeleteTextures (1 , &textureID);
170+ stbi_image_free (imgData->imgData );
171+ return std::unexpected (ERROR (" Cubemap texture faces must have the same dimensions and channel counts" ));
172+ }
173+ SPDLOG_DEBUG (" Loaded cubemap %d texture with dimensions %dx%d" ,
174+ cubemapFaces[i].c_str (), imgData->width , imgData->height );
175+
176+ const GLint faceDir = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
177+ assert (faceDir >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceDir <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
178+
179+ const GLint format = getGLChannels (imgData->channelCount );
180+ glTexImage2D (faceDir,
181+ 0 , format, imgData->width , imgData->height , 0 , format, GL_UNSIGNED_BYTE, imgData->imgData );
182+ stbi_image_free (imgData->imgData );
183+ }
184+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
185+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
186+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
187+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
188+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
189+
190+ return textureID;
191+ }
192+
193+ std::expected<unsigned int , Error> loadCubemapSingle (const std::string& filePath)
194+ {
195+ unsigned int textureID;
196+ glGenTextures (1 , &textureID);
197+ glBindTexture (GL_TEXTURE_CUBE_MAP, textureID);
198+
199+ Expected<ImageData> imgData = loadImage (filePath.c_str ());
200+ if (!imgData) {
201+ glDeleteTextures (1 , &textureID);
202+ return std::unexpected (FW_ERROR (imgData.error (), " Failed to load cubemap texture" ));
203+ }
204+ if (imgData->width != imgData->height ) {
205+ glDeleteTextures (1 , &textureID);
206+ stbi_image_free (imgData->imgData );
207+ return std::unexpected (ERROR (" Cubemap texture must be square" ));
208+ }
209+
210+ const GLint format = getGLChannels (imgData->channelCount );
211+ for (int i = 0 ; i < 6 ; i++) {
212+ const GLint faceDir = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
213+ assert (faceDir >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceDir <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
214+ glTexImage2D (faceDir,
215+ 0 , format, imgData->width , imgData->height , 0 , format, GL_UNSIGNED_BYTE, imgData->imgData );
216+ }
217+ stbi_image_free (imgData->imgData );
218+
219+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
220+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
221+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
222+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
223+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
224+
225+ return textureID;
226+ }
227+
228+ std::expected<unsigned int , Error> loadCubemapSingle (const unsigned char * data, int size)
229+ {
230+ unsigned int textureID;
231+ glGenTextures (1 , &textureID);
232+ glBindTexture (GL_TEXTURE_CUBE_MAP, textureID);
125233
126- const GLint format = getChannelCount (imgData->channelCount );
234+ Expected<ImageData> imgData = loadImageMemory (data, size);
235+ if (!imgData) {
236+ glDeleteTextures (1 , &textureID);
237+ return std::unexpected (FW_ERROR (imgData.error (), " Failed to load cubemap texture" ));
238+ }
239+ if (imgData->width != imgData->height ) {
240+ glDeleteTextures (1 , &textureID);
241+ stbi_image_free (imgData->imgData );
242+ return std::unexpected (ERROR (" Cubemap texture must be square" ));
243+ }
244+
245+ const GLint format = getGLChannels (imgData->channelCount );
246+ for (int i = 0 ; i < 6 ; i++) {
247+ const GLint faceDir = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
248+ assert (faceDir >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceDir <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
127249 glTexImage2D (faceDir,
128250 0 , format, imgData->width , imgData->height , 0 , format, GL_UNSIGNED_BYTE, imgData->imgData );
129251 }
252+ stbi_image_free (imgData->imgData );
253+
130254 glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
131255 glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
132256 glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
0 commit comments