#include #include #include using rw::uint8; using rw::uint16; using rw::uint32; using rw::uint64; using rw::int8; using rw::int16; using rw::int32; using rw::int64; using rw::bool32; using rw::float32; typedef uint8 uchar; typedef uint16 ushort; typedef uint32 uint; #define WIDTH 640 #define HEIGHT 448 #include "ps2.h" // getting undefined references otherwise :/ int *__errno() { return &errno; } // NONINTERLACED and FRAME have half of the FIELD vertical resolution! // NONINTERLACED has half the vertical units uint128 packetbuf[128]; uint128 vuXYZScale; uint128 vuXYZOffset; extern uint32 geometryCall[]; extern uint32 skinPipe[]; uint128 *curVifPtr; uint128 lightpacket[128]; int32 numLightQ; rw::World *world; rw::Camera *camera; int frames; void printquad(uint128 p) { uint64 *lp; lp = (uint64*)&p; printf("%016lx %016lx\n", lp[1], lp[0]); } void printquad4(uint128 p) { uint32 *lp; lp = (uint32*)&p; printf("%08x %08x %08x %08x\n", lp[0], lp[1], lp[2], lp[3]); } void dump4(uint128 *p, int n) { printf("data at %p\n", p); while(n--) printquad4(*p++); } struct DmaChannel { uint32 chcr; uint32 pad0[3]; uint32 madr; uint32 pad1[3]; uint32 qwc; uint32 pad2[3]; uint32 tadr; uint32 pad3[3]; uint32 asr0; uint32 pad4[3]; uint32 asr1; uint32 pad5[3]; uint32 pad6[8]; uint32 sadr; }; static struct DmaChannel *dmaChannels[] = { (struct DmaChannel *) &D0_CHCR, (struct DmaChannel *) &D1_CHCR, (struct DmaChannel *) &D2_CHCR, (struct DmaChannel *) &D3_CHCR, (struct DmaChannel *) &D4_CHCR, (struct DmaChannel *) &D5_CHCR, (struct DmaChannel *) &D6_CHCR, (struct DmaChannel *) &D7_CHCR, (struct DmaChannel *) &D8_CHCR, (struct DmaChannel *) &D9_CHCR }; void dmaReset(void) { /* don't clear the SIF channels */ int doclear[] = { 1, 1, 1, 1, 1, 0, 0, 0, 1, 1 }; int i; D_CTRL = 0; for(i = 0; i < 10; i++) if(doclear[i]){ dmaChannels[i]->chcr = 0; dmaChannels[i]->madr = 0; dmaChannels[i]->qwc = 0; dmaChannels[i]->tadr = 0; dmaChannels[i]->asr0 = 0; dmaChannels[i]->asr1 = 0; dmaChannels[i]->sadr = 0; } D_CTRL = 1; } void waitDMA(volatile uint32 *chcr) { while(*chcr & (1<<8)); } void qwcpy(uint128 *dst, uint128 *src, int n) { while(n--) *dst++ = *src++; } void toGIF(void *src, int n) { FlushCache(0); D2_QWC = n; D2_MADR = (uint32)src; D2_CHCR = 1<<8; waitDMA(&D2_CHCR); } void toGIFchain(void *src) { FlushCache(0); D2_QWC = 0; D2_TADR = (uint32)src & 0x0FFFFFFF; D2_CHCR = 1<<0 | 1<<2 | 1<<6 | 1<<8; waitDMA(&D2_CHCR); } void toVIF1chain(void *src) { FlushCache(0); D1_QWC = 0; D1_TADR = (uint32)src & 0x0FFFFFFF; D1_CHCR = 1<<0 | 1<<2 | 1<<6 | 1<<8; waitDMA(&D1_CHCR); } GsCrtState gsCrtState; int psmsizemap[64] = { 4, // GS_PSMCT32 4, // GS_PSMCT24 2, // GS_PSMCT16 0, 0, 0, 0, 0, 0, 0, 2, // GS_PSMCT16S 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, // GS_PSMZ32 4, // GS_PSMZ24 2, // GS_PSMZ16 2, // GS_PSMZ16S 0, 0, 0, 0, 0 }; void GsResetCrt(uchar inter, uchar mode, uchar ff) { gsCrtState.inter = inter; gsCrtState.mode = mode; gsCrtState.ff = ff; GS_CSR = 1 << GS_CSR_RESET_O; __asm__("sync.p; nop"); GsPutIMR(0xff00); SetGsCrt(gsCrtState.inter, gsCrtState.mode, gsCrtState.ff); } uint gsAllocPtr = 0; void GsInitDispCtx(GsDispCtx *disp, int width, int height, int psm) { int magh, magv; int dx, dy; int dw, dh; dx = gsCrtState.mode == GS_NTSC ? 636 : 656; dy = gsCrtState.mode == GS_NTSC ? 25 : 36; magh = 2560/width - 1; magv = 0; dw = 2560-1; dh = height-1; if(gsCrtState.inter == GS_INTERLACED){ dy *= 2; if(gsCrtState.ff == GS_FRAME) dh = (dh+1)*2-1; } disp->pmode.d = GS_MAKE_PMODE(0, 1, 1, 1, 0, 0x00); disp->bgcolor.d = 0x404040; disp->dispfb1.d = 0; disp->dispfb2.d = GS_MAKE_DISPFB(0, width/64, psm, 0, 0); disp->display1.d = 0; disp->display2.d = GS_MAKE_DISPLAY(dx, dy, magh, magv, dw, dh); } void GsPutDispCtx(GsDispCtx *disp) { GS_PMODE = disp->pmode.d; GS_DISPFB1 = disp->dispfb1.d; GS_DISPLAY1 = disp->display1.d; GS_DISPFB2 = disp->dispfb2.d; GS_DISPLAY2 = disp->display2.d; GS_BGCOLOR = disp->bgcolor.d; } void GsInitDrawCtx(GsDrawCtx *draw, int width, int height, int psm, int zpsm) { MAKE128(draw->gifTag, 0xe, GIF_MAKE_TAG(8, 1, 0, 0, GIF_PACKED, 1)); draw->frame1.d = GS_MAKE_FRAME(0, width/64, psm, 0); draw->ad_frame1 = GS_FRAME_1; draw->frame2.d = draw->frame1.d; draw->ad_frame2 = GS_FRAME_2; draw->zbuf1.d = GS_MAKE_ZBUF(0, zpsm, 0); draw->ad_zbuf1 = GS_ZBUF_1; draw->zbuf2.d = draw->zbuf1.d; draw->ad_zbuf2 = GS_ZBUF_2; draw->xyoffset1.d = GS_MAKE_XYOFFSET(2048<<4, 2048<<4); draw->ad_xyoffset1 = GS_XYOFFSET_1; draw->xyoffset2.d = draw->xyoffset1.d; draw->ad_xyoffset2 = GS_XYOFFSET_2; draw->scissor1.d = GS_MAKE_SCISSOR(0, width-1, 0, height-1); draw->ad_scissor1 = GS_SCISSOR_1; draw->scissor2.d = draw->scissor1.d; draw->ad_scissor2 = GS_SCISSOR_2; } void GsPutDrawCtx(GsDrawCtx *draw) { printquad(*(uint128*)&draw->frame1); toGIF(draw, 9); } void GsInitCtx(GsCtx *ctx, int width, int height, int psm, int zpsm) { uint fbsz, zbsz; uint fbp, zbp; fbsz = (width*height*psmsizemap[psm] + 2047)/2048; zbsz = (width*height*psmsizemap[0x30|zpsm] + 2047)/2048; gsAllocPtr = 2*fbsz + zbsz; fbp = fbsz; zbp = fbsz*2; GsInitDispCtx(&ctx->disp[0], width, height, psm); GsInitDispCtx(&ctx->disp[1], width, height, psm); GsInitDrawCtx(&ctx->draw[0], width, height, psm, zpsm); GsInitDrawCtx(&ctx->draw[1], width, height, psm, zpsm); ctx->disp[1].dispfb2.f.FBP = fbp/4; ctx->draw[0].frame1.f.FBP = fbp/4; ctx->draw[0].frame2.f.FBP = fbp/4; ctx->draw[0].zbuf1.f.ZBP = zbp/4; ctx->draw[0].zbuf2.f.ZBP = zbp/4; ctx->draw[1].zbuf1.f.ZBP = zbp/4; ctx->draw[1].zbuf2.f.ZBP = zbp/4; } void initrender(void) { uint128 *p, tmp; p = packetbuf; MAKE128(tmp, 0xe, GIF_MAKE_TAG(2, 1, 0, 0, GIF_PACKED, 1)); *p++ = tmp; MAKE128(tmp, GS_PRMODECONT, 1); *p++ = tmp; MAKE128(tmp, GS_COLCLAMP, 1); *p++ = tmp; toGIF(packetbuf, 3); } void clearscreen(int r, int g, int b) { int x, y; uint128 *p, tmp; p = packetbuf; x = (2048 + 640)<<4; y = (2048 + 448)<<4; MAKE128(tmp, 0xe, GIF_MAKE_TAG(5, 1, 0, 0, GIF_PACKED, 1)); *p++ = tmp; MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 1)); *p++ = tmp; MAKE128(tmp, GS_PRIM, GS_MAKE_PRIM(GS_PRIM_SPRITE,0,0,0,0,0,0,0,0)); *p++ = tmp; MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(r, g, b, 0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(2048<<4, 2048<<4, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x, y, 0)); *p++ = tmp; toGIF(packetbuf, 6); } void drawtest(void) { int x0, x1, x2, x3; int y0, y1, y2; uint128 *p, tmp; int n; x0 = 2048<<4; x1 = (2048 + 210)<<4; x2 = (2048 + 430)<<4; x3 = (2048 + 640)<<4; y0 = 2048<<4; y1 = (2048 + 224)<<4; y2 = (2048 + 448)<<4; n = 2 + 3*7; p = packetbuf; MAKEQ(tmp, 0x70000000 | n+1, 0, 0, 0); *p++ = tmp; MAKE128(tmp, 0xe, GIF_MAKE_TAG(n, 1, 0, 0, GIF_PACKED, 1)); *p++ = tmp; MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 1)); *p++ = tmp; MAKE128(tmp, GS_PRIM, GS_MAKE_PRIM(GS_PRIM_SPRITE,0,0,0,0,0,0,0,0)); *p++ = tmp; MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 0, 0, 0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x0, y0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y1, 0)); *p++ = tmp; MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 255, 0, 0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y1, 0)); *p++ = tmp; MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 0, 255, 0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, y1, 0)); *p++ = tmp; MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 255, 255, 0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x0, y1, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y2, 0)); *p++ = tmp; MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 0, 255, 0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y1, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y2, 0)); *p++ = tmp; MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 255, 0, 0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y1, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, y2, 0)); *p++ = tmp; MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 255, 255, 0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ((2048+20)<<4, y0, 0)); *p++ = tmp; MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, (2048+20)<<4, 0)); *p++ = tmp; toGIFchain(packetbuf); } void drawtri(void) { uint128 *p, tmp; uint32 *ip; int nverts, n; nverts = 3; n = 2*nverts; p = packetbuf; MAKEQ(tmp, 0x70000000 | n+1, 0, 0, 0); *p++ = tmp; MAKE128(tmp, (0x5<<4) | 0x1, GIF_MAKE_TAG(nverts, 1, 1, GS_MAKE_PRIM(GS_PRIM_TRI, 1, 0, 0, 0, 0, 0, 0, 0), GIF_PACKED, 2)); *p++ = tmp; MAKEQ(tmp, 255, 0, 0, 0); *p++ = tmp; MAKEQ(tmp, (2048+85)<<4, (2048+70)<<4, 0, 0); *p++ = tmp; MAKEQ(tmp, 0, 255, 0, 0); *p++ = tmp; MAKEQ(tmp, (2048+260)<<4, (2048+200)<<4, 0, 0); *p++ = tmp; MAKEQ(tmp, 0, 0, 255, 0); *p++ = tmp; MAKEQ(tmp, (2048+180)<<4, (2048+350)<<4, 0, 0); *p++ = tmp; toGIFchain(packetbuf); } void printMatrix(rw::Matrix *m) { rw::V3d *x = &m->right; rw::V3d *y = &m->up; rw::V3d *z = &m->at; rw::V3d *w = &m->pos; printf( "[ [ %8.4f, %8.4f, %8.4f, %8.4f ]\n" " [ %8.4f, %8.4f, %8.4f, %8.4f ]\n" " [ %8.4f, %8.4f, %8.4f, %8.4f ]\n" " [ %8.4f, %8.4f, %8.4f, %8.4f ] ]\n" " %08x == flags\n", x->x, y->x, z->x, w->x, x->y, y->y, z->y, w->y, x->z, y->z, z->z, w->z, 0.0f, 0.0f, 0.0f, 1.0f, m->flags); } // This is not proper data, just for testing void setupLight(rw::Atomic *atomic) { using namespace rw; Matrix *lightmat; float32 *lp; numLightQ = 0; lp = (float32*)lightpacket; // TODO: this is the wrong matrix. we actually want to // transform the light, not all normals. lightmat = atomic->getFrame()->getLTM(); *lp++ = lightmat->right.x; *lp++ = lightmat->right.y; *lp++ = lightmat->right.z; *lp++ = 0.0f; *lp++ = lightmat->up.x; *lp++ = lightmat->up.y; *lp++ = lightmat->up.z; *lp++ = 0.0f; *lp++ = lightmat->at.x; *lp++ = lightmat->at.y; *lp++ = lightmat->at.z; *lp++ = 0.0f; *lp++ = lightmat->pos.x; *lp++ = lightmat->pos.y; *lp++ = lightmat->pos.z; *lp++ = 1.0f; // TODO: make a proper light block // ambient *lp++ = 80.0f; *lp++ = 80.0f; *lp++ = 80.0f; *lp++ = 0.0f; // directional *lp++ = 0.5f; *lp++ = -0.5f; *lp++ = -0.7071f; *lp++ = 0.0f; numLightQ = 6; } void setupTransform(rw::Atomic *atomic, rw::Matrix *trans) { rw::Matrix::mult(trans, atomic->getFrame()->getLTM(), &camera->viewMatrix); } enum { DMAcnt = 0x10000000, DMAref = 0x30000000, DMAcall = 0x50000000, DMAret = 0x60000000, DMAend = 0x70000000, V4_32 = 0x6C }; #define UNPACK(type, nq, offset) ((type)<<24 | (nq)<<16 | (offset)) #define STCYCL(WL,CL) (0x01000000 | (WL)<<8 | (CL)) void drawAtomic(rw::Atomic *atomic) { using namespace rw; Matrix trans; Geometry *geo; ps2::ObjPipeline *pipe; ps2::MatPipeline *matpipe; Material *material; uint128 tmp, *lp; uint32 *vec; RGBAf color; int i; geo = atomic->geometry; pipe = (ps2::ObjPipeline*)atomic->getPipeline(); if(pipe->platform != PLATFORM_PS2) return; setupLight(atomic); setupTransform(atomic, &trans); curVifPtr = packetbuf; // upload lights MAKEQ(tmp, DMAcnt | numLightQ+8, 0, STCYCL(4,4), UNPACK(V4_32, numLightQ, 0x3d0)); *curVifPtr++ = tmp; for(lp = lightpacket; numLightQ--;) *curVifPtr++ = *lp++; // upload transformation matrix MAKEQ(tmp, 0, 0, STCYCL(4,4), UNPACK(V4_32, 4, 0x3f0)); *curVifPtr++ = tmp; vec = (uint32*)&trans.right; MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]); *curVifPtr++ = tmp; vec = (uint32*)&trans.up; MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]); *curVifPtr++ = tmp; vec = (uint32*)&trans.at; MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]); *curVifPtr++ = tmp; vec = (uint32*)&trans.pos; MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]); *curVifPtr++ = tmp; // upload camera/screen info MAKEQ(tmp, 0, 0, STCYCL(4,4), UNPACK(V4_32, 2, 0x3f7)); *curVifPtr++ = tmp; *curVifPtr++ = vuXYZScale; *curVifPtr++ = vuXYZOffset; assert(geo->instData != NULL); rw::ps2::InstanceDataHeader *instData = (rw::ps2::InstanceDataHeader*)geo->instData; rw::MeshHeader *meshHeader = geo->meshHeader; rw::Mesh *mesh; for(i = 0; i < instData->numMeshes; i++){ material = instData->instanceMeshes[i].material; matpipe = pipe->groupPipeline; if(matpipe == nil) matpipe = (ps2::MatPipeline*)material->pipeline; if(matpipe == nil) matpipe = ps2::defaultMatPipe; // call vu code MAKEQ(tmp, DMAcall, (uint32)skinPipe, 0, 0); *curVifPtr++ = tmp; // unpack GIF tag, material color, surface properties MAKEQ(tmp, DMAcnt | 3, 0, STCYCL(4,4), UNPACK(V4_32, 3, 0x3fa)); *curVifPtr++ = tmp; MAKE128(tmp, 0x412, GIF_MAKE_TAG(0, 1, 1, GS_MAKE_PRIM(GS_PRIM_TRI_STRIP,1,0,0,0,0,0,0,0), GIF_PACKED, 3)); *curVifPtr++ = tmp; convColor(&color, &material->color); color.alpha *= 128.0f/255.0f; MAKEQ(tmp, *(uint32*)&color.red, *(uint32*)&color.green, *(uint32*)&color.blue, *(uint32*)&color.alpha); *curVifPtr++ = tmp; MAKEQ(tmp, *(uint32*)&material->surfaceProps.ambient, *(uint32*)&material->surfaceProps.specular, *(uint32*)&material->surfaceProps.diffuse, 0.0f); // extra *curVifPtr++ = tmp; // call geometry MAKEQ(tmp, DMAcall, (uint32)instData->instanceMeshes[i].data, 0x03000000, 0x02000000 | matpipe->vifOffset); *curVifPtr++ = tmp; } MAKEQ(tmp, DMAend, 0, 0, 0); *curVifPtr++ = tmp; for(lp = packetbuf; lp < curVifPtr; lp++) printquad4(*lp); toVIF1chain(packetbuf); } void beginCamera(void) { uint128 *p, tmp; float32 *f; p = packetbuf; MAKE128(tmp, 0xe, GIF_MAKE_TAG(2, 1, 0, 0, GIF_PACKED, 1)); *p++ = tmp; MAKE128(tmp, GS_XYOFFSET_1, GS_MAKE_XYOFFSET(2048-WIDTH/2 <<4, 2048-HEIGHT/2 <<4)); *p++ = tmp; MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 2)); *p++ = tmp; toGIF(packetbuf, 3); f = (float32*)&vuXYZScale; f[0] = WIDTH; f[1] = HEIGHT; f[2] = camera->zScale; f[3] = 0.0f; f = (float32*)&vuXYZOffset; f[0] = 2048.0f; f[1] = 2048.0f; f[2] = camera->zShift; f[3] = 0.0f; } rw::EngineStartParams engineStartParams; void pluginattach(void) { rw::ps2::registerPDSPlugin(40); rw::ps2::registerPluginPDSPipes(); rw::registerMeshPlugin(); rw::registerNativeDataPlugin(); rw::registerAtomicRightsPlugin(); rw::registerMaterialRightsPlugin(); rw::xbox::registerVertexFormatPlugin(); rw::registerSkinPlugin(); rw::registerHAnimPlugin(); rw::registerMatFXPlugin(); rw::registerUVAnimPlugin(); rw::ps2::registerADCPlugin(); } bool32 initrw(void) { rw::version = 0x34000; rw::platform = rw::PLATFORM_PS2; if(!rw::Engine::init()) return 0; pluginattach(); if(!rw::Engine::open()) return 0; if(!rw::Engine::start(&engineStartParams)) return 0; rw::engine->loadTextures = 0; rw::TexDictionary::setCurrent(rw::TexDictionary::create()); rw::Image::setSearchPath("."); world = rw::World::create(); camera = rw::Camera::create(); camera->setFrame(rw::Frame::create()); rw::V3d t = { 0.0f, 0.0f, -4.0f }; // rw::V3d t = { 0.0f, 0.0f, -40.0f }; camera->getFrame()->translate(&t, rw::COMBINEPOSTCONCAT); rw::V3d axis = { 0.0f, 1.0f, 0.0f }; camera->getFrame()->rotate(&axis, 40.0f, rw::COMBINEPOSTCONCAT); camera->setNearPlane(0.1f); camera->setFarPlane(450.0f); camera->setFOV(60.0f, 4.0f/3.0f); world->addCamera(camera); return 1; } int vsynch(int id) { frames++; ExitHandler(); return 0; } int main() { FlushCache(0); if(!initrw()){ printf("init failed!\n"); for(;;); } rw::uint32 len; rw::uint8 *data = rw::getFileContents("host:player.DFF", &len); // rw::uint8 *data = rw::getFileContents("host:od_newscafe_dy.dff", &len); rw::StreamMemory in; in.open(data, len); rw::findChunk(&in, rw::ID_CLUMP, NULL, NULL); rw::Clump *clump = rw::Clump::streamRead(&in); in.close(); rwFree(data); GsCtx gsCtx; dmaReset(); // GsResetCrt(GS_NONINTERLACED, GS_NTSC, 0); // GsInitCtx(&gsCtx, 640, 224, GS_PSMCT32, GS_PSMZ32); // GsResetCrt(GS_INTERLACED, GS_NTSC, GS_FRAME); // GsInitCtx(&gsCtx, 640, 224, GS_PSMCT32, GS_PSMZ32); GsResetCrt(GS_INTERLACED, GS_NTSC, GS_FIELD); GsInitCtx(&gsCtx, WIDTH, HEIGHT, GS_PSMCT32, GS_PSMZ32); initrender(); AddIntcHandler(2, vsynch, 0); EnableIntc(2); GsPutDrawCtx(&gsCtx.draw[0]); GsPutDispCtx(&gsCtx.disp[1]); // PCSX2 needs a delay for some reason { int i; for(i = 0; i < 1000000; i++); } clearscreen(0x80, 0x80, 0x80); // drawtest(); // drawtri(); camera->beginUpdate(); beginCamera(); FORLIST(lnk, clump->atomics) drawAtomic(rw::Atomic::fromClump(lnk)); camera->endUpdate(); printf("hello %p\n", clump); for(;;); // printf(""); return 0; }