From 5c0d7b31fc39708b2951d4f0e92adccc6c3df033 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 7 Nov 2023 12:37:39 -0500 Subject: [PATCH 1/8] init3DView: Fix potential screenTriangleVertices leak --- src/display3d.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/display3d.cpp b/src/display3d.cpp index e83b48a6f06..562f0ddb9f1 100644 --- a/src/display3d.cpp +++ b/src/display3d.cpp @@ -1560,14 +1560,17 @@ bool init3DView() batchedObjectStatusRenderer.initialize(); - // vertex attributes for a single triangle that covers the screen - gfx_api::gfxFloat screenTriangleVertices[] = { - -1.f, -1.f, - 3.f, -1.f, - -1.f, 3.f - }; - pScreenTriangleVBO = gfx_api::context::get().create_buffer_object(gfx_api::buffer::usage::vertex_buffer, gfx_api::context::buffer_storage_hint::static_draw, "screenTriangleVertices"); - pScreenTriangleVBO->upload(sizeof(screenTriangleVertices), screenTriangleVertices); + if (!pScreenTriangleVBO) + { + // vertex attributes for a single triangle that covers the screen + gfx_api::gfxFloat screenTriangleVertices[] = { + -1.f, -1.f, + 3.f, -1.f, + -1.f, 3.f + }; + pScreenTriangleVBO = gfx_api::context::get().create_buffer_object(gfx_api::buffer::usage::vertex_buffer, gfx_api::context::buffer_storage_hint::static_draw, "screenTriangleVertices"); + pScreenTriangleVBO->upload(sizeof(screenTriangleVertices), screenTriangleVertices); + } return true; } From 8f0b749080aad314a6c0b1ea7748ef5641ef0612 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 7 Nov 2023 12:53:45 -0500 Subject: [PATCH 2/8] Fix potential crash in DROID_GROUP::remove --- src/group.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/group.cpp b/src/group.cpp index b3cc2552a5e..0121747016e 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -219,14 +219,14 @@ void DROID_GROUP::remove(DROID *psDroid) } } + intCommanderGroupChanged((type == GT_COMMAND && psCommander) ? psCommander : nullptr); + // free the group if necessary if (refCount <= 0) { grpGlobalManager.erase(id); delete this; } - - intCommanderGroupChanged((type == GT_COMMAND && psCommander) ? psCommander : nullptr); } // count the members of a group From acdbc1994f8ec202a62fa3fddda1997263f1947a Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:49:01 -0500 Subject: [PATCH 3/8] [OpenGL] GL_MAX_VERTEX_OUTPUT_COMPONENTS requires OpenGL 3.2+ --- lib/ivis_opengl/gfx_api_gl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index 56813fcca81..ab679a130ea 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -2689,7 +2689,7 @@ int32_t gl_context::get_context_value(const context_value property) // special-handling for MAX_VERTEX_OUTPUT_COMPONENTS if (!gles) { - if (GLAD_GL_VERSION_3_0) + if (GLAD_GL_VERSION_3_2) { glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &value); } From aaf0c312d9235ed1a573ea5bfb56adbefb8bce09 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 7 Nov 2023 15:22:07 -0500 Subject: [PATCH 4/8] texLoad: Additional null check --- src/texture.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/texture.cpp b/src/texture.cpp index a9db60fef24..bb8c55f215b 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -412,7 +412,14 @@ bool texLoad(const char *fileName) } } // flush all of the array textures - decalTexArr->flush(); + if (decalTexArr) + { + decalTexArr->flush(); + } + else + { + debug(LOG_FATAL, "Failed to load one or more terrain decals"); + } if (decalNormalArr) { decalNormalArr->flush(); } if (decalSpecularArr) { decalSpecularArr->flush(); } if (decalHeightArr) { decalHeightArr->flush(); } From f23304460325942253fe2f5fc8b7092e5684498d Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:03:02 -0500 Subject: [PATCH 5/8] map.cpp: Additional validity checks --- src/map.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/map.cpp b/src/map.cpp index 83f0d542eba..2cf9ee53e5f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -131,6 +131,8 @@ static int numTile_names; static std::unique_ptr Tile_names = nullptr; static std::unique_ptr map; // 3D array pointer that holds the texturetype +static int numTile_types = 0; + static std::unique_ptr mapDecals; // array that tells us what tile is a decal #define MAX_TERRAIN_TILES 0x0200 // max that we support (for now), see TILE_NUMMASK @@ -436,6 +438,7 @@ static void SetGroundForTile(const char *filename, const char *nametype) //increment the pointer to the start of the next record pFileData = strchr(pFileData, '\n') + 1; + numTile_types = numlines; map = std::unique_ptr (new int[numlines * 2 * 2]()); for (i = 0; i < numlines; i++) @@ -476,6 +479,12 @@ static int getTextureType(const char *textureType) // so map[10][0][1] would be map[10*2*2 + 0*2 + 1] == map[41] static int groundFromMapTile(int tile, int j, int k) { + auto tileNumber = TileNumber_tile(tile); + if (tileNumber >= numTile_types) + { + debug(LOG_INFO, "Invalid ground tile number: %d", (int)tileNumber); + return 0; + } return map[TileNumber_tile(tile) * 2 * 2 + j * 2 + k]; } From 8b4c1e7da5ecee07102a0c7be45d1d415fb055f1 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:27:04 -0500 Subject: [PATCH 6/8] NETallowJoining: Fix NETisMessageReady check --- lib/netplay/netplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netplay/netplay.cpp b/lib/netplay/netplay.cpp index e27fd86cf4e..411ffb86e7b 100644 --- a/lib/netplay/netplay.cpp +++ b/lib/netplay/netplay.cpp @@ -4056,8 +4056,8 @@ static void NETallowJoining() NETcloseTempSocket(i); sync_counter.cantjoin++; - continue; } + continue; } if (NETgetMessage(NETnetTmpQueue(i))->type == NET_JOIN) From de77ec6dd8bc911be76185d8c2250983102547e5 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:51:22 -0500 Subject: [PATCH 7/8] gfx_api: loadTextureArrayFromFiles - support default texture generator in additional situations --- lib/ivis_opengl/gfx_api.cpp | 64 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/lib/ivis_opengl/gfx_api.cpp b/lib/ivis_opengl/gfx_api.cpp index 22d52bec340..17febf26cfc 100644 --- a/lib/ivis_opengl/gfx_api.cpp +++ b/lib/ivis_opengl/gfx_api.cpp @@ -953,6 +953,33 @@ gfx_api::texture_array* gfx_api::context::loadTextureArrayFromFiles(const std::v bool uncompressedExtractionFormat = gfx_api::is_uncompressed_format(desiredImageExtractionFormat); std::vector> defaultTextureMips; + auto getDefaultTextureMipsP = [&defaultTextureMips, &defaultTextureGenerator, textureType, maxWidth, maxHeight](size_t layer, unsigned int width, unsigned int height, size_t mipmap_levels, gfx_api::pixel_format format) -> std::vector>* { + if (defaultTextureMips.empty()) + { + ASSERT_OR_RETURN(nullptr, defaultTextureGenerator != nullptr, "Failed to generate default texture - no default texture generator provided"); + ASSERT_OR_RETURN(nullptr, gfx_api::is_uncompressed_format(format), "Expected uncompressed extraction format, but received: %s", gfx_api::format_to_str(format)); + if (defaultTextureGenerator) + { + auto pCurrentImage = defaultTextureGenerator((layer > 0) ? width : maxWidth, (layer > 0) ? height : maxHeight, gfx_api::format_channels(format)); + ASSERT_OR_RETURN(nullptr, pCurrentImage != nullptr, "Failed to generate default texture"); + if (layer > 0) + { + ASSERT_OR_RETURN(nullptr, pCurrentImage->width() == width && pCurrentImage->height() == height, "Failed to generate matching default texture"); + } + size_t expectedMipLevels = calcMipmapLevelsForUncompressedImage(*pCurrentImage, textureType); + if (layer > 0) + { + ASSERT_OR_RETURN(nullptr, expectedMipLevels == mipmap_levels, "Failed to generate matching default texture"); + } + auto miplevels = generateMipMapsFromUncompressedImage(*pCurrentImage, expectedMipLevels, textureType); + defaultTextureMips.push_back(std::move(pCurrentImage)); + defaultTextureMips.insert(defaultTextureMips.end(), std::make_move_iterator(miplevels.begin()), std::make_move_iterator(miplevels.end())); + miplevels.clear(); + } + } + return &defaultTextureMips; + }; + std::unique_ptr texture_array = nullptr; unsigned int width = 0; unsigned int height = 0; @@ -968,36 +995,23 @@ gfx_api::texture_array* gfx_api::context::loadTextureArrayFromFiles(const std::v std::vector>* pImagesForLayer = nullptr; if (imageLoadFilename.isEmpty()) { - if (defaultTextureMips.empty()) - { - ASSERT_OR_RETURN(nullptr, defaultTextureGenerator != nullptr, "Failed to generate default texture - no default texture generator provided"); - ASSERT_OR_RETURN(nullptr, uncompressedExtractionFormat, "Expected uncompressed extraction format, but received: %s", gfx_api::format_to_str(desiredImageExtractionFormat)); - if (defaultTextureGenerator) - { - auto pCurrentImage = defaultTextureGenerator((layer > 0) ? width : maxWidth, (layer > 0) ? height : maxHeight, gfx_api::format_channels(desiredImageExtractionFormat)); - ASSERT_OR_RETURN(nullptr, pCurrentImage != nullptr, "Failed to generate default texture"); - if (layer > 0) - { - ASSERT_OR_RETURN(nullptr, pCurrentImage->width() == width && pCurrentImage->height() == height, "Failed to generate matching default texture"); - } - size_t expectedMipLevels = calcMipmapLevelsForUncompressedImage(*pCurrentImage, textureType); - if (layer > 0) - { - ASSERT_OR_RETURN(nullptr, expectedMipLevels == mipmap_levels, "Failed to generate matching default texture"); - } - auto miplevels = generateMipMapsFromUncompressedImage(*pCurrentImage, expectedMipLevels, textureType); - defaultTextureMips.push_back(std::move(pCurrentImage)); - defaultTextureMips.insert(defaultTextureMips.end(), std::make_move_iterator(miplevels.begin()), std::make_move_iterator(miplevels.end())); - miplevels.clear(); - } - } - pImagesForLayer = &defaultTextureMips; + pImagesForLayer = getDefaultTextureMipsP(layer, width, height, mipmap_levels, desiredImageExtractionFormat); + ASSERT_OR_RETURN(nullptr, pImagesForLayer != nullptr, "Failed to generate matching default texture"); } else if (uncompressedExtractionFormat || imageLoadFilename.endsWith(".png")) { // load into an uncompressed format loadedImagesForLayer = loadUncompressedImageWithMips(imageLoadFilename.toUtf8(), textureType, maxWidth, maxHeight, desiredImageExtractionFormat == gfx_api::pixel_format::FORMAT_RGBA8_UNORM_PACK8); - pImagesForLayer = &loadedImagesForLayer; + if (!loadedImagesForLayer.empty()) + { + pImagesForLayer = &loadedImagesForLayer; + } + else + { + // failed to load image + debug(LOG_INFO, "Using default texture generator for failed image: %s", imageLoadFilename.toUtf8().c_str()); + pImagesForLayer = getDefaultTextureMipsP(layer, width, height, mipmap_levels, desiredImageExtractionFormat); + } } else { From f7657ee63d47b68d35d3eb71c1f9a06346020d92 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:52:21 -0500 Subject: [PATCH 8/8] texLoad: Use default texture generator for missing decals --- src/texture.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/texture.cpp b/src/texture.cpp index bb8c55f215b..3eda70d52f6 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -367,7 +367,11 @@ bool texLoad(const char *fileName) } } - decalTexArr = gfx_api::context::get().loadTextureArrayFromFiles(tile_base_filepaths, gfx_api::texture_type::game_texture, mipmap_max, mipmap_max, nullptr, nullptr, "decalTexArr"); + decalTexArr = gfx_api::context::get().loadTextureArrayFromFiles(tile_base_filepaths, gfx_api::texture_type::game_texture, mipmap_max, mipmap_max, [](int width, int height, int channels) -> std::unique_ptr { + std::unique_ptr pDefaultTexture = std::unique_ptr(new iV_Image); + pDefaultTexture->allocate(width, height, channels, true); + return pDefaultTexture; + }, nullptr, "decalTexArr"); if (has_auxillary_texture_info) { if (has_nm)