Fixing minor bugs

This commit is contained in:
Vladislav Khorev 2025-12-07 17:48:23 +03:00
parent 38f4f6b7fc
commit 72a2b4c47c
4 changed files with 187 additions and 23 deletions

View File

@ -67,7 +67,7 @@ void Game::setup() {
cubemap.RefreshVBO();
//Load texture
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromBmp24("./resources/DefaultMaterial_BaseColor.bmp", CONST_ZIP_FILE));
spaceshipTexture = std::make_unique<Texture>(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 });

View File

@ -2,6 +2,7 @@
#ifdef PNG_ENABLED
#include "png.h"
#endif
#include <iostream>
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<char>& 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<char> 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

View File

@ -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

100
space-game001plain.html Normal file
View File

@ -0,0 +1,100 @@
<!doctypehtml>
<html lang=en-us>
<head>
<meta charset=utf-8>
<meta content="text/html; charset=utf-8" http-equiv=Content-Type>
<title>Space Game</title>
<style>
body {
font-family: arial;
margin: 0;
overflow: hidden;
padding: 0;
min-height: 100vh;
background-color: #000;
}
.emscripten {
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block
}
div.emscripten {
text-align: center
}
div.emscripten_border {
border: 1px solid #000
}
canvas.emscripten {
border: 0 none;
background-color: #000;
width: 90%;
height: 100vh;
}
@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0)
}
to {
-webkit-transform: rotate(360deg)
}
}
@-moz-keyframes rotation {
from {
-moz-transform: rotate(0)
}
to {
-moz-transform: rotate(360deg)
}
}
@-o-keyframes rotation {
from {
-o-transform: rotate(0)
}
to {
-o-transform: rotate(360deg)
}
}
@keyframes rotation {
from {
transform: rotate(0)
}
to {
transform: rotate(360deg)
}
}
#status {
display: none;
}
#progress {
height: 20px;
width: 300px
}
</style>
</head>
<body>
<div class=emscripten id=status></div>
<div class=emscripten><progress hidden id=progress max=100 value=0></progress></div>
<div class=emscripten_border><canvas class=emscripten id=canvas oncontextmenu=event.preventDefault()
tabindex=-1></canvas></div>
<script>var statusElement = document.getElementById("status"), progressElement = document.getElementById("progress"), spinnerElement = document.getElementById("spinner"), Module = { print: function () { var e = document.getElementById("output"); return e && (e.value = ""), function (t) { arguments.length > 1 && (t = Array.prototype.slice.call(arguments).join(" ")), console.log(t), e && (e.value += t + "\n", e.scrollTop = e.scrollHeight) } }(), canvas: (() => { var e = document.getElementById("canvas"); return e.addEventListener("webglcontextlost", (e => { alert("WebGL context lost. You will need to reload the page."), e.preventDefault() }), !1), e })(), setStatus: e => { if (Module.setStatus.last || (Module.setStatus.last = { time: Date.now(), text: "" }), e !== Module.setStatus.last.text) { var t = e.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/), n = Date.now(); t && n - Module.setStatus.last.time < 30 || (Module.setStatus.last.time = n, Module.setStatus.last.text = e, t ? (e = t[1], progressElement.value = 100 * parseInt(t[2]), progressElement.max = 100 * parseInt(t[4]), progressElement.hidden = !1, spinnerElement.hidden = !1) : (progressElement.value = null, progressElement.max = null, progressElement.hidden = !0, e || (spinnerElement.style.display = "none")), statusElement.innerHTML = e) } }, totalDependencies: 0, monitorRunDependencies: e => { this.totalDependencies = Math.max(this.totalDependencies, e), Module.setStatus(e ? "Preparing... (" + (this.totalDependencies - e) + "/" + this.totalDependencies + ")" : "All downloads complete.") } }; Module.setStatus("Downloading..."), window.onerror = e => { Module.setStatus("Exception thrown, see JavaScript console"), spinnerElement.style.display = "none", Module.setStatus = e => { e && console.error("[post-exception status] " + e) } }</script>
<script async src=space-game001.js></script>
</body>
</html>