diff --git a/assets/textures/bricks1.json b/assets/textures/bricks1.json index ac5ef94..69057df 100644 --- a/assets/textures/bricks1.json +++ b/assets/textures/bricks1.json @@ -1,6 +1,6 @@ { "type": "texture", - "psm": "palette", + "psm": "16", "alpha": false, "file": "uv_tester.png" } \ No newline at end of file diff --git a/assets/textures/rgb.png b/assets/textures/rgb.png new file mode 100644 index 0000000..1efd081 Binary files /dev/null and b/assets/textures/rgb.png differ diff --git a/assets/textures/uv_tester.png b/assets/textures/uv_tester.png index ddf16a1..f23ac67 100644 Binary files a/assets/textures/uv_tester.png and b/assets/textures/uv_tester.png differ diff --git a/compile.sh b/compile.sh index efaadd7..2ddf404 100755 --- a/compile.sh +++ b/compile.sh @@ -5,11 +5,11 @@ set -e if [ ! "$1" ] || [ $1 != "ci" ]; then # Check if apt is installed before trying to run prereqs if command -v apt 2>&1 /dev/null; then - sudo apt install -y build-essential binutils-dev git cmake genisoimage libassimp-dev libmagick++-dev sox autoconf automake autopoint + sudo apt install -y build-essential binutils-dev git cmake genisoimage libstb-dev libassimp-dev libmagick++-dev sox autoconf automake autopoint fi if command -v pacman 2>&1 /dev/null; then - sudo pacman -S gcc make cmake patch texinfo flex bison gettext wget gsl gmp zlib mpfr mpc glibc linux-headers linux-api-headers ncurses assimp jsoncpp cdrkit libelf cimg imagemagick pkgconf sox + sudo pacman -S gcc make cmake patch texinfo flex bison gettext wget gsl gmp zlib mpfr mpc glibc linux-headers linux-api-headers ncurses assimp jsoncpp cdrkit libelf cimg imagemagick pkgconf sox stb fi fi diff --git a/dependencies/egg-ps2-graphics-lib/include/egg-ps2-graphics-lib/texture.hpp b/dependencies/egg-ps2-graphics-lib/include/egg-ps2-graphics-lib/texture.hpp index e2575d7..26207cb 100644 --- a/dependencies/egg-ps2-graphics-lib/include/egg-ps2-graphics-lib/texture.hpp +++ b/dependencies/egg-ps2-graphics-lib/include/egg-ps2-graphics-lib/texture.hpp @@ -30,7 +30,4 @@ struct texture_descriptor void upload_texture(texture_descriptor& texture, void* texture_data, void* clut_data); void unload_texture(texture_descriptor& texture); - -// Sets the texture currently being drawn -bool set_texture(texture_descriptor& texture); } // namespace egg::ps2::graphics \ No newline at end of file diff --git a/dependencies/egg-ps2-graphics-lib/src/gs_mem.cc b/dependencies/egg-ps2-graphics-lib/src/gs_mem.cc index 35f0151..55a09c1 100644 --- a/dependencies/egg-ps2-graphics-lib/src/gs_mem.cc +++ b/dependencies/egg-ps2-graphics-lib/src/gs_mem.cc @@ -85,7 +85,6 @@ int allocate_texture_slot(u32 pages) // If the pointer overflows the vram size if (graph_vram_pointer > graph_vram_max_words) { - graph_vram_pointer -= size; return -1; } diff --git a/dependencies/egg-ps2-graphics-lib/src/mesh.cc b/dependencies/egg-ps2-graphics-lib/src/mesh.cc index 329e0dc..79b7127 100644 --- a/dependencies/egg-ps2-graphics-lib/src/mesh.cc +++ b/dependencies/egg-ps2-graphics-lib/src/mesh.cc @@ -222,7 +222,7 @@ void draw_mesh_strip(const Matrix& mesh_to_screen_matrix, const mesh_descriptor& assert(mesh.is_valid()); // TODO: calculate this dynamically based on how much stuff is being put into vu mem - static constexpr s32 verts_per_call = 80; + static constexpr s32 verts_per_call = 64; for (u32 i = 0;;) { diff --git a/dependencies/egg-ps2-graphics-lib/src/texture.cc b/dependencies/egg-ps2-graphics-lib/src/texture.cc index 204610c..67345ec 100644 --- a/dependencies/egg-ps2-graphics-lib/src/texture.cc +++ b/dependencies/egg-ps2-graphics-lib/src/texture.cc @@ -36,7 +36,7 @@ texture_descriptor::texture_descriptor() t_texbuff.info.width = 0; t_texbuff.info.height = 0; - t_texbuff.info.components = TEXTURE_COMPONENTS_RGB; + t_texbuff.info.components = TEXTURE_COMPONENTS_RGBA; t_texbuff.info.function = TEXTURE_FUNCTION_DECAL; wrap.horizontal = WRAP_REPEAT; @@ -72,7 +72,9 @@ void upload_texture(texture_descriptor& texture, void* texture_data, void* clut_ return; } - utils::inline_packet2<50> texture_packet(P2_TYPE_NORMAL, P2_MODE_CHAIN, 0); + assert(__is_aligned(texture_data, 16)); + utils::inline_packet2<128> texture_packet(P2_TYPE_NORMAL, P2_MODE_CHAIN, 0); + packet2_update(texture_packet, draw_texture_transfer( texture_packet->next, texture_data, @@ -80,12 +82,15 @@ void upload_texture(texture_descriptor& texture, void* texture_data, void* clut_ texture.get_width_height().second, texture.t_texbuff.psm, texture.t_texbuff.address, - texture.t_texbuff.width)); + std::max((u32)64, texture.get_width_height().first))); + u8 clut_width = texture.t_texbuff.psm == GS_PSM_8 ? 16 : 8; + u8 clut_height = texture.t_texbuff.psm == GS_PSM_8 ? 16 : 2; if (clut_data) { - u8 clut_width = texture.t_texbuff.psm == GS_PSM_8 ? 16 : 8; - u8 clut_height = texture.t_texbuff.psm == GS_PSM_8 ? 16 : 2; + assert(__is_aligned(clut_data, 16)); + + printf("clut width, height : %u, %u\n", clut_width, clut_height); packet2_update(texture_packet, draw_texture_transfer( texture_packet->next, @@ -94,10 +99,12 @@ void upload_texture(texture_descriptor& texture, void* texture_data, void* clut_ clut_height, texture.clut.psm, texture.clut.address, - clut_width)); + 64)); } + printf("Texture min: %d, %d\n", texture.wrap.minu, texture.wrap.minv); printf("Texture max: %d, %d\n", texture.wrap.maxu, texture.wrap.maxv); + packet2_chain_open_cnt(texture_packet, 0, 0, 0); packet2_update(texture_packet, draw_texture_wrapping( texture_packet->next, @@ -106,6 +113,7 @@ void upload_texture(texture_descriptor& texture, void* texture_data, void* clut_ packet2_chain_close_tag(texture_packet); packet2_update(texture_packet, draw_texture_flush(texture_packet->next)); + dma_channel_wait(DMA_CHANNEL_GIF, 0); dma_channel_send_packet2(texture_packet, DMA_CHANNEL_GIF, 1); dma_wait_fast(); @@ -129,20 +137,4 @@ void unload_texture(texture_descriptor& texture) texture.is_uploaded = false; } -bool set_texture(texture_descriptor& texture) -{ - packet2_utils_vu_open_unpack(get_current_vif_packet(), 0, 1); - { - packet2_utils_gif_add_set(get_current_vif_packet(), 1); - packet2_utils_gs_add_lod(get_current_vif_packet(), &texture.lod); - packet2_utils_gs_add_texbuff_clut(get_current_vif_packet(), &texture.t_texbuff, &texture.clut); - packet2_utils_gs_add_prim_giftag(get_current_vif_packet(), &get_empty_prim(), 0, - ((u64)GIF_REG_RGBAQ) << 0, 1, 0); - } - packet2_utils_vu_close_unpack(get_current_vif_packet()); - packet2_utils_vu_add_start_program(get_current_vif_packet(), vu1_programs::get_kick_program_addr()); - - return true; -} - } // namespace egg::ps2::graphics \ No newline at end of file diff --git a/include/renderer/texture.hpp b/include/renderer/texture.hpp index 803b221..c1607e3 100644 --- a/include/renderer/texture.hpp +++ b/include/renderer/texture.hpp @@ -18,8 +18,6 @@ struct Texture: public Debuggable // Deallocates the texture from gs memory bool unload_texture(); - bool use_texture(); - AssetRegistry::Asset* texture_asset; class TextureFileHeader* get_texture() const; diff --git a/src/renderer/gs.cc b/src/renderer/gs.cc index 2e6b2a1..40e3dbf 100644 --- a/src/renderer/gs.cc +++ b/src/renderer/gs.cc @@ -150,12 +150,12 @@ void render() _gs_state.camera_rotation = Camera::get().transform.get_rotation(); - epg::clear_screen(255, 192, 203); + epg::clear_screen(255, 255, 255); { epg::start_draw(); - epg::set_fog_color(255, 192, 203); + epg::set_fog_color(255, 255, 255); draw_objects(_gs_state); diff --git a/src/renderer/texture.cc b/src/renderer/texture.cc index cb3fb4d..940fb5d 100644 --- a/src/renderer/texture.cc +++ b/src/renderer/texture.cc @@ -30,6 +30,7 @@ Texture::Texture(Asset::Reference texture_asset_ref, AssetRegistry::Asset* in_te texture_descriptor.t_texbuff.info.function = texture->function; texture_descriptor.t_texbuff.psm = texture->psm; + texture_descriptor.clut.start = 0; texture_descriptor.clut.psm = GS_PSM_32; texture_descriptor.clut.load_method = texture->clut.length > 0 ? CLUT_LOAD : CLUT_NO_LOAD; texture_descriptor.clut.storage_mode = CLUT_STORAGE_MODE1; @@ -99,22 +100,6 @@ bool Texture::unload_texture() return true; } -bool Texture::use_texture() -{ - TextureFileHeader* texture = get_texture(); - if (texture == nullptr) - { - return false; - } - - if (texture_descriptor.is_uploaded == false) - { - return false; - } - - return egg::ps2::graphics::set_texture(texture_descriptor); -} - TextureFileHeader* Texture::get_texture() const { return reinterpret_cast(texture_asset->data.get()); diff --git a/tools/ps2-mesh-converter/CMakeLists.txt b/tools/ps2-mesh-converter/CMakeLists.txt index a4db0f2..554d0a9 100644 --- a/tools/ps2-mesh-converter/CMakeLists.txt +++ b/tools/ps2-mesh-converter/CMakeLists.txt @@ -17,7 +17,7 @@ FILE(GLOB_RECURSE Source "src/**.cpp") add_executable(egg-ps2-mesh-converter ${Source}) -target_include_directories(egg-ps2-mesh-converter PRIVATE include "/usr/include/jsoncpp" ${ImageMagick_INCLUDE_DIRS}) +target_include_directories(egg-ps2-mesh-converter PRIVATE include "/usr/include/jsoncpp" "/usr/include" ${ImageMagick_INCLUDE_DIRS}) target_link_libraries(egg-ps2-mesh-converter PUBLIC meshoptimizer::meshoptimizer assimp ps2-egg jsoncpp ${ImageMagick_LIBRARIES}) set_property(TARGET egg-ps2-mesh-converter PROPERTY CXX_STANDARD 20) diff --git a/tools/ps2-mesh-converter/src/texture/texture.cpp b/tools/ps2-mesh-converter/src/texture/texture.cpp index a6e638b..7c76368 100644 --- a/tools/ps2-mesh-converter/src/texture/texture.cpp +++ b/tools/ps2-mesh-converter/src/texture/texture.cpp @@ -2,6 +2,7 @@ #include "egg/texture_header.hpp" +#include "app.hpp" #include #include #include @@ -11,10 +12,8 @@ #include "app.hpp" #include "types.hpp" -#define MAGICKCORE_QUANTUM_DEPTH 8 -#define MAGICKCORE_HDRI_ENABLE false - -#include +#define STB_IMAGE_IMPLEMENTATION +#include "stb/stb_image.h" // Copied from gs_psm.h @@ -64,6 +63,12 @@ #define WRAP_REGION_CLAMP 2 #define WRAP_REGION_REPEAT 3 +struct image +{ + int width, height, channels; + unsigned char* data; +}; + static std::filesystem::path get_file_path(std::string_view json_path, const Json::Value& obj) { std::string input_file_path = obj["file"].asString(); @@ -71,7 +76,7 @@ static std::filesystem::path get_file_path(std::string_view json_path, const Jso return std::filesystem::path(json_path).parent_path() / input_file_path; } -union PalleteColor +union Color { struct { @@ -82,19 +87,54 @@ union PalleteColor }; uint32_t color; }; -static_assert(sizeof(PalleteColor) == 4); +static_assert(sizeof(Color) == 4); -static PalleteColor fromColorRGB(const Magick::ColorRGB& c, bool alpha) +struct Color24 { - PalleteColor new_color; - new_color.alpha = alpha ? c.alpha() * 255 : 255; - new_color.red = c.red() * 255; - new_color.green = c.green() * 255; - new_color.blue = c.blue() * 255; + uint8_t red; + uint8_t green; + uint8_t blue; +}; +static_assert(sizeof(Color24) == 3); + +static Color fromColorRGB(const image& img, size_t x, size_t y, bool alpha) +{ + int i = x + y * img.width; + + Color new_color; + if (img.channels == 1) + { + new_color.alpha = 1; + new_color.red = img.data[i] / 8; + new_color.green = img.data[i] / 8; + new_color.blue = img.data[i] / 8; + } + else if (img.channels == 3) + { + const Color24* colors = (const Color24*)img.data; + + new_color.alpha = 255; + new_color.red = colors[i].red; + new_color.green = colors[i].green; + new_color.blue = colors[i].blue; + } + else if (img.channels == 4) + { + const Color* colors = (const Color*)img.data; + + new_color.alpha = alpha ? colors[i].alpha : 255; + new_color.red = colors[i].red; + new_color.green = colors[i].green; + new_color.blue = colors[i].blue; + } + else + { + assert(false); + } return new_color; } -union PalleteColor16 +union Color16 { struct { @@ -105,42 +145,69 @@ union PalleteColor16 }; uint16_t color; }; -static_assert(sizeof(PalleteColor16) == 2); +static_assert(sizeof(Color16) == 2); + +static Color16 fromColorRGB16(const image& img, size_t x, size_t y, bool alpha) +{ + int i = x + y * img.width; + + Color16 new_color; + if (img.channels == 1) + { + new_color.alpha = 1; + new_color.red = img.data[i] / 8; + new_color.green = img.data[i] / 8; + new_color.blue = img.data[i] / 8; + } + else if (img.channels == 3) + { + const Color24* colors = (const Color24*)img.data; + + new_color.alpha = 1; + new_color.red = colors[i].red / 8; + new_color.green = colors[i].green / 8; + new_color.blue = colors[i].blue / 8; + } + else if (img.channels == 4) + { + const Color* colors = (const Color*)img.data; + + new_color.alpha = alpha ? colors[i].alpha > 128 : 1; + new_color.red = colors[i].red / 8; + new_color.green = colors[i].green / 8; + new_color.blue = colors[i].blue / 8; + } + else + { + assert(false); + } + return new_color; +} template <> -struct std::hash +struct std::hash { - std::size_t operator()(const PalleteColor& k) const + std::size_t operator()(const Color& k) const { return k.color; } }; -static bool operator==(const PalleteColor& lhs, const PalleteColor& rhs) +static bool operator==(const Color& lhs, const Color& rhs) { return lhs.color == rhs.color; } -static bool writePalette() -{ - return true; -} - // Collects the palette into palette_colors, sets the PSM and CLUT on texture_header -static bool collectPalette(const Magick::Image& image, std::vector& palette_colors, TextureFileHeader& texture_header, bool alpha) +static bool collectPalette(const image& image, std::vector& palette_colors, TextureFileHeader& texture_header, bool alpha) { - using namespace Magick; - std::unordered_set colors(256); + std::unordered_set<::Color> colors(256); - for (size_t x = 0; x < image.columns(); ++x) + for (size_t x = 0; x < image.width; ++x) { - for (size_t y = 0; y < image.rows(); ++y) + for (size_t y = 0; y < image.height; ++y) { - // The pixel read doesn't work without this line. I don't understand why - const void* pixel = image.getConstPixels(x, y, 1, 1); - - PalleteColor new_color = fromColorRGB(image.pixelColor(x, y), alpha); - + ::Color new_color = fromColorRGB(image, x, y, alpha); colors.insert(new_color); } } @@ -168,10 +235,11 @@ static bool collectPalette(const Magick::Image& image, std::vector& pa // Write the palette { size_t i = 0; - for (const PalleteColor& c : colors) + for (const Color& c : colors) { palette_colors[i] = c.color; print("Palette color: r: %u, g: %u, b: %u, a: %u", c.red, c.green, c.blue, c.alpha); + i++; } @@ -181,13 +249,11 @@ static bool collectPalette(const Magick::Image& image, std::vector& pa return true; } -static bool writePalletizedImageData(const Magick::Image& image, const std::vector& palette_colors, std::vector& image_data, bool alpha) +static bool writePalletizedImageData(const image& image, const std::vector& palette_colors, std::vector& image_data, bool alpha) { - using namespace Magick; - assert(palette_colors.size() == 16 || palette_colors.size() == 256); - const uint32_t num_pixels = image.columns() * image.rows(); + const uint32_t num_pixels = image.width * image.height; if (palette_colors.size() == 16) { image_data.resize((num_pixels / 2) + (num_pixels % 2)); @@ -199,17 +265,15 @@ static bool writePalletizedImageData(const Magick::Image& image, const std::vect // Write the data int i = 0; - for (size_t x = 0; x < image.columns(); ++x) + for (size_t x = 0; x < image.width; ++x) { - for (size_t y = 0; y < image.rows(); ++y) + for (size_t y = 0; y < image.height; ++y) { - // The pixel read doesn't work without this line. I don't understand why - const void* pixel = image.getConstPixels(x, y, 1, 1); - - PalleteColor new_color = fromColorRGB(image.pixelColor(x, y), alpha); + Color new_color = fromColorRGB(image, x, y, alpha); ptrdiff_t new_index = std::find(palette_colors.begin(), palette_colors.end(), new_color.color) - palette_colors.begin(); assert(new_index < palette_colors.size()); + assert(new_index >= 0); switch (palette_colors.size()) { @@ -234,6 +298,7 @@ static bool writePalletizedImageData(const Magick::Image& image, const std::vect break; default: + assert(false); break; } @@ -278,21 +343,27 @@ void checkTextureHeader(const TextureFileHeader& texture_header, const std::vect bool parseTexture(std::string_view path, const Json::Value& obj, std::vector& out_data) { - using namespace Magick; print("Opening texture!"); const std::filesystem::path texture_file_path = get_file_path(path, obj); print("Texture file path: %s", texture_file_path.c_str()); - Magick::Image my_image; - my_image.read(texture_file_path); + image img; + img.data = stbi_load(texture_file_path.c_str(), &img.width, &img.height, &img.channels, STBI_rgb); + if (img.data == nullptr) + { + print_error("Failed to load image!"); + return false; + } + print("Num channels in image: %lu", img.channels); + TextureFileHeader texture_header; - texture_header.size_x = my_image.columns(); - texture_header.size_y = my_image.rows(); + texture_header.size_x = img.width; + texture_header.size_y = img.height; texture_header.function = TEXTURE_FUNCTION_DECAL; - texture_header.components = obj["alpha"].asBool() ? TEXTURE_COMPONENTS_RGBA : TEXTURE_COMPONENTS_RGB; + texture_header.components = TEXTURE_COMPONENTS_RGBA; //obj["alpha"].asBool() ? TEXTURE_COMPONENTS_RGBA : TEXTURE_COMPONENTS_RGB; print("Setting texture to repeat mapping"); texture_header.horizontal = WRAP_REPEAT; @@ -312,14 +383,14 @@ bool parseTexture(std::string_view path, const Json::Value& obj, std::vector palette_colors; - if (!collectPalette(my_image, palette_colors, texture_header, obj["alpha"].asBool())) + if (!collectPalette(img, palette_colors, texture_header, obj["alpha"].asBool())) { print_error("Failed to collect color palette!"); return false; } std::vector image_data; - if (!writePalletizedImageData(my_image, palette_colors, image_data, obj["alpha"].asBool())) + if (!writePalletizedImageData(img, palette_colors, image_data, obj["alpha"].asBool())) { print_error("Failed to write image data!"); return false; @@ -328,12 +399,13 @@ bool parseTexture(std::string_view path, const Json::Value& obj, std::vector= 0.5 : 1; - new_color[i].red = c.red() * 31; - new_color[i].green = c.green() * 31; - new_color[i].blue = c.blue() * 31; + new_color[i] = fromColorRGB16(img, x, y, obj["alpha"].asBool()); i++; }