Skip to content

Instantly share code, notes, and snippets.

@Pokechu22
Last active September 1, 2021 23:00
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/fabbd02f7ce17cb3779c3b8d5dfed213 to your computer and use it in GitHub Desktop.
Save Pokechu22/fabbd02f7ce17cb3779c3b8d5dfed213 to your computer and use it in GitHub Desktop.
build/
*.dol
*.elf
/*---------------------------------------------------------------------------------
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);
}
#---------------------------------------------------------------------------------
# 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
<filepath="Mud.bmp" id="mud" colfmt=14 />
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