Skip to content

Instantly share code, notes, and snippets.

@Pokechu22
Last active April 17, 2021 04:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pokechu22/dac1a542f6b99ef0b4140564b5d118fc to your computer and use it in GitHub Desktop.
Save Pokechu22/dac1a542f6b99ef0b4140564b5d118fc to your computer and use it in GitHub Desktop.
Dolphin Luigi's Mansion portrait indirect texture issue

Adapted from my normalize test case, in turn adapted from libogc texturetest.

Due to general confusion, the previous tests had a variable called use_luigi_matrix which actually enabled the identity matrix. This also affected the filename of the saved results, which is why the luigi matrix appeared to have much more drastic changes despite using values with a much smaller magnitude. Oops.

Anyways, I simplified the test to only use the 256x256 base texture, the "normal" indirect texture, and the identity matrix. I also added a mode where it doesn't use indirect texturing at all (during which GX_SetTevDirect is used). I also made it attempt to save screenshots every frame, but only actually save them if the frame is new compared to other ones for the same configuration; this reduces the number of duplicate screenshots but still allows seeing variations. (I didn't think to make it save what order it saw the duplicates in; most of the time it flickered every other one frame though.)

As with the 3rd test, I used OpenGL with the fix from PR 8296 (setting the tex coord to 0 when out of bounds for indirect textures). It turns out Dolphin already did that for direct textures (see cb121dab).

The results are in Results_HW.7z and Results_OGL.7z, and differences.7z shows the two xor'd together. Note that Dolphin is slightly off with the texture positioning, so the xor'd images are slightly off, but looking at them directly shows things basically correct (at least for one of the two triangles, with the other one usually changing rapidly).

