From 356561a5b4782c050742fb45e46acda6a76edcd0 Mon Sep 17 00:00:00 2001 From: KiritoDev Date: Fri, 7 May 2021 00:59:16 -0500 Subject: [PATCH] [WIP] Started texture support on addons --- src/moon/libs/miniz/zip_file.hpp | 16 ++ src/moon/mod-engine/engine.cpp | 77 ++++- src/moon/mod-engine/engine.h | 9 + src/moon/mod-engine/interfaces/bit-module.h | 8 + src/moon/mod-engine/interfaces/file-entry.h | 9 + src/moon/moon64.cpp | 24 ++ src/moon/moon64.h | 9 + src/pc/gfx/gfx_pc.c | 300 +++++++++++--------- src/pc/gfx/gfx_pc.h | 19 +- src/pc/pc_main.c | 12 +- 10 files changed, 330 insertions(+), 153 deletions(-) create mode 100644 src/moon/mod-engine/interfaces/file-entry.h diff --git a/src/moon/libs/miniz/zip_file.hpp b/src/moon/libs/miniz/zip_file.hpp index 5014b68d..028015cd 100644 --- a/src/moon/libs/miniz/zip_file.hpp +++ b/src/moon/libs/miniz/zip_file.hpp @@ -32,6 +32,7 @@ #include #include #include +#include "moon/mod-engine/interfaces/file-entry.h" /* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing See "unlicense" statement at the end of this file. @@ -5456,6 +5457,21 @@ class zip_file return extracted; } + void read_texture(const zip_info &info, TextureFileEntry** entry) { + std::size_t size; + char *data = static_cast(mz_zip_reader_extract_file_to_heap(archive_.get(), info.filename.c_str(), &size, 0)); + if(data == nullptr) + { + throw std::runtime_error("file couldn't be read"); + } + (*entry)->data = data; + (*entry)->size = size; + } + + void read_texture(const std::string &name, TextureFileEntry** entry){ + read_texture(getinfo(name), entry); + } + std::string read(const std::string &name) { return read(getinfo(name)); diff --git a/src/moon/mod-engine/engine.cpp b/src/moon/mod-engine/engine.cpp index 8c8f7e86..83a04384 100644 --- a/src/moon/mod-engine/engine.cpp +++ b/src/moon/mod-engine/engine.cpp @@ -1,6 +1,7 @@ #include "moon/mod-engine/interfaces/mod-module.h" #include "moon/mod-engine/modules/test-module.h" #include "moon/mod-engine/interfaces/bit-module.h" +#include "interfaces/file-entry.h" #include "moon/wrapper.h" #include "moon/libs/nlohmann/json.hpp" @@ -14,10 +15,14 @@ using json = nlohmann::json; #include #include #include +#include using namespace std; vector addons; +map textureMap; + +map baseGameTextures; extern "C" { #include "moon/libs/lua/lualib.h" @@ -26,6 +31,21 @@ extern "C" { #include "text/libs/io_utils.h" } +void Moon_LoadAddonTextures(BitModule* module); + +void Moon_LoadDefaultAddon(){ + BitModule* bit = new BitModule(); + bit->name = "Moon64"; + bit->description = "SM64 Original Textures"; + bit->author = "Nintendo"; + bit->version = 1.0f; + bit->readOnly = true; + bit->textures = baseGameTextures; + addons.push_back(bit); + Moon_LoadAddonTextures(bit); +} + + void Moon_LoadAddon(string path){ miniz_cpp::zip_file file(path); @@ -42,6 +62,7 @@ void Moon_LoadAddon(string path){ bit->website = j["bit"]["website"]; bit->icon = j["bit"]["icon"]; bit->main = j["bit"]["main"]; + bit->readOnly = false; if(file.has_file(bit->main)){ std::cout << file.read(bit->main) << std::endl; @@ -55,8 +76,11 @@ void Moon_LoadAddon(string path){ if(!name.rfind(graphicsPath, 0)){ vector allowedTextures = {"png", "jpg", "jpeg"}; if(std::count(allowedTextures.begin(), allowedTextures.end(), string(get_filename_ext(name.c_str())))){ - string texName = name.substr(graphicsPath.length(), name.length() - 1); - // std::cout << texName << std::endl; + string texName = name.substr(graphicsPath.length()); + string rawname = texName.substr(0, texName.find_last_of(".")); + TextureFileEntry *entry = new TextureFileEntry(); + file.read_texture(name, &entry); + bit->textures.insert(pair(texName, entry)); } } if(!name.rfind(textsPath, 0)){ @@ -66,6 +90,11 @@ void Moon_LoadAddon(string path){ } } } + + if(!bit->textures.empty()) + Moon_LoadAddonTextures(bit); + + addons.push_back(bit); } } else { std::cout << "Failed to load addon: [" << file.get_filename() << "]" << std::endl; @@ -95,6 +124,48 @@ void Moon_ScanAddonsDirectory( char *exePath, char *gamedir ){ } } -void Moon_InitModEngine(){ +void Moon_LoadAddonTextures(BitModule* module){ + if(module->textures.empty()) return; + cout << "Loading from " << module->name << " " << to_string(module->textures.size()) << " textures " << endl; + + for (map::iterator entry = module->textures.begin(); entry != module->textures.end(); ++entry) { + + map::iterator texIt; + texIt = textureMap.find(entry->first); + + if(texIt != textureMap.end()){ + cout << "Erasing: " << entry->first << endl; + textureMap.erase(texIt); + } + + TextureFileEntry* texEntry = entry->second; + if(texEntry->data != nullptr) { + overload_memory_texture(texEntry->data, texEntry->size, entry->first.c_str()); + } + } +} + +void Moon_SaveTexture(TextureData* data, string tex){ + cout << "Saving: " << tex << endl; + textureMap.insert(pair(tex, data)); +} + +void Moon_LoadBaseTexture(char* data, long size, string texture){ + if(baseGameTextures.find(texture) == baseGameTextures.end()){ + baseGameTextures.insert(pair(texture.substr(4), new TextureFileEntry({.size = size, .data = data}))); + } +} + +TextureData* Moon_GetTexture(string texture){ + return textureMap.find(texture) != textureMap.end() ? textureMap.find(texture)->second : nullptr; +} + +void Moon_PreInitModEngine(){ + // Moon_LoadDefaultAddon(); Moon_LoadAddon("/home/alex/disks/uwu/Projects/UnderVolt/example.bit"); + Moon_LoadAddon("/home/alex/disks/uwu/Projects/UnderVolt/owo.bit"); +} + +void Moon_InitModEngine(){ + } \ No newline at end of file diff --git a/src/moon/mod-engine/engine.h b/src/moon/mod-engine/engine.h index 5a87a92b..c90e51f4 100644 --- a/src/moon/mod-engine/engine.h +++ b/src/moon/mod-engine/engine.h @@ -1,6 +1,15 @@ #ifndef Moon64ModEngine #define Moon64ModEngine +extern "C" { +#include "pc/gfx/gfx_pc.h" +} + +void Moon_SaveTexture(TextureData* data, string tex); +TextureData* Moon_GetTexture(string texture); +void Moon_PreInitModEngine(); void Moon_InitModEngine(); +void Moon_LoadBaseTexture(char* data, long size, string texture); + #endif \ No newline at end of file diff --git a/src/moon/mod-engine/interfaces/bit-module.h b/src/moon/mod-engine/interfaces/bit-module.h index 3e518077..2a986105 100644 --- a/src/moon/mod-engine/interfaces/bit-module.h +++ b/src/moon/mod-engine/interfaces/bit-module.h @@ -1,9 +1,14 @@ #ifndef Moon64BitModule #define Moon64BitModule +#include "file-entry.h" +#include #include #include +extern "C" { +#include "pc/gfx/gfx_pc.h" +} class BitModule{ public: std::string name; @@ -13,6 +18,9 @@ public: std::string website; std::string icon; std::string main; + std::map textures; + // GFXTextureCache* textureCache; + bool readOnly; }; #endif \ No newline at end of file diff --git a/src/moon/mod-engine/interfaces/file-entry.h b/src/moon/mod-engine/interfaces/file-entry.h new file mode 100644 index 00000000..19c2169f --- /dev/null +++ b/src/moon/mod-engine/interfaces/file-entry.h @@ -0,0 +1,9 @@ +#ifndef Moon64FileEntry +#define Moon64FileEntry + +struct TextureFileEntry { + long size; + char* data; +}; + +#endif \ No newline at end of file diff --git a/src/moon/moon64.cpp b/src/moon/moon64.cpp index 37ae2dcc..a75aa42a 100644 --- a/src/moon/moon64.cpp +++ b/src/moon/moon64.cpp @@ -78,4 +78,28 @@ void moon_update_window(void* window){ if(tmp != NULL) tmp->window = window; } +void moon_mod_engine_preinit(){ + Moon_PreInitModEngine(); +} + +void moon_mod_engine_init(){ + Moon_InitModEngine(); +} + +void moon_engine_save_texture(struct TextureData* data, char* tex){ + Moon_SaveTexture(data, string(tex)); +} + +struct TextureData* moon_engine_get_texture(char* tex){ + return Moon_GetTexture(string(tex)); +} + +struct TextureData* moon_engine_init_texture(){ + return new TextureData(); +} + +void moon_load_base_texture(char* data, long size, char* texture){ + Moon_LoadBaseTexture(data, size, string(texture)); +} + } \ No newline at end of file diff --git a/src/moon/moon64.h b/src/moon/moon64.h index 4e08baf4..0f5f803d 100644 --- a/src/moon/moon64.h +++ b/src/moon/moon64.h @@ -3,6 +3,7 @@ #ifndef __cplusplus #include "types.h" +#include "pc/gfx/gfx_pc.h" void moon_init_languages(char *executable, char *gamedir); u8 * moon_language_get_key( char* key ); @@ -18,5 +19,13 @@ void moon_modules_init(); void moon_modules_update(); void moon_update_window(void* window); +void moon_mod_engine_preinit(); +void moon_mod_engine_init(); + +void moon_engine_save_texture(struct TextureData* data, char* tex); +struct TextureData* moon_engine_get_texture(char* tex); +struct TextureData* moon_engine_init_texture(); +void moon_load_base_texture(char* data, long size, char* texture); + #endif #endif \ No newline at end of file diff --git a/src/pc/gfx/gfx_pc.c b/src/pc/gfx/gfx_pc.c index f6daa6b8..149d7374 100644 --- a/src/pc/gfx/gfx_pc.c +++ b/src/pc/gfx/gfx_pc.c @@ -25,6 +25,7 @@ #include "../platform.h" #include "../configfile.h" #include "../fs/fs.h" +#include "moon/moon64.h" #define SUPPORT_CHECK(x) assert(x) @@ -48,12 +49,6 @@ #define MAX_LIGHTS 2 #define MAX_VERTICES 64 -# define MAX_CACHED_TEXTURES 4096 // for preloading purposes -# define HASH_SHIFT 0 - -#define HASHMAP_LEN (MAX_CACHED_TEXTURES * 2) -#define HASH_MASK (HASHMAP_LEN - 1) - struct RGBA { uint8_t r, g, b, a; }; @@ -69,22 +64,6 @@ struct LoadedVertex { uint8_t clip_rej; }; -struct TextureHashmapNode { - struct TextureHashmapNode *next; - - const uint8_t *texture_addr; - uint8_t fmt, siz; - - uint32_t texture_id; - uint8_t cms, cmt; - bool linear_filter; -}; -static struct { - struct TextureHashmapNode *hashmap[HASHMAP_LEN]; - struct TextureHashmapNode pool[MAX_CACHED_TEXTURES]; - uint32_t pool_pos; -} gfx_texture_cache; - struct ColorCombiner { uint32_t cc_id; struct ShaderProgram *prg; @@ -97,24 +76,24 @@ static uint8_t color_combiner_pool_size; static struct RSP { float modelview_matrix_stack[11][4][4]; uint8_t modelview_matrix_stack_size; - + float MP_matrix[4][4]; float P_matrix[4][4]; - + Light_t current_lights[MAX_LIGHTS + 1]; float current_lights_coeffs[MAX_LIGHTS][3]; float current_lookat_coeffs[2][3]; // lookat_x, lookat_y uint8_t current_num_lights; // includes ambient light bool lights_changed; - + uint32_t geometry_mode; int16_t fog_mul, fog_offset; - + struct { // U0.16 uint16_t s, t; } texture_scaling_factor; - + struct LoadedVertex loaded_vertices[MAX_VERTICES + 4]; } rsp; @@ -137,10 +116,10 @@ static struct RDP { uint32_t line_size_bytes; } texture_tile; bool textures_changed[2]; - + uint32_t other_mode_l, other_mode_h; uint32_t combine_mode; - + struct RGBA env_color, prim_color, fog_color, fill_color; struct XYWidthHeight viewport, scissor; bool viewport_or_scissor_changed; @@ -155,7 +134,7 @@ static struct RenderingState { bool alpha_blend; struct XYWidthHeight viewport, scissor; struct ShaderProgram *shader_program; - struct TextureHashmapNode *textures[2]; + struct TextureData *textures[2]; } rendering_state; struct GfxDimensions gfx_current_dimensions; @@ -266,7 +245,7 @@ static struct ColorCombiner *gfx_lookup_or_create_color_combiner(uint32_t cc_id) if (prev_combiner != NULL && prev_combiner->cc_id == cc_id) { return prev_combiner; } - + for (size_t i = 0; i < color_combiner_pool_size; i++) { if (color_combiner_pool[i].cc_id == cc_id) { return prev_combiner = &color_combiner_pool[i]; @@ -278,43 +257,37 @@ static struct ColorCombiner *gfx_lookup_or_create_color_combiner(uint32_t cc_id) return prev_combiner = comb; } -static bool gfx_texture_cache_lookup(int tile, struct TextureHashmapNode **n, const uint8_t *orig_addr, uint32_t fmt, uint32_t siz) { - size_t hash = string_hash(orig_addr); - #define CMPADDR(x, y) (x && !sys_strcasecmp((const char *)x, (const char *)y)) +static bool gfx_texture_cache_lookup(int tile, struct TextureData **n, const uint8_t *orig_addr, uint32_t fmt, uint32_t siz) { + struct TextureData *node = moon_engine_get_texture(orig_addr); - hash = (hash >> HASH_SHIFT) & HASH_MASK; + if(node != NULL){ + gfx_rapi->select_texture(tile, node->texture_id); + if(n != NULL) *n = node; + return true; + } else node = moon_engine_init_texture(); - struct TextureHashmapNode **node = &gfx_texture_cache.hashmap[hash]; - while (*node != NULL && *node - gfx_texture_cache.pool < gfx_texture_cache.pool_pos) { - if (CMPADDR((*node)->texture_addr, orig_addr) && (*node)->fmt == fmt && (*node)->siz == siz) { - gfx_rapi->select_texture(tile, (*node)->texture_id); - *n = *node; - return true; - } - node = &(*node)->next; - } - if (gfx_texture_cache.pool_pos == sizeof(gfx_texture_cache.pool) / sizeof(struct TextureHashmapNode)) { - // Pool is full. We just invalidate everything and start over. - gfx_texture_cache.pool_pos = 0; - node = &gfx_texture_cache.hashmap[hash]; - // puts("Clearing texture cache"); - } - *node = &gfx_texture_cache.pool[gfx_texture_cache.pool_pos++]; - if ((*node)->texture_addr == NULL) { - (*node)->texture_id = gfx_rapi->new_texture(); - } - gfx_rapi->select_texture(tile, (*node)->texture_id); + if (node->texture_addr == NULL) + node->texture_id = gfx_rapi->new_texture(); + + gfx_rapi->select_texture(tile, node->texture_id); gfx_rapi->set_sampler_parameters(tile, false, 0, 0); - (*node)->cms = 0; - (*node)->cmt = 0; - (*node)->linear_filter = false; - (*node)->next = NULL; - (*node)->texture_addr = orig_addr; - (*node)->fmt = fmt; - (*node)->siz = siz; - *n = *node; + node->cms = 0; + node->cmt = 0; + node->linear_filter = false; + node->texture_addr = orig_addr; + node->fmt = fmt; + node->siz = siz; + moon_engine_save_texture(node, orig_addr); + return false; - #undef CMPADDR +} + +static inline void preload_base_texture(const char *fullpath) { + int w, h; + u64 imgsize = 0; + + u8 *imgdata = fs_load_file(fullpath, &imgsize); + if (imgdata) moon_load_base_texture(imgdata, imgsize, fullpath); } static inline void load_texture(const char *fullpath) { @@ -338,6 +311,25 @@ static inline void load_texture(const char *fullpath) { gfx_rapi->upload_texture(missing_texture, MISSING_W, MISSING_H); } +static inline void load_memory_texture(void *imgdata, long size) { + int w, h; + + if (imgdata) { + // TODO: implement stbi_callbacks or some shit instead of loading the whole texture + u8 *data = stbi_load_from_memory(imgdata, size, &w, &h, NULL, 4); + // free(imgdata); + if (data) { + gfx_rapi->upload_texture(data, w, h); + stbi_image_free(data); // don't need this anymore + return; + } + } + + // fprintf(stderr, "could not load memory texture\n"); + // replace with missing texture + gfx_rapi->upload_texture(missing_texture, MISSING_W, MISSING_H); +} + // this is taken straight from n64graphics static bool texname_to_texformat(const char *name, u8 *fmt, u8 *siz) { @@ -398,9 +390,33 @@ static bool preload_texture(void *user, const char *path) { actualname = sys_strdup(actualname); assert(actualname); - struct TextureHashmapNode *n; - if (!gfx_texture_cache_lookup(0, &n, actualname, fmt, siz)) - load_texture(path); // new texture, load it + preload_base_texture(path); + + return true; +} + +void overload_memory_texture(void* data, long size, const char *path) { + // strip off the extension + char texname[SYS_MAX_PATH]; + strncpy(texname, path, sizeof(texname)); + texname[sizeof(texname)-1] = 0; + char *dot = strrchr(texname, '.'); + if (dot) *dot = 0; + + // get the format and size from filename + u8 fmt, siz; + if (!texname_to_texformat(texname, &fmt, &siz)) { + fprintf(stderr, "unknown texture format: `%s`, skipping\n", texname); + return true; // just skip it, might be a stray skybox or something + } + + char *actualname = texname; + if (!strncmp(FS_TEXTUREDIR "/", actualname, 4)) actualname += 4; + actualname = sys_strdup(actualname); + assert(actualname); + + if (!gfx_texture_cache_lookup(0, NULL, actualname, fmt, siz)) + load_memory_texture(data, size); return true; } @@ -477,7 +493,7 @@ static void gfx_sp_matrix(uint8_t parameters, const int32_t *addr) { #else memcpy(matrix, addr, sizeof(matrix)); #endif - + if (parameters & G_MTX_PROJECTION) { if (parameters & G_MTX_LOAD) { memcpy(rsp.P_matrix, matrix, sizeof(matrix)); @@ -519,17 +535,17 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti const Vtx_t *v = &vertices[i].v; const Vtx_tn *vn = &vertices[i].n; struct LoadedVertex *d = &rsp.loaded_vertices[dest_index]; - + float x = v->ob[0] * rsp.MP_matrix[0][0] + v->ob[1] * rsp.MP_matrix[1][0] + v->ob[2] * rsp.MP_matrix[2][0] + rsp.MP_matrix[3][0]; float y = v->ob[0] * rsp.MP_matrix[0][1] + v->ob[1] * rsp.MP_matrix[1][1] + v->ob[2] * rsp.MP_matrix[2][1] + rsp.MP_matrix[3][1]; float z = v->ob[0] * rsp.MP_matrix[0][2] + v->ob[1] * rsp.MP_matrix[1][2] + v->ob[2] * rsp.MP_matrix[2][2] + rsp.MP_matrix[3][2]; float w = v->ob[0] * rsp.MP_matrix[0][3] + v->ob[1] * rsp.MP_matrix[1][3] + v->ob[2] * rsp.MP_matrix[2][3] + rsp.MP_matrix[3][3]; - + x = gfx_adjust_x_for_aspect_ratio(x); - + short U = v->tc[0] * rsp.texture_scaling_factor.s >> 16; short V = v->tc[1] * rsp.texture_scaling_factor.t >> 16; - + if (rsp.geometry_mode & G_LIGHTING) { if (rsp.lights_changed) { for (int i = 0; i < rsp.current_num_lights - 1; i++) { @@ -541,11 +557,11 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti calculate_normal_dir(&lookat_y, rsp.current_lookat_coeffs[1]); rsp.lights_changed = false; } - + int r = rsp.current_lights[rsp.current_num_lights - 1].col[0]; int g = rsp.current_lights[rsp.current_num_lights - 1].col[1]; int b = rsp.current_lights[rsp.current_num_lights - 1].col[2]; - + for (int i = 0; i < rsp.current_num_lights - 1; i++) { float intensity = 0; intensity += vn->n[0] * rsp.current_lights_coeffs[i][0]; @@ -558,11 +574,11 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti b += intensity * rsp.current_lights[i].col[2]; } } - + d->color.r = r > 255 ? 255 : r; d->color.g = g > 255 ? 255 : g; d->color.b = b > 255 ? 255 : b; - + if (rsp.geometry_mode & G_TEXTURE_GEN) { float dotx = 0, doty = 0; dotx += vn->n[0] * rsp.current_lookat_coeffs[0][0]; @@ -571,7 +587,7 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti doty += vn->n[0] * rsp.current_lookat_coeffs[1][0]; doty += vn->n[1] * rsp.current_lookat_coeffs[1][1]; doty += vn->n[2] * rsp.current_lookat_coeffs[1][2]; - + U = (int32_t)((dotx / 127.0f + 1.0f) / 4.0f * rsp.texture_scaling_factor.s); V = (int32_t)((doty / 127.0f + 1.0f) / 4.0f * rsp.texture_scaling_factor.t); } @@ -580,10 +596,10 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti d->color.g = v->cn[1]; d->color.b = v->cn[2]; } - + d->u = U; d->v = V; - + // trivial clip rejection d->clip_rej = 0; if (x < -w) d->clip_rej |= 1; @@ -592,23 +608,23 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti if (y > w) d->clip_rej |= 8; if (z < -w) d->clip_rej |= 16; if (z > w) d->clip_rej |= 32; - + d->x = x; d->y = y; d->z = z; d->w = w; - + if (rsp.geometry_mode & G_FOG) { if (fabsf(w) < 0.001f) { // To avoid division by zero w = 0.001f; } - + float winv = 1.0f / w; if (winv < 0.0f) { winv = 32767.0f; } - + float fog_z = z * winv * rsp.fog_mul + rsp.fog_offset; if (fog_z < 0) fog_z = 0; if (fog_z > 255) fog_z = 255; @@ -624,27 +640,27 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { struct LoadedVertex *v2 = &rsp.loaded_vertices[vtx2_idx]; struct LoadedVertex *v3 = &rsp.loaded_vertices[vtx3_idx]; struct LoadedVertex *v_arr[3] = {v1, v2, v3}; - + //if (rand()%2) return; - + if (v1->clip_rej & v2->clip_rej & v3->clip_rej) { // The whole triangle lies outside the visible area return; } - + if ((rsp.geometry_mode & G_CULL_BOTH) != 0) { float dx1 = v1->x / (v1->w) - v2->x / (v2->w); float dy1 = v1->y / (v1->w) - v2->y / (v2->w); float dx2 = v3->x / (v3->w) - v2->x / (v2->w); float dy2 = v3->y / (v3->w) - v2->y / (v2->w); float cross = dx1 * dy2 - dy1 * dx2; - + if ((v1->w < 0) ^ (v2->w < 0) ^ (v3->w < 0)) { // If one vertex lies behind the eye, negating cross will give the correct result. // If all vertices lie behind the eye, the triangle will be rejected anyway. cross = -cross; } - + switch (rsp.geometry_mode & G_CULL_BOTH) { case G_CULL_FRONT: if (cross <= 0) return; @@ -657,28 +673,28 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { return; } } - + bool depth_test = (rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER; if (depth_test != rendering_state.depth_test) { gfx_flush(); gfx_rapi->set_depth_test(depth_test); rendering_state.depth_test = depth_test; } - + bool z_upd = (rdp.other_mode_l & Z_UPD) == Z_UPD; if (z_upd != rendering_state.depth_mask) { gfx_flush(); gfx_rapi->set_depth_mask(z_upd); rendering_state.depth_mask = z_upd; } - + bool zmode_decal = (rdp.other_mode_l & ZMODE_DEC) == ZMODE_DEC; if (zmode_decal != rendering_state.decal_mode) { gfx_flush(); gfx_rapi->set_zmode_decal(zmode_decal); rendering_state.decal_mode = zmode_decal; } - + if (rdp.viewport_or_scissor_changed) { if (memcmp(&rdp.viewport, &rendering_state.viewport, sizeof(rdp.viewport)) != 0) { gfx_flush(); @@ -692,27 +708,27 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { } rdp.viewport_or_scissor_changed = false; } - + uint32_t cc_id = rdp.combine_mode; - + bool use_alpha = (rdp.other_mode_l & (G_BL_A_MEM << 18)) == 0; bool use_fog = (rdp.other_mode_l >> 30) == G_BL_CLR_FOG; bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA; bool use_noise = (rdp.other_mode_l & G_AC_DITHER) == G_AC_DITHER; - + if (texture_edge) { use_alpha = true; } - + if (use_alpha) cc_id |= SHADER_OPT_ALPHA; if (use_fog) cc_id |= SHADER_OPT_FOG; if (texture_edge) cc_id |= SHADER_OPT_TEXTURE_EDGE; if (use_noise) cc_id |= SHADER_OPT_NOISE; - + if (!use_alpha) { cc_id &= ~0xfff000; } - + struct ColorCombiner *comb = gfx_lookup_or_create_color_combiner(cc_id); struct ShaderProgram *prg = comb->prg; if (prg != rendering_state.shader_program) { @@ -729,7 +745,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { uint8_t num_inputs; bool used_textures[2]; gfx_rapi->shader_get_info(prg, &num_inputs, used_textures); - + for (int i = 0; i < 2; i++) { if (used_textures[i]) { if (rdp.textures_changed[i]) { @@ -747,13 +763,13 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { } } } - + bool use_texture = used_textures[0] || used_textures[1]; uint32_t tex_width = (rdp.texture_tile.lrs - rdp.texture_tile.uls + 4) / 4; uint32_t tex_height = (rdp.texture_tile.lrt - rdp.texture_tile.ult + 4) / 4; - + bool z_is_from_0_to_1 = gfx_rapi->z_is_from_0_to_1(); - + for (int i = 0; i < 3; i++) { float z = v_arr[i]->z, w = v_arr[i]->w; if (z_is_from_0_to_1) { @@ -763,7 +779,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { buf_vbo[buf_vbo_len++] = v_arr[i]->y; buf_vbo[buf_vbo_len++] = z; buf_vbo[buf_vbo_len++] = w; - + if (use_texture) { float u = (v_arr[i]->u - rdp.texture_tile.uls * 8) / 32.0f; float v = (v_arr[i]->v - rdp.texture_tile.ult * 8) / 32.0f; @@ -775,14 +791,14 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { buf_vbo[buf_vbo_len++] = u / tex_width; buf_vbo[buf_vbo_len++] = v / tex_height; } - + if (use_fog) { buf_vbo[buf_vbo_len++] = rdp.fog_color.r / 255.0f; buf_vbo[buf_vbo_len++] = rdp.fog_color.g / 255.0f; buf_vbo[buf_vbo_len++] = rdp.fog_color.b / 255.0f; buf_vbo[buf_vbo_len++] = v_arr[i]->color.a / 255.0f; // fog factor (not alpha) } - + for (int j = 0; j < num_inputs; j++) { struct RGBA *color; struct RGBA tmp; @@ -847,17 +863,17 @@ static void gfx_calc_and_set_viewport(const Vp_t *viewport) { float height = 2.0f * viewport->vscale[1] / 4.0f; float x = (viewport->vtrans[0] / 4.0f) - width / 2.0f; float y = SCREEN_HEIGHT - ((viewport->vtrans[1] / 4.0f) + height / 2.0f); - + width *= RATIO_X; height *= RATIO_Y; x *= RATIO_X; y *= RATIO_Y; - + rdp.viewport.x = x; rdp.viewport.y = y; rdp.viewport.width = width; rdp.viewport.height = height; - + rdp.viewport_or_scissor_changed = true; } @@ -922,12 +938,12 @@ static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32 float y = (SCREEN_HEIGHT - lry / 4.0f) * RATIO_Y; float width = (lrx - ulx) / 4.0f * RATIO_X; float height = (lry - uly) / 4.0f * RATIO_Y; - + rdp.scissor.x = x; rdp.scissor.y = y; rdp.scissor.width = width; rdp.scissor.height = height; - + rdp.viewport_or_scissor_changed = true; } @@ -937,7 +953,7 @@ static void gfx_dp_set_texture_image(uint32_t format, uint32_t size, uint32_t wi } static void gfx_dp_set_tile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t tmem, uint8_t tile, uint32_t palette, uint32_t cmt, uint32_t maskt, uint32_t shiftt, uint32_t cms, uint32_t masks, uint32_t shifts) { - + if (tile == G_TX_RENDERTILE) { SUPPORT_CHECK(palette == 0); // palette should set upper 4 bits of color index in 4b mode rdp.texture_tile.fmt = fmt; @@ -948,7 +964,7 @@ static void gfx_dp_set_tile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t t rdp.textures_changed[0] = true; rdp.textures_changed[1] = true; } - + if (tile == G_TX_LOADTILE) { rdp.texture_to_load.tile_number = tmem / 256; } @@ -976,7 +992,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t SUPPORT_CHECK(tile == G_TX_LOADTILE); SUPPORT_CHECK(uls == 0); SUPPORT_CHECK(ult == 0); - + // The lrs field rather seems to be number of pixels to load uint32_t word_size_shift; switch (rdp.texture_to_load.siz) { @@ -996,7 +1012,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t uint32_t size_bytes = (lrs + 1) << word_size_shift; rdp.loaded_texture[rdp.texture_to_load.tile_number].size_bytes = size_bytes; rdp.loaded_texture[rdp.texture_to_load.tile_number].addr = rdp.texture_to_load.addr; - + rdp.textures_changed[rdp.texture_to_load.tile_number] = true; } @@ -1102,66 +1118,66 @@ static void gfx_dp_set_fill_color(uint32_t packed_color) { static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { uint32_t saved_other_mode_h = rdp.other_mode_h; uint32_t cycle_type = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); - + if (cycle_type == G_CYC_COPY) { rdp.other_mode_h = (rdp.other_mode_h & ~(3U << G_MDSFT_TEXTFILT)) | G_TF_POINT; } - + // U10.2 coordinates float ulxf = ulx; float ulyf = uly; float lrxf = lrx; float lryf = lry; - + ulxf = ulxf / (4.0f * HALF_SCREEN_WIDTH) - 1.0f; ulyf = -(ulyf / (4.0f * HALF_SCREEN_HEIGHT)) + 1.0f; lrxf = lrxf / (4.0f * HALF_SCREEN_WIDTH) - 1.0f; lryf = -(lryf / (4.0f * HALF_SCREEN_HEIGHT)) + 1.0f; - + ulxf = gfx_adjust_x_for_aspect_ratio(ulxf); lrxf = gfx_adjust_x_for_aspect_ratio(lrxf); - + struct LoadedVertex* ul = &rsp.loaded_vertices[MAX_VERTICES + 0]; struct LoadedVertex* ll = &rsp.loaded_vertices[MAX_VERTICES + 1]; struct LoadedVertex* lr = &rsp.loaded_vertices[MAX_VERTICES + 2]; struct LoadedVertex* ur = &rsp.loaded_vertices[MAX_VERTICES + 3]; - + ul->x = ulxf; ul->y = ulyf; ul->z = -1.0f; ul->w = 1.0f; - + ll->x = ulxf; ll->y = lryf; ll->z = -1.0f; ll->w = 1.0f; - + lr->x = lrxf; lr->y = lryf; lr->z = -1.0f; lr->w = 1.0f; - + ur->x = lrxf; ur->y = ulyf; ur->z = -1.0f; ur->w = 1.0f; - + // The coordinates for texture rectangle shall bypass the viewport setting struct XYWidthHeight default_viewport = {0, 0, gfx_current_dimensions.width, gfx_current_dimensions.height}; struct XYWidthHeight viewport_saved = rdp.viewport; uint32_t geometry_mode_saved = rsp.geometry_mode; - + rdp.viewport = default_viewport; rdp.viewport_or_scissor_changed = true; rsp.geometry_mode = 0; - + gfx_sp_tri1(MAX_VERTICES + 0, MAX_VERTICES + 1, MAX_VERTICES + 3); gfx_sp_tri1(MAX_VERTICES + 1, MAX_VERTICES + 2, MAX_VERTICES + 3); - + rsp.geometry_mode = geometry_mode_saved; rdp.viewport = viewport_saved; rdp.viewport_or_scissor_changed = true; - + if (cycle_type == G_CYC_COPY) { rdp.other_mode_h = saved_other_mode_h; } @@ -1173,15 +1189,15 @@ static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int3 // Per RDP Command Summary Set Tile's shift s and this dsdx should be set to 4 texels // Divide by 4 to get 1 instead dsdx >>= 2; - + // Color combiner is turned off in copy mode gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_TEXEL0), color_comb(0, 0, 0, G_ACMUX_TEXEL0)); - + // Per documentation one extra pixel is added in this modes to each edge lrx += 1 << 2; lry += 1 << 2; } - + // uls and ult are S10.5 // dsdx and dtdy are S5.10 // lrx, lry, ulx, uly are U10.2 @@ -1194,7 +1210,7 @@ static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int3 int16_t height = !flip ? lry - uly : lrx - ulx; float lrs = ((uls << 7) + dsdx * width) >> 7; float lrt = ((ult << 7) + dtdy * height) >> 7; - + struct LoadedVertex* ul = &rsp.loaded_vertices[MAX_VERTICES + 0]; struct LoadedVertex* ll = &rsp.loaded_vertices[MAX_VERTICES + 1]; struct LoadedVertex* lr = &rsp.loaded_vertices[MAX_VERTICES + 2]; @@ -1214,7 +1230,7 @@ static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int3 ur->u = uls; ur->v = lrt; } - + gfx_draw_rectangle(ulx, uly, lrx, lry); rdp.combine_mode = saved_combine_mode; } @@ -1225,18 +1241,18 @@ static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t return; } uint32_t mode = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); - + if (mode == G_CYC_COPY || mode == G_CYC_FILL) { // Per documentation one extra pixel is added in this modes to each edge lrx += 1 << 2; lry += 1 << 2; } - + for (int i = MAX_VERTICES; i < MAX_VERTICES + 4; i++) { struct LoadedVertex* v = &rsp.loaded_vertices[i]; v->color = rdp.fill_color; } - + uint32_t saved_combine_mode = rdp.combine_mode; gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_SHADE), color_comb(0, 0, 0, G_ACMUX_SHADE)); gfx_draw_rectangle(ulx, uly, lrx, lry); @@ -1270,7 +1286,7 @@ static void gfx_run_dl(Gfx* cmd) { int dummy = 0; for (;;) { uint32_t opcode = cmd->words.w0 >> 24; - + switch (opcode) { // RSP commands: case G_MTX: @@ -1369,7 +1385,7 @@ static void gfx_run_dl(Gfx* cmd) { gfx_sp_set_other_mode(C0(8, 8) + 32, C0(0, 8), (uint64_t) cmd->words.w1 << 32); #endif break; - + // RDP Commands: case G_SETTIMG: gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), seg_addr(cmd->words.w1)); @@ -1487,7 +1503,7 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, co gfx_rapi = rapi; gfx_wapi->init(window_title); gfx_rapi->init(); - + // Used in the 120 star TAS static uint32_t precomp_shaders[] = { 0x01200200, @@ -1543,15 +1559,15 @@ void gfx_start_frame(void) { void gfx_run(Gfx *commands) { gfx_sp_reset(); - + //puts("New frame"); - + if (!gfx_wapi->start_frame()) { dropped_frame = true; return; } dropped_frame = false; - + double t0 = gfx_wapi->get_time(); gfx_rapi->start_frame(); gfx_run_dl(commands); diff --git a/src/pc/gfx/gfx_pc.h b/src/pc/gfx/gfx_pc.h index 716221a4..98650e3f 100644 --- a/src/pc/gfx/gfx_pc.h +++ b/src/pc/gfx/gfx_pc.h @@ -1,6 +1,8 @@ #ifndef GFX_PC_H #define GFX_PC_H +#include + struct GfxRenderingAPI; struct GfxWindowManagerAPI; @@ -9,6 +11,21 @@ struct GfxDimensions { float aspect_ratio; }; +# define MAX_CACHED_TEXTURES 4096 // for preloading purposes +# define HASH_SHIFT 0 + +#define HASHMAP_LEN (MAX_CACHED_TEXTURES * 2) +#define HASH_MASK (HASHMAP_LEN - 1) + +struct TextureData { + const uint8_t *texture_addr; + uint8_t fmt, siz; + + uint32_t texture_id; + uint8_t cms, cmt; + char linear_filter; +}; + extern struct GfxDimensions gfx_current_dimensions; #ifdef __cplusplus @@ -22,7 +39,7 @@ void gfx_run(Gfx *commands); void gfx_end_frame(void); void gfx_precache_textures(void); void gfx_shutdown(void); - +void overload_memory_texture(void* data, long size, const char *path); #ifdef __cplusplus } #endif diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index be94d3a3..89e18069 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -192,7 +192,6 @@ void main_func(char *argv[]) { const char *userpath = gCLIOpts.SavePath[0] ? gCLIOpts.SavePath : sys_user_path(); fs_init(sys_ropaths, gamedir, userpath); configfile_load(configfile_name()); - moon_init_languages(argv[0], gamedir); if (gCLIOpts.FullScreen == 1) @@ -251,12 +250,11 @@ void main_func(char *argv[]) { thread5_game_loop(NULL); inited = true; - // precache data if needed - if (configPrecacheRes) { - fprintf(stdout, "precaching data\n"); - fflush(stdout); - gfx_precache_textures(); - } + fprintf(stdout, "precaching data\n"); + fflush(stdout); + gfx_precache_textures(); + moon_mod_engine_preinit(); + moon_mod_engine_init(); #ifdef DISCORDRPC discord_init();