Requires a modified gxtexconv, available at https://github.com/Pokechu22/gamecube-tools/tree/arbitrary-mipmaps.
Last active
September 1, 2021 23:00
-
-
Save Pokechu22/fabbd02f7ce17cb3779c3b8d5dfed213 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
build/ | |
*.dol | |
*.elf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*--------------------------------------------------------------------------------- | |
nehe lesson 10 GX port by ccfreak2k | |
https://github.com/devkitPro/wii-examples/tree/master/graphics/gx/neheGX/lesson10 | |
---------------------------------------------------------------------------------*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <malloc.h> | |
#include <math.h> | |
#include <gccore.h> | |
#include <wiiuse/wpad.h> | |
#include "manual_mipmap_tpl.h" | |
#include "manual_mipmap.h" | |
//#include "mud_tpl.h" | |
//#include "mud.h" | |
#include "world_txt.h" | |
#include <fat.h> | |
#include <time.h> | |
#include <sys/stat.h> | |
#include <sdcard/wiisd_io.h> | |
#include <png.h> | |
#include <zlib.h> | |
#define DEFAULT_FIFO_SIZE (256*1024) | |
/* DATA FILE FORMAT | |
Each triangle in our data file is declared as follows: | |
X1 Y1 Z1 U1 V1 | |
X2 Y2 Z2 U2 V2 | |
X3 Y3 Z3 U3 V3 */ | |
static void *frameBuffer[2] = { NULL, NULL}; | |
GXRModeObj *rmode; | |
static u32 *efb_buffer = NULL; | |
f32 xrot; // x rotation | |
f32 yrot; // y rotation | |
f32 xspeed; // x rotation speed | |
f32 yspeed; // y rotation speed | |
f32 walkbias = 0; | |
f32 walkbiasangle = 0; | |
f32 lookupdown = 0.0f; | |
float xpos, zpos; | |
f32 zdepth=0.0f; // depth into the screen | |
static GXColor LightColors[] = { | |
{ 0xFF, 0xFF, 0xFF, 0xFF }, // Light color 1 | |
{ 0x80, 0x80, 0x80, 0xFF }, // Ambient 1 | |
{ 0x80, 0x80, 0x80, 0xFF } // Material 1 | |
}; | |
// A vertex is the basic element of our room. | |
typedef struct tagVERTEX // vertex coords - 3d and texture | |
{ | |
float x, y, z; // 3d coords | |
float u, v; // tex coords | |
} VERTEX; | |
// Triangle is a set of three vertices. | |
typedef struct tagTRIANGLE // triangle | |
{ | |
VERTEX vertex[3]; // 3 vertices | |
} TRIANGLE; | |
// Sector represents a room, i.e. series of tris. | |
typedef struct tagSECTOR | |
{ | |
int numtriangles; // Number of tris in this sector | |
TRIANGLE* triangle; // Ptr to array of tris | |
} SECTOR; | |
SECTOR sector1; | |
char* screenshot_dir = NULL; | |
u8 aniso; | |
bool edge_lod; | |
bool bias_clamp; | |
f32 bias; | |
bool min_linear, mag_linear; | |
enum MipMode { | |
MIPMODE_NONE, | |
MIPMODE_POINT, | |
MIPMODE_LINEAR, | |
}; | |
enum MipMode mipmap_filter; | |
f32 tex_scale_multiplier; | |
void LoadDefaultConfig(void) { | |
aniso = GX_ANISO_1; | |
edge_lod = GX_ENABLE; | |
bias_clamp = GX_DISABLE; | |
bias = 1.5f; | |
min_linear = false; | |
mipmap_filter = MIPMODE_POINT; | |
mag_linear = false; | |
tex_scale_multiplier = 1.0f; | |
} | |
void ApplyConfigurationToTexture(GXTexObj *texture) { | |
u8 mag_filter = (mag_linear ? GX_LINEAR : GX_NEAR); | |
u8 min_filter = 0; | |
// Due to how GX_InitTexObjFilterMode works, we can't test invalid (3) for mipmap_filter | |
switch (mipmap_filter) { | |
case MIPMODE_NONE: | |
min_filter = (min_linear ? GX_LINEAR : GX_NEAR); | |
break; | |
case MIPMODE_POINT: | |
min_filter = (min_linear ? GX_LIN_MIP_NEAR : GX_NEAR_MIP_NEAR); | |
break; | |
case MIPMODE_LINEAR: | |
min_filter = (min_linear ? GX_LIN_MIP_LIN : GX_NEAR_MIP_LIN); | |
break; | |
} | |
GX_InitTexObjFilterMode(texture, min_filter, mag_filter); | |
GX_InitTexObjEdgeLOD(texture, edge_lod); | |
GX_InitTexObjBiasClamp(texture, bias_clamp); | |
GX_InitTexObjMaxAniso(texture, aniso); | |
GX_InitTexObjLODBias(texture, bias); | |
GX_InitTexObjMinLOD(texture, 3.0); | |
GX_InitTexObjMaxLOD(texture, 5.0); | |
} | |
void DrawScene(Mtx v, GXTexObj texture); | |
void SetLight(Mtx view,GXColor litcol, GXColor ambcol,GXColor matcol); | |
int SetupWorld(void); | |
void readstr(FILE *f, char *string); | |
void save_screenshot(void); | |
static void save_rgba_png(char* fn, u32 *buffer, u16 width, u16 height); | |
//--------------------------------------------------------------------------------- | |
int main( int argc, char **argv ){ | |
//--------------------------------------------------------------------------------- | |
fatMountSimple("sd", &__io_wiisd); | |
f32 yscale; | |
u32 xfbHeight; | |
// various matrices for things like view | |
Mtx view,mv,mr; | |
Mtx44 perspective; | |
// the texure we're going to paint | |
GXTexObj texture; | |
TPLFile mudTPL; | |
u32 fb = 0; // initial framebuffer index | |
GXColor background = {0, 0, 0, 0xff}; | |
// init the vi. | |
VIDEO_Init(); | |
WPAD_Init(); | |
rmode = VIDEO_GetPreferredMode(NULL); | |
// allocate 2 framebuffers for double buffering | |
frameBuffer[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); | |
frameBuffer[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); | |
efb_buffer = malloc(rmode->fbWidth*rmode->efbHeight*sizeof(u32)); | |
// configure video and wait for the screen to blank | |
VIDEO_Configure(rmode); | |
VIDEO_SetNextFramebuffer(frameBuffer[fb]); | |
VIDEO_SetBlack(FALSE); | |
VIDEO_Flush(); | |
VIDEO_WaitVSync(); | |
if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); | |
// setup the fifo... | |
void *gp_fifo = NULL; | |
gp_fifo = memalign(32,DEFAULT_FIFO_SIZE); | |
memset(gp_fifo,0,DEFAULT_FIFO_SIZE); | |
// ...then init the flipper | |
GX_Init(gp_fifo,DEFAULT_FIFO_SIZE); | |
// clears the bg to color and clears the z buffer | |
GX_SetCopyClear(background, 0x00ffffff); | |
// other gx setup | |
GX_SetViewport(0,0,rmode->fbWidth,rmode->efbHeight,0,1); | |
yscale = GX_GetYScaleFactor(rmode->efbHeight,rmode->xfbHeight); | |
xfbHeight = GX_SetDispCopyYScale(yscale); | |
GX_SetScissor(0,0,rmode->fbWidth,rmode->efbHeight); | |
GX_SetDispCopySrc(0,0,rmode->fbWidth,rmode->efbHeight); | |
GX_SetDispCopyDst(rmode->fbWidth,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(frameBuffer[fb],GX_TRUE); | |
GX_SetDispCopyGamma(GX_GM_1_0); | |
// setup the vertex attribute table | |
// describes the data | |
// args: vat location 0-7, type of data, data format, size, scale | |
// so for ex. in the first call we are sending position data with | |
// 3 values X,Y,Z of size F32. scale sets the number of fractional | |
// bits for non float data. | |
GX_InvVtxCache(); | |
GX_ClearVtxDesc(); | |
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); | |
GX_SetVtxDesc(GX_VA_NRM, GX_DIRECT); | |
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); | |
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); | |
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0); | |
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); | |
// setup texture coordinate generation | |
// args: texcoord slot 0-7, matrix type, source to generate texture coordinates from, matrix to use | |
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_TEX0, GX_IDENTITY); | |
f32 w = rmode->viWidth; | |
f32 h = rmode->viHeight; | |
guLightPerspective(mv,45, (f32)w/h, 1.05F, 1.0F, 0.0F, 0.0F); | |
guMtxTrans(mr, 0.0F, 0.0F, -1.0F); | |
guMtxConcat(mv, mr, mv); | |
GX_LoadTexMtxImm(mv, GX_TEXMTX0, GX_MTX3x4); | |
GX_InvalidateTexAll(); | |
TPL_OpenTPLFromMemory(&mudTPL, (void *)manual_mipmap_tpl,manual_mipmap_tpl_size); | |
TPL_GetTexture(&mudTPL,manual_mipmap,&texture); | |
LoadDefaultConfig(); | |
ApplyConfigurationToTexture(&texture); | |
// setup our camera at the origin | |
// looking down the -z axis with y up | |
guVector cam = {0.0F, 0.0F, 0.0F}, | |
up = {0.0F, 1.0F, 0.0F}, | |
look = {0.0F, 0.0F, -1.0F}; | |
guLookAt(view, &cam, &up, &look); | |
// setup our projection matrix | |
// this creates a perspective matrix with a view angle of 90, | |
// and aspect ratio based on the display resolution | |
guPerspective(perspective, 45, (f32)w/h, 0.1F, 300.0F); | |
GX_LoadProjectionMtx(perspective, GX_PERSPECTIVE); | |
// get the room ready to render | |
SetupWorld(); | |
while(1) { | |
WPAD_ScanPads(); | |
if(WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) exit(0); | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) { | |
aniso++; | |
aniso &= 3; // GX_ANISO_1, GX_ANISO_2, GX_ANISO_4, invalid | |
ApplyConfigurationToTexture(&texture); | |
} | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_B) { | |
edge_lod = !edge_lod; | |
ApplyConfigurationToTexture(&texture); | |
} | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_2) { | |
//bias_clamp = !bias_clamp; | |
if (tex_scale_multiplier == 1) tex_scale_multiplier = 2; | |
else if (tex_scale_multiplier == 2) tex_scale_multiplier = 4; | |
else if (tex_scale_multiplier == 4) tex_scale_multiplier = 0; | |
else tex_scale_multiplier = 1; | |
ApplyConfigurationToTexture(&texture); | |
} | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) { | |
bias += .5f; | |
if (bias > +4.0f) bias = -4.0f; | |
ApplyConfigurationToTexture(&texture); | |
} | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) { | |
bias -= .5f; | |
if (bias < -4.0f) bias = +4.0f; | |
ApplyConfigurationToTexture(&texture); | |
} | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_1) { | |
LoadDefaultConfig(); | |
ApplyConfigurationToTexture(&texture); | |
} | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_MINUS) { | |
xpos = 0; | |
yrot = 0; | |
zpos = 0; | |
walkbiasangle = 0; | |
walkbiasangle = 0; | |
} | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) yrot += 15; | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) yrot -= 15; | |
struct expansion_t data; | |
WPAD_Expansion(WPAD_CHAN_0, &data); // Get expansion info from the first wiimote | |
s8 tpad = 0; | |
if (data.type == WPAD_EXP_NUNCHUK) { // Ensure there's a nunchuk | |
tpad = data.nunchuk.js.pos.x - data.nunchuk.js.center.x; | |
if ((tpad < -8) || (tpad > 8)) yrot -= (float)tpad / 50.f; | |
tpad = data.nunchuk.js.pos.y - data.nunchuk.js.center.y; | |
// NOTE: walkbiasangle = head bob | |
// Go forward. | |
if(tpad > 50) { | |
xpos -= (float)sin(DegToRad(yrot)) * 0.05f; // Move on the x-plane based on player direction | |
zpos -= (float)cos(DegToRad(yrot)) * 0.05f; // Move on the z-plane based on player direction | |
if (walkbiasangle >= 359.0f) { | |
walkbiasangle = 0.0f; // Bring walkbiasangle back around | |
} else { | |
walkbiasangle += 10; // if walkbiasangle < 359 increase it by 10 | |
} | |
walkbias = (float)sin(DegToRad(walkbiasangle))/20.0f; | |
} | |
// Go backward | |
if(tpad < -50) { | |
xpos += (float)sin(DegToRad(yrot)) * 0.05f; | |
zpos += (float)cos(DegToRad(yrot)) * 0.05f; | |
if (walkbiasangle <= 1.0f) { | |
walkbiasangle = 359.0f; | |
} else { | |
walkbiasangle -= 10; | |
} | |
walkbias = (float)sin(DegToRad(walkbiasangle))/20.0f; | |
} | |
} | |
// do this before drawing | |
GX_SetViewport(0,0,rmode->fbWidth,rmode->efbHeight,0,1); | |
//set number of textures to generate | |
GX_SetNumTexGens(1); | |
// Draw things | |
DrawScene(view,texture); | |
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); | |
GX_SetColorUpdate(GX_TRUE); | |
// do this stuff after drawing | |
GX_DrawDone(); | |
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_PLUS) { | |
save_screenshot(); | |
} | |
GX_CopyDisp(frameBuffer[fb],GX_TRUE); | |
fb ^= 1; // flip framebuffer | |
VIDEO_SetNextFramebuffer(frameBuffer[fb]); | |
VIDEO_Flush(); | |
VIDEO_WaitVSync(); | |
} | |
return 0; | |
} | |
// Perform the actual scene drawing. | |
void DrawScene(Mtx v, GXTexObj texture) { | |
// Draw things | |
// FIXME: Need to clear first? | |
// FIXME: Check datatype sizes | |
f32 x_m,y_m,z_m,u_m,v_m; // Float types for temp x, y, z, u and v vertices | |
f32 xtrans = -xpos; // Used for player translation on the x axis | |
f32 ztrans = -zpos; // Used for player translation on the z axis | |
f32 ytrans = -walkbias-0.25f; // Used for bouncing motion up and down | |
f32 sceneroty = 360.0f - yrot; // 360 degree angle for player direction | |
int numtriangles; // Integer to hold the number of triangles | |
Mtx m; // Model matrix | |
Mtx mt; // Model rotated matrix | |
Mtx mv; // Modelview matrix | |
guVector axis; // Vector for axis we're rotating on | |
SetLight(v,LightColors[0],LightColors[1],LightColors[2]); | |
// Set up TEV to paint the textures properly. | |
GX_SetTevOp(GX_TEVSTAGE0,GX_MODULATE); | |
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); | |
// Load up the textures (just one this time). | |
GX_LoadTexObj(&texture, GX_TEXMAP0); | |
//glRotatef(lookupdown,1.0f,0,0); | |
axis.x = 1.0f; | |
axis.y = 0; | |
axis.z = 0; | |
guMtxIdentity(m); | |
guMtxRotAxisDeg(m, &axis, lookupdown); | |
guMtxConcat(m,v,mv); | |
//glrotatef(sceneroty,0,1.0f,0); | |
axis.x = 0; | |
axis.y = 1.0f; | |
axis.z = 0; | |
guMtxIdentity(m); | |
guMtxRotAxisDeg(m, &axis, sceneroty); | |
guMtxConcat(mv,m,mv); | |
// Translate the camera view | |
guMtxApplyTrans(mv,mt,xtrans,ytrans,ztrans); | |
//glTranslatef(xtrans,ytrans,ztrans); | |
//guMtxIdentity(m); | |
//guMtxTrans(m, xtrans, ytrans, ztrans); | |
//guMtxConcat(v,m,v); | |
// load the modelview matrix into matrix memory | |
GX_LoadPosMtxImm(mt, GX_PNMTX0); | |
numtriangles = sector1.numtriangles; | |
// HACK: v tex coord is inverted so textures are rightside up. | |
for (int loop_m = 0; loop_m < numtriangles; loop_m++) { | |
GX_Begin(GX_TRIANGLES,GX_VTXFMT0,3); | |
x_m = sector1.triangle[loop_m].vertex[0].x; | |
y_m = sector1.triangle[loop_m].vertex[0].y; | |
z_m = sector1.triangle[loop_m].vertex[0].z; | |
u_m = sector1.triangle[loop_m].vertex[0].u * tex_scale_multiplier; | |
v_m = sector1.triangle[loop_m].vertex[0].v * tex_scale_multiplier; | |
GX_Position3f32(x_m,y_m,z_m); | |
GX_Normal3f32((f32)0,(f32)0,(f32)1); | |
//GX_Color3f32(0.7f,0.7f,0.7f); | |
GX_TexCoord2f32(u_m,-v_m); | |
x_m = sector1.triangle[loop_m].vertex[1].x; | |
y_m = sector1.triangle[loop_m].vertex[1].y; | |
z_m = sector1.triangle[loop_m].vertex[1].z; | |
u_m = sector1.triangle[loop_m].vertex[1].u * tex_scale_multiplier; | |
v_m = sector1.triangle[loop_m].vertex[1].v * tex_scale_multiplier; | |
GX_Position3f32(x_m,y_m,z_m); | |
GX_Normal3f32((f32)0,(f32)0,(f32)1); | |
//GX_Color3f32(0.7f,0.7f,0.7f); | |
GX_TexCoord2f32(u_m,-v_m); | |
x_m = sector1.triangle[loop_m].vertex[2].x; | |
y_m = sector1.triangle[loop_m].vertex[2].y; | |
z_m = sector1.triangle[loop_m].vertex[2].z; | |
u_m = sector1.triangle[loop_m].vertex[2].u * tex_scale_multiplier; | |
v_m = sector1.triangle[loop_m].vertex[2].v * tex_scale_multiplier; | |
GX_Position3f32(x_m,y_m,z_m); | |
GX_Normal3f32((f32)0,(f32)0,(f32)1); | |
//GX_Color3f32(0.7f,0.7f,0.7f); | |
GX_TexCoord2f32(u_m,-v_m); | |
GX_End(); | |
} | |
return; | |
} | |
// This one originally written by shagkur | |
void SetLight(Mtx view,GXColor litcol, GXColor ambcol,GXColor matcol) | |
{ | |
guVector lpos; | |
GXLightObj lobj; | |
lpos.x = 0; | |
lpos.y = 0; | |
lpos.z = 2.0f; | |
guVecMultiply(view,&lpos,&lpos); | |
GX_InitLightPos(&lobj,lpos.x,lpos.y,lpos.z); | |
GX_InitLightColor(&lobj,litcol); | |
GX_LoadLightObj(&lobj,GX_LIGHT0); | |
// set number of rasterized color channels | |
GX_SetNumChans(1); | |
GX_SetChanCtrl(GX_COLOR0A0,GX_ENABLE,GX_SRC_REG,GX_SRC_REG,GX_LIGHT0,GX_DF_CLAMP,GX_AF_NONE); | |
GX_SetChanAmbColor(GX_COLOR0A0,ambcol); | |
GX_SetChanMatColor(GX_COLOR0A0,matcol); | |
} | |
// Read in and parse world info. | |
int SetupWorld(void) { | |
FILE *filein; | |
int numtriangles; // Number of triangles in sector | |
char line[255]; // String to store data in | |
float x = 0; // 3D coords | |
float y = 0; | |
float z = 0; | |
float u = 0; // tex coords | |
float v = 0; | |
// open file in memory | |
filein = fmemopen((void *)world_txt, world_txt_size, "rb"); | |
// read in data | |
readstr(filein, line); // Get single line of data | |
sscanf(line, "NUMPOLYS %d\n", &numtriangles); // Read in number of triangles | |
// allocate new triangle objects | |
sector1.triangle = (TRIANGLE*)malloc(sizeof(TRIANGLE)*numtriangles); | |
sector1.numtriangles = numtriangles; | |
// Step through each tri in sector | |
for (int triloop = 0; triloop < numtriangles; triloop++) { | |
// Step through each vertex in tri | |
for (int vertloop = 0; vertloop < 3; vertloop++) { | |
readstr(filein,line); // Read string | |
if (line[0] == '\r' || line[0] == '\n') { // Ignore blank lines. | |
vertloop--; | |
continue; | |
} | |
if (line[0] == '/') { // Ignore lines with comments. | |
vertloop--; | |
continue; | |
} | |
sscanf(line, "%f %f %f %f %f", &x, &y, &z, &u, &v); // Read in data from string | |
// Store values into respective vertices | |
sector1.triangle[triloop].vertex[vertloop].x = x; | |
sector1.triangle[triloop].vertex[vertloop].y = y; | |
sector1.triangle[triloop].vertex[vertloop].z = z; | |
sector1.triangle[triloop].vertex[vertloop].u = u; | |
sector1.triangle[triloop].vertex[vertloop].v = v; | |
} | |
} | |
fclose(filein); | |
return 0; | |
} | |
// Read in each line. | |
void readstr(FILE *f, char *string) { | |
do { | |
fgets(string, 255, f); | |
} while ((string[0] == '/') || (string[0] == '\n')); | |
return; | |
} | |
void save_screenshot(void) { | |
// 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)); | |
if (screenshot_dir == NULL) { | |
time_t rawtime; | |
time(&rawtime); | |
struct tm* curtime = localtime(&rawtime); | |
screenshot_dir = malloc(100); | |
strftime(screenshot_dir, 100, "sd:/Test_%H%M%S", curtime); | |
mkdir(screenshot_dir, 0777); | |
} | |
char filename[256]; | |
snprintf(filename, sizeof(filename), "%s/%c%c%c_A%d_%c_%c_%.1f_%d_%.1f.png", | |
screenshot_dir, min_linear ? 'L' : 'N', | |
mipmap_filter == MIPMODE_LINEAR ? 'L' : (mipmap_filter == MIPMODE_POINT ? 'P' : 'X'), | |
mag_linear ? 'L' : 'N', 1 << aniso, edge_lod ? 'E' : 'D', bias_clamp ? 'C' : 'N', bias, (int)yrot, tex_scale_multiplier); | |
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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#--------------------------------------------------------------------------------- | |
# 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 := -lwiiuse -lbte -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 := world.txt | |
SCFFILES := $(foreach dir,$(TEXTURES),$(notdir $(wildcard $(dir)/*.scf))) | |
TPLFILES := $(SCFFILES:.scf=.tpl) manual_mipmap.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 | |
#--------------------------------------------------------------------------------- | |
run: | |
wiiload $(OUTPUT).dol | |
#--------------------------------------------------------------------------------- | |
else | |
#--------------------------------------------------------------------------------- | |
# main targets | |
#--------------------------------------------------------------------------------- | |
$(OUTPUT).dol: $(OUTPUT).elf | |
$(OUTPUT).elf: $(OFILES) | |
$(OFILES_SOURCES) : $(HFILES) | |
#--------------------------------------------------------------------------------- | |
%.txt.o %_txt.h : %.txt | |
#--------------------------------------------------------------------------------- | |
@echo $(notdir $<) | |
@$(bin2o) | |
#--------------------------------------------------------------------------------- | |
%.tpl.o %_tpl.h : %.tpl | |
#--------------------------------------------------------------------------------- | |
@echo $(notdir $<) | |
@$(bin2o) | |
-include $(DEPSDIR)/*.d | |
#--------------------------------------------------------------------------------- | |
endif | |
#--------------------------------------------------------------------------------- | |
#--------------------------------------------------------------------------------- | |
# Custom-generated mipmap file | |
#--------------------------------------------------------------------------------- | |
manual_mipmap.tpl: ../../gamecube-tools/build/gxtexconv Makefile Pattern_Mip0.png Pattern_Mip1.png Pattern_Mip2.png Pattern_Mip3.png Pattern_Mip4.png Pattern_Mip5.png Pattern_Mip6.png Pattern_Mip7.png Pattern_Mip8.png Pattern_Mip9.png Pattern_Mip10.png | |
../../gamecube-tools/build/gxtexconv -i ../Pattern_Mip%d.png -o manual_mipmap.tpl colfmt=6 mipmap=arbitrary minlod=0 maxlod=10 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<filepath="Mud.bmp" id="mud" colfmt=14 /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NUMPOLYS 36 | |
// Floor 1 | |
-3.0 0.0 -3.0 0.0 6.0 | |
-3.0 0.0 3.0 0.0 0.0 | |
3.0 0.0 3.0 6.0 0.0 | |
-3.0 0.0 -3.0 0.0 6.0 | |
3.0 0.0 -3.0 6.0 6.0 | |
3.0 0.0 3.0 6.0 0.0 | |
// Ceiling 1 | |
-3.0 1.0 -3.0 0.0 6.0 | |
-3.0 1.0 3.0 0.0 0.0 | |
3.0 1.0 3.0 6.0 0.0 | |
-3.0 1.0 -3.0 0.0 6.0 | |
3.0 1.0 -3.0 6.0 6.0 | |
3.0 1.0 3.0 6.0 0.0 | |
// A1 | |
-2.0 1.0 -2.0 0.0 1.0 | |
-2.0 0.0 -2.0 0.0 0.0 | |
-0.5 0.0 -2.0 1.5 0.0 | |
-2.0 1.0 -2.0 0.0 1.0 | |
-0.5 1.0 -2.0 1.5 1.0 | |
-0.5 0.0 -2.0 1.5 0.0 | |
// A2 | |
2.0 1.0 -2.0 2.0 1.0 | |
2.0 0.0 -2.0 2.0 0.0 | |
0.5 0.0 -2.0 0.5 0.0 | |
2.0 1.0 -2.0 2.0 1.0 | |
0.5 1.0 -2.0 0.5 1.0 | |
0.5 0.0 -2.0 0.5 0.0 | |
// B1 | |
-2.0 1.0 2.0 2.0 1.0 | |
-2.0 0.0 2.0 2.0 0.0 | |
-0.5 0.0 2.0 0.5 0.0 | |
-2.0 1.0 2.0 2.0 1.0 | |
-0.5 1.0 2.0 0.5 1.0 | |
-0.5 0.0 2.0 0.5 0.0 | |
// B2 | |
2.0 1.0 2.0 2.0 1.0 | |
2.0 0.0 2.0 2.0 0.0 | |
0.5 0.0 2.0 0.5 0.0 | |
2.0 1.0 2.0 2.0 1.0 | |
0.5 1.0 2.0 0.5 1.0 | |
0.5 0.0 2.0 0.5 0.0 | |
// C1 | |
-2.0 1.0 -2.0 0.0 1.0 | |
-2.0 0.0 -2.0 0.0 0.0 | |
-2.0 0.0 -0.5 1.5 0.0 | |
-2.0 1.0 -2.0 0.0 1.0 | |
-2.0 1.0 -0.5 1.5 1.0 | |
-2.0 0.0 -0.5 1.5 0.0 | |
// C2 | |
-2.0 1.0 2.0 2.0 1.0 | |
-2.0 0.0 2.0 2.0 0.0 | |
-2.0 0.0 0.5 0.5 0.0 | |
-2.0 1.0 2.0 2.0 1.0 | |
-2.0 1.0 0.5 0.5 1.0 | |
-2.0 0.0 0.5 0.5 0.0 | |
// D1 | |
2.0 1.0 -2.0 0.0 1.0 | |
2.0 0.0 -2.0 0.0 0.0 | |
2.0 0.0 -0.5 1.5 0.0 | |
2.0 1.0 -2.0 0.0 1.0 | |
2.0 1.0 -0.5 1.5 1.0 | |
2.0 0.0 -0.5 1.5 0.0 | |
// D2 | |
2.0 1.0 2.0 2.0 1.0 | |
2.0 0.0 2.0 2.0 0.0 | |
2.0 0.0 0.5 0.5 0.0 | |
2.0 1.0 2.0 2.0 1.0 | |
2.0 1.0 0.5 0.5 1.0 | |
2.0 0.0 0.5 0.5 0.0 | |
// Upper hallway - L | |
-0.5 1.0 -3.0 0.0 1.0 | |
-0.5 0.0 -3.0 0.0 0.0 | |
-0.5 0.0 -2.0 1.0 0.0 | |
-0.5 1.0 -3.0 0.0 1.0 | |
-0.5 1.0 -2.0 1.0 1.0 | |
-0.5 0.0 -2.0 1.0 0.0 | |
// Upper hallway - R | |
0.5 1.0 -3.0 0.0 1.0 | |
0.5 0.0 -3.0 0.0 0.0 | |
0.5 0.0 -2.0 1.0 0.0 | |
0.5 1.0 -3.0 0.0 1.0 | |
0.5 1.0 -2.0 1.0 1.0 | |
0.5 0.0 -2.0 1.0 0.0 | |
// Lower hallway - L | |
-0.5 1.0 3.0 0.0 1.0 | |
-0.5 0.0 3.0 0.0 0.0 | |
-0.5 0.0 2.0 1.0 0.0 | |
-0.5 1.0 3.0 0.0 1.0 | |
-0.5 1.0 2.0 1.0 1.0 | |
-0.5 0.0 2.0 1.0 0.0 | |
// Lower hallway - R | |
0.5 1.0 3.0 0.0 1.0 | |
0.5 0.0 3.0 0.0 0.0 | |
0.5 0.0 2.0 1.0 0.0 | |
0.5 1.0 3.0 0.0 1.0 | |
0.5 1.0 2.0 1.0 1.0 | |
0.5 0.0 2.0 1.0 0.0 | |
// Left hallway - Lw | |
-3.0 1.0 0.5 1.0 1.0 | |
-3.0 0.0 0.5 1.0 0.0 | |
-2.0 0.0 0.5 0.0 0.0 | |
-3.0 1.0 0.5 1.0 1.0 | |
-2.0 1.0 0.5 0.0 1.0 | |
-2.0 0.0 0.5 0.0 0.0 | |
// Left hallway - Hi | |
-3.0 1.0 -0.5 1.0 1.0 | |
-3.0 0.0 -0.5 1.0 0.0 | |
-2.0 0.0 -0.5 0.0 0.0 | |
-3.0 1.0 -0.5 1.0 1.0 | |
-2.0 1.0 -0.5 0.0 1.0 | |
-2.0 0.0 -0.5 0.0 0.0 | |
// Right hallway - Lw | |
3.0 1.0 0.5 1.0 1.0 | |
3.0 0.0 0.5 1.0 0.0 | |
2.0 0.0 0.5 0.0 0.0 | |
3.0 1.0 0.5 1.0 1.0 | |
2.0 1.0 0.5 0.0 1.0 | |
2.0 0.0 0.5 0.0 0.0 | |
// Right hallway - Hi | |
3.0 1.0 -0.5 1.0 1.0 | |
3.0 0.0 -0.5 1.0 0.0 | |
2.0 0.0 -0.5 0.0 0.0 | |
3.0 1.0 -0.5 1.0 1.0 | |
2.0 1.0 -0.5 0.0 1.0 | |
2.0 0.0 -0.5 0.0 0.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment