2022-03-21 21:52:44 -04:00
# include <math.h>
# include <stdint.h>
# include <stdlib.h>
# include <string.h>
# include <stdbool.h>
# include <assert.h>
# include <stdio.h>
# include <map>
2022-04-18 05:37:47 -04:00
# include <set>
2022-03-21 21:52:44 -04:00
# include <unordered_map>
# include <vector>
2022-05-11 13:18:24 -04:00
# include <list>
2022-03-21 21:52:44 -04:00
# ifndef _LANGUAGE_C
# define _LANGUAGE_C
# endif
# include <PR/ultra64/gbi.h>
# include <PR/ultra64/gs2dex.h>
# include <string>
# include <iostream>
2022-07-24 16:01:28 -04:00
# include "../../Cvar.h"
2022-03-21 21:52:44 -04:00
# include "gfx_pc.h"
# include "gfx_cc.h"
# include "gfx_window_manager_api.h"
# include "gfx_rendering_api.h"
# include "gfx_screen_config.h"
2022-06-27 19:43:28 -04:00
# include "../../Hooks.h"
2022-03-21 21:52:44 -04:00
# include "../../luslog.h"
# include "../StrHash64.h"
2022-06-27 19:43:28 -04:00
# include "../../ImGuiImpl.h"
2022-04-18 05:37:47 -04:00
# include "../../Environment.h"
2022-05-11 15:14:40 -04:00
# include "../../GameVersions.h"
# include "../../ResourceMgr.h"
2022-07-05 23:53:42 -04:00
# include "../../Utils.h"
2022-03-21 21:52:44 -04:00
// OTRTODO: fix header files for these
extern " C " {
2022-05-15 15:32:05 -04:00
const char * ResourceMgr_GetNameByCRC ( uint64_t crc ) ;
2022-03-21 21:52:44 -04:00
int32_t * ResourceMgr_LoadMtxByCRC ( uint64_t crc ) ;
Vtx * ResourceMgr_LoadVtxByCRC ( uint64_t crc ) ;
Gfx * ResourceMgr_LoadGfxByCRC ( uint64_t crc ) ;
char * ResourceMgr_LoadTexByCRC ( uint64_t crc ) ;
void ResourceMgr_RegisterResourcePatch ( uint64_t hash , uint32_t instrIndex , uintptr_t origData ) ;
char * ResourceMgr_LoadTexByName ( char * texPath ) ;
int ResourceMgr_OTRSigCheck ( char * imgData ) ;
}
using namespace std ;
2022-05-11 13:18:24 -04:00
# define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1)
2022-03-21 21:52:44 -04:00
# define SUPPORT_CHECK(x) assert(x)
// SCALE_M_N: upscale/downscale M-bit integer to N-bit
# define SCALE_5_8(VAL_) (((VAL_) * 0xFF) / 0x1F)
# define SCALE_8_5(VAL_) ((((VAL_) + 4) * 0x1F) / 0xFF)
# define SCALE_4_8(VAL_) ((VAL_) * 0x11)
# define SCALE_8_4(VAL_) ((VAL_) / 0x11)
# define SCALE_3_8(VAL_) ((VAL_) * 0x24)
# define SCALE_8_3(VAL_) ((VAL_) / 0x24)
2022-07-05 20:02:47 -04:00
// SCREEN_WIDTH and SCREEN_HEIGHT are defined in the headerfile
2022-03-21 21:52:44 -04:00
# define HALF_SCREEN_WIDTH (SCREEN_WIDTH / 2)
# define HALF_SCREEN_HEIGHT (SCREEN_HEIGHT / 2)
# define RATIO_X (gfx_current_dimensions.width / (2.0f * HALF_SCREEN_WIDTH))
# define RATIO_Y (gfx_current_dimensions.height / (2.0f * HALF_SCREEN_HEIGHT))
# define MAX_BUFFERED 256
//#define MAX_LIGHTS 2
# define MAX_LIGHTS 32
# define MAX_VERTICES 64
# define TEXTURE_CACHE_MAX_SIZE 500
struct RGBA {
uint8_t r , g , b , a ;
} ;
struct LoadedVertex {
float x , y , z , w ;
float u , v ;
struct RGBA color ;
uint8_t clip_rej ;
} ;
static struct {
TextureCacheMap map ;
2022-05-15 15:20:32 -04:00
list < TextureCacheMapIter > lru ;
2022-03-21 21:52:44 -04:00
vector < uint32_t > free_texture_ids ;
} gfx_texture_cache ;
struct ColorCombiner {
uint64_t shader_id0 ;
uint32_t shader_id1 ;
bool used_textures [ 2 ] ;
struct ShaderProgram * prg [ 16 ] ;
uint8_t shader_input_mapping [ 2 ] [ 7 ] ;
} ;
static map < uint64_t , struct ColorCombiner > color_combiner_pool ;
static map < uint64_t , struct ColorCombiner > : : iterator prev_combiner = color_combiner_pool . end ( ) ;
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 lookat [ 2 ] ;
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 ;
static struct RDP {
2022-04-02 13:57:20 -04:00
const uint8_t * palettes [ 2 ] ;
2022-03-21 21:52:44 -04:00
struct {
const uint8_t * addr ;
uint8_t siz ;
uint32_t width ;
2022-05-15 15:32:05 -04:00
const char * otr_path ;
2022-03-21 21:52:44 -04:00
} texture_to_load ;
struct {
const uint8_t * addr ;
uint32_t size_bytes ;
uint32_t full_image_line_size_bytes ;
uint32_t line_size_bytes ;
2022-05-15 15:32:05 -04:00
const char * otr_path ;
2022-03-21 21:52:44 -04:00
} loaded_texture [ 2 ] ;
struct {
uint8_t fmt ;
uint8_t siz ;
uint8_t cms , cmt ;
uint8_t shifts , shiftt ;
uint16_t uls , ult , lrs , lrt ; // U10.2
2022-04-02 13:57:20 -04:00
uint16_t tmem ; // 0-511, in 64-bit word units
2022-03-21 21:52:44 -04:00
uint32_t line_size_bytes ;
uint8_t palette ;
uint8_t tmem_index ; // 0 or 1 for offset 0 kB or offset 2 kB, respectively
} texture_tile [ 8 ] ;
bool textures_changed [ 2 ] ;
uint8_t first_tile_index ;
uint32_t other_mode_l , other_mode_h ;
uint64_t combine_mode ;
2022-04-25 16:19:00 -04:00
bool grayscale ;
2022-03-21 21:52:44 -04:00
uint8_t prim_lod_fraction ;
2022-04-25 16:19:00 -04:00
struct RGBA env_color , prim_color , fog_color , fill_color , grayscale_color ;
2022-03-21 21:52:44 -04:00
struct XYWidthHeight viewport , scissor ;
bool viewport_or_scissor_changed ;
void * z_buf_address ;
void * color_image_address ;
} rdp ;
static struct RenderingState {
uint8_t depth_test_and_mask ; // 1: depth test, 2: depth mask
bool decal_mode ;
bool alpha_blend ;
struct XYWidthHeight viewport , scissor ;
struct ShaderProgram * shader_program ;
TextureCacheNode * textures [ 2 ] ;
} rendering_state ;
2022-04-18 05:37:47 -04:00
struct GfxDimensions gfx_current_window_dimensions ;
2022-03-21 21:52:44 -04:00
struct GfxDimensions gfx_current_dimensions ;
static struct GfxDimensions gfx_prev_dimensions ;
2022-04-18 05:37:47 -04:00
struct XYWidthHeight gfx_current_game_window_viewport ;
static bool game_renders_to_framebuffer ;
static int game_framebuffer ;
static int game_framebuffer_msaa_resolved ;
uint32_t gfx_msaa_level = 1 ;
2022-03-21 21:52:44 -04:00
2022-05-13 18:43:55 -04:00
static bool has_drawn_imgui_menu ;
2022-03-21 21:52:44 -04:00
static bool dropped_frame ;
2022-05-13 18:43:55 -04:00
static const std : : unordered_map < Mtx * , MtxF > * current_mtx_replacements ;
2022-03-21 21:52:44 -04:00
static float buf_vbo [ MAX_BUFFERED * ( 32 * 3 ) ] ; // 3 vertices in a triangle and 32 floats per vtx
static size_t buf_vbo_len ;
static size_t buf_vbo_num_tris ;
static struct GfxWindowManagerAPI * gfx_wapi ;
static struct GfxRenderingAPI * gfx_rapi ;
static int markerOn ;
static uintptr_t segmentPointers [ 16 ] ;
struct FBInfo {
uint32_t orig_width , orig_height ;
uint32_t applied_width , applied_height ;
} ;
static bool fbActive = 0 ;
static map < int , FBInfo > : : iterator active_fb ;
static map < int , FBInfo > framebuffers ;
2022-04-18 05:37:47 -04:00
static set < pair < float , float > > get_pixel_depth_pending ;
2022-07-05 19:29:57 -04:00
static unordered_map < pair < float , float > , uint16_t , hash_pair_ff > get_pixel_depth_cached ;
2022-04-18 05:37:47 -04:00
2022-05-11 13:18:24 -04:00
# ifdef _WIN32
2022-03-21 21:52:44 -04:00
// TODO: Properly implement for MSVC
static unsigned long get_time ( void )
{
return 0 ;
}
# else
# include <time.h>
# include <string>
static unsigned long get_time ( void ) {
struct timespec ts ;
clock_gettime ( CLOCK_MONOTONIC , & ts ) ;
return ( unsigned long ) ts . tv_sec * 1000000 + ts . tv_nsec / 1000 ;
}
# endif
static void gfx_flush ( void ) {
if ( buf_vbo_len > 0 ) {
int num = buf_vbo_num_tris ;
unsigned long t0 = get_time ( ) ;
if ( markerOn )
{
int bp = 0 ;
}
gfx_rapi - > draw_triangles ( buf_vbo , buf_vbo_len , buf_vbo_num_tris ) ;
buf_vbo_len = 0 ;
buf_vbo_num_tris = 0 ;
unsigned long t1 = get_time ( ) ;
/*if (t1 - t0 > 1000) {
printf ( " f: %d %d \n " , num , ( int ) ( t1 - t0 ) ) ;
} */
}
}
static struct ShaderProgram * gfx_lookup_or_create_shader_program ( uint64_t shader_id0 , uint32_t shader_id1 ) {
struct ShaderProgram * prg = gfx_rapi - > lookup_shader ( shader_id0 , shader_id1 ) ;
if ( prg = = NULL ) {
gfx_rapi - > unload_shader ( rendering_state . shader_program ) ;
prg = gfx_rapi - > create_and_load_new_shader ( shader_id0 , shader_id1 ) ;
rendering_state . shader_program = prg ;
}
return prg ;
}
static const char * ccmux_to_string ( uint32_t ccmux ) {
static const char * const tbl [ ] = {
" G_CCMUX_COMBINED " ,
" G_CCMUX_TEXEL0 " ,
" G_CCMUX_TEXEL1 " ,
" G_CCMUX_PRIMITIVE " ,
" G_CCMUX_SHADE " ,
" G_CCMUX_ENVIRONMENT " ,
" G_CCMUX_1 " ,
" G_CCMUX_COMBINED_ALPHA " ,
" G_CCMUX_TEXEL0_ALPHA " ,
" G_CCMUX_TEXEL1_ALPHA " ,
" G_CCMUX_PRIMITIVE_ALPHA " ,
" G_CCMUX_SHADE_ALPHA " ,
" G_CCMUX_ENV_ALPHA " ,
" G_CCMUX_LOD_FRACTION " ,
" G_CCMUX_PRIM_LOD_FRAC " ,
" G_CCMUX_K5 " ,
} ;
if ( ccmux > 15 ) {
return " G_CCMUX_0 " ;
}
else {
return tbl [ ccmux ] ;
}
}
static const char * acmux_to_string ( uint32_t acmux ) {
static const char * const tbl [ ] = {
" G_ACMUX_COMBINED or G_ACMUX_LOD_FRACTION " ,
" G_ACMUX_TEXEL0 " ,
" G_ACMUX_TEXEL1 " ,
" G_ACMUX_PRIMITIVE " ,
" G_ACMUX_SHADE " ,
" G_ACMUX_ENVIRONMENT " ,
" G_ACMUX_1 or G_ACMUX_PRIM_LOD_FRAC " ,
" G_ACMUX_0 " ,
} ;
return tbl [ acmux ] ;
}
static void gfx_generate_cc ( struct ColorCombiner * comb , uint64_t cc_id ) {
if ( markerOn )
{
int bp = 0 ;
}
bool is_2cyc = ( cc_id & ( uint64_t ) SHADER_OPT_2CYC < < CC_SHADER_OPT_POS ) ! = 0 ;
uint8_t c [ 2 ] [ 2 ] [ 4 ] ;
uint64_t shader_id0 = 0 ;
uint32_t shader_id1 = ( cc_id > > CC_SHADER_OPT_POS ) ;
uint8_t shader_input_mapping [ 2 ] [ 7 ] = { { 0 } } ;
bool used_textures [ 2 ] = { false , false } ;
for ( int i = 0 ; i < 2 & & ( i = = 0 | | is_2cyc ) ; i + + ) {
uint32_t rgb_a = ( cc_id > > ( i * 28 ) ) & 0xf ;
uint32_t rgb_b = ( cc_id > > ( i * 28 + 4 ) ) & 0xf ;
uint32_t rgb_c = ( cc_id > > ( i * 28 + 8 ) ) & 0x1f ;
uint32_t rgb_d = ( cc_id > > ( i * 28 + 13 ) ) & 7 ;
uint32_t alpha_a = ( cc_id > > ( i * 28 + 16 ) ) & 7 ;
uint32_t alpha_b = ( cc_id > > ( i * 28 + 16 + 3 ) ) & 7 ;
uint32_t alpha_c = ( cc_id > > ( i * 28 + 16 + 6 ) ) & 7 ;
uint32_t alpha_d = ( cc_id > > ( i * 28 + 16 + 9 ) ) & 7 ;
if ( rgb_a > = 8 ) rgb_a = G_CCMUX_0 ;
if ( rgb_b > = 8 ) rgb_b = G_CCMUX_0 ;
if ( rgb_c > = 16 ) rgb_c = G_CCMUX_0 ;
if ( rgb_d = = 7 ) rgb_d = G_CCMUX_0 ;
if ( rgb_a = = rgb_b | | rgb_c = = G_CCMUX_0 ) {
// Normalize
rgb_a = G_CCMUX_0 ;
rgb_b = G_CCMUX_0 ;
rgb_c = G_CCMUX_0 ;
}
if ( alpha_a = = alpha_b | | alpha_c = = G_ACMUX_0 ) {
// Normalize
alpha_a = G_ACMUX_0 ;
alpha_b = G_ACMUX_0 ;
alpha_c = G_ACMUX_0 ;
}
if ( i = = 1 ) {
if ( rgb_a ! = G_CCMUX_COMBINED & & rgb_b ! = G_CCMUX_COMBINED & & rgb_c ! = G_CCMUX_COMBINED & & rgb_d ! = G_CCMUX_COMBINED ) {
// First cycle RGB not used, so clear it away
c [ 0 ] [ 0 ] [ 0 ] = c [ 0 ] [ 0 ] [ 1 ] = c [ 0 ] [ 0 ] [ 2 ] = c [ 0 ] [ 0 ] [ 3 ] = G_CCMUX_0 ;
}
if ( rgb_c ! = G_CCMUX_COMBINED_ALPHA & & alpha_a ! = G_ACMUX_COMBINED & & alpha_b ! = G_ACMUX_COMBINED & & alpha_d ! = G_ACMUX_COMBINED )
{
// First cycle ALPHA not used, so clear it away
c [ 0 ] [ 1 ] [ 0 ] = c [ 0 ] [ 1 ] [ 1 ] = c [ 0 ] [ 1 ] [ 2 ] = c [ 0 ] [ 1 ] [ 3 ] = G_ACMUX_0 ;
}
}
c [ i ] [ 0 ] [ 0 ] = rgb_a ;
c [ i ] [ 0 ] [ 1 ] = rgb_b ;
c [ i ] [ 0 ] [ 2 ] = rgb_c ;
c [ i ] [ 0 ] [ 3 ] = rgb_d ;
c [ i ] [ 1 ] [ 0 ] = alpha_a ;
c [ i ] [ 1 ] [ 1 ] = alpha_b ;
c [ i ] [ 1 ] [ 2 ] = alpha_c ;
c [ i ] [ 1 ] [ 3 ] = alpha_d ;
}
if ( ! is_2cyc ) {
for ( int i = 0 ; i < 2 ; i + + ) {
for ( int k = 0 ; k < 4 ; k + + ) {
c [ 1 ] [ i ] [ k ] = i = = 0 ? G_CCMUX_0 : G_ACMUX_0 ;
}
}
}
{
uint8_t input_number [ 32 ] = { 0 } ;
int next_input_number = SHADER_INPUT_1 ;
for ( int i = 0 ; i < 2 & & ( i = = 0 | | is_2cyc ) ; i + + ) {
for ( int j = 0 ; j < 4 ; j + + ) {
uint32_t val = 0 ;
switch ( c [ i ] [ 0 ] [ j ] ) {
case G_CCMUX_0 :
val = SHADER_0 ;
break ;
case G_CCMUX_1 :
val = SHADER_1 ;
break ;
case G_CCMUX_TEXEL0 :
val = SHADER_TEXEL0 ;
used_textures [ 0 ] = true ;
break ;
case G_CCMUX_TEXEL1 :
val = SHADER_TEXEL1 ;
used_textures [ 1 ] = true ;
break ;
case G_CCMUX_TEXEL0_ALPHA :
val = SHADER_TEXEL0A ;
used_textures [ 0 ] = true ;
break ;
case G_CCMUX_TEXEL1_ALPHA :
val = SHADER_TEXEL1A ;
used_textures [ 1 ] = true ;
break ;
case G_CCMUX_PRIMITIVE :
case G_CCMUX_PRIMITIVE_ALPHA :
case G_CCMUX_PRIM_LOD_FRAC :
case G_CCMUX_SHADE :
case G_CCMUX_ENVIRONMENT :
case G_CCMUX_ENV_ALPHA :
case G_CCMUX_LOD_FRACTION :
if ( input_number [ c [ i ] [ 0 ] [ j ] ] = = 0 ) {
shader_input_mapping [ 0 ] [ next_input_number - 1 ] = c [ i ] [ 0 ] [ j ] ;
input_number [ c [ i ] [ 0 ] [ j ] ] = next_input_number + + ;
}
val = input_number [ c [ i ] [ 0 ] [ j ] ] ;
break ;
case G_CCMUX_COMBINED :
val = SHADER_COMBINED ;
break ;
default :
fprintf ( stderr , " Unsupported ccmux: %d \n " , c [ i ] [ 0 ] [ j ] ) ;
break ;
}
shader_id0 | = ( uint64_t ) val < < ( i * 32 + j * 4 ) ;
}
}
}
{
uint8_t input_number [ 16 ] = { 0 } ;
int next_input_number = SHADER_INPUT_1 ;
for ( int i = 0 ; i < 2 ; i + + ) {
for ( int j = 0 ; j < 4 ; j + + ) {
uint32_t val = 0 ;
switch ( c [ i ] [ 1 ] [ j ] ) {
case G_ACMUX_0 :
val = SHADER_0 ;
break ;
case G_ACMUX_TEXEL0 :
val = SHADER_TEXEL0 ;
used_textures [ 0 ] = true ;
break ;
case G_ACMUX_TEXEL1 :
val = SHADER_TEXEL1 ;
used_textures [ 1 ] = true ;
break ;
case G_ACMUX_LOD_FRACTION :
//case G_ACMUX_COMBINED: same numerical value
if ( j ! = 2 ) {
val = SHADER_COMBINED ;
break ;
}
c [ i ] [ 1 ] [ j ] = G_CCMUX_LOD_FRACTION ;
2022-05-11 13:18:24 -04:00
[[fallthrough]] ; // for G_ACMUX_LOD_FRACTION
2022-03-21 21:52:44 -04:00
case G_ACMUX_1 :
//case G_ACMUX_PRIM_LOD_FRAC: same numerical value
if ( j ! = 2 ) {
val = SHADER_1 ;
break ;
}
2022-05-11 13:18:24 -04:00
[[fallthrough]] ; // for G_ACMUX_PRIM_LOD_FRAC
2022-03-21 21:52:44 -04:00
case G_ACMUX_PRIMITIVE :
case G_ACMUX_SHADE :
case G_ACMUX_ENVIRONMENT :
if ( input_number [ c [ i ] [ 1 ] [ j ] ] = = 0 ) {
shader_input_mapping [ 1 ] [ next_input_number - 1 ] = c [ i ] [ 1 ] [ j ] ;
input_number [ c [ i ] [ 1 ] [ j ] ] = next_input_number + + ;
}
val = input_number [ c [ i ] [ 1 ] [ j ] ] ;
break ;
}
shader_id0 | = ( uint64_t ) val < < ( i * 32 + 16 + j * 4 ) ;
}
}
}
comb - > shader_id0 = shader_id0 ;
comb - > shader_id1 = shader_id1 ;
comb - > used_textures [ 0 ] = used_textures [ 0 ] ;
comb - > used_textures [ 1 ] = used_textures [ 1 ] ;
//comb->prg = gfx_lookup_or_create_shader_program(shader_id0, shader_id1);
memcpy ( comb - > shader_input_mapping , shader_input_mapping , sizeof ( shader_input_mapping ) ) ;
}
static struct ColorCombiner * gfx_lookup_or_create_color_combiner ( uint64_t cc_id ) {
if ( prev_combiner ! = color_combiner_pool . end ( ) & & prev_combiner - > first = = cc_id ) {
return & prev_combiner - > second ;
}
prev_combiner = color_combiner_pool . find ( cc_id ) ;
if ( prev_combiner ! = color_combiner_pool . end ( ) ) {
return & prev_combiner - > second ;
}
gfx_flush ( ) ;
prev_combiner = color_combiner_pool . insert ( make_pair ( cc_id , ColorCombiner ( ) ) ) . first ;
gfx_generate_cc ( & prev_combiner - > second , cc_id ) ;
return & prev_combiner - > second ;
}
void gfx_texture_cache_clear ( )
{
for ( const auto & entry : gfx_texture_cache . map ) {
gfx_texture_cache . free_texture_ids . push_back ( entry . second . texture_id ) ;
}
gfx_texture_cache . map . clear ( ) ;
gfx_texture_cache . lru . clear ( ) ;
}
2022-04-02 13:57:20 -04:00
static bool gfx_texture_cache_lookup ( int i , int tile ) {
uint8_t fmt = rdp . texture_tile [ tile ] . fmt ;
uint8_t siz = rdp . texture_tile [ tile ] . siz ;
uint32_t tmem_index = rdp . texture_tile [ tile ] . tmem_index ;
TextureCacheNode * * n = & rendering_state . textures [ i ] ;
const uint8_t * orig_addr = rdp . loaded_texture [ tmem_index ] . addr ;
uint8_t palette_index = rdp . texture_tile [ tile ] . palette ;
TextureCacheKey key ;
if ( fmt = = G_IM_FMT_CI ) {
key = { orig_addr , { rdp . palettes [ 0 ] , rdp . palettes [ 1 ] } , fmt , siz , palette_index } ;
} else {
key = { orig_addr , { } , fmt , siz , palette_index } ;
}
2022-05-15 15:20:32 -04:00
TextureCacheMap : : iterator it = gfx_texture_cache . map . find ( key ) ;
2022-03-21 21:52:44 -04:00
if ( it ! = gfx_texture_cache . map . end ( ) ) {
gfx_rapi - > select_texture ( i , it - > second . texture_id ) ;
* n = & * it ;
2022-05-15 15:20:32 -04:00
gfx_texture_cache . lru . splice ( gfx_texture_cache . lru . end ( ) , gfx_texture_cache . lru , it - > second . lru_location ) ; // move to back
2022-03-21 21:52:44 -04:00
return true ;
}
if ( gfx_texture_cache . map . size ( ) > = TEXTURE_CACHE_MAX_SIZE ) {
// Remove the texture that was least recently used
2022-05-15 15:20:32 -04:00
it = gfx_texture_cache . lru . front ( ) . it ;
2022-03-21 21:52:44 -04:00
gfx_texture_cache . free_texture_ids . push_back ( it - > second . texture_id ) ;
gfx_texture_cache . map . erase ( it ) ;
gfx_texture_cache . lru . pop_front ( ) ;
}
uint32_t texture_id ;
if ( ! gfx_texture_cache . free_texture_ids . empty ( ) ) {
texture_id = gfx_texture_cache . free_texture_ids . back ( ) ;
gfx_texture_cache . free_texture_ids . pop_back ( ) ;
} else {
texture_id = gfx_rapi - > new_texture ( ) ;
}
it = gfx_texture_cache . map . insert ( make_pair ( key , TextureCacheValue ( ) ) ) . first ;
TextureCacheNode * node = & * it ;
node - > second . texture_id = texture_id ;
2022-05-15 15:20:32 -04:00
node - > second . lru_location = gfx_texture_cache . lru . insert ( gfx_texture_cache . lru . end ( ) , { it } ) ;
2022-03-21 21:52:44 -04:00
gfx_rapi - > select_texture ( i , texture_id ) ;
gfx_rapi - > set_sampler_parameters ( i , false , 0 , 0 ) ;
* n = node ;
return false ;
}
static void gfx_texture_cache_delete ( const uint8_t * orig_addr )
{
while ( gfx_texture_cache . map . bucket_count ( ) > 0 ) {
2022-07-10 10:51:12 -04:00
TextureCacheKey key = { orig_addr , { 0 } , 0 , 0 } ; // bucket index only depends on the address
2022-03-21 21:52:44 -04:00
size_t bucket = gfx_texture_cache . map . bucket ( key ) ;
bool again = false ;
for ( auto it = gfx_texture_cache . map . begin ( bucket ) ; it ! = gfx_texture_cache . map . end ( bucket ) ; + + it ) {
if ( it - > first . texture_addr = = orig_addr ) {
2022-05-15 15:20:32 -04:00
gfx_texture_cache . lru . erase ( it - > second . lru_location ) ;
2022-03-21 21:52:44 -04:00
gfx_texture_cache . free_texture_ids . push_back ( it - > second . texture_id ) ;
2022-05-11 13:18:24 -04:00
gfx_texture_cache . map . erase ( it - > first ) ;
2022-03-21 21:52:44 -04:00
again = true ;
break ;
}
}
if ( ! again ) {
break ;
}
}
}
static void import_texture_rgba16 ( int tile ) {
uint8_t rgba32_buf [ 480 * 240 * 4 ] ;
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
//SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes);
for ( uint32_t i = 0 ; i < size_bytes / 2 ; i + + ) {
uint16_t col16 = ( addr [ 2 * i ] < < 8 ) | addr [ 2 * i + 1 ] ;
uint8_t a = col16 & 1 ;
uint8_t r = col16 > > 11 ;
uint8_t g = ( col16 > > 6 ) & 0x1f ;
uint8_t b = ( col16 > > 1 ) & 0x1f ;
rgba32_buf [ 4 * i + 0 ] = SCALE_5_8 ( r ) ;
rgba32_buf [ 4 * i + 1 ] = SCALE_5_8 ( g ) ;
rgba32_buf [ 4 * i + 2 ] = SCALE_5_8 ( b ) ;
rgba32_buf [ 4 * i + 3 ] = a ? 255 : 0 ;
}
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes / 2 ;
uint32_t height = size_bytes / rdp . texture_tile [ tile ] . line_size_bytes ;
gfx_rapi - > upload_texture ( rgba32_buf , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height);
}
static void import_texture_rgba32 ( int tile ) {
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
SUPPORT_CHECK ( full_image_line_size_bytes = = line_size_bytes ) ;
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes / 2 ;
uint32_t height = ( size_bytes / 2 ) / rdp . texture_tile [ tile ] . line_size_bytes ;
gfx_rapi - > upload_texture ( addr , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, addr, width, height);
}
static void import_texture_ia4 ( int tile ) {
uint8_t rgba32_buf [ 32768 ] ;
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
SUPPORT_CHECK ( full_image_line_size_bytes = = line_size_bytes ) ;
for ( uint32_t i = 0 ; i < size_bytes * 2 ; i + + ) {
uint8_t byte = addr [ i / 2 ] ;
uint8_t part = ( byte > > ( 4 - ( i % 2 ) * 4 ) ) & 0xf ;
uint8_t intensity = part > > 1 ;
uint8_t alpha = part & 1 ;
uint8_t r = intensity ;
uint8_t g = intensity ;
uint8_t b = intensity ;
rgba32_buf [ 4 * i + 0 ] = SCALE_3_8 ( r ) ;
rgba32_buf [ 4 * i + 1 ] = SCALE_3_8 ( g ) ;
rgba32_buf [ 4 * i + 2 ] = SCALE_3_8 ( b ) ;
rgba32_buf [ 4 * i + 3 ] = alpha ? 255 : 0 ;
}
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes * 2 ;
uint32_t height = size_bytes / rdp . texture_tile [ tile ] . line_size_bytes ;
gfx_rapi - > upload_texture ( rgba32_buf , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height);
}
static void import_texture_ia8 ( int tile ) {
uint8_t rgba32_buf [ 16384 ] ;
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
SUPPORT_CHECK ( full_image_line_size_bytes = = line_size_bytes ) ;
for ( uint32_t i = 0 ; i < size_bytes ; i + + ) {
uint8_t intensity = addr [ i ] > > 4 ;
uint8_t alpha = addr [ i ] & 0xf ;
uint8_t r = intensity ;
uint8_t g = intensity ;
uint8_t b = intensity ;
rgba32_buf [ 4 * i + 0 ] = SCALE_4_8 ( r ) ;
rgba32_buf [ 4 * i + 1 ] = SCALE_4_8 ( g ) ;
rgba32_buf [ 4 * i + 2 ] = SCALE_4_8 ( b ) ;
rgba32_buf [ 4 * i + 3 ] = SCALE_4_8 ( alpha ) ;
}
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes ;
uint32_t height = size_bytes / rdp . texture_tile [ tile ] . line_size_bytes ;
gfx_rapi - > upload_texture ( rgba32_buf , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height);
}
static void import_texture_ia16 ( int tile ) {
uint8_t rgba32_buf [ 8192 ] ;
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
SUPPORT_CHECK ( full_image_line_size_bytes = = line_size_bytes ) ;
for ( uint32_t i = 0 ; i < size_bytes / 2 ; i + + ) {
uint8_t intensity = addr [ 2 * i ] ;
uint8_t alpha = addr [ 2 * i + 1 ] ;
uint8_t r = intensity ;
uint8_t g = intensity ;
uint8_t b = intensity ;
rgba32_buf [ 4 * i + 0 ] = r ;
rgba32_buf [ 4 * i + 1 ] = g ;
rgba32_buf [ 4 * i + 2 ] = b ;
rgba32_buf [ 4 * i + 3 ] = alpha ;
}
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes / 2 ;
uint32_t height = size_bytes / rdp . texture_tile [ tile ] . line_size_bytes ;
gfx_rapi - > upload_texture ( rgba32_buf , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height);
}
static void import_texture_i4 ( int tile ) {
uint8_t rgba32_buf [ 32768 ] ;
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
//SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes);
for ( uint32_t i = 0 ; i < size_bytes * 2 ; i + + ) {
uint8_t byte = addr [ i / 2 ] ;
uint8_t part = ( byte > > ( 4 - ( i % 2 ) * 4 ) ) & 0xf ;
uint8_t intensity = part ;
uint8_t r = intensity ;
uint8_t g = intensity ;
uint8_t b = intensity ;
uint8_t a = intensity ;
rgba32_buf [ 4 * i + 0 ] = SCALE_4_8 ( r ) ;
rgba32_buf [ 4 * i + 1 ] = SCALE_4_8 ( g ) ;
rgba32_buf [ 4 * i + 2 ] = SCALE_4_8 ( b ) ;
rgba32_buf [ 4 * i + 3 ] = SCALE_4_8 ( a ) ;
}
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes * 2 ;
uint32_t height = size_bytes / rdp . texture_tile [ tile ] . line_size_bytes ;
gfx_rapi - > upload_texture ( rgba32_buf , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height);
}
static void import_texture_i8 ( int tile ) {
uint8_t rgba32_buf [ 16384 ] ;
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
//SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes);
for ( uint32_t i = 0 ; i < size_bytes ; i + + ) {
uint8_t intensity = addr [ i ] ;
uint8_t r = intensity ;
uint8_t g = intensity ;
uint8_t b = intensity ;
uint8_t a = intensity ;
rgba32_buf [ 4 * i + 0 ] = r ;
rgba32_buf [ 4 * i + 1 ] = g ;
rgba32_buf [ 4 * i + 2 ] = b ;
rgba32_buf [ 4 * i + 3 ] = a ;
}
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes ;
uint32_t height = size_bytes / rdp . texture_tile [ tile ] . line_size_bytes ;
gfx_rapi - > upload_texture ( rgba32_buf , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height);
}
static void import_texture_ci4 ( int tile ) {
uint8_t rgba32_buf [ 32768 ] ;
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
2022-04-02 13:57:20 -04:00
uint32_t pal_idx = rdp . texture_tile [ tile ] . palette ; // 0-15
const uint8_t * palette = rdp . palettes [ pal_idx / 8 ] + ( pal_idx % 8 ) * 16 * 2 ; // 16 pixel entries, 16 bits each
2022-03-21 21:52:44 -04:00
SUPPORT_CHECK ( full_image_line_size_bytes = = line_size_bytes ) ;
for ( uint32_t i = 0 ; i < size_bytes * 2 ; i + + ) {
uint8_t byte = addr [ i / 2 ] ;
uint8_t idx = ( byte > > ( 4 - ( i % 2 ) * 4 ) ) & 0xf ;
uint16_t col16 = ( palette [ idx * 2 ] < < 8 ) | palette [ idx * 2 + 1 ] ; // Big endian load
uint8_t a = col16 & 1 ;
uint8_t r = col16 > > 11 ;
uint8_t g = ( col16 > > 6 ) & 0x1f ;
uint8_t b = ( col16 > > 1 ) & 0x1f ;
rgba32_buf [ 4 * i + 0 ] = SCALE_5_8 ( r ) ;
rgba32_buf [ 4 * i + 1 ] = SCALE_5_8 ( g ) ;
rgba32_buf [ 4 * i + 2 ] = SCALE_5_8 ( b ) ;
rgba32_buf [ 4 * i + 3 ] = a ? 255 : 0 ;
}
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes * 2 ;
uint32_t height = size_bytes / rdp . texture_tile [ tile ] . line_size_bytes ;
gfx_rapi - > upload_texture ( rgba32_buf , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height);
}
static void import_texture_ci8 ( int tile ) {
uint8_t rgba32_buf [ 16384 ] ;
const uint8_t * addr = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr ;
uint32_t size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t full_image_line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes ;
uint32_t line_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes ;
for ( uint32_t i = 0 , j = 0 ; i < size_bytes ; j + = full_image_line_size_bytes - line_size_bytes )
{
for ( uint32_t k = 0 ; k < line_size_bytes ; i + + , k + + , j + + ) {
uint8_t idx = addr [ j ] ;
2022-04-02 13:57:20 -04:00
uint16_t col16 = ( rdp . palettes [ idx / 128 ] [ ( idx % 128 ) * 2 ] < < 8 ) | rdp . palettes [ idx / 128 ] [ ( idx % 128 ) * 2 + 1 ] ; // Big endian load
2022-03-21 21:52:44 -04:00
uint8_t a = col16 & 1 ;
uint8_t r = col16 > > 11 ;
uint8_t g = ( col16 > > 6 ) & 0x1f ;
uint8_t b = ( col16 > > 1 ) & 0x1f ;
rgba32_buf [ 4 * i + 0 ] = SCALE_5_8 ( r ) ;
rgba32_buf [ 4 * i + 1 ] = SCALE_5_8 ( g ) ;
rgba32_buf [ 4 * i + 2 ] = SCALE_5_8 ( b ) ;
rgba32_buf [ 4 * i + 3 ] = a ? 255 : 0 ;
}
}
uint32_t width = rdp . texture_tile [ tile ] . line_size_bytes ;
uint32_t height = size_bytes / rdp . texture_tile [ tile ] . line_size_bytes ;
if ( size_bytes > 15000 )
{
int bp = 0 ;
}
gfx_rapi - > upload_texture ( rgba32_buf , width , height ) ;
// DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height);
}
static void import_texture ( int i , int tile ) {
uint8_t fmt = rdp . texture_tile [ tile ] . fmt ;
uint8_t siz = rdp . texture_tile [ tile ] . siz ;
uint32_t tmem_index = rdp . texture_tile [ tile ] . tmem_index ;
2022-04-02 13:57:20 -04:00
if ( gfx_texture_cache_lookup ( i , tile ) )
2022-03-21 21:52:44 -04:00
{
return ;
}
int t0 = get_time ( ) ;
if ( fmt = = G_IM_FMT_RGBA ) {
if ( siz = = G_IM_SIZ_16b ) {
import_texture_rgba16 ( tile ) ;
} else if ( siz = = G_IM_SIZ_32b ) {
import_texture_rgba32 ( tile ) ;
} else {
//abort(); // OTRTODO: Sometimes, seemingly randomly, we end up here. Could be a bad dlist, could be something F3D does not have supported. Further investigation is needed.
}
} else if ( fmt = = G_IM_FMT_IA ) {
if ( siz = = G_IM_SIZ_4b ) {
import_texture_ia4 ( tile ) ;
} else if ( siz = = G_IM_SIZ_8b ) {
import_texture_ia8 ( tile ) ;
} else if ( siz = = G_IM_SIZ_16b ) {
import_texture_ia16 ( tile ) ;
} else {
abort ( ) ;
}
} else if ( fmt = = G_IM_FMT_CI ) {
if ( siz = = G_IM_SIZ_4b ) {
import_texture_ci4 ( tile ) ;
} else if ( siz = = G_IM_SIZ_8b ) {
import_texture_ci8 ( tile ) ;
} else {
abort ( ) ;
}
} else if ( fmt = = G_IM_FMT_I ) {
if ( siz = = G_IM_SIZ_4b ) {
import_texture_i4 ( tile ) ;
} else if ( siz = = G_IM_SIZ_8b ) {
import_texture_i8 ( tile ) ;
} else {
abort ( ) ;
}
} else {
abort ( ) ;
}
int t1 = get_time ( ) ;
//printf("Time diff: %d\n", t1 - t0);
}
static void gfx_normalize_vector ( float v [ 3 ] ) {
float s = sqrtf ( v [ 0 ] * v [ 0 ] + v [ 1 ] * v [ 1 ] + v [ 2 ] * v [ 2 ] ) ;
v [ 0 ] / = s ;
v [ 1 ] / = s ;
v [ 2 ] / = s ;
}
static void gfx_transposed_matrix_mul ( float res [ 3 ] , const float a [ 3 ] , const float b [ 4 ] [ 4 ] ) {
res [ 0 ] = a [ 0 ] * b [ 0 ] [ 0 ] + a [ 1 ] * b [ 0 ] [ 1 ] + a [ 2 ] * b [ 0 ] [ 2 ] ;
res [ 1 ] = a [ 0 ] * b [ 1 ] [ 0 ] + a [ 1 ] * b [ 1 ] [ 1 ] + a [ 2 ] * b [ 1 ] [ 2 ] ;
res [ 2 ] = a [ 0 ] * b [ 2 ] [ 0 ] + a [ 1 ] * b [ 2 ] [ 1 ] + a [ 2 ] * b [ 2 ] [ 2 ] ;
}
static void calculate_normal_dir ( const Light_t * light , float coeffs [ 3 ] ) {
float light_dir [ 3 ] = {
light - > dir [ 0 ] / 127.0f ,
light - > dir [ 1 ] / 127.0f ,
light - > dir [ 2 ] / 127.0f
} ;
2022-07-05 19:29:57 -04:00
2022-03-21 21:52:44 -04:00
gfx_transposed_matrix_mul ( coeffs , light_dir , rsp . modelview_matrix_stack [ rsp . modelview_matrix_stack_size - 1 ] ) ;
gfx_normalize_vector ( coeffs ) ;
}
static void gfx_matrix_mul ( float res [ 4 ] [ 4 ] , const float a [ 4 ] [ 4 ] , const float b [ 4 ] [ 4 ] ) {
float tmp [ 4 ] [ 4 ] ;
for ( int i = 0 ; i < 4 ; i + + ) {
for ( int j = 0 ; j < 4 ; j + + ) {
tmp [ i ] [ j ] = a [ i ] [ 0 ] * b [ 0 ] [ j ] +
a [ i ] [ 1 ] * b [ 1 ] [ j ] +
a [ i ] [ 2 ] * b [ 2 ] [ j ] +
a [ i ] [ 3 ] * b [ 3 ] [ j ] ;
}
}
memcpy ( res , tmp , sizeof ( tmp ) ) ;
}
static void gfx_sp_matrix ( uint8_t parameters , const int32_t * addr ) {
float matrix [ 4 ] [ 4 ] ;
2022-05-13 18:43:55 -04:00
if ( auto it = current_mtx_replacements - > find ( ( Mtx * ) addr ) ; it ! = current_mtx_replacements - > end ( ) ) {
for ( int i = 0 ; i < 4 ; i + + ) {
for ( int j = 0 ; j < 4 ; j + + ) {
float v = it - > second . mf [ i ] [ j ] ;
int as_int = ( int ) ( v * 65536.0f ) ;
matrix [ i ] [ j ] = as_int * ( 1.0f / 65536.0f ) ;
}
}
} else {
2022-03-21 21:52:44 -04:00
# ifndef GBI_FLOATS
2022-05-13 18:43:55 -04:00
// Original GBI where fixed point matrices are used
for ( int i = 0 ; i < 4 ; i + + ) {
for ( int j = 0 ; j < 4 ; j + = 2 ) {
int32_t int_part = addr [ i * 2 + j / 2 ] ;
uint32_t frac_part = addr [ 8 + i * 2 + j / 2 ] ;
matrix [ i ] [ j ] = ( int32_t ) ( ( int_part & 0xffff0000 ) | ( frac_part > > 16 ) ) / 65536.0f ;
matrix [ i ] [ j + 1 ] = ( int32_t ) ( ( int_part < < 16 ) | ( frac_part & 0xffff ) ) / 65536.0f ;
}
2022-03-21 21:52:44 -04:00
}
# else
2022-05-13 18:43:55 -04:00
// For a modified GBI where fixed point values are replaced with floats
memcpy ( matrix , addr , sizeof ( matrix ) ) ;
2022-03-21 21:52:44 -04:00
# endif
2022-05-13 18:43:55 -04:00
}
2022-03-21 21:52:44 -04:00
if ( parameters & G_MTX_PROJECTION ) {
if ( parameters & G_MTX_LOAD ) {
memcpy ( rsp . P_matrix , matrix , sizeof ( matrix ) ) ;
} else {
gfx_matrix_mul ( rsp . P_matrix , matrix , rsp . P_matrix ) ;
}
} else { // G_MTX_MODELVIEW
if ( ( parameters & G_MTX_PUSH ) & & rsp . modelview_matrix_stack_size < 11 ) {
+ + rsp . modelview_matrix_stack_size ;
memcpy ( rsp . modelview_matrix_stack [ rsp . modelview_matrix_stack_size - 1 ] , rsp . modelview_matrix_stack [ rsp . modelview_matrix_stack_size - 2 ] , sizeof ( matrix ) ) ;
}
if ( parameters & G_MTX_LOAD ) {
memcpy ( rsp . modelview_matrix_stack [ rsp . modelview_matrix_stack_size - 1 ] , matrix , sizeof ( matrix ) ) ;
} else {
gfx_matrix_mul ( rsp . modelview_matrix_stack [ rsp . modelview_matrix_stack_size - 1 ] , matrix , rsp . modelview_matrix_stack [ rsp . modelview_matrix_stack_size - 1 ] ) ;
}
rsp . lights_changed = 1 ;
}
gfx_matrix_mul ( rsp . MP_matrix , rsp . modelview_matrix_stack [ rsp . modelview_matrix_stack_size - 1 ] , rsp . P_matrix ) ;
}
static void gfx_sp_pop_matrix ( uint32_t count ) {
while ( count - - ) {
if ( rsp . modelview_matrix_stack_size > 0 ) {
- - rsp . modelview_matrix_stack_size ;
if ( rsp . modelview_matrix_stack_size > 0 ) {
gfx_matrix_mul ( rsp . MP_matrix , rsp . modelview_matrix_stack [ rsp . modelview_matrix_stack_size - 1 ] , rsp . P_matrix ) ;
}
}
}
}
static float gfx_adjust_x_for_aspect_ratio ( float x )
{
if ( fbActive )
return x ;
else
return x * ( 4.0f / 3.0f ) / ( ( float ) gfx_current_dimensions . width / ( float ) gfx_current_dimensions . height ) ;
}
static void gfx_adjust_width_height_for_scale ( uint32_t & width , uint32_t & height ) {
width = round ( width * RATIO_Y ) ;
height = round ( height * RATIO_Y ) ;
if ( width = = 0 ) {
width = 1 ;
}
if ( height = = 0 ) {
height = 1 ;
}
}
static void gfx_sp_vertex ( size_t n_vertices , size_t dest_index , const Vtx * vertices ) {
for ( size_t i = 0 ; i < n_vertices ; i + + , dest_index + + ) {
const Vtx_t * v = & vertices [ i ] . v ;
const Vtx_tn * vn = & vertices [ i ] . n ;
struct LoadedVertex * d = & rsp . loaded_vertices [ dest_index ] ;
if ( v = = NULL )
return ;
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 + + ) {
calculate_normal_dir ( & rsp . current_lights [ i ] , rsp . current_lights_coeffs [ i ] ) ;
}
/*static const Light_t lookat_x = {{0, 0, 0}, 0, {0, 0, 0}, 0, {127, 0, 0}, 0};
static const Light_t lookat_y = { { 0 , 0 , 0 } , 0 , { 0 , 0 , 0 } , 0 , { 0 , 127 , 0 } , 0 } ; */
calculate_normal_dir ( & rsp . lookat [ 0 ] , rsp . current_lookat_coeffs [ 0 ] ) ;
calculate_normal_dir ( & rsp . lookat [ 1 ] , 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 ] ;
intensity + = vn - > n [ 1 ] * rsp . current_lights_coeffs [ i ] [ 1 ] ;
intensity + = vn - > n [ 2 ] * rsp . current_lights_coeffs [ i ] [ 2 ] ;
intensity / = 127.0f ;
if ( intensity > 0.0f ) {
r + = intensity * rsp . current_lights [ i ] . col [ 0 ] ;
g + = intensity * rsp . current_lights [ i ] . col [ 1 ] ;
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 ] ;
dotx + = vn - > n [ 1 ] * rsp . current_lookat_coeffs [ 0 ] [ 1 ] ;
dotx + = vn - > n [ 2 ] * rsp . current_lookat_coeffs [ 0 ] [ 2 ] ;
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 ] ;
dotx / = 127.0f ;
doty / = 127.0f ;
2022-07-05 23:53:42 -04:00
dotx = math : : clamp ( dotx , - 1.0f , 1.0f ) ;
doty = math : : clamp ( doty , - 1.0f , 1.0f ) ;
2022-03-21 21:52:44 -04:00
if ( rsp . geometry_mode & G_TEXTURE_GEN_LINEAR ) {
// Not sure exactly what formula we should use to get accurate values
/*dotx = (2.906921f * dotx * dotx + 1.36114f) * dotx;
doty = ( 2.906921f * doty * doty + 1.36114f ) * doty ;
dotx = ( dotx + 1.0f ) / 4.0f ;
doty = ( doty + 1.0f ) / 4.0f ; */
2022-07-05 19:29:57 -04:00
dotx = acosf ( - dotx ) /* M_PI */ / 4.0f ;
doty = acosf ( - doty ) /* M_PI */ / 4.0f ;
2022-03-21 21:52:44 -04:00
}
else {
dotx = ( dotx + 1.0f ) / 4.0f ;
doty = ( doty + 1.0f ) / 4.0f ;
}
U = ( int32_t ) ( dotx * rsp . texture_scaling_factor . s ) ;
V = ( int32_t ) ( doty * rsp . texture_scaling_factor . t ) ;
}
} else {
d - > color . r = v - > cn [ 0 ] ;
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 ;
2022-07-05 19:29:57 -04:00
if ( x < - w ) d - > clip_rej | = 1 ; // CLIP_LEFT
if ( x > w ) d - > clip_rej | = 2 ; // CLIP_RIGHT
if ( y < - w ) d - > clip_rej | = 4 ; // CLIP_BOTTOM
if ( y > w ) d - > clip_rej | = 8 ; // CLIP_TOP
// if (z < -w) d->clip_rej |= 16; // CLIP_NEAR
if ( z > w ) d - > clip_rej | = 32 ; // CLIP_FAR
2022-03-21 21:52:44 -04:00
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 ;
2022-07-05 19:29:57 -04:00
if ( winv < 0.0f ) winv = std : : numeric_limits < int16_t > : : max ( ) ;
2022-03-21 21:52:44 -04:00
float fog_z = z * winv * rsp . fog_mul + rsp . fog_offset ;
2022-07-05 23:53:42 -04:00
fog_z = math : : clamp ( fog_z , 0.0f , 255.0f ) ;
2022-03-21 21:52:44 -04:00
d - > color . a = fog_z ; // Use alpha variable to store fog factor
} else {
d - > color . a = v - > cn [ 3 ] ;
}
}
}
static void gfx_sp_modify_vertex ( uint16_t vtx_idx , uint8_t where , uint32_t val ) {
SUPPORT_CHECK ( where = = G_MWO_POINT_ST ) ;
int16_t s = ( int16_t ) ( val > > 16 ) ;
int16_t t = ( int16_t ) val ;
struct LoadedVertex * v = & rsp . loaded_vertices [ vtx_idx ] ;
v - > u = s ;
v - > v = t ;
}
static void gfx_sp_tri1 ( uint8_t vtx1_idx , uint8_t vtx2_idx , uint8_t vtx3_idx , bool is_rect ) {
struct LoadedVertex * v1 = & rsp . loaded_vertices [ vtx1_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 ;
break ;
case G_CULL_BACK :
if ( cross > = 0 ) return ;
break ;
case G_CULL_BOTH :
// Why is this even an option?
return ;
}
}
bool depth_test = ( rsp . geometry_mode & G_ZBUFFER ) = = G_ZBUFFER ;
bool depth_mask = ( rdp . other_mode_l & Z_UPD ) = = Z_UPD ;
uint8_t depth_test_and_mask = ( depth_test ? 1 : 0 ) | ( depth_mask ? 2 : 0 ) ;
if ( depth_test_and_mask ! = rendering_state . depth_test_and_mask ) {
gfx_flush ( ) ;
gfx_rapi - > set_depth_test_and_mask ( depth_test , depth_mask ) ;
rendering_state . depth_test_and_mask = depth_test_and_mask ;
}
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 ( ) ;
gfx_rapi - > set_viewport ( rdp . viewport . x , rdp . viewport . y , rdp . viewport . width , rdp . viewport . height ) ;
rendering_state . viewport = rdp . viewport ;
}
if ( memcmp ( & rdp . scissor , & rendering_state . scissor , sizeof ( rdp . scissor ) ) ! = 0 ) {
gfx_flush ( ) ;
gfx_rapi - > set_scissor ( rdp . scissor . x , rdp . scissor . y , rdp . scissor . width , rdp . scissor . height ) ;
rendering_state . scissor = rdp . scissor ;
}
rdp . viewport_or_scissor_changed = false ;
}
uint64_t cc_id = rdp . combine_mode ;
bool use_alpha = ( rdp . other_mode_l & ( 3 < < 20 ) ) = = ( G_BL_CLR_MEM < < 20 ) & & ( rdp . other_mode_l & ( 3 < < 16 ) ) = = ( G_BL_1MA < < 16 ) ;
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 & ( 3U < < G_MDSFT_ALPHACOMPARE ) ) = = G_AC_DITHER ;
bool use_2cyc = ( rdp . other_mode_h & ( 3U < < G_MDSFT_CYCLETYPE ) ) = = G_CYC_2CYCLE ;
bool alpha_threshold = ( rdp . other_mode_l & ( 3U < < G_MDSFT_ALPHACOMPARE ) ) = = G_AC_THRESHOLD ;
bool invisible = ( rdp . other_mode_l & ( 3 < < 24 ) ) = = ( G_BL_0 < < 24 ) & & ( rdp . other_mode_l & ( 3 < < 20 ) ) = = ( G_BL_CLR_MEM < < 20 ) ;
2022-04-25 16:19:00 -04:00
bool use_grayscale = rdp . grayscale ;
2022-03-21 21:52:44 -04:00
if ( texture_edge ) {
use_alpha = true ;
}
if ( use_alpha ) cc_id | = ( uint64_t ) SHADER_OPT_ALPHA < < CC_SHADER_OPT_POS ;
if ( use_fog ) cc_id | = ( uint64_t ) SHADER_OPT_FOG < < CC_SHADER_OPT_POS ;
if ( texture_edge ) cc_id | = ( uint64_t ) SHADER_OPT_TEXTURE_EDGE < < CC_SHADER_OPT_POS ;
if ( use_noise ) cc_id | = ( uint64_t ) SHADER_OPT_NOISE < < CC_SHADER_OPT_POS ;
if ( use_2cyc ) cc_id | = ( uint64_t ) SHADER_OPT_2CYC < < CC_SHADER_OPT_POS ;
if ( alpha_threshold ) cc_id | = ( uint64_t ) SHADER_OPT_ALPHA_THRESHOLD < < CC_SHADER_OPT_POS ;
if ( invisible ) cc_id | = ( uint64_t ) SHADER_OPT_INVISIBLE < < CC_SHADER_OPT_POS ;
2022-04-25 16:19:00 -04:00
if ( use_grayscale ) cc_id | = ( uint64_t ) SHADER_OPT_GRAYSCALE < < CC_SHADER_OPT_POS ;
2022-03-21 21:52:44 -04:00
if ( ! use_alpha ) {
cc_id & = ~ ( ( 0xfff < < 16 ) | ( ( uint64_t ) 0xfff < < 44 ) ) ;
}
2022-04-25 16:19:00 -04:00
ColorCombiner * comb = gfx_lookup_or_create_color_combiner ( cc_id ) ;
2022-03-21 21:52:44 -04:00
uint32_t tm = 0 ;
uint32_t tex_width [ 2 ] , tex_height [ 2 ] , tex_width2 [ 2 ] , tex_height2 [ 2 ] ;
for ( int i = 0 ; i < 2 ; i + + ) {
uint32_t tile = rdp . first_tile_index + i ;
if ( comb - > used_textures [ i ] ) {
if ( rdp . textures_changed [ i ] ) {
gfx_flush ( ) ;
import_texture ( i , tile ) ;
rdp . textures_changed [ i ] = false ;
}
uint8_t cms = rdp . texture_tile [ tile ] . cms ;
uint8_t cmt = rdp . texture_tile [ tile ] . cmt ;
uint32_t tex_size_bytes = rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes ;
uint32_t line_size = rdp . texture_tile [ tile ] . line_size_bytes ;
if ( line_size = = 0 )
line_size = 1 ;
tex_height [ i ] = tex_size_bytes / line_size ;
switch ( rdp . texture_tile [ tile ] . siz ) {
case G_IM_SIZ_4b :
line_size < < = 1 ;
break ;
case G_IM_SIZ_8b :
break ;
case G_IM_SIZ_16b :
line_size / = G_IM_SIZ_16b_LINE_BYTES ;
break ;
case G_IM_SIZ_32b :
line_size / = G_IM_SIZ_32b_LINE_BYTES ; // this is 2!
tex_height [ i ] / = 2 ;
break ;
}
tex_width [ i ] = line_size ;
tex_width2 [ i ] = ( rdp . texture_tile [ tile ] . lrs - rdp . texture_tile [ tile ] . uls + 4 ) / 4 ;
tex_height2 [ i ] = ( rdp . texture_tile [ tile ] . lrt - rdp . texture_tile [ tile ] . ult + 4 ) / 4 ;
uint32_t tex_width1 = tex_width [ i ] < < ( cms & G_TX_MIRROR ) ;
uint32_t tex_height1 = tex_height [ i ] < < ( cmt & G_TX_MIRROR ) ;
if ( ( cms & G_TX_CLAMP ) & & ( ( cms & G_TX_MIRROR ) | | tex_width1 ! = tex_width2 [ i ] ) ) {
tm | = 1 < < 2 * i ;
cms & = ~ G_TX_CLAMP ;
}
if ( ( cmt & G_TX_CLAMP ) & & ( ( cmt & G_TX_MIRROR ) | | tex_height1 ! = tex_height2 [ i ] ) ) {
tm | = 1 < < 2 * i + 1 ;
cmt & = ~ G_TX_CLAMP ;
}
bool linear_filter = ( rdp . other_mode_h & ( 3U < < G_MDSFT_TEXTFILT ) ) ! = G_TF_POINT ;
if ( linear_filter ! = rendering_state . textures [ i ] - > second . linear_filter | | cms ! = rendering_state . textures [ i ] - > second . cms | | cmt ! = rendering_state . textures [ i ] - > second . cmt ) {
gfx_flush ( ) ;
gfx_rapi - > set_sampler_parameters ( i , linear_filter , cms , cmt ) ;
rendering_state . textures [ i ] - > second . linear_filter = linear_filter ;
rendering_state . textures [ i ] - > second . cms = cms ;
rendering_state . textures [ i ] - > second . cmt = cmt ;
}
}
}
struct ShaderProgram * prg = comb - > prg [ tm ] ;
if ( prg = = NULL ) {
comb - > prg [ tm ] = prg = gfx_lookup_or_create_shader_program ( comb - > shader_id0 , comb - > shader_id1 | ( tm * SHADER_OPT_TEXEL0_CLAMP_S ) ) ;
}
if ( prg ! = rendering_state . shader_program ) {
gfx_flush ( ) ;
gfx_rapi - > unload_shader ( rendering_state . shader_program ) ;
gfx_rapi - > load_shader ( prg ) ;
rendering_state . shader_program = prg ;
}
if ( use_alpha ! = rendering_state . alpha_blend ) {
gfx_flush ( ) ;
gfx_rapi - > set_use_alpha ( use_alpha ) ;
rendering_state . alpha_blend = use_alpha ;
}
uint8_t num_inputs ;
bool used_textures [ 2 ] ;
if ( markerOn )
{
int bp = 0 ;
}
gfx_rapi - > shader_get_info ( prg , & num_inputs , used_textures ) ;
2022-04-18 05:37:47 -04:00
struct GfxClipParameters clip_parameters = gfx_rapi - > get_clip_parameters ( ) ;
2022-03-21 21:52:44 -04:00
for ( int i = 0 ; i < 3 ; i + + ) {
float z = v_arr [ i ] - > z , w = v_arr [ i ] - > w ;
2022-04-18 05:37:47 -04:00
if ( clip_parameters . z_is_from_0_to_1 ) {
2022-03-21 21:52:44 -04:00
z = ( z + w ) / 2.0f ;
}
if ( markerOn )
{
//z = 10;
}
buf_vbo [ buf_vbo_len + + ] = v_arr [ i ] - > x ;
2022-04-18 05:37:47 -04:00
buf_vbo [ buf_vbo_len + + ] = clip_parameters . invert_y ? - v_arr [ i ] - > y : v_arr [ i ] - > y ;
2022-03-21 21:52:44 -04:00
buf_vbo [ buf_vbo_len + + ] = z ;
buf_vbo [ buf_vbo_len + + ] = w ;
for ( int t = 0 ; t < 2 ; t + + ) {
if ( ! used_textures [ t ] ) {
continue ;
}
float u = v_arr [ i ] - > u / 32.0f ;
float v = v_arr [ i ] - > v / 32.0f ;
int shifts = rdp . texture_tile [ rdp . first_tile_index + t ] . shifts ;
int shiftt = rdp . texture_tile [ rdp . first_tile_index + t ] . shiftt ;
if ( shifts ! = 0 ) {
if ( shifts < = 10 ) {
u / = 1 < < shifts ;
} else {
u * = 1 < < ( 16 - shifts ) ;
}
}
if ( shiftt ! = 0 ) {
if ( shiftt < = 10 ) {
v / = 1 < < shiftt ;
} else {
v * = 1 < < ( 16 - shiftt ) ;
}
}
u - = rdp . texture_tile [ rdp . first_tile_index + t ] . uls / 4.0f ;
v - = rdp . texture_tile [ rdp . first_tile_index + t ] . ult / 4.0f ;
if ( ( rdp . other_mode_h & ( 3U < < G_MDSFT_TEXTFILT ) ) ! = G_TF_POINT ) {
// Linear filter adds 0.5f to the coordinates
if ( ! is_rect ) {
u + = 0.5f ;
v + = 0.5f ;
}
}
buf_vbo [ buf_vbo_len + + ] = u / tex_width [ t ] ;
buf_vbo [ buf_vbo_len + + ] = v / tex_height [ t ] ;
if ( tm & ( 1 < < 2 * t ) ) {
buf_vbo [ buf_vbo_len + + ] = ( tex_width2 [ t ] - 0.5f ) / tex_width [ t ] ;
}
if ( tm & ( 1 < < 2 * t + 1 ) ) {
buf_vbo [ buf_vbo_len + + ] = ( tex_height2 [ t ] - 0.5f ) / tex_height [ t ] ;
}
}
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)
}
2022-04-25 16:19:00 -04:00
if ( use_grayscale ) {
buf_vbo [ buf_vbo_len + + ] = rdp . grayscale_color . r / 255.0f ;
buf_vbo [ buf_vbo_len + + ] = rdp . grayscale_color . g / 255.0f ;
buf_vbo [ buf_vbo_len + + ] = rdp . grayscale_color . b / 255.0f ;
2022-04-25 18:07:40 -04:00
buf_vbo [ buf_vbo_len + + ] = rdp . grayscale_color . a / 255.0f ; // lerp interpolation factor (not alpha)
2022-04-25 16:19:00 -04:00
}
2022-03-21 21:52:44 -04:00
for ( int j = 0 ; j < num_inputs ; j + + ) {
struct RGBA * color = 0 ;
struct RGBA tmp ;
for ( int k = 0 ; k < 1 + ( use_alpha ? 1 : 0 ) ; k + + ) {
switch ( comb - > shader_input_mapping [ k ] [ j ] ) {
// Note: CCMUX constants and ACMUX constants used here have same value, which is why this works (except LOD fraction).
case G_CCMUX_PRIMITIVE :
color = & rdp . prim_color ;
break ;
case G_CCMUX_SHADE :
color = & v_arr [ i ] - > color ;
break ;
case G_CCMUX_ENVIRONMENT :
color = & rdp . env_color ;
break ;
case G_CCMUX_PRIMITIVE_ALPHA :
{
tmp . r = tmp . g = tmp . b = rdp . prim_color . a ;
color = & tmp ;
break ;
}
case G_CCMUX_ENV_ALPHA :
{
tmp . r = tmp . g = tmp . b = rdp . env_color . a ;
color = & tmp ;
break ;
}
case G_CCMUX_PRIM_LOD_FRAC :
{
tmp . r = tmp . g = tmp . b = rdp . prim_lod_fraction ;
color = & tmp ;
break ;
}
case G_CCMUX_LOD_FRACTION :
{
if ( rdp . other_mode_l & G_TL_LOD ) {
// "Hack" that works for Bowser - Peach painting
float distance_frac = ( v1 - > w - 3000.0f ) / 3000.0f ;
if ( distance_frac < 0.0f ) distance_frac = 0.0f ;
if ( distance_frac > 1.0f ) distance_frac = 1.0f ;
tmp . r = tmp . g = tmp . b = tmp . a = distance_frac * 255.0f ;
} else {
tmp . r = tmp . g = tmp . b = tmp . a = 255.0f ;
}
color = & tmp ;
break ;
}
case G_ACMUX_PRIM_LOD_FRAC :
tmp . a = rdp . prim_lod_fraction ;
color = & tmp ;
break ;
default :
memset ( & tmp , 0 , sizeof ( tmp ) ) ;
color = & tmp ;
break ;
}
if ( k = = 0 ) {
buf_vbo [ buf_vbo_len + + ] = color - > r / 255.0f ;
buf_vbo [ buf_vbo_len + + ] = color - > g / 255.0f ;
buf_vbo [ buf_vbo_len + + ] = color - > b / 255.0f ;
}
else {
if ( use_fog & & color = = & v_arr [ i ] - > color ) {
// Shade alpha is 100% for fog
buf_vbo [ buf_vbo_len + + ] = 1.0f ;
}
else {
buf_vbo [ buf_vbo_len + + ] = color - > a / 255.0f ;
}
}
}
}
//struct RGBA *color = &v_arr[i]->color;
//buf_vbo[buf_vbo_len++] = color->r / 255.0f;
//buf_vbo[buf_vbo_len++] = color->g / 255.0f;
//buf_vbo[buf_vbo_len++] = color->b / 255.0f;
//buf_vbo[buf_vbo_len++] = color->a / 255.0f;
}
if ( + + buf_vbo_num_tris = = MAX_BUFFERED ) {
//if (++buf_vbo_num_tris == 1) {
if ( markerOn )
{
int bp = 0 ;
}
gfx_flush ( ) ;
}
}
static void gfx_sp_geometry_mode ( uint32_t clear , uint32_t set ) {
rsp . geometry_mode & = ~ clear ;
rsp . geometry_mode | = set ;
}
2022-04-18 05:37:47 -04:00
static void gfx_adjust_viewport_or_scissor ( XYWidthHeight * area ) {
if ( ! fbActive ) {
area - > width * = RATIO_X ;
area - > height * = RATIO_Y ;
area - > x * = RATIO_X ;
area - > y = SCREEN_HEIGHT - area - > y ;
area - > y * = RATIO_Y ;
if ( ! game_renders_to_framebuffer | | ( gfx_msaa_level > 1 & & gfx_current_dimensions . width = = gfx_current_game_window_viewport . width & & gfx_current_dimensions . height = = gfx_current_game_window_viewport . height ) ) {
area - > x + = gfx_current_game_window_viewport . x ;
area - > y + = gfx_current_window_dimensions . height - ( gfx_current_game_window_viewport . y + gfx_current_game_window_viewport . height ) ;
}
} else {
area - > width * = RATIO_Y ;
area - > height * = RATIO_Y ;
area - > x * = RATIO_Y ;
area - > y = active_fb - > second . orig_height - area - > y ;
area - > y * = RATIO_Y ;
}
}
2022-03-21 21:52:44 -04:00
static void gfx_calc_and_set_viewport ( const Vp_t * viewport ) {
// 2 bits fraction
float width = 2.0f * viewport - > vscale [ 0 ] / 4.0f ;
float height = 2.0f * viewport - > vscale [ 1 ] / 4.0f ;
float x = ( viewport - > vtrans [ 0 ] / 4.0f ) - width / 2.0f ;
float y = ( ( viewport - > vtrans [ 1 ] / 4.0f ) + height / 2.0f ) ;
rdp . viewport . x = x ;
rdp . viewport . y = y ;
rdp . viewport . width = width ;
rdp . viewport . height = height ;
2022-04-18 05:37:47 -04:00
gfx_adjust_viewport_or_scissor ( & rdp . viewport ) ;
2022-03-21 21:52:44 -04:00
rdp . viewport_or_scissor_changed = true ;
}
static void gfx_sp_movemem ( uint8_t index , uint8_t offset , const void * data ) {
switch ( index ) {
case G_MV_VIEWPORT :
gfx_calc_and_set_viewport ( ( const Vp_t * ) data ) ;
break ;
#if 0
case G_MV_LOOKATY :
case G_MV_LOOKATX :
memcpy ( rsp . current_lookat + ( index - G_MV_LOOKATY ) / 2 , data , sizeof ( Light_t ) ) ;
//rsp.lights_changed = 1;
break ;
# endif
# ifdef F3DEX_GBI_2
case G_MV_LIGHT : {
int lightidx = offset / 24 - 2 ;
if ( lightidx > = 0 & & lightidx < = MAX_LIGHTS ) { // skip lookat
// NOTE: reads out of bounds if it is an ambient light
memcpy ( rsp . current_lights + lightidx , data , sizeof ( Light_t ) ) ;
} else if ( lightidx < 0 ) {
memcpy ( rsp . lookat + offset / 24 , data , sizeof ( Light_t ) ) ;
}
break ;
}
# else
case G_MV_L0 :
case G_MV_L1 :
case G_MV_L2 :
// NOTE: reads out of bounds if it is an ambient light
memcpy ( rsp . current_lights + ( index - G_MV_L0 ) / 2 , data , sizeof ( Light_t ) ) ;
break ;
# endif
}
}
2022-05-14 19:19:02 -04:00
static void gfx_sp_moveword ( uint8_t index , uint16_t offset , uintptr_t data ) {
2022-03-21 21:52:44 -04:00
switch ( index ) {
case G_MW_NUMLIGHT :
# ifdef F3DEX_GBI_2
rsp . current_num_lights = data / 24 + 1 ; // add ambient light
# else
// Ambient light is included
// The 31th bit is a flag that lights should be recalculated
rsp . current_num_lights = ( data - 0x80000000U ) / 32 ;
# endif
rsp . lights_changed = 1 ;
break ;
case G_MW_FOG :
rsp . fog_mul = ( int16_t ) ( data > > 16 ) ;
rsp . fog_offset = ( int16_t ) data ;
break ;
case G_MW_SEGMENT :
int segNumber = offset / 4 ;
segmentPointers [ segNumber ] = data ;
break ;
}
}
static void gfx_sp_texture ( uint16_t sc , uint16_t tc , uint8_t level , uint8_t tile , uint8_t on ) {
rsp . texture_scaling_factor . s = sc ;
rsp . texture_scaling_factor . t = tc ;
if ( rdp . first_tile_index ! = tile ) {
rdp . textures_changed [ 0 ] = true ;
rdp . textures_changed [ 1 ] = true ;
}
rdp . first_tile_index = tile ;
}
static void gfx_dp_set_scissor ( uint32_t mode , uint32_t ulx , uint32_t uly , uint32_t lrx , uint32_t lry ) {
float x = ulx / 4.0f ;
float y = lry / 4.0f ;
float width = ( lrx - ulx ) / 4.0f ;
float height = ( lry - uly ) / 4.0f ;
rdp . scissor . x = x ;
rdp . scissor . y = y ;
rdp . scissor . width = width ;
rdp . scissor . height = height ;
2022-04-18 05:37:47 -04:00
gfx_adjust_viewport_or_scissor ( & rdp . scissor ) ;
2022-03-21 21:52:44 -04:00
rdp . viewport_or_scissor_changed = true ;
}
2022-05-15 15:32:05 -04:00
static void gfx_dp_set_texture_image ( uint32_t format , uint32_t size , uint32_t width , const void * addr , const char * otr_path ) {
2022-03-21 21:52:44 -04:00
rdp . texture_to_load . addr = ( const uint8_t * ) addr ;
rdp . texture_to_load . siz = size ;
rdp . texture_to_load . width = width ;
2022-05-15 15:32:05 -04:00
if ( otr_path ! = nullptr & & ! strncmp ( otr_path , " __OTR__ " , 7 ) ) otr_path = otr_path + 7 ;
2022-03-21 21:52:44 -04:00
rdp . texture_to_load . otr_path = otr_path ;
}
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 ) {
// OTRTODO:
//SUPPORT_CHECK(tmem == 0 || tmem == 256);
if ( cms = = G_TX_WRAP & & masks = = G_TX_NOMASK ) {
cms = G_TX_CLAMP ;
}
if ( cmt = = G_TX_WRAP & & maskt = = G_TX_NOMASK ) {
cmt = G_TX_CLAMP ;
}
rdp . texture_tile [ tile ] . palette = palette ; // palette should set upper 4 bits of color index in 4b mode
rdp . texture_tile [ tile ] . fmt = fmt ;
rdp . texture_tile [ tile ] . siz = siz ;
rdp . texture_tile [ tile ] . cms = cms ;
rdp . texture_tile [ tile ] . cmt = cmt ;
rdp . texture_tile [ tile ] . shifts = shifts ;
rdp . texture_tile [ tile ] . shiftt = shiftt ;
rdp . texture_tile [ tile ] . line_size_bytes = line * 8 ;
if ( rdp . texture_tile [ tile ] . line_size_bytes > 15000 )
{
int bp = 0 ;
}
2022-04-02 13:57:20 -04:00
rdp . texture_tile [ tile ] . tmem = tmem ;
2022-03-21 21:52:44 -04:00
//rdp.texture_tile[tile].tmem_index = tmem / 256; // tmem is the 64-bit word offset, so 256 words means 2 kB
rdp . texture_tile [ tile ] . tmem_index = tmem ! = 0 ; // assume one texture is loaded at address 0 and another texture at any other address
rdp . textures_changed [ 0 ] = true ;
rdp . textures_changed [ 1 ] = true ;
}
static void gfx_dp_set_tile_size ( uint8_t tile , uint16_t uls , uint16_t ult , uint16_t lrs , uint16_t lrt ) {
rdp . texture_tile [ tile ] . uls = uls ;
rdp . texture_tile [ tile ] . ult = ult ;
rdp . texture_tile [ tile ] . lrs = lrs ;
rdp . texture_tile [ tile ] . lrt = lrt ;
rdp . textures_changed [ 0 ] = true ;
rdp . textures_changed [ 1 ] = true ;
}
static void gfx_dp_load_tlut ( uint8_t tile , uint32_t high_index ) {
2022-04-02 13:57:20 -04:00
SUPPORT_CHECK ( tile = = G_TX_LOADTILE ) ;
SUPPORT_CHECK ( rdp . texture_to_load . siz = = G_IM_SIZ_16b ) ;
SUPPORT_CHECK ( ( rdp . texture_tile [ tile ] . tmem = = 256 & & ( high_index < = 127 | | high_index = = 255 ) ) | | ( rdp . texture_tile [ tile ] . tmem = = 384 & & high_index = = 127 ) ) ;
2022-03-21 21:52:44 -04:00
2022-04-02 13:57:20 -04:00
if ( rdp . texture_tile [ tile ] . tmem = = 256 ) {
rdp . palettes [ 0 ] = rdp . texture_to_load . addr ;
if ( high_index = = 255 ) {
rdp . palettes [ 1 ] = rdp . texture_to_load . addr + 2 * 128 ;
}
} else {
rdp . palettes [ 1 ] = rdp . texture_to_load . addr ;
}
2022-03-21 21:52:44 -04:00
}
static void gfx_dp_load_block ( uint8_t tile , uint32_t uls , uint32_t ult , uint32_t lrs , uint32_t dxt ) {
if ( markerOn )
{
int bp = 0 ;
}
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
2022-05-11 13:18:24 -04:00
uint32_t word_size_shift = 0 ;
2022-03-21 21:52:44 -04:00
switch ( rdp . texture_to_load . siz ) {
case G_IM_SIZ_4b :
word_size_shift = 0 ; // Or -1? It's unused in SM64 anyway.
break ;
case G_IM_SIZ_8b :
word_size_shift = 0 ;
break ;
case G_IM_SIZ_16b :
word_size_shift = 1 ;
break ;
case G_IM_SIZ_32b :
word_size_shift = 2 ;
break ;
}
uint32_t size_bytes = ( lrs + 1 ) < < word_size_shift ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes = size_bytes ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes = size_bytes ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes = size_bytes ;
//assert(size_bytes <= 4096 && "bug: too big texture");
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr = rdp . texture_to_load . addr ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . otr_path = rdp . texture_to_load . otr_path ;
rdp . textures_changed [ rdp . texture_tile [ tile ] . tmem_index ] = true ;
}
static void gfx_dp_load_tile ( uint8_t tile , uint32_t uls , uint32_t ult , uint32_t lrs , uint32_t lrt ) {
SUPPORT_CHECK ( tile = = G_TX_LOADTILE ) ;
2022-05-11 13:18:24 -04:00
uint32_t word_size_shift = 0 ;
2022-03-21 21:52:44 -04:00
switch ( rdp . texture_to_load . siz ) {
case G_IM_SIZ_4b :
word_size_shift = 0 ;
break ;
case G_IM_SIZ_8b :
word_size_shift = 0 ;
break ;
case G_IM_SIZ_16b :
word_size_shift = 1 ;
break ;
case G_IM_SIZ_32b :
word_size_shift = 2 ;
break ;
}
uint32_t size_bytes = ( ( ( ( lrs - uls ) > > G_TEXTURE_IMAGE_FRAC ) + 1 ) * ( ( ( lrt - ult ) > > G_TEXTURE_IMAGE_FRAC ) + 1 ) ) < < word_size_shift ;
uint32_t full_image_line_size_bytes = ( rdp . texture_to_load . width + 1 ) < < word_size_shift ;
uint32_t line_size_bytes = ( ( ( lrs - uls ) > > G_TEXTURE_IMAGE_FRAC ) + 1 ) < < word_size_shift ;
uint32_t start_offset = full_image_line_size_bytes * ( ult > > G_TEXTURE_IMAGE_FRAC ) + ( ( uls > > G_TEXTURE_IMAGE_FRAC ) < < word_size_shift ) ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . size_bytes = size_bytes ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . full_image_line_size_bytes = full_image_line_size_bytes ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . line_size_bytes = line_size_bytes ;
assert ( size_bytes < = 4096 & & " bug: too big texture " ) ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . addr = rdp . texture_to_load . addr + start_offset ;
rdp . loaded_texture [ rdp . texture_tile [ tile ] . tmem_index ] . otr_path = rdp . texture_to_load . otr_path ;
rdp . texture_tile [ tile ] . uls = uls ;
rdp . texture_tile [ tile ] . ult = ult ;
rdp . texture_tile [ tile ] . lrs = lrs ;
rdp . texture_tile [ tile ] . lrt = lrt ;
rdp . textures_changed [ rdp . texture_tile [ tile ] . tmem_index ] = true ;
}
/*static uint8_t color_comb_component(uint32_t v) {
switch ( v ) {
case G_CCMUX_TEXEL0 :
return CC_TEXEL0 ;
case G_CCMUX_TEXEL1 :
return CC_TEXEL1 ;
case G_CCMUX_PRIMITIVE :
return CC_PRIM ;
case G_CCMUX_SHADE :
return CC_SHADE ;
case G_CCMUX_ENVIRONMENT :
return CC_ENV ;
case G_CCMUX_TEXEL0_ALPHA :
return CC_TEXEL0A ;
case G_CCMUX_LOD_FRACTION :
return CC_LOD ;
default :
return CC_0 ;
}
}
static inline uint32_t color_comb ( uint32_t a , uint32_t b , uint32_t c , uint32_t d ) {
return color_comb_component ( a ) |
( color_comb_component ( b ) < < 3 ) |
( color_comb_component ( c ) < < 6 ) |
( color_comb_component ( d ) < < 9 ) ;
}
static void gfx_dp_set_combine_mode ( uint32_t rgb , uint32_t alpha ) {
rdp . combine_mode = rgb | ( alpha < < 12 ) ;
} */
static void gfx_dp_set_combine_mode ( uint32_t rgb , uint32_t alpha , uint32_t rgb_cyc2 , uint32_t alpha_cyc2 ) {
rdp . combine_mode = rgb | ( alpha < < 16 ) | ( ( uint64_t ) rgb_cyc2 < < 28 ) | ( ( uint64_t ) alpha_cyc2 < < 44 ) ;
}
static inline uint32_t color_comb ( uint32_t a , uint32_t b , uint32_t c , uint32_t d ) {
return ( a & 0xf ) | ( ( b & 0xf ) < < 4 ) | ( ( c & 0x1f ) < < 8 ) | ( ( d & 7 ) < < 13 ) ;
}
static inline uint32_t alpha_comb ( uint32_t a , uint32_t b , uint32_t c , uint32_t d ) {
return ( a & 7 ) | ( ( b & 7 ) < < 3 ) | ( ( c & 7 ) < < 6 ) | ( ( d & 7 ) < < 9 ) ;
}
2022-04-25 16:19:00 -04:00
static void gfx_dp_set_grayscale_color ( uint8_t r , uint8_t g , uint8_t b , uint8_t a ) {
rdp . grayscale_color . r = r ;
rdp . grayscale_color . g = g ;
rdp . grayscale_color . b = b ;
rdp . grayscale_color . a = a ;
}
2022-03-21 21:52:44 -04:00
static void gfx_dp_set_env_color ( uint8_t r , uint8_t g , uint8_t b , uint8_t a ) {
rdp . env_color . r = r ;
rdp . env_color . g = g ;
rdp . env_color . b = b ;
rdp . env_color . a = a ;
}
static void gfx_dp_set_prim_color ( uint8_t m , uint8_t l , uint8_t r , uint8_t g , uint8_t b , uint8_t a ) {
rdp . prim_lod_fraction = l ;
rdp . prim_color . r = r ;
rdp . prim_color . g = g ;
rdp . prim_color . b = b ;
rdp . prim_color . a = a ;
}
static void gfx_dp_set_fog_color ( uint8_t r , uint8_t g , uint8_t b , uint8_t a ) {
rdp . fog_color . r = r ;
rdp . fog_color . g = g ;
rdp . fog_color . b = b ;
rdp . fog_color . a = a ;
}
static void gfx_dp_set_fill_color ( uint32_t packed_color ) {
uint16_t col16 = ( uint16_t ) packed_color ;
uint32_t r = col16 > > 11 ;
uint32_t g = ( col16 > > 6 ) & 0x1f ;
uint32_t b = ( col16 > > 1 ) & 0x1f ;
uint32_t a = col16 & 1 ;
rdp . fill_color . r = SCALE_5_8 ( r ) ;
rdp . fill_color . g = SCALE_5_8 ( g ) ;
rdp . fill_color . b = SCALE_5_8 ( b ) ;
rdp . fill_color . a = a * 255 ;
}
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
2022-04-18 05:37:47 -04:00
struct XYWidthHeight default_viewport = { 0 , SCREEN_HEIGHT , SCREEN_WIDTH , SCREEN_HEIGHT } ;
2022-03-21 21:52:44 -04:00
struct XYWidthHeight viewport_saved = rdp . viewport ;
uint32_t geometry_mode_saved = rsp . geometry_mode ;
2022-04-18 05:37:47 -04:00
gfx_adjust_viewport_or_scissor ( & default_viewport ) ;
2022-03-21 21:52:44 -04:00
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 , true ) ;
gfx_sp_tri1 ( MAX_VERTICES + 1 , MAX_VERTICES + 2 , MAX_VERTICES + 3 , true ) ;
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 ;
}
}
static void gfx_dp_texture_rectangle ( int32_t ulx , int32_t uly , int32_t lrx , int32_t lry , uint8_t tile , int16_t uls , int16_t ult , int16_t dsdx , int16_t dtdy , bool flip ) {
//printf("render %d at %d\n", tile, lrx);
uint64_t saved_combine_mode = rdp . combine_mode ;
if ( ( rdp . other_mode_h & ( 3U < < G_MDSFT_CYCLETYPE ) ) = = G_CYC_COPY ) {
// 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 ) , alpha_comb ( 0 , 0 , 0 , G_ACMUX_TEXEL0 ) , 0 , 0 ) ;
// 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
// lrs, lrt are S10.5
if ( flip ) {
dsdx = - dsdx ;
dtdy = - dtdy ;
}
int16_t width = ! flip ? lrx - ulx : lry - uly ;
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 ] ;
struct LoadedVertex * ur = & rsp . loaded_vertices [ MAX_VERTICES + 3 ] ;
ul - > u = uls ;
ul - > v = ult ;
lr - > u = lrs ;
lr - > v = lrt ;
if ( ! flip ) {
ll - > u = uls ;
ll - > v = lrt ;
ur - > u = lrs ;
ur - > v = ult ;
} else {
ll - > u = lrs ;
ll - > v = ult ;
ur - > u = uls ;
ur - > v = lrt ;
}
uint8_t saved_tile = rdp . first_tile_index ;
if ( saved_tile ! = tile ) {
rdp . textures_changed [ 0 ] = true ;
rdp . textures_changed [ 1 ] = true ;
}
rdp . first_tile_index = tile ;
gfx_draw_rectangle ( ulx , uly , lrx , lry ) ;
if ( saved_tile ! = tile ) {
rdp . textures_changed [ 0 ] = true ;
rdp . textures_changed [ 1 ] = true ;
}
rdp . first_tile_index = saved_tile ;
rdp . combine_mode = saved_combine_mode ;
}
static void gfx_dp_fill_rectangle ( int32_t ulx , int32_t uly , int32_t lrx , int32_t lry ) {
if ( rdp . color_image_address = = rdp . z_buf_address ) {
// Don't clear Z buffer here since we already did it with glClear
return ;
}
uint32_t mode = ( rdp . other_mode_h & ( 3U < < G_MDSFT_CYCLETYPE ) ) ;
// OTRTODO: This is a bit of a hack for widescreen screen fades, but it'll work for now...
if ( ulx = = 0 & & uly = = 0 & & lrx = = ( 319 * 4 ) & & lry = = ( 239 * 4 ) )
{
ulx = - 1024 ;
uly = - 1024 ;
lrx = 2048 ;
lry = 2048 ;
}
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 ;
}
uint64_t saved_combine_mode = rdp . combine_mode ;
if ( mode = = G_CYC_FILL )
gfx_dp_set_combine_mode ( color_comb ( 0 , 0 , 0 , G_CCMUX_SHADE ) , alpha_comb ( 0 , 0 , 0 , G_ACMUX_SHADE ) , 0 , 0 ) ;
gfx_draw_rectangle ( ulx , uly , lrx , lry ) ;
rdp . combine_mode = saved_combine_mode ;
}
static void gfx_dp_set_z_image ( void * z_buf_address ) {
rdp . z_buf_address = z_buf_address ;
}
static void gfx_dp_set_color_image ( uint32_t format , uint32_t size , uint32_t width , void * address ) {
rdp . color_image_address = address ;
}
static void gfx_sp_set_other_mode ( uint32_t shift , uint32_t num_bits , uint64_t mode ) {
uint64_t mask = ( ( ( uint64_t ) 1 < < num_bits ) - 1 ) < < shift ;
uint64_t om = rdp . other_mode_l | ( ( uint64_t ) rdp . other_mode_h < < 32 ) ;
om = ( om & ~ mask ) | mode ;
rdp . other_mode_l = ( uint32_t ) om ;
rdp . other_mode_h = ( uint32_t ) ( om > > 32 ) ;
}
static void gfx_dp_set_other_mode ( uint32_t h , uint32_t l ) {
rdp . other_mode_h = h ;
rdp . other_mode_l = l ;
}
static void gfx_s2dex_bg_copy ( const uObjBg * bg ) {
/*
bg - > b . imageX = 0 ;
bg - > b . imageW = width * 4 ;
bg - > b . frameX = frameX * 4 ;
bg - > b . imageY = 0 ;
bg - > b . imageH = height * 4 ;
bg - > b . frameY = frameY * 4 ;
bg - > b . imagePtr = source ;
bg - > b . imageLoad = G_BGLT_LOADTILE ;
bg - > b . imageFmt = fmt ;
bg - > b . imageSiz = siz ;
bg - > b . imagePal = 0 ;
bg - > b . imageFlip = 0 ;
*/
SUPPORT_CHECK ( bg - > b . imageSiz = = G_IM_SIZ_16b ) ;
gfx_dp_set_texture_image ( G_IM_FMT_RGBA , G_IM_SIZ_16b , 0 , bg - > b . imagePtr , nullptr ) ;
gfx_dp_set_tile ( G_IM_FMT_RGBA , G_IM_SIZ_16b , 0 , 0 , G_TX_LOADTILE , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
gfx_dp_load_block ( G_TX_LOADTILE , 0 , 0 , ( bg - > b . imageW * bg - > b . imageH > > 4 ) - 1 , 0 ) ;
gfx_dp_set_tile ( bg - > b . imageFmt , G_IM_SIZ_16b , bg - > b . imageW > > 4 , 0 , G_TX_RENDERTILE , bg - > b . imagePal , 0 , 0 , 0 , 0 , 0 , 0 ) ;
gfx_dp_set_tile_size ( G_TX_RENDERTILE , 0 , 0 , bg - > b . imageW , bg - > b . imageH ) ;
gfx_dp_texture_rectangle ( bg - > b . frameX , bg - > b . frameY , bg - > b . frameX + bg - > b . imageW - 4 , bg - > b . frameY + bg - > b . imageH - 4 , G_TX_RENDERTILE , bg - > b . imageX < < 3 , bg - > b . imageY < < 3 , 4 < < 10 , 1 < < 10 , false ) ;
}
static inline void * seg_addr ( uintptr_t w1 )
{
// Segmented?
2022-05-11 13:18:24 -04:00
if ( w1 & 1 )
2022-03-21 21:52:44 -04:00
{
uint32_t segNum = ( w1 > > 24 ) ;
2022-05-11 13:18:24 -04:00
uint32_t offset = w1 & 0x00FFFFFE ;
2022-03-21 21:52:44 -04:00
//offset = 0; // Cursed Malon bug
if ( segmentPointers [ segNum ] ! = 0 )
return ( void * ) ( segmentPointers [ segNum ] + offset ) ;
else
return ( void * ) w1 ;
}
else
{
return ( void * ) w1 ;
}
}
# define C0(pos, width) ((cmd->words.w0 >> (pos)) & ((1U << width) - 1))
# define C1(pos, width) ((cmd->words.w1 >> (pos)) & ((1U << width) - 1))
2022-05-11 13:18:24 -04:00
unsigned int dListBP ;
2022-03-21 21:52:44 -04:00
int matrixBP ;
uintptr_t clearMtx ;
extern " C "
{
uintptr_t jsjutanShadowTex = 0 ;
} ;
static void gfx_run_dl ( Gfx * cmd ) {
//puts("dl");
int dummy = 0 ;
char dlName [ 128 ] ;
2022-05-15 15:32:05 -04:00
const char * fileName ;
2022-03-21 21:52:44 -04:00
Gfx * dListStart = cmd ;
uint64_t ourHash = - 1 ;
for ( ; ; ) {
uint32_t opcode = cmd - > words . w0 > > 24 ;
//uint32_t opcode = cmd->words.w0 & 0xFF;
//if (markerOn)
//printf("OP: %02X\n", opcode);
switch ( opcode ) {
// RSP commands:
case G_MARKER :
{
cmd + + ;
ourHash = ( ( uint64_t ) cmd - > words . w0 < < 32 ) + cmd - > words . w1 ;
# if _DEBUG
//uint64_t hash = ((uint64_t)cmd->words.w0 << 32) + cmd->words.w1;
//ResourceMgr_GetNameByCRC(hash, dlName);
//lusprintf(__FILE__, __LINE__, 6, "G_MARKER: %s\n", dlName);
# endif
markerOn = true ;
}
break ;
case G_INVALTEXCACHE :
{
uintptr_t texAddr = cmd - > words . w1 ;
if ( texAddr = = 0 )
gfx_texture_cache_clear ( ) ;
else
gfx_texture_cache_delete ( ( const uint8_t * ) texAddr ) ;
}
break ;
case G_NOOP :
{
uint32_t index = C0 ( 0 , 16 ) ;
uint32_t type = C0 ( 16 , 8 ) ;
if ( type = = 2 ) {
const char * str = ( const char * ) cmd - > words . w1 ;
//printf("%s, %u\n", str, index);
}
}
break ;
case G_MTX : {
uintptr_t mtxAddr = cmd - > words . w1 ;
// OTRTODO: Temp way of dealing with gMtxClear. Need something more elegant in the future...
2022-05-11 15:14:40 -04:00
uint32_t gameVersion = Ship : : GlobalCtx2 : : GetInstance ( ) - > GetResourceManager ( ) - > GetGameVersion ( ) ;
if ( gameVersion = = OOT_PAL_GC ) {
if ( mtxAddr = = SEG_ADDR ( 0 , 0x0FBC20 ) ) {
mtxAddr = clearMtx ;
}
} else {
if ( mtxAddr = = SEG_ADDR ( 0 , 0x12DB20 ) | | mtxAddr = = SEG_ADDR ( 0 , 0x12DB40 ) ) {
mtxAddr = clearMtx ;
}
}
2022-03-21 21:52:44 -04:00
# ifdef F3DEX_GBI_2
gfx_sp_matrix ( C0 ( 0 , 8 ) ^ G_MTX_PUSH , ( const int32_t * ) seg_addr ( mtxAddr ) ) ;
# else
gfx_sp_matrix ( C0 ( 16 , 8 ) , ( const int32_t * ) seg_addr ( cmd - > words . w1 ) ) ;
# endif
break ;
}
case G_MTX_OTR : {
cmd + + ;
uint64_t hash = ( ( uint64_t ) cmd - > words . w0 < < 32 ) + cmd - > words . w1 ;
# if _DEBUG
//char fileName[4096];
//ResourceMgr_GetNameByCRC(hash, fileName);
//printf("G_MTX_OTR: %s\n", fileName);
# endif
int32_t * mtx = ResourceMgr_LoadMtxByCRC ( hash ) ;
# ifdef F3DEX_GBI_2
if ( mtx ! = NULL )
{
cmd - - ;
gfx_sp_matrix ( C0 ( 0 , 8 ) ^ G_MTX_PUSH , mtx ) ;
cmd + + ;
}
# else
gfx_sp_matrix ( C0 ( 16 , 8 ) , ( const int32_t * ) seg_addr ( cmd - > words . w1 ) ) ;
# endif
break ;
}
case ( uint8_t ) G_POPMTX :
# ifdef F3DEX_GBI_2
gfx_sp_pop_matrix ( cmd - > words . w1 / 64 ) ;
# else
gfx_sp_pop_matrix ( 1 ) ;
# endif
break ;
case G_MOVEMEM :
# ifdef F3DEX_GBI_2
gfx_sp_movemem ( C0 ( 0 , 8 ) , C0 ( 8 , 8 ) * 8 , seg_addr ( cmd - > words . w1 ) ) ;
# else
gfx_sp_movemem ( C0 ( 16 , 8 ) , 0 , seg_addr ( cmd - > words . w1 ) ) ;
# endif
break ;
case ( uint8_t ) G_MOVEWORD :
# ifdef F3DEX_GBI_2
gfx_sp_moveword ( C0 ( 16 , 8 ) , C0 ( 0 , 16 ) , cmd - > words . w1 ) ;
# else
gfx_sp_moveword ( C0 ( 0 , 8 ) , C0 ( 8 , 16 ) , cmd - > words . w1 ) ;
# endif
break ;
case ( uint8_t ) G_TEXTURE :
# ifdef F3DEX_GBI_2
gfx_sp_texture ( C1 ( 16 , 16 ) , C1 ( 0 , 16 ) , C0 ( 11 , 3 ) , C0 ( 8 , 3 ) , C0 ( 1 , 7 ) ) ;
# else
gfx_sp_texture ( C1 ( 16 , 16 ) , C1 ( 0 , 16 ) , C0 ( 11 , 3 ) , C0 ( 8 , 3 ) , C0 ( 0 , 8 ) ) ;
# endif
break ;
case G_VTX :
# ifdef F3DEX_GBI_2
gfx_sp_vertex ( C0 ( 12 , 8 ) , C0 ( 1 , 7 ) - C0 ( 12 , 8 ) , ( const Vtx * ) seg_addr ( cmd - > words . w1 ) ) ;
# elif defined(F3DEX_GBI) || defined(F3DLP_GBI)
gfx_sp_vertex ( C0 ( 10 , 6 ) , C0 ( 16 , 8 ) / 2 , seg_addr ( cmd - > words . w1 ) ) ;
# else
gfx_sp_vertex ( ( C0 ( 0 , 16 ) ) / sizeof ( Vtx ) , C0 ( 16 , 4 ) , seg_addr ( cmd - > words . w1 ) ) ;
# endif
break ;
case G_VTX_OTR :
{
uintptr_t offset = cmd - > words . w1 ;
cmd + + ;
uint64_t hash = ( ( uint64_t ) cmd - > words . w0 < < 32 ) + cmd - > words . w1 ;
# if _DEBUG
//char fileName[4096];
//ResourceMgr_GetNameByCRC(hash, fileName);
//printf("G_VTX_OTR: %s, 0x%08X\n", fileName, hash);
# endif
if ( offset > 0xFFFFF )
{
cmd - - ;
gfx_sp_vertex ( C0 ( 12 , 8 ) , C0 ( 1 , 7 ) - C0 ( 12 , 8 ) , ( Vtx * ) offset ) ;
cmd + + ;
}
else
{
Vtx * vtx = ResourceMgr_LoadVtxByCRC ( hash ) ;
if ( vtx ! = NULL )
{
vtx = ( Vtx * ) ( ( char * ) vtx + offset ) ;
cmd - - ;
2022-05-11 13:18:24 -04:00
if ( ourHash ! = ( uint64_t ) - 1 )
2022-03-21 21:52:44 -04:00
ResourceMgr_RegisterResourcePatch ( ourHash , cmd - dListStart , cmd - > words . w1 ) ;
cmd - > words . w1 = ( uintptr_t ) vtx ;
gfx_sp_vertex ( C0 ( 12 , 8 ) , C0 ( 1 , 7 ) - C0 ( 12 , 8 ) , vtx ) ;
cmd + + ;
}
}
}
break ;
case G_MODIFYVTX :
gfx_sp_modify_vertex ( C0 ( 1 , 15 ) , C0 ( 16 , 8 ) , cmd - > words . w1 ) ;
break ;
case G_DL :
if ( cmd - > words . w1 = = dListBP )
{
int bp = 0 ;
}
if ( C0 ( 16 , 1 ) = = 0 ) {
// Push return address
gfx_run_dl ( ( Gfx * ) seg_addr ( cmd - > words . w1 ) ) ;
} else {
cmd = ( Gfx * ) seg_addr ( cmd - > words . w1 ) ;
- - cmd ; // increase after break
}
break ;
case G_DL_OTR :
if ( C0 ( 16 , 1 ) = = 0 )
{
// Push return address
cmd + + ;
uint64_t hash = ( ( uint64_t ) cmd - > words . w0 < < 32 ) + cmd - > words . w1 ;
# if _DEBUG
//char fileName[4096];
//ResourceMgr_GetNameByCRC(hash, fileName);
//printf("G_DL_OTR: %s\n", fileName);
# endif
Gfx * gfx = ResourceMgr_LoadGfxByCRC ( hash ) ;
if ( gfx ! = 0 )
gfx_run_dl ( gfx ) ;
}
else {
cmd = ( Gfx * ) seg_addr ( cmd - > words . w1 ) ;
cmd + + ;
- - cmd ; // increase after break
}
break ;
case G_BRANCH_Z_OTR :
{
// Push return address
uint8_t vbidx = cmd - > words . w0 & 0x00000FFF ;
uint32_t zval = cmd - > words . w1 ;
cmd + + ;
if ( rsp . loaded_vertices [ vbidx ] . z < = zval )
{
uint64_t hash = ( ( uint64_t ) cmd - > words . w0 < < 32 ) + cmd - > words . w1 ;
# if _DEBUG
//char fileName[4096];
//ResourceMgr_GetNameByCRC(hash, fileName);
//printf("G_BRANCH_Z_OTR: %s\n", fileName);
# endif
Gfx * gfx = ResourceMgr_LoadGfxByCRC ( hash ) ;
if ( gfx ! = 0 )
{
cmd = gfx ;
- - cmd ; // increase after break
}
}
}
break ;
case ( uint8_t ) G_ENDDL :
//if (markerOn)
//printf("END DL ON MARKER\n");
markerOn = false ;
return ;
# ifdef F3DEX_GBI_2
case G_GEOMETRYMODE :
gfx_sp_geometry_mode ( ~ C0 ( 0 , 24 ) , cmd - > words . w1 ) ;
break ;
# else
case ( uint8_t ) G_SETGEOMETRYMODE :
gfx_sp_geometry_mode ( 0 , cmd - > words . w1 ) ;
break ;
case ( uint8_t ) G_CLEARGEOMETRYMODE :
gfx_sp_geometry_mode ( cmd - > words . w1 , 0 ) ;
break ;
# endif
case ( uint8_t ) G_TRI1 :
# ifdef F3DEX_GBI_2
gfx_sp_tri1 ( C0 ( 16 , 8 ) / 2 , C0 ( 8 , 8 ) / 2 , C0 ( 0 , 8 ) / 2 , false ) ;
# elif defined(F3DEX_GBI) || defined(F3DLP_GBI)
gfx_sp_tri1 ( C1 ( 16 , 8 ) / 2 , C1 ( 8 , 8 ) / 2 , C1 ( 0 , 8 ) / 2 , false ) ;
# else
gfx_sp_tri1 ( C1 ( 16 , 8 ) / 10 , C1 ( 8 , 8 ) / 10 , C1 ( 0 , 8 ) / 10 , false ) ;
# endif
break ;
# ifdef F3DEX_GBI_2
case G_QUAD :
{
int bp = 0 ;
2022-05-11 13:18:24 -04:00
[[fallthrough]] ;
2022-03-21 21:52:44 -04:00
}
# endif
# if defined(F3DEX_GBI) || defined(F3DLP_GBI)
case ( uint8_t ) G_TRI2 :
gfx_sp_tri1 ( C0 ( 16 , 8 ) / 2 , C0 ( 8 , 8 ) / 2 , C0 ( 0 , 8 ) / 2 , false ) ;
gfx_sp_tri1 ( C1 ( 16 , 8 ) / 2 , C1 ( 8 , 8 ) / 2 , C1 ( 0 , 8 ) / 2 , false ) ;
break ;
# endif
case ( uint8_t ) G_SETOTHERMODE_L :
# ifdef F3DEX_GBI_2
gfx_sp_set_other_mode ( 31 - C0 ( 8 , 8 ) - C0 ( 0 , 8 ) , C0 ( 0 , 8 ) + 1 , cmd - > words . w1 ) ;
# else
gfx_sp_set_other_mode ( C0 ( 8 , 8 ) , C0 ( 0 , 8 ) , cmd - > words . w1 ) ;
# endif
break ;
case ( uint8_t ) G_SETOTHERMODE_H :
# ifdef F3DEX_GBI_2
gfx_sp_set_other_mode ( 63 - C0 ( 8 , 8 ) - C0 ( 0 , 8 ) , C0 ( 0 , 8 ) + 1 , ( uint64_t ) cmd - > words . w1 < < 32 ) ;
# else
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 : {
uintptr_t i = ( uintptr_t ) seg_addr ( cmd - > words . w1 ) ;
char * imgData = ( char * ) i ;
2022-05-11 13:18:24 -04:00
if ( ( i & 1 ) ! = 1 )
2022-03-21 21:52:44 -04:00
if ( ResourceMgr_OTRSigCheck ( imgData ) = = 1 )
i = ( uintptr_t ) ResourceMgr_LoadTexByName ( imgData ) ;
2022-05-11 13:18:24 -04:00
gfx_dp_set_texture_image ( C0 ( 21 , 3 ) , C0 ( 19 , 2 ) , C0 ( 0 , 10 ) , ( void * ) i , imgData ) ;
2022-03-21 21:52:44 -04:00
break ;
}
case G_SETTIMG_OTR :
{
uintptr_t addr = cmd - > words . w1 ;
cmd + + ;
uint64_t hash = ( ( uint64_t ) cmd - > words . w0 < < 32 ) + ( uint64_t ) cmd - > words . w1 ;
2022-05-15 15:32:05 -04:00
fileName = ResourceMgr_GetNameByCRC ( hash ) ;
2022-03-31 19:42:44 -04:00
# if _DEBUG && 0
char * tex = ResourceMgr_LoadTexByCRC ( hash ) ;
ResourceMgr_GetNameByCRC ( hash , fileName ) ;
printf ( " G_SETTIMG_OTR: %s, %08X \n " , fileName , hash ) ;
# else
char * tex = NULL ;
2022-03-21 21:52:44 -04:00
# endif
2022-05-11 13:18:24 -04:00
if ( addr ! = 0 )
2022-03-21 21:52:44 -04:00
{
tex = ( char * ) addr ;
}
else
{
tex = ResourceMgr_LoadTexByCRC ( hash ) ;
if ( tex ! = nullptr )
{
cmd - - ;
uintptr_t oldData = cmd - > words . w1 ;
cmd - > words . w1 = ( uintptr_t ) tex ;
2022-05-11 13:18:24 -04:00
if ( ourHash ! = ( uint64_t ) - 1 )
2022-03-21 21:52:44 -04:00
ResourceMgr_RegisterResourcePatch ( ourHash , cmd - dListStart , oldData ) ;
cmd + + ;
}
}
cmd - - ;
uint32_t fmt = C0 ( 21 , 3 ) ;
uint32_t size = C0 ( 19 , 2 ) ;
uint32_t width = C0 ( 0 , 10 ) ;
if ( tex ! = NULL )
gfx_dp_set_texture_image ( fmt , size , width , tex , fileName ) ;
cmd + + ;
break ;
2022-04-25 16:19:00 -04:00
}
2022-03-21 21:52:44 -04:00
case G_SETFB :
{
gfx_flush ( ) ;
fbActive = 1 ;
active_fb = framebuffers . find ( cmd - > words . w1 ) ;
2022-04-18 05:37:47 -04:00
gfx_rapi - > start_draw_to_framebuffer ( active_fb - > first , ( float ) active_fb - > second . applied_height / active_fb - > second . orig_height ) ;
gfx_rapi - > clear_framebuffer ( ) ;
2022-03-21 21:52:44 -04:00
break ;
2022-04-25 16:19:00 -04:00
}
2022-03-21 21:52:44 -04:00
case G_RESETFB :
{
gfx_flush ( ) ;
fbActive = 0 ;
2022-04-18 05:37:47 -04:00
gfx_rapi - > start_draw_to_framebuffer ( game_renders_to_framebuffer ? game_framebuffer : 0 , ( float ) gfx_current_dimensions . height / SCREEN_HEIGHT ) ;
2022-03-21 21:52:44 -04:00
break ;
}
case G_SETTIMG_FB :
{
gfx_flush ( ) ;
gfx_rapi - > select_texture_fb ( cmd - > words . w1 ) ;
rdp . textures_changed [ 0 ] = false ;
rdp . textures_changed [ 1 ] = false ;
//if (texPtr != NULL)
//gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), texPtr);
2022-04-25 16:19:00 -04:00
break ;
}
case G_SETGRAYSCALE :
{
rdp . grayscale = cmd - > words . w1 ;
break ;
2022-03-21 21:52:44 -04:00
}
case G_LOADBLOCK :
gfx_dp_load_block ( C1 ( 24 , 3 ) , C0 ( 12 , 12 ) , C0 ( 0 , 12 ) , C1 ( 12 , 12 ) , C1 ( 0 , 12 ) ) ;
break ;
case G_LOADTILE :
gfx_dp_load_tile ( C1 ( 24 , 3 ) , C0 ( 12 , 12 ) , C0 ( 0 , 12 ) , C1 ( 12 , 12 ) , C1 ( 0 , 12 ) ) ;
break ;
case G_SETTILE :
gfx_dp_set_tile ( C0 ( 21 , 3 ) , C0 ( 19 , 2 ) , C0 ( 9 , 9 ) , C0 ( 0 , 9 ) , C1 ( 24 , 3 ) , C1 ( 20 , 4 ) , C1 ( 18 , 2 ) , C1 ( 14 , 4 ) , C1 ( 10 , 4 ) , C1 ( 8 , 2 ) , C1 ( 4 , 4 ) , C1 ( 0 , 4 ) ) ;
break ;
case G_SETTILESIZE :
gfx_dp_set_tile_size ( C1 ( 24 , 3 ) , C0 ( 12 , 12 ) , C0 ( 0 , 12 ) , C1 ( 12 , 12 ) , C1 ( 0 , 12 ) ) ;
break ;
case G_LOADTLUT :
gfx_dp_load_tlut ( C1 ( 24 , 3 ) , C1 ( 14 , 10 ) ) ;
break ;
case G_SETENVCOLOR :
gfx_dp_set_env_color ( C1 ( 24 , 8 ) , C1 ( 16 , 8 ) , C1 ( 8 , 8 ) , C1 ( 0 , 8 ) ) ;
break ;
case G_SETPRIMCOLOR :
gfx_dp_set_prim_color ( C0 ( 8 , 8 ) , C0 ( 0 , 8 ) , C1 ( 24 , 8 ) , C1 ( 16 , 8 ) , C1 ( 8 , 8 ) , C1 ( 0 , 8 ) ) ;
break ;
case G_SETFOGCOLOR :
gfx_dp_set_fog_color ( C1 ( 24 , 8 ) , C1 ( 16 , 8 ) , C1 ( 8 , 8 ) , C1 ( 0 , 8 ) ) ;
break ;
case G_SETFILLCOLOR :
gfx_dp_set_fill_color ( cmd - > words . w1 ) ;
break ;
2022-04-25 16:19:00 -04:00
case G_SETINTENSITY :
gfx_dp_set_grayscale_color ( C1 ( 24 , 8 ) , C1 ( 16 , 8 ) , C1 ( 8 , 8 ) , C1 ( 0 , 8 ) ) ;
break ;
2022-03-21 21:52:44 -04:00
case G_SETCOMBINE :
gfx_dp_set_combine_mode (
color_comb ( C0 ( 20 , 4 ) , C1 ( 28 , 4 ) , C0 ( 15 , 5 ) , C1 ( 15 , 3 ) ) ,
alpha_comb ( C0 ( 12 , 3 ) , C1 ( 12 , 3 ) , C0 ( 9 , 3 ) , C1 ( 9 , 3 ) ) ,
color_comb ( C0 ( 5 , 4 ) , C1 ( 24 , 4 ) , C0 ( 0 , 5 ) , C1 ( 6 , 3 ) ) ,
alpha_comb ( C1 ( 21 , 3 ) , C1 ( 3 , 3 ) , C1 ( 18 , 3 ) , C1 ( 0 , 3 ) ) ) ;
break ;
// G_SETPRIMCOLOR, G_CCMUX_PRIMITIVE, G_ACMUX_PRIMITIVE, is used by Goddard
// G_CCMUX_TEXEL1, LOD_FRACTION is used in Bowser room 1
case G_TEXRECT :
case G_TEXRECTFLIP :
{
int32_t lrx , lry , tile , ulx , uly ;
uint32_t uls , ult , dsdx , dtdy ;
# ifdef F3DEX_GBI_2E
lrx = ( int32_t ) ( C0 ( 0 , 24 ) < < 8 ) > > 8 ;
lry = ( int32_t ) ( C1 ( 0 , 24 ) < < 8 ) > > 8 ;
tile = C1 ( 24 , 3 ) ;
+ + cmd ;
ulx = ( int32_t ) ( C0 ( 0 , 24 ) < < 8 ) > > 8 ;
uly = ( int32_t ) ( C1 ( 0 , 24 ) < < 8 ) > > 8 ;
+ + cmd ;
uls = C0 ( 16 , 16 ) ;
ult = C0 ( 0 , 16 ) ;
dsdx = C1 ( 16 , 16 ) ;
dtdy = C1 ( 0 , 16 ) ;
# else
lrx = C0 ( 12 , 12 ) ;
lry = C0 ( 0 , 12 ) ;
tile = C1 ( 24 , 3 ) ;
ulx = C1 ( 12 , 12 ) ;
uly = C1 ( 0 , 12 ) ;
+ + cmd ;
uls = C1 ( 16 , 16 ) ;
ult = C1 ( 0 , 16 ) ;
+ + cmd ;
dsdx = C1 ( 16 , 16 ) ;
dtdy = C1 ( 0 , 16 ) ;
# endif
gfx_dp_texture_rectangle ( ulx , uly , lrx , lry , tile , uls , ult , dsdx , dtdy , opcode = = G_TEXRECTFLIP ) ;
break ;
}
2022-04-18 05:37:47 -04:00
case G_TEXRECT_WIDE :
2022-03-21 21:52:44 -04:00
{
int32_t lrx , lry , tile , ulx , uly ;
uint32_t uls , ult , dsdx , dtdy ;
lrx = static_cast < int32_t > ( ( C0 ( 0 , 24 ) < < 8 ) ) > > 8 ;
lry = static_cast < int32_t > ( ( C1 ( 0 , 24 ) < < 8 ) ) > > 8 ;
tile = C1 ( 24 , 3 ) ;
+ + cmd ;
ulx = static_cast < int32_t > ( ( C0 ( 0 , 24 ) < < 8 ) ) > > 8 ;
uly = static_cast < int32_t > ( ( C1 ( 0 , 24 ) < < 8 ) ) > > 8 ;
+ + cmd ;
uls = C0 ( 16 , 16 ) ;
ult = C0 ( 0 , 16 ) ;
dsdx = C1 ( 16 , 16 ) ;
dtdy = C1 ( 0 , 16 ) ;
gfx_dp_texture_rectangle ( ulx , uly , lrx , lry , tile , uls , ult , dsdx , dtdy , opcode = = G_TEXRECTFLIP ) ;
break ;
}
case G_FILLRECT :
# ifdef F3DEX_GBI_2E
{
int32_t lrx , lry , ulx , uly ;
lrx = ( int32_t ) ( C0 ( 0 , 24 ) < < 8 ) > > 8 ;
lry = ( int32_t ) ( C1 ( 0 , 24 ) < < 8 ) > > 8 ;
+ + cmd ;
ulx = ( int32_t ) ( C0 ( 0 , 24 ) < < 8 ) > > 8 ;
uly = ( int32_t ) ( C1 ( 0 , 24 ) < < 8 ) > > 8 ;
gfx_dp_fill_rectangle ( ulx , uly , lrx , lry ) ;
break ;
}
# else
gfx_dp_fill_rectangle ( C1 ( 12 , 12 ) , C1 ( 0 , 12 ) , C0 ( 12 , 12 ) , C0 ( 0 , 12 ) ) ;
break ;
case G_FILLWIDERECT :
{
int32_t lrx , lry , ulx , uly ;
lrx = ( int32_t ) ( C0 ( 0 , 24 ) < < 8 ) > > 8 ;
lry = ( int32_t ) ( C1 ( 0 , 24 ) < < 8 ) > > 8 ;
+ + cmd ;
ulx = ( int32_t ) ( C0 ( 0 , 24 ) < < 8 ) > > 8 ;
uly = ( int32_t ) ( C1 ( 0 , 24 ) < < 8 ) > > 8 ;
gfx_dp_fill_rectangle ( ulx , uly , lrx , lry ) ;
break ;
}
# endif
case G_SETSCISSOR :
gfx_dp_set_scissor ( C1 ( 24 , 2 ) , C0 ( 12 , 12 ) , C0 ( 0 , 12 ) , C1 ( 12 , 12 ) , C1 ( 0 , 12 ) ) ;
break ;
case G_SETZIMG :
gfx_dp_set_z_image ( seg_addr ( cmd - > words . w1 ) ) ;
break ;
case G_SETCIMG :
gfx_dp_set_color_image ( C0 ( 21 , 3 ) , C0 ( 19 , 2 ) , C0 ( 0 , 11 ) , seg_addr ( cmd - > words . w1 ) ) ;
break ;
case G_RDPSETOTHERMODE :
gfx_dp_set_other_mode ( C0 ( 0 , 24 ) , cmd - > words . w1 ) ;
break ;
// S2DEX
case G_BG_COPY :
if ( ! markerOn )
gfx_s2dex_bg_copy ( ( const uObjBg * ) cmd - > words . w1 ) ; // not seg_addr here it seems
break ;
}
+ + cmd ;
}
}
static void gfx_sp_reset ( ) {
rsp . modelview_matrix_stack_size = 1 ;
rsp . current_num_lights = 2 ;
rsp . lights_changed = true ;
}
void gfx_get_dimensions ( uint32_t * width , uint32_t * height ) {
gfx_wapi - > get_dimensions ( width , height ) ;
}
2022-07-05 20:02:47 -04:00
void gfx_init ( struct GfxWindowManagerAPI * wapi , struct GfxRenderingAPI * rapi , const char * game_name , bool start_in_fullscreen , uint32_t width , uint32_t height ) {
2022-03-21 21:52:44 -04:00
gfx_wapi = wapi ;
gfx_rapi = rapi ;
2022-07-05 20:02:47 -04:00
gfx_wapi - > init ( game_name , start_in_fullscreen , width , height ) ;
2022-03-21 21:52:44 -04:00
gfx_rapi - > init ( ) ;
2022-07-05 20:02:47 -04:00
gfx_rapi - > update_framebuffer_parameters ( 0 , width , height , 1 , false , true , true , true ) ;
2022-07-24 16:01:28 -04:00
gfx_current_dimensions . internal_mul = CVar_GetFloat ( " gInternalResolution " , 1 ) ;
gfx_msaa_level = CVar_GetS32 ( " gMSAAValue " , 1 ) ;
2022-07-05 20:02:47 -04:00
gfx_current_dimensions . width = width ;
gfx_current_dimensions . height = height ;
2022-04-18 05:37:47 -04:00
game_framebuffer = gfx_rapi - > create_framebuffer ( ) ;
game_framebuffer_msaa_resolved = gfx_rapi - > create_framebuffer ( ) ;
2022-03-21 21:52:44 -04:00
for ( int i = 0 ; i < 16 ; i + + )
2022-05-11 13:18:24 -04:00
segmentPointers [ i ] = 0 ;
2022-03-21 21:52:44 -04:00
// Used in the 120 star TAS
static uint32_t precomp_shaders [ ] = {
0x01200200 ,
0x00000045 ,
0x00000200 ,
0x01200a00 ,
0x00000a00 ,
0x01a00045 ,
0x00000551 ,
0x01045045 ,
0x05a00a00 ,
0x01200045 ,
0x05045045 ,
0x01045a00 ,
0x01a00a00 ,
0x0000038d ,
0x01081081 ,
0x0120038d ,
0x03200045 ,
0x03200a00 ,
0x01a00a6f ,
0x01141045 ,
0x07a00a00 ,
0x05200200 ,
0x03200200 ,
0x09200200 ,
0x0920038d ,
0x09200045
} ;
for ( size_t i = 0 ; i < sizeof ( precomp_shaders ) / sizeof ( uint32_t ) ; i + + ) {
//gfx_lookup_or_create_shader_program(precomp_shaders[i]);
}
2022-05-21 13:22:25 -04:00
ModInternal : : ExecuteHooks < ModInternal : : GfxInit > ( ) ;
2022-03-21 21:52:44 -04:00
}
struct GfxRenderingAPI * gfx_get_current_rendering_api ( void ) {
return gfx_rapi ;
}
void gfx_start_frame ( void ) {
gfx_wapi - > handle_events ( ) ;
2022-04-18 05:37:47 -04:00
gfx_wapi - > get_dimensions ( & gfx_current_window_dimensions . width , & gfx_current_window_dimensions . height ) ;
SohImGui : : DrawMainMenuAndCalculateGameSize ( ) ;
2022-05-13 18:43:55 -04:00
has_drawn_imgui_menu = true ;
2022-03-21 21:52:44 -04:00
if ( gfx_current_dimensions . height = = 0 ) {
// Avoid division by zero
gfx_current_dimensions . height = 1 ;
}
gfx_current_dimensions . aspect_ratio = ( float ) gfx_current_dimensions . width / ( float ) gfx_current_dimensions . height ;
if ( gfx_current_dimensions . height ! = gfx_prev_dimensions . height ) {
for ( auto & fb : framebuffers ) {
uint32_t width = fb . second . orig_width , height = fb . second . orig_height ;
gfx_adjust_width_height_for_scale ( width , height ) ;
if ( width ! = fb . second . applied_width | | height ! = fb . second . applied_height ) {
2022-04-18 05:37:47 -04:00
gfx_rapi - > update_framebuffer_parameters ( fb . first , width , height , 1 , true , true , true , true ) ;
2022-03-21 21:52:44 -04:00
fb . second . applied_width = width ;
fb . second . applied_height = height ;
}
}
}
gfx_prev_dimensions = gfx_current_dimensions ;
2022-04-18 05:37:47 -04:00
bool different_size = gfx_current_dimensions . width ! = gfx_current_game_window_viewport . width | | gfx_current_dimensions . height ! = gfx_current_game_window_viewport . height ;
if ( different_size | | gfx_msaa_level > 1 ) {
game_renders_to_framebuffer = true ;
if ( different_size ) {
gfx_rapi - > update_framebuffer_parameters ( game_framebuffer , gfx_current_dimensions . width , gfx_current_dimensions . height , gfx_msaa_level , true , true , true , true ) ;
} else {
// MSAA framebuffer needs to be resolved to an equally sized target when complete, which must therefore match the window size
gfx_rapi - > update_framebuffer_parameters ( game_framebuffer , gfx_current_window_dimensions . width , gfx_current_window_dimensions . height , gfx_msaa_level , false , true , true , true ) ;
}
if ( gfx_msaa_level > 1 & & different_size ) {
gfx_rapi - > update_framebuffer_parameters ( game_framebuffer_msaa_resolved , gfx_current_dimensions . width , gfx_current_dimensions . height , 1 , false , false , false , false ) ;
}
} else {
game_renders_to_framebuffer = false ;
}
2022-03-21 21:52:44 -04:00
fbActive = 0 ;
}
2022-05-13 18:43:55 -04:00
void gfx_run ( Gfx * commands , const std : : unordered_map < Mtx * , MtxF > & mtx_replacements ) {
2022-03-21 21:52:44 -04:00
gfx_sp_reset ( ) ;
//puts("New frame");
2022-04-18 05:37:47 -04:00
get_pixel_depth_pending . clear ( ) ;
get_pixel_depth_cached . clear ( ) ;
2022-03-21 21:52:44 -04:00
if ( ! gfx_wapi - > start_frame ( ) ) {
dropped_frame = true ;
2022-05-13 18:43:55 -04:00
if ( has_drawn_imgui_menu ) {
SohImGui : : DrawFramebufferAndGameInput ( ) ;
SohImGui : : CancelFrame ( ) ;
has_drawn_imgui_menu = false ;
}
2022-03-21 21:52:44 -04:00
return ;
}
dropped_frame = false ;
2022-05-13 18:43:55 -04:00
if ( ! has_drawn_imgui_menu ) {
SohImGui : : DrawMainMenuAndCalculateGameSize ( ) ;
}
current_mtx_replacements = & mtx_replacements ;
2022-03-21 21:52:44 -04:00
double t0 = gfx_wapi - > get_time ( ) ;
2022-04-18 05:37:47 -04:00
gfx_rapi - > update_framebuffer_parameters ( 0 , gfx_current_window_dimensions . width , gfx_current_window_dimensions . height , 1 , false , true , true , ! game_renders_to_framebuffer ) ;
2022-03-21 21:52:44 -04:00
gfx_rapi - > start_frame ( ) ;
2022-04-18 05:37:47 -04:00
gfx_rapi - > start_draw_to_framebuffer ( game_renders_to_framebuffer ? game_framebuffer : 0 , ( float ) gfx_current_dimensions . height / SCREEN_HEIGHT ) ;
gfx_rapi - > clear_framebuffer ( ) ;
2022-05-29 12:16:23 -04:00
rdp . viewport_or_scissor_changed = true ;
rendering_state . viewport = { } ;
rendering_state . scissor = { } ;
2022-03-21 21:52:44 -04:00
gfx_run_dl ( commands ) ;
gfx_flush ( ) ;
2022-04-18 05:37:47 -04:00
SohUtils : : saveEnvironmentVar ( " framebuffer " , string ( ) ) ;
if ( game_renders_to_framebuffer ) {
gfx_rapi - > start_draw_to_framebuffer ( 0 , 1 ) ;
gfx_rapi - > clear_framebuffer ( ) ;
if ( gfx_msaa_level > 1 ) {
bool different_size = gfx_current_dimensions . width ! = gfx_current_game_window_viewport . width | | gfx_current_dimensions . height ! = gfx_current_game_window_viewport . height ;
if ( different_size ) {
gfx_rapi - > resolve_msaa_color_buffer ( game_framebuffer_msaa_resolved , game_framebuffer ) ;
SohUtils : : saveEnvironmentVar ( " framebuffer " , std : : to_string ( ( uintptr_t ) gfx_rapi - > get_framebuffer_texture_id ( game_framebuffer_msaa_resolved ) ) ) ;
} else {
gfx_rapi - > resolve_msaa_color_buffer ( 0 , game_framebuffer ) ;
}
} else {
SohUtils : : saveEnvironmentVar ( " framebuffer " , std : : to_string ( ( uintptr_t ) gfx_rapi - > get_framebuffer_texture_id ( game_framebuffer ) ) ) ;
}
}
SohImGui : : DrawFramebufferAndGameInput ( ) ;
SohImGui : : Render ( ) ;
2022-03-21 21:52:44 -04:00
double t1 = gfx_wapi - > get_time ( ) ;
//printf("Process %f %f\n", t1, t1 - t0);
gfx_rapi - > end_frame ( ) ;
gfx_wapi - > swap_buffers_begin ( ) ;
2022-05-13 18:43:55 -04:00
has_drawn_imgui_menu = false ;
2022-03-21 21:52:44 -04:00
}
void gfx_end_frame ( void ) {
if ( ! dropped_frame ) {
gfx_rapi - > finish_render ( ) ;
gfx_wapi - > swap_buffers_end ( ) ;
}
}
2022-05-29 12:16:23 -04:00
void gfx_set_target_fps ( int fps ) {
gfx_wapi - > set_target_fps ( fps ) ;
}
void gfx_set_maximum_frame_latency ( int latency ) {
gfx_wapi - > set_maximum_frame_latency ( latency ) ;
}
float gfx_get_detected_hz ( void ) {
return gfx_wapi - > get_detected_hz ( ) ;
2022-03-21 21:52:44 -04:00
}
int gfx_create_framebuffer ( uint32_t width , uint32_t height ) {
uint32_t orig_width = width , orig_height = height ;
gfx_adjust_width_height_for_scale ( width , height ) ;
2022-04-18 05:37:47 -04:00
int fb = gfx_rapi - > create_framebuffer ( ) ;
gfx_rapi - > update_framebuffer_parameters ( fb , width , height , 1 , true , true , true , true ) ;
2022-03-21 21:52:44 -04:00
framebuffers [ fb ] = { orig_width , orig_height , width , height } ;
return fb ;
}
2022-04-18 05:37:47 -04:00
void gfx_set_framebuffer ( int fb , float noise_scale ) {
gfx_rapi - > start_draw_to_framebuffer ( fb , noise_scale ) ;
gfx_rapi - > clear_framebuffer ( ) ;
2022-03-21 21:52:44 -04:00
}
2022-04-18 05:37:47 -04:00
void gfx_reset_framebuffer ( ) {
gfx_rapi - > start_draw_to_framebuffer ( 0 , ( float ) gfx_current_dimensions . height / SCREEN_HEIGHT ) ;
}
static void adjust_pixel_depth_coordinates ( float & x , float & y ) {
x = x * RATIO_Y - ( SCREEN_WIDTH * RATIO_Y - gfx_current_dimensions . width ) / 2 ;
y * = RATIO_Y ;
if ( ! game_renders_to_framebuffer | | ( gfx_msaa_level > 1 & & gfx_current_dimensions . width = = gfx_current_game_window_viewport . width & & gfx_current_dimensions . height = = gfx_current_game_window_viewport . height ) ) {
x + = gfx_current_game_window_viewport . x ;
y + = gfx_current_window_dimensions . height - ( gfx_current_game_window_viewport . y + gfx_current_game_window_viewport . height ) ;
}
}
void gfx_get_pixel_depth_prepare ( float x , float y ) {
adjust_pixel_depth_coordinates ( x , y ) ;
get_pixel_depth_pending . emplace ( x , y ) ;
2022-03-21 21:52:44 -04:00
}
uint16_t gfx_get_pixel_depth ( float x , float y ) {
2022-04-18 05:37:47 -04:00
adjust_pixel_depth_coordinates ( x , y ) ;
if ( auto it = get_pixel_depth_cached . find ( make_pair ( x , y ) ) ; it ! = get_pixel_depth_cached . end ( ) ) {
return it - > second ;
}
get_pixel_depth_pending . emplace ( x , y ) ;
2022-07-05 19:29:57 -04:00
unordered_map < pair < float , float > , uint16_t , hash_pair_ff > res = gfx_rapi - > get_pixel_depth ( game_renders_to_framebuffer ? game_framebuffer : 0 , get_pixel_depth_pending ) ;
2022-04-18 05:37:47 -04:00
get_pixel_depth_cached . merge ( res ) ;
get_pixel_depth_pending . clear ( ) ;
return get_pixel_depth_cached . find ( make_pair ( x , y ) ) - > second ;
2022-03-21 21:52:44 -04:00
}