diff --git a/Game.cpp b/Game.cpp index cd98935..700fe85 100755 --- a/Game.cpp +++ b/Game.cpp @@ -67,7 +67,7 @@ void Game::setup() { cubemap.RefreshVBO(); //Load texture - spaceshipTexture = std::make_unique(CreateTextureDataFromBmp24("./resources/DefaultMaterial_BaseColor.bmp", CONST_ZIP_FILE)); + spaceshipTexture = std::make_unique(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE)); spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE); spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0))); spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 }); diff --git a/TextureManager.cpp b/TextureManager.cpp index 8fd8745..3db8f65 100755 --- a/TextureManager.cpp +++ b/TextureManager.cpp @@ -2,6 +2,7 @@ #ifdef PNG_ENABLED #include "png.h" #endif +#include namespace ZL { @@ -249,36 +250,84 @@ namespace ZL #ifdef PNG_ENABLED - TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName) + // Структура для хранения данных о файле/массиве и текущей позиции чтения + struct png_data_t { + const char* data; + size_t size; + size_t offset; + }; + + // Пользовательская функция чтения для libpng + // 'png_ptr' - указатель на структуру png + // 'out_ptr' - куда записывать прочитанные данные + // 'bytes_to_read' - сколько байт нужно прочитать + void user_read_data(png_structp png_ptr, png_bytep out_ptr, png_size_t bytes_to_read) { + // Получаем указатель на нашу структуру png_data_t, которую мы установили с помощью png_set_read_fn + png_data_t* data = (png_data_t*)png_get_io_ptr(png_ptr); + + if (data->offset + bytes_to_read > data->size) { + // Попытка прочитать больше, чем есть в массиве. + // Вместо вызова стандартной ошибки, мы можем просто прочитать остаток или вызвать ошибку. + // В этом случае мы вызовем ошибку libpng. + png_error(png_ptr, "PNG Read Error: Attempted to read past end of data buffer."); + bytes_to_read = data->size - data->offset; // Устанавливаем, чтобы прочитать оставшееся + } + + // Копируем данные из нашего массива в буфер libpng + std::memcpy(out_ptr, data->data + data->offset, bytes_to_read); + + // Обновляем смещение + data->offset += bytes_to_read; + } + + // Пользовательская функция предупреждений (по желанию, можно использовать nullptr) + void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg) { + // Здесь можно реализовать логирование предупреждений + //throw std::runtime_error(); + std::cout << "PNG Warning: " << warning_msg << std::endl; + } + + // Пользовательская функция ошибок (обязательна для setjmp) + void user_error_fn(png_structp png_ptr, png_const_charp error_msg) { + // Здесь можно реализовать логирование ошибок + std::cout << "PNG Error: " << error_msg << std::endl; + // Обязательно вызываем longjmp для выхода из процесса чтения/записи PNG + longjmp(png_jmpbuf(png_ptr), 1); + } + + TextureDataStruct CreateTextureDataFromPng(const std::vector& fileArr) { TextureDataStruct texData; - FILE* file = fopen(fullFileName.c_str(), "rb"); - if (!file) { - fclose(file); - throw std::runtime_error("Could not open file " + fullFileName); - } + // Структура для управления чтением из массива + png_data_t png_data = { fileArr.data(), fileArr.size(), 0 }; png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png) { - fclose(file); throw std::runtime_error("Could not create PNG read structure"); } png_infop info = png_create_info_struct(png); if (!info) { - fclose(file); png_destroy_read_struct(&png, nullptr, nullptr); throw std::runtime_error("Could not create PNG info structure"); } + // === Установка пользовательских функций чтения и обработки ошибок === + // 1. Установка обработчика ошибок и longjmp if (setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png, &info, nullptr); - fclose(file); - throw std::runtime_error("Error during PNG read"); + throw std::runtime_error("Error during PNG read (longjmp was executed)"); } - png_init_io(png, file); + // 2. Установка пользовательских функций для обработки ошибок и предупреждений + // Вместо nullptr в error_ptr и warning_ptr можно передать указатель на свою структуру данных, если необходимо + png_set_error_fn(png, nullptr, user_error_fn, user_warning_fn); + + // 3. Установка пользовательской функции чтения и передача ей нашей структуры png_data + png_set_read_fn(png, &png_data, user_read_data); + // =================================================================== + png_read_info(png, info); texData.width = png_get_image_width(png, info); @@ -286,6 +335,7 @@ namespace ZL png_byte color_type = png_get_color_type(png, info); png_byte bit_depth = png_get_bit_depth(png, info); + // === Блок преобразований (оставлен без изменений) === if (bit_depth == 16) png_set_strip_16(png); @@ -308,8 +358,9 @@ namespace ZL png_set_gray_to_rgb(png); png_read_update_info(png, info); + // ==================================================== - + // === Чтение пикселей (оставлен без изменений) === png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * texData.height); for (int y = 0; y < texData.height; y++) { row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info)); @@ -317,8 +368,6 @@ namespace ZL png_read_image(png, row_pointers); - fclose(file); - bool has_alpha = (color_type & PNG_COLOR_MASK_ALPHA) || (png_get_valid(png, info, PNG_INFO_tRNS)); size_t dataSize; @@ -337,11 +386,9 @@ namespace ZL dataSize = texData.width * texData.height * channels; texData.data.resize(dataSize); - - //for (int y = 0; y < texData.height; y++) { //Go in reverse because of UV coord start point - for (int y = texData.height-1; y >= 0; y--) { - //png_bytep row = row_pointers[y];//Go in reverse because of UV coord start point - png_bytep row = row_pointers[texData.height - 1 - y]; + + for (int y = texData.height - 1; y >= 0; y--) { + png_bytep row = row_pointers[texData.height - 1 - y]; for (int x = 0; x < texData.width; x++) { png_bytep px = &(row[x * 4]); texData.data[(y * texData.width + x) * channels + 0] = px[0]; // R @@ -351,15 +398,32 @@ namespace ZL texData.data[(y * texData.width + x) * channels + 3] = px[3]; // A } } - //free(row_pointers[y]);//Go in reverse because of UV coord start point - free(row_pointers[texData.height - 1 - y]);//Go in reverse because of UV coord start point + free(row_pointers[texData.height - 1 - y]); } free(row_pointers); + // ================================================== png_destroy_read_struct(&png, &info, nullptr); return texData; } + + + TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName, const std::string& ZIPFileName) + { + std::vector fileArr; + + fileArr = !ZIPFileName.empty() ? readFileFromZIP(fullFileName, ZIPFileName) : readFile(fullFileName); + + if (fileArr.empty()) { + throw std::runtime_error("Could not read file data into memory"); + } + + // Вызываем новую функцию, которая работает с массивом байт + return CreateTextureDataFromPng(fileArr); + } + + #endif diff --git a/TextureManager.h b/TextureManager.h index 6663cc0..be3c7e1 100755 --- a/TextureManager.h +++ b/TextureManager.h @@ -49,7 +49,7 @@ namespace ZL TextureDataStruct CreateTextureDataFromBmp24(const std::string& fullFileName, const std::string& ZIPFileName=""); TextureDataStruct CreateTextureDataFromBmp32(const std::string& fullFileName, const std::string& ZIPFileName=""); #ifdef PNG_ENABLED - TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName); + TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName, const std::string& ZIPFileName = ""); #endif diff --git a/space-game001plain.html b/space-game001plain.html new file mode 100644 index 0000000..17708db --- /dev/null +++ b/space-game001plain.html @@ -0,0 +1,100 @@ + + + + + + + Space Game + + + + +
+
+
+ + + + + \ No newline at end of file