summaryrefslogtreecommitdiff
path: root/3dlib/treeki3d.cpp
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2011-03-12 23:17:12 +0100
committerTreeki <treeki@gmail.com>2011-03-12 23:17:12 +0100
commit7d4e4c0b34a613dd3c0220475ae4e448197522c1 (patch)
tree4f5cee367de3fdef4f9a7c84af59ffe76a2bb1c3 /3dlib/treeki3d.cpp
downloadkamek-7d4e4c0b34a613dd3c0220475ae4e448197522c1.tar.gz
kamek-7d4e4c0b34a613dd3c0220475ae4e448197522c1.zip
initial commit. now I can start playing with stuff!
Diffstat (limited to '3dlib/treeki3d.cpp')
-rw-r--r--3dlib/treeki3d.cpp502
1 files changed, 502 insertions, 0 deletions
diff --git a/3dlib/treeki3d.cpp b/3dlib/treeki3d.cpp
new file mode 100644
index 0000000..3c72652
--- /dev/null
+++ b/3dlib/treeki3d.cpp
@@ -0,0 +1,502 @@
+/* Treeki's 3D Library for Wii */
+
+#include "3dlib/treeki3d.h"
+
+#include <game.h>
+#include "rvl/PPCWGPipe.h"
+#include "rvl/GXVert.h"
+
+namespace T3D {
+
+const GXColor Black = {0,0,0,255};
+const GXColor White = {255,255,255,255};
+
+u32 HasBeenInited;
+
+RenderInfo *RenderQueue;
+int RenderQueuePos;
+
+CameraInfo Camera;
+
+tmdl_material *LastMaterial;
+
+int tmdl_header_sizes[] = {0, 0, sizeof(tmdl_headerv2), sizeof(tmdl_header)};
+
+bool Init(bool test) {
+ if (HasBeenInited == 'T3Df')
+ return test;
+
+ HasBeenInited = 'T3Df';
+
+ OSReport("T3D Engine revision 3 -- created by Treeki\n");
+ OSReport("Setting up the render queue for %d model(s).\n", OBJ_COUNT);
+
+ RenderQueue = new RenderInfo[OBJ_COUNT];
+ RenderQueuePos = 0;
+
+ // Setup camera
+ Camera.projection = GX_PERSPECTIVE;
+
+ GXRenderModeObj *rm = Hook_GetGXRenderModeObj();
+ f32 aspect = (f32)rm->viWidth / (f32)rm->viHeight;
+
+ OSReport("Dump of GXRenderModeObj settings:\n");
+ OSReport("viTVmode => %d; fbWidth => %d; efbHeight => %d; xfbHeight => %d\n", rm->viTVmode, rm->fbWidth, rm->efbHeight, rm->xfbHeight);
+ OSReport("viXOrigin => %d; viYOrigin => %d; viWidth => %d; viHeight => %d\n", rm->viXOrigin, rm->viYOrigin, rm->viWidth, rm->viHeight);
+ OSReport("xFBmode => %d; field_rendering => %d; aa => %d\n", rm->xFBmode, rm->field_rendering, rm->aa);
+
+ OSReport("Calculated VI aspect: %f\n", aspect);
+
+ MTXPerspective(Camera.projection_matrix, 45, aspect, 0.1f, 2400.0f);
+
+ Point3d camPos = {0,0,-150};
+ Vec camUp = {0,1,0};
+ Point3d target = {0,0,0};
+ MTXLookAt(Camera.view_matrix, &camPos, &camUp, &target);
+
+ return test;
+}
+
+bool Model::bind(void *data, const char *mdlname) {
+ ARCHandle arc;
+ ARCFileInfo model_info;
+ tmdl_header *model = 0;
+
+ OSReport("[T3D] Loading model %s\n", mdlname);
+
+ // obtain the files from the arc
+ char model_name[64];
+ snprintf(model_name, 64, "t3d/mdl_%s.tmdl", mdlname);
+
+ if (!ARCInitHandle(data, &arc)) {
+ OSReport("[T3D] CANNOT LOAD ARC!!\n");
+ OSReport("ARCInitHandle returned false\n");
+ return false;
+ }
+
+ if (ARCOpen(&arc, model_name, &model_info)) {
+ model = (tmdl_header*)ARCGetStartAddrInMem(&model_info);
+ ARCClose(&model_info);
+ } else {
+ OSReport("[T3D] CANNOT GET MODEL!!\n");
+ OSReport("ARCOpen could not get %s\n", model_name);
+ return false;
+ }
+
+ // bind it
+ if (model->version != 3 && model->version != 2) {
+ OSReport("[T3D] INVALID VERSION!!\n");
+ OSReport("this revision of T3D expects a v2 or v3 model file, not %d\n", model->version);
+ return false;
+ }
+
+ OSReport("Loading model version %d\n", model->version);
+
+ // fix up every shape's GX arrays
+ for (int shape_id = 0; shape_id < model->shape_count; shape_id++) {
+ u32 shape_offset = *(u32*)((u32)model + tmdl_header_sizes[model->version] + (4*shape_id));
+ tmdl_shape *shape = (tmdl_shape*)((u32)model + shape_offset);
+
+ void *pos_arr = (void*)((u32)model + shape->pos_arr_offset);
+ void *nrm_arr = (void*)((u32)model + shape->nrm_arr_offset);
+ void *uv_arr = (void*)((u32)model + shape->uv_arr_offset);
+
+ DCStoreRangeNoSync(pos_arr, shape->pos_arr_size);
+ DCStoreRangeNoSync(nrm_arr, shape->nrm_arr_size);
+ DCStoreRangeNoSync(uv_arr, shape->uv_arr_size);
+ }
+
+ if (model->version == 2) {
+ ARCFileInfo texture_info;
+ char texture_name[64];
+ snprintf(texture_name, 64, "t3d/tex_%s.tpl", mdlname);
+
+ if (ARCOpen(&arc, texture_name, &texture_info)) {
+ this->texture_res = (TPLPalette*)ARCGetStartAddrInMem(&texture_info);
+ ARCClose(&texture_info);
+ }
+
+ if (this->texture_res) {
+ TPLBind(this->texture_res);
+ }
+ }
+
+ if (model->version >= 3) {
+ // now fix up every material
+ tmdl_material *mat = (tmdl_material*)((u32)model + sizeof(tmdl_header) + (4*model->shape_count));
+ for (int mat_id = 0; mat_id < model->material_count; mat_id++) {
+ ARCFileInfo texture_info;
+ TPLPalette *texture = 0;
+
+ if (ARCOpen(&arc, mat->texture_name, &texture_info)) {
+ texture = (TPLPalette*)ARCGetStartAddrInMem(&texture_info);
+ ARCClose(&texture_info);
+ }
+
+ if (texture) {
+ TPLBind(texture);
+ TPLGetGXTexObjFromPalette(texture, &mat->texobj, 0);
+ GXInitTexObjWrapMode(&mat->texobj, GX_REPEAT, GX_REPEAT);
+ } else {
+ OSReport("[T3D] WARNING!! Texture %s was not found while loading model %s!\n", mat->texture_name, mdlname);
+ }
+
+ mat++;
+ }
+ }
+
+ // done!
+ this->model_res = model;
+
+ return true;
+}
+
+void Model::addToDrawList(Mtx mtx) {
+ if (RenderQueuePos >= OBJ_COUNT) {
+ OSReport("FATAL ERROR!!\n");
+ OSReport("T3D object limit reached, render queue will overflow\n");
+ return;
+ }
+
+ RenderInfo *info = &RenderQueue[RenderQueuePos++];
+ MTXCopy(mtx, info->matrix);
+ info->model = this;
+}
+
+void Model::draw(RenderInfo *info) {
+ Mtx matrix, inv_matrix;
+ MTXCopy(Camera.view_matrix, matrix);
+ MTXConcat(info->matrix, matrix, matrix);
+
+ GXLoadPosMtxImm(matrix, GX_PNMTX0);
+
+ MTXInverse(matrix, inv_matrix);
+ GXLoadNrmMtxImm(inv_matrix, GX_PNMTX0);
+
+ for (int i = 0; i < this->model_res->shape_count; i++)
+ this->drawShape(info, i);
+}
+
+void Model::drawShape(RenderInfo *info, int shape_id) {
+ u32 shape_offset = *(u32*)((u32)this->model_res + tmdl_header_sizes[this->model_res->version] + (4*shape_id));
+ tmdl_shape *shape = (tmdl_shape*)((u32)this->model_res + shape_offset);
+
+ if (this->model_res->version == 2) {
+ tmdl_materialv2 *materialv2 = (tmdl_materialv2*)((u32)this->model_res + shape->mat_offset);
+ this->setupMaterialGXv2(materialv2);
+ } else {
+ tmdl_material *material = (tmdl_material*)((u32)this->model_res + shape->mat_offset);
+ this->setupMaterialGX(material);
+ }
+
+ void *pos_arr = (void*)((u32)this->model_res + shape->pos_arr_offset);
+ void *nrm_arr = (void*)((u32)this->model_res + shape->nrm_arr_offset);
+ void *uv_arr = (void*)((u32)this->model_res + shape->uv_arr_offset);
+
+ GXSetArray(GX_VA_POS, pos_arr, 12);
+ GXSetArray(GX_VA_NRM, nrm_arr, 12);
+ GXSetArray(GX_VA_TEX0, uv_arr, 8);
+
+ void *dl_ptr = (void*)((u32)this->model_res + shape->dl_offset);
+ GXCallDisplayList(dl_ptr, shape->dl_size);
+}
+
+void Model::setupMaterialGXv2(tmdl_materialv2 *material) {
+ LastMaterial = 0; // reset this
+
+ if (material->texture_id != 0xFFFFFFFF) {
+ GXSetChanMatColor(GX_COLOR0A0, White);
+ GXSetChanMatColor(GX_COLOR1A1, White);
+
+ GXTexObj tex;
+
+ TPLGetGXTexObjFromPalette(this->texture_res, &tex, material->texture_id);
+ GXInitTexObjWrapMode(&tex, GX_REPEAT, GX_REPEAT);
+ GXLoadTexObj(&tex, GX_TEXMAP0);
+
+ GXSetNumTexGens(1);
+ GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
+
+ GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
+
+ // TEV blending ops:
+ // First off, use the equivalent of GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE)
+ //GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE);
+ GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_RASC, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+
+ // Then do the same for stage1, but blend TEVPREV with RASC/RASA
+ GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_RASC, GX_CC_CPREV, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_RASA, GX_CA_APREV, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+
+ } else {
+ GXSetChanMatColor(GX_COLOR0A0, material->mat_colour);
+ GXSetChanMatColor(GX_COLOR1A1, White);
+
+ GXSetNumTexGens(0);
+
+ GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR1A1);
+
+ // TEV blending ops:
+ // First stage becomes GX_PASSCLR
+ GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
+
+ // Then blend this colour with RASA/RASC in the second stage
+ GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_RASC, GX_CC_CPREV, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_RASA, GX_CA_APREV, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ }
+}
+void Model::setupMaterialGX(tmdl_material *material) {
+ if (material == LastMaterial)
+ return;
+
+ LastMaterial = material; // small optimisation
+
+ if (material->texture_name[0] != 0) {
+ GXSetChanMatColor(GX_COLOR0A0, White);
+ GXSetChanMatColor(GX_COLOR1A1, White);
+
+ GXLoadTexObj(&material->texobj, GX_TEXMAP0);
+
+ GXSetNumTexGens(1);
+ GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
+
+ GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR1A1);
+
+ // TEV blending ops:
+ // First off, use the equivalent of GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE)
+ //GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE);
+ GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_RASC, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+
+ // Then do the same for stage1, but blend TEVPREV with RASC/RASA
+ GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_RASC, GX_CC_CPREV, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_RASA, GX_CA_APREV, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+
+ } else {
+ GXSetChanMatColor(GX_COLOR0A0, material->mat_colour);
+ GXSetChanMatColor(GX_COLOR1A1, White);
+
+ GXSetNumTexGens(0);
+
+ GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR1A1);
+
+ // TEV blending ops:
+ // First stage becomes GX_PASSCLR
+ GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
+
+ // Then blend this colour with RASA/RASC in the second stage
+ GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_RASC, GX_CC_CPREV, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_RASA, GX_CA_APREV, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ }
+}
+
+// todo: try out GXInit and see if it fixes the issues
+// if so, it's something in there
+void DrawQueue() {
+ LastMaterial = NULL;
+
+ GXInvalidateVtxCache();
+ GXInvalidateTexAll();
+ GXClearVtxDesc();
+
+ GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
+ GXSetVtxDesc(GX_VA_NRM, GX_INDEX16);
+ GXSetVtxDesc(GX_VA_TEX0, GX_INDEX16);
+
+ GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
+ GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
+ GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
+
+ GXSetCurrentMtx(GX_PNMTX0);
+
+ GXRenderModeObj *rm = Hook_GetGXRenderModeObj();
+ if (rm->field_rendering)
+ GXSetViewportJitter(0, 0, rm->fbWidth, rm->efbHeight, 0, 1, VIGetNextField());
+ else
+ GXSetViewport(0, 0, rm->fbWidth, rm->efbHeight, 0, 1);
+
+ GXSetProjection(Camera.projection_matrix, Camera.projection);
+
+ GXSetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR);
+ GXSetCullMode(GX_CULL_FRONT);
+ GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
+ GXSetZCompLoc(GX_TRUE);
+
+ GXSetNumTevStages(2);
+ GXSetTevDirect(GX_TEVSTAGE0);
+ GXSetTevDirect(GX_TEVSTAGE1);
+
+ GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
+
+ GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
+ GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0);
+
+ /*GXInitLightDir(&light, 0, -1, 0);
+ GXInitLightSpot(&light, 45, GX_SP_COS);
+ GXInitLightDistAttn(&light, 30, 0.7, GX_DA_GENTLE);*/
+ GXLightObj light, light2;
+
+ Point3d lightPos = {0,-500.0,0};
+ MTXMultVec(Camera.view_matrix, &lightPos, &lightPos);
+
+ GXInitLightColor(&light, White);
+ GXInitLightPos(&light, lightPos.x, lightPos.y, lightPos.z);
+ GXLoadLightObjImm(&light, GX_LIGHT0);
+
+ GXInitLightColor(&light2, White);
+ GXInitSpecularDir(&light2, 0.5, 0.5, 0);
+ GXInitLightShininess(&light2, 4.0f);
+ GXLoadLightObjImm(&light2, GX_LIGHT1);
+
+ GXSetNumChans(2);
+ GXSetChanAmbColor(GX_COLOR0A0, (GXColor){128,128,128,255});
+ GXSetChanAmbColor(GX_COLOR1A1, (GXColor){128,128,128,255});
+
+ GXSetChanCtrl(GX_COLOR0A0, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_CLAMP, GX_AF_NONE);
+ GXSetChanCtrl(GX_COLOR1A1, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT1, GX_DF_CLAMP, GX_AF_SPEC);
+
+ GXSetFog(GX_FOG_NONE, 0, 0, 0, 0, (GXColor){0,0,0,0});
+
+
+ for (int idx = 0; idx < RenderQueuePos; idx++) {
+ RenderQueue[idx].model->draw(&RenderQueue[idx]);
+ }
+
+ RenderQueuePos = 0;
+
+
+
+ // THIS IS JUST FOR TESTING
+ static bool isCreated = false;
+ static mTexture_c *tex[14];
+
+ if (!isCreated) {
+ isCreated = true;
+
+ for (int i = 0; i < 14; i++) {
+ tex[i] = new mTexture_c(128, 8, GX_TF_RGBA8);
+ tex[i]->allocateBuffer();
+
+ for (int y = 0; y < 8; y++) {
+ for (int x = 0; x < 128; x++) {
+ tex[i]->plotPixel(x, y, (GXColor){255,106,0,255});
+ }
+ }
+
+ //tex[i]->makeLinearGradient(i >> 1, 's', 0, 128, Black, White, ((i & 1) != 0));
+ tex[i]->makeLinearGradient(i >> 1, 's', 0, 128, (GXColor){255,106,0,255}, (GXColor){0,255,30,255}, false);
+ //tex[i]->plotPixel(0, 0, White);
+ //tex[i]->plotPixel(2, 2, White);
+ //tex[i]->plotPixel(4, 4, White);
+ tex[i]->flushDC();
+ }
+ }
+
+ Mtx matrix, inv_matrix;
+ MTXIdentity(matrix);
+ GXLoadPosMtxImm(matrix, GX_PNMTX0);
+
+ MTXInverse(matrix, inv_matrix);
+ GXLoadNrmMtxImm(inv_matrix, GX_PNMTX0);
+
+ GXSetChanMatColor(GX_COLOR0A0, White);
+ GXSetChanMatColor(GX_COLOR1A1, White);
+
+ GXSetNumTexGens(1);
+ GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
+
+ GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
+ GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
+ GXSetNumTevStages(1);
+
+ // TEV blending ops:
+ // First off, use the equivalent of GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE)
+ GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
+ /*GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_RASC, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+
+ // Then do the same for stage1, but blend TEVPREV with RASC/RASA
+ GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_RASC, GX_CC_CPREV, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_RASA, GX_CA_APREV, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);*/
+
+ GXCullMode(GX_CULL_NONE);
+ GXClearVtxDesc();
+ GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
+ GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
+ GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
+ GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
+
+ float y = -40.0f;
+ for (int i = 0; i < 14; i++) {
+ tex[i]->load(GX_TEXMAP0);
+ GXBegin(GX_QUADS, GX_VTXFMT0, 4);
+
+ GXPosition3f32(-40.0f, y, -120.0f);
+ GXTexCoord2f32(0.0f, 1.0f);
+ GXPosition3f32(40.0f, y, -120.0f);
+ GXTexCoord2f32(1.0f, 1.0f);
+ GXPosition3f32(40.0f, y+5.0f, -120.0f);
+ GXTexCoord2f32(1.0f, 0.0f);
+ GXPosition3f32(-40.0f, y+5.0f, -120.0f);
+ GXTexCoord2f32(0.0f, 0.0f);
+ GXEnd();
+
+ y += 5.0f;
+ }
+}
+
+
+
+namespace Util {
+
+/*void RotateToFace(const Vec &O, const Vec &P, const Vec &U, Mtx out) {
+ // http://forums.create.msdn.com/forums/p/10228/363692.aspx
+ Vec D, Right, Backwards, Up;
+
+ VECSubtract(&O, &P, &D);
+ VECCrossProduct(&U, &D, &Right);
+ VECNormalize(&Right, &Right);
+ VECCrossProduct(&Right, &U, &Backwards);
+ VECNormalize(&Backwards, &Backwards);
+ VECCrossProduct(&Backwards, &Right, &Up);
+
+ out[0][0] = Right.x;
+ out[0][1] = Right.y;
+ out[0][2] = Right.z;
+ out[0][3] = 0;
+ out[1][0] = Up.x;
+ out[1][1] = Up.y;
+ out[1][2] = Up.z;
+ out[1][3] = 0;
+ out[2][0] = Backwards.x;
+ out[2][1] = Backwards.y;
+ out[2][2] = Backwards.z;
+ out[2][3] = 0;
+}*/
+
+
+};
+
+};
+