Theoretically, things could behave differently for tex coords 3-7 (and 4-8 tex gens), but I don't think that's worth worrying about (scaling up this test to that size would require 8×8×9 = 576 passes, which would take too long).

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#include <gccore.h>
#include <fat.h>
#include <time.h>
#include <sys/stat.h>
#include <sdcard/wiisd_io.h>
#include <png.h>
#include <zlib.h>
#include <ogc/consol.h>
#include <ogc/tpl.h>
#include <ogc/stm.h>
#include "textures_tpl.h"
#include "textures.h"
#define DEFAULT_FIFO_SIZE (256*1024)
#define NUM_FRAMES 30
typedef struct tagcamera {
guVector pos;
guVector up;
guVector view;
}camera;
f32 square[] ATTRIBUTE_ALIGN(32) =
{
// x y z
-50, 50, 0, // 0
50, 50, 0, // 1
50, -50, 0, // 2
-50, -50, 0, // 3
};
static void *xfb = NULL;
static u8 *console_buffer = NULL;
static u32 *efb_buffer = NULL; // For screenshots
static uLong frame_crcs[NUM_FRAMES];
static u32 do_copy = GX_FALSE;
GXRModeObj *rmode;
GXTexObj image_base_160_tex, image_base_256_tex;
GXTexObj image_ind_tex, image_ind_greyer_tex, image_ind_trans_tex;
#define NUM_BASE 2
GXTexObj* base_texs[NUM_BASE] = {&image_base_160_tex, &image_base_256_tex};
const char* base_names[NUM_BASE] = {"160x160", "256x256"};
#define NUM_IND 3
GXTexObj* ind_texs[NUM_IND] = {&image_ind_tex, &image_ind_greyer_tex, &image_ind_trans_tex};
const char* ind_names[NUM_IND] = {"Normal", "Greyer", "Transp"};
const char* matrix_names[2] = {"Luigi", "Ident"};
TPLFile spriteTPL;
camera cam = {{0.0F, 0.0F, 0.0F},
{0.0F, 1.0F, 0.0F},
{0.0F, 0.0F, -1.0F}};
static void draw_vert(u8 pos, f32 s, f32 t);
static void draw_square(Mtx v);
void run_test(int num_tex_gens, int base_image, int ind_image, int base_coord, int ind_coord, bool use_identity_matrix);
void save_screenshot(char* dir, int frame_counter, int num_tex_gens, int base_image, int ind_image, int base_coord, int ind_coord, bool use_identity_matrix);
static void save_rgba_png(char* fn, u32 *buffer, u16 width, u16 height);
static void copy_to_xfb(u32 count);
int main() {
Mtx p; // perspective matrix
GXColor background = {0, 0, 0, 0xff};
VIDEO_Init();
rmode = VIDEO_GetPreferredMode(NULL);
PAD_Init();
xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
// Characters are 16 pixels tall, and the XFB uses 2 bytes per pixel
console_buffer = malloc(2*rmode->fbWidth*16);
CON_Init(console_buffer, 0, 0, rmode->fbWidth, 16, rmode->fbWidth*VI_DISPLAY_PIX_SZ);
VIDEO_Configure(rmode);
VIDEO_SetNextFramebuffer(xfb);
VIDEO_SetPostRetraceCallback(copy_to_xfb);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
void *gp_fifo = NULL;
gp_fifo = MEM_K0_TO_K1(memalign(32,DEFAULT_FIFO_SIZE));
memset(gp_fifo,0,DEFAULT_FIFO_SIZE);
GX_Init(gp_fifo,DEFAULT_FIFO_SIZE);
GX_SetCopyClear(background, 0x00ffffff);
GX_SetViewport(0,0,rmode->fbWidth,rmode->efbHeight,0,1);
GX_SetDispCopyYScale((f32)rmode->xfbHeight/(f32)rmode->efbHeight);
GX_SetScissor(0,0,rmode->fbWidth,rmode->efbHeight);
GX_SetDispCopySrc(0,0,rmode->fbWidth,rmode->efbHeight);
GX_SetDispCopyDst(rmode->fbWidth,rmode->xfbHeight);
GX_SetCopyFilter(rmode->aa,rmode->sample_pattern,GX_TRUE,rmode->vfilter);
GX_SetFieldMode(rmode->field_rendering,((rmode->viHeight==2*rmode->xfbHeight)?GX_ENABLE:GX_DISABLE));
if (rmode->aa) {
GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR);
} else {
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
}
GX_SetCullMode(GX_CULL_NONE);
GX_CopyDisp(xfb,GX_TRUE);
GX_SetDispCopyGamma(GX_GM_1_0);
guPerspective(p, 60, 1.33F, 10.0F, 1000.0F);
GX_LoadProjectionMtx(p, GX_PERSPECTIVE);
GX_InvalidateTexAll();
TPL_OpenTPLFromMemory(&spriteTPL, (void *)textures_tpl,textures_tpl_size);
TPL_GetTexture(&spriteTPL,image_base_160,&image_base_160_tex);
TPL_GetTexture(&spriteTPL,image_base_256,&image_base_256_tex);
TPL_GetTexture(&spriteTPL,image_ind,&image_ind_tex);
TPL_GetTexture(&spriteTPL,image_ind_greyer,&image_ind_greyer_tex);
TPL_GetTexture(&spriteTPL,image_ind_trans,&image_ind_trans_tex);
fatMountSimple("sd", &__io_wiisd);
time_t rawtime;
time(&rawtime);
struct tm* curtime = localtime(&rawtime);
char screenshotfolder[100];
strftime(screenshotfolder, sizeof(screenshotfolder), "sd:/Test_%H%M%S", curtime);
mkdir(screenshotfolder, 0777);
efb_buffer = malloc(rmode->fbWidth*rmode->efbHeight*sizeof(u32));
printf("\x1b[30;0m\x1b[47;1m"); // Switch to black text on a white background.
for (u32 iteration = 0; iteration < 4*3*4; iteration++) {
memset(frame_crcs, 0, sizeof(frame_crcs));
for (u32 frame_counter = 0; frame_counter < NUM_FRAMES; frame_counter++) {
// Compute configuration -- done each frame so that the loops can be swapped to make recording a FIFO easier
u32 number = iteration;
int num_tex_gens = (number % 4); number /= 4;
int base_image = 1; // (number % NUM_BASE); number /= NUM_BASE;
int ind_image = 0; // (number % NUM_IND ); number /= NUM_IND;
int base_coord = (number % 3); number /= 3; // GX_TEXCOORD0-GX_TEXCOORD2 are just 0-2
int ind_coord = (number % 4) - 1; number /= 4; // -1 => disabled
bool use_identity_matrix = true; // !(number % 2); number /= 2;
// Newline first to avoid having the only visible line be blank
char ind_coord_display = ind_coord == -1 ? 'X' : ind_coord + '0';
printf("\nFrame: %02d; Tex gens: %d; Base: %s; Ind: %s; BC: %d; IC: %c; Matrix: %s", frame_counter, num_tex_gens,
base_names[base_image], ind_names[ind_image], base_coord, ind_coord_display, matrix_names[use_identity_matrix]);
run_test(num_tex_gens, base_image, ind_image, base_coord, ind_coord, use_identity_matrix);
GX_DrawDone();
save_screenshot(screenshotfolder, frame_counter, num_tex_gens, base_image, ind_image, base_coord, ind_coord, use_identity_matrix);
do_copy = GX_TRUE;
VIDEO_WaitVSync();
PAD_ScanPads();
if(PAD_ButtonsDown(0) & PAD_BUTTON_START) {
exit(0);
}
}
}
STM_ShutdownToStandby();
return 0;
}
void draw_vert(u8 pos, f32 s, f32 t) {
GX_Position1x8(pos);
GX_TexCoord2f32(s*2, t*2);
GX_TexCoord2f32(s, t);
GX_TexCoord2f32(s*3, t*3);
}
void draw_square(Mtx v) {
Mtx m; // model matrix.
Mtx mv; // modelview matrix.
guMtxIdentity(m);
guMtxTransApply(m, m, 0, 0, -100);
guMtxConcat(v,m,mv);
GX_LoadPosMtxImm(mv, GX_PNMTX0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
draw_vert(0, 0.0, 0.0);
draw_vert(1, 1.0, 0.0);
draw_vert(2, 1.0, 1.0);
draw_vert(3, 0.0, 1.0);
GX_End();
}
void run_test(int num_tex_gens, int base_image, int ind_image, int base_coord, int ind_coord, bool use_identity_matrix) {
Mtx v; // view matrix
GXTexObj* base_tex = base_texs[base_image];
GXTexObj* ind_tex = ind_texs[ind_image];
// Actually configure and render
GX_SetNumChans(0);
GX_SetNumTexGens(num_tex_gens);
GX_SetNumIndStages(1);
GX_SetNumTevStages(1);
GX_ClearVtxDesc();
GX_SetVtxDesc(GX_VA_POS, GX_INDEX8);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GX_SetVtxDesc(GX_VA_TEX1, GX_DIRECT);
GX_SetVtxDesc(GX_VA_TEX2, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX1, GX_TEX_ST, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX2, GX_TEX_ST, GX_F32, 0);
GX_SetArray(GX_VA_POS, square, 3*sizeof(f32));
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, GX_IDENTITY);
GX_SetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX2, GX_IDENTITY);
if (ind_coord != -1) {
GX_SetIndTexOrder(GX_INDTEXSTAGE0, ind_coord, GX_TEXMAP1);
if (use_identity_matrix) {
// Identity matrix (requires dividing values by 2 and using a scale 1 higher
// due to internal representation, as noted in the docs for GX_SetIndTexMatrix)
f32 offset_mtx[2][3] = {{.5f, 0, 0}, {0, .5f, 0}};
GX_SetIndTexMatrix(GX_ITM_0, offset_mtx, 1);
} else {
// This is what Luigi's Mansion does
f32 offset_mtx[2][3] = {{0.009765625f, 0.009765625f, 0}, {0.009765625f, 0.009765625f, 0}};
GX_SetIndTexMatrix(GX_ITM_0, offset_mtx, 1);
}
}
GX_SetTevOrder(GX_TEVSTAGE0, base_coord, GX_TEXMAP0, GX_COLORNULL);
GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL);
if (ind_coord != -1) {
GX_SetTevIndirect(GX_TEVSTAGE0, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_STU, GX_ITM_0, GX_ITW_OFF, GX_ITW_OFF, GX_FALSE, GX_FALSE, GX_ITBA_OFF);
} else {
GX_SetTevDirect(GX_TEVSTAGE0);
}
GX_LoadTexObj(base_tex, GX_TEXMAP0);
GX_LoadTexObj(ind_tex, GX_TEXMAP1);
GX_SetViewport(0,0,rmode->fbWidth,rmode->efbHeight,0,1);
guLookAt(v, &cam.pos, &cam.up, &cam.view);
GX_InvVtxCache();
GX_Flush();
draw_square(v);
}
void save_screenshot(char* dir, int frame_counter,int num_tex_gens, int base_image, int ind_image, int base_coord, int ind_coord, bool use_identity_matrix) {
// Based on Open Homebrew Channel code (GPLv2):
// https://github.com/fail0verflow/hbc/blob/a8e5f6c0f7e484c7f7112967eee6eee47b27d9ac/channel/channelapp/source/gfx.c#L506-L538
// https://github.com/fail0verflow/hbc/blob/a8e5f6c0f7e484c7f7112967eee6eee47b27d9ac/channel/channelapp/source/view.c#L252-L269
u16 x, y;
GXColor c;
u32 val;
u32 *p = efb_buffer;
for (y = 0; y < rmode->efbHeight; ++y) {
for (x = 0; x < rmode->fbWidth; ++x) {
GX_PeekARGB(x, y, &c);
val = ((u32) c.a) << 24;
val |= ((u32) c.r) << 16;
val |= ((u32) c.g) << 8;
val |= c.b;
*p++ = val;
}
}
uLong crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, (u8*)efb_buffer, rmode->fbWidth*rmode->efbHeight*sizeof(u32));
frame_crcs[frame_counter] = crc;
// Check if the screenshot matches.
for (u32 i = 0; i < frame_counter; i++) {
if (frame_crcs[i] == crc) {
// This result has already been seen
return;
}
}
char filename[256];
// snprintf(filename, sizeof(filename), "%s/%s_%s_%s_BC%d_IC%d_%dTG_F%02d.png",
// dir, matrix_names[use_identity_matrix],
// base_names[base_image], ind_names[ind_image],
// base_coord, ind_coord, num_tex_gens, frame_counter);
char ind_coord_display = ind_coord == -1 ? 'X' : ind_coord + '0';
snprintf(filename, sizeof(filename), "%s/F%02d_BC%d_IC%c_TG%d.png",
dir, frame_counter, base_coord, ind_coord_display, num_tex_gens);
save_rgba_png(filename, efb_buffer, rmode->fbWidth, rmode->efbHeight);
}
static void save_rgba_png(char* fn, u32 *buffer, u16 width, u16 height) {
// Code from Open Homebrew Channel (with x -> width and y -> height):
// https://github.com/fail0verflow/hbc/blob/a8e5f6c0f7e484c7f7112967eee6eee47b27d9ac/channel/channelapp/source/tex.c#L182-L261
FILE *fp = NULL;
png_structp png_ptr = NULL;
png_infop info_ptr;
png_bytep *row_pointers;
u16 i;
row_pointers = (png_bytep *) malloc(height * sizeof(png_bytep));
fp = fopen(fn, "wb");
if (!fp) {
// gprintf("couldnt open %s for writing\n", fn);
goto exit;
}
setbuf(fp, NULL);
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (!png_ptr) {
// gprintf ("png_create_write_struct failed\n");
goto exit;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
// gprintf ("png_create_info_struct failed\n");
goto exit;
}
if (setjmp(png_jmpbuf(png_ptr))) {
// gprintf ("setjmp failed\n");
goto exit;
}
png_init_io(png_ptr, fp);
png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
for (i = 0; i < height; ++i)
row_pointers[i] = (png_bytep) (buffer + i * width);
png_set_swap_alpha(png_ptr);
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
// gprintf("saved %s\n", fn);
exit:
if (png_ptr)
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
free(row_pointers);
fclose(fp);
}
// copy efb to xfb when ready
static void copy_to_xfb(u32 count) {
if(do_copy==GX_TRUE) {
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
GX_SetColorUpdate(GX_TRUE);
GX_CopyDisp(xfb,GX_TRUE);
GX_Flush();
// Display the console at the top... by copying it into the xfb.
// This requires "defer EFB copies to RAM" to be unchecked in Dolphin.
// It does not work on the FIFO player at all.
for (int i = 0; i < 6; i++) {
// Loop is needed to make things show up properly on hardware
// Otherwise it just ends up getting cut off in a weird way.
// This might just be a timing thing and not something related to the framebuffer?
memcpy(xfb+2*rmode->fbWidth*16, console_buffer, 2*rmode->fbWidth*16);
}
// This one doesn't need to be in a loop (though it is influenced by the number
// of times the above loop runs)
memcpy(xfb+2*rmode->fbWidth*448, console_buffer, 2*rmode->fbWidth*16);
do_copy = GX_FALSE;
}
}
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES:
.SECONDARY:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC")
endif
include $(DEVKITPPC)/wii_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := .
DATA :=
TEXTURES := .
INCLUDES :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE)
CXXFLAGS = $(CFLAGS)
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -logc -lm -lfat -lpng -lz
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(foreach dir,$(TEXTURES),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
SCFFILES := $(foreach dir,$(TEXTURES),$(notdir $(wildcard $(dir)/*.scf)))
TPLFILES := $(SCFFILES:.scf=.tpl)
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
export LD := $(CC)
else
export LD := $(CXX)
endif
export OFILES_BIN := $(addsuffix .o,$(BINFILES)) $(addsuffix .o,$(TPLFILES))
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES))) $(addsuffix .h,$(subst .,_,$(TPLFILES)))
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD) \
-I$(LIBOGC_INC)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
-L$(LIBOGC_LIB)
export OUTPUT := $(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).dol: $(OUTPUT).elf
$(OUTPUT).elf: $(OFILES)
$(OFILES_SOURCES) : $(HFILES)
#---------------------------------------------------------------------------------
# This rule links in binary data with the .bin extension
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
%.tpl.o %_tpl.h : %.tpl
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
run:
wiiload $(TARGET).dol
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

This file has been truncated, but you can view the full file.
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment