diff --git a/src/d3d/d3d.cpp b/src/d3d/d3d.cpp index f6465a9..2011016 100644 --- a/src/d3d/d3d.cpp +++ b/src/d3d/d3d.cpp @@ -383,6 +383,7 @@ rasterCreateTexture(Raster *raster) }else format = formatInfo[(raster->format >> 8) & 0xF].d3dformat; natras->format = format; + raster->depth = formatInfo[(raster->format >> 8) & 0xF].depth; natras->hasAlpha = formatInfo[(raster->format >> 8) & 0xF].hasAlpha; levels = Raster::calculateNumLevels(raster->width, raster->height); natras->texture = createTexture(raster->width, raster->height, diff --git a/src/d3d/d3ddevice.cpp b/src/d3d/d3ddevice.cpp index 91d2fa3..bca94a2 100755 --- a/src/d3d/d3ddevice.cpp +++ b/src/d3d/d3ddevice.cpp @@ -1064,6 +1064,9 @@ Device renderdevice = { d3d::showRaster, d3d::setRwRenderState, d3d::getRwRenderState, + d3d::im2DRenderLine, + d3d::im2DRenderTriangle, + d3d::im2DRenderPrimitive, d3d::im2DRenderIndexedPrimitive, d3d::im3DTransform, d3d::im3DRenderIndexed, diff --git a/src/d3d/d3dimmed.cpp b/src/d3d/d3dimmed.cpp index 3d9cdfb..4154253 100644 --- a/src/d3d/d3dimmed.cpp +++ b/src/d3d/d3dimmed.cpp @@ -10,6 +10,7 @@ #include "../rwengine.h" #include "rwd3d.h" #include "rwd3d9.h" +#include "rwd3dimpl.h" namespace rw { namespace d3d { @@ -56,6 +57,73 @@ closeIm2D(void) deleteObject(im2dindbuf); } +static Im2DVertex tmpprimbuf[3]; + +void +im2DRenderLine(void *vertices, int32 numVertices, int32 vert1, int32 vert2) +{ + Im2DVertex *verts = (Im2DVertex*)vertices; + tmpprimbuf[0] = verts[vert1]; + tmpprimbuf[1] = verts[vert2]; + im2DRenderPrimitive(PRIMTYPELINELIST, tmpprimbuf, 2); +} + +void +im2DRenderTriangle(void *vertices, int32 numVertices, int32 vert1, int32 vert2, int32 vert3) +{ + Im2DVertex *verts = (Im2DVertex*)vertices; + tmpprimbuf[0] = verts[vert1]; + tmpprimbuf[1] = verts[vert2]; + tmpprimbuf[2] = verts[vert3]; + im2DRenderPrimitive(PRIMTYPETRILIST, tmpprimbuf, 3); +} + +void +im2DRenderPrimitive(PrimitiveType primType, void *vertices, int32 numVertices) +{ + if(numVertices > NUMVERTICES){ + // TODO: error + return; + } + uint8 *lockedvertices = lockVertices(im2dvertbuf, 0, numVertices*sizeof(Im2DVertex), D3DLOCK_NOSYSLOCK); + memcpy(lockedvertices, vertices, numVertices*sizeof(Im2DVertex)); + unlockVertices(im2dvertbuf); + + d3ddevice->SetStreamSource(0, im2dvertbuf, 0, sizeof(Im2DVertex)); + d3ddevice->SetVertexDeclaration(im2ddecl); + setTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + setTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + setTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + setTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + setTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + setTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + + d3d::flushCache(); + + uint32 primCount = 0; + switch(primType){ + case PRIMTYPELINELIST: + primCount = numVertices/2; + break; + case PRIMTYPEPOLYLINE: + primCount = numVertices-1; + break; + case PRIMTYPETRILIST: + primCount = numVertices/3; + break; + case PRIMTYPETRISTRIP: + primCount = numVertices-2; + break; + case PRIMTYPETRIFAN: + primCount = numVertices-2; + break; + case PRIMTYPEPOINTLIST: + primCount = numVertices; + break; + } + d3ddevice->DrawPrimitive((D3DPRIMITIVETYPE)primTypeMap[primType], 0, primCount); +} + void im2DRenderIndexedPrimitive(PrimitiveType primType, void *vertices, int32 numVertices, void *indices, int32 numIndices) diff --git a/src/d3d/rwd3d.h b/src/d3d/rwd3d.h index c5bc854..5fa6884 100644 --- a/src/d3d/rwd3d.h +++ b/src/d3d/rwd3d.h @@ -32,10 +32,16 @@ struct Im3DVertex void setY(float32 y) { this->position.y = y; } void setZ(float32 z) { this->position.z = z; } void setColor(uint8 r, uint8 g, uint8 b, uint8 a) { this->color = D3DCOLOR_ARGB(a, r, g, b); } - RGBA getColor(void) { return makeRGBA(this->color>>16 & 0xFF, this->color>>8 & 0xFF, - this->color & 0xFF, this->color>>24 & 0xFF); } void setU(float32 u) { this->u = u; } void setV(float32 v) { this->v = v; } + + float getX(void) { return this->position.x; } + float getY(void) { return this->position.y; } + float getZ(void) { return this->position.z; } + RGBA getColor(void) { return makeRGBA(this->color>>16 & 0xFF, this->color>>8 & 0xFF, + this->color & 0xFF, this->color>>24 & 0xFF); } + float getU(void) { return this->u; } + float getV(void) { return this->v; } }; struct Im2DVertex @@ -53,6 +59,15 @@ struct Im2DVertex void setColor(uint8 r, uint8 g, uint8 b, uint8 a) { this->color = D3DCOLOR_ARGB(a, r, g, b); } void setU(float32 u, float recipZ) { this->u = u; } void setV(float32 v, float recipZ) { this->v = v; } + + float getScreenX(void) { return this->x; } + float getScreenY(void) { return this->y; } + float getScreenZ(void) { return this->z; } + float getCameraZ(void) { return this->w; } + RGBA getColor(void) { return makeRGBA(this->color>>16 & 0xFF, this->color>>8 & 0xFF, + this->color & 0xFF, this->color>>24 & 0xFF); } + float getU(void) { return this->u; } + float getV(void) { return this->v; } }; void setD3dMaterial(D3DMATERIAL9 *mat9); diff --git a/src/d3d/rwd3dimpl.h b/src/d3d/rwd3dimpl.h index 7ad5827..5f2751e 100644 --- a/src/d3d/rwd3dimpl.h +++ b/src/d3d/rwd3dimpl.h @@ -4,6 +4,12 @@ namespace d3d { #ifdef RW_D3D9 void openIm2D(void); void closeIm2D(void); +void im2DRenderLine(void *vertices, int32 numVertices, + int32 vert1, int32 vert2); +void im2DRenderTriangle(void *vertices, int32 numVertices, + int32 vert1, int32 vert2, int32 vert3); +void im2DRenderPrimitive(PrimitiveType primType, + void *vertices, int32 numVertices); void im2DRenderIndexedPrimitive(PrimitiveType primType, void *vertices, int32 numVertices, void *indices, int32 numIndices); diff --git a/src/engine.cpp b/src/engine.cpp index 3a98fcf..3b33d04 100755 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -209,6 +209,9 @@ void showRaster(Raster*) { } void setRenderState(int32, void*) { } void *getRenderState(int32) { return 0; } +void im2DRenderLine(void*, int32, int32, int32) { } +void im2DRenderTriangle(void*, int32, int32, int32, int32) { } +void im2DRenderPrimitive(PrimitiveType, void*, int32) { } void im2DRenderIndexedPrimitive(PrimitiveType, void*, int32, void*, int32) { } void im3DTransform(void *vertices, int32 numVertices, Matrix *world) { } @@ -268,6 +271,9 @@ Device renderdevice = { null::showRaster, null::setRenderState, null::getRenderState, + null::im2DRenderLine, + null::im2DRenderTriangle, + null::im2DRenderPrimitive, null::im2DRenderIndexedPrimitive, null::im3DTransform, null::im3DRenderIndexed, diff --git a/src/gl/gl3device.cpp b/src/gl/gl3device.cpp index 2bde1b9..adc2cfd 100755 --- a/src/gl/gl3device.cpp +++ b/src/gl/gl3device.cpp @@ -859,6 +859,9 @@ Device renderdevice = { gl3::showRaster, gl3::setRenderState, gl3::getRenderState, + gl3::im2DRenderLine, + gl3::im2DRenderTriangle, + gl3::im2DRenderPrimitive, gl3::im2DRenderIndexedPrimitive, gl3::im3DTransform, gl3::im3DRenderIndexed, diff --git a/src/gl/gl3immed.cpp b/src/gl/gl3immed.cpp index 1d24fb0..bc31582 100644 --- a/src/gl/gl3immed.cpp +++ b/src/gl/gl3immed.cpp @@ -11,6 +11,7 @@ #ifdef RW_OPENGL #include #include "rwgl3.h" +#include "rwgl3impl.h" #include "rwgl3shader.h" namespace rw { @@ -73,6 +74,53 @@ closeIm2D(void) im2dShader = nil; } +static Im2DVertex tmpprimbuf[3]; + +void +im2DRenderLine(void *vertices, int32 numVertices, int32 vert1, int32 vert2) +{ + Im2DVertex *verts = (Im2DVertex*)vertices; + tmpprimbuf[0] = verts[vert1]; + tmpprimbuf[1] = verts[vert2]; + im2DRenderPrimitive(PRIMTYPELINELIST, tmpprimbuf, 2); +} + +void +im2DRenderTriangle(void *vertices, int32 numVertices, int32 vert1, int32 vert2, int32 vert3) +{ + Im2DVertex *verts = (Im2DVertex*)vertices; + tmpprimbuf[0] = verts[vert1]; + tmpprimbuf[1] = verts[vert2]; + tmpprimbuf[2] = verts[vert3]; + im2DRenderPrimitive(PRIMTYPETRILIST, tmpprimbuf, 3); +} + +void +im2DRenderPrimitive(PrimitiveType primType, void *vertices, int32 numVertices) +{ + GLfloat xform[4]; + Camera *cam; + cam = (Camera*)engine->currentCamera; + + glBindBuffer(GL_ARRAY_BUFFER, im2DVbo); + glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(Im2DVertex), + vertices, GL_DYNAMIC_DRAW); + + xform[0] = 2.0f/cam->frameBuffer->width; + xform[1] = -2.0f/cam->frameBuffer->height; + xform[2] = -1.0f; + xform[3] = 1.0f; + + im2dShader->use(); + setAttribPointers(im2dattribDesc, 3); + + glUniform4fv(currentShader->uniformLocations[u_xform], 1, xform); + + flushCache(); + glDrawArrays(primTypeMap[primType], 0, numVertices); + disableAttribPointers(im2dattribDesc, 3); +} + void im2DRenderIndexedPrimitive(PrimitiveType primType, void *vertices, int32 numVertices, diff --git a/src/gl/rwgl3.h b/src/gl/rwgl3.h index ac3150a..24cf96e 100644 --- a/src/gl/rwgl3.h +++ b/src/gl/rwgl3.h @@ -96,9 +96,15 @@ struct Im3DVertex void setZ(float32 z) { this->position.z = z; } void setColor(uint8 r, uint8 g, uint8 b, uint8 a) { this->r = r; this->g = g; this->b = b; this->a = a; } - RGBA getColor(void) { return makeRGBA(this->r, this->g, this->b, this->a); } void setU(float32 u) { this->u = u; } void setV(float32 v) { this->v = v; } + + float getX(void) { return this->position.x; } + float getY(void) { return this->position.y; } + float getZ(void) { return this->position.z; } + RGBA getColor(void) { return makeRGBA(this->r, this->g, this->b, this->a); } + float getU(void) { return this->u; } + float getV(void) { return this->v; } }; struct Im2DVertex @@ -116,6 +122,14 @@ struct Im2DVertex this->r = r; this->g = g; this->b = b; this->a = a; } void setU(float32 u, float recipz) { this->u = u; } void setV(float32 v, float recipz) { this->v = v; } + + float getScreenX(void) { return this->x; } + float getScreenY(void) { return this->y; } + float getScreenZ(void) { return this->z; } + float getCameraZ(void) { return this->w; } + RGBA getColor(void) { return makeRGBA(this->r, this->g, this->b, this->a); } + float getU(void) { return this->u; } + float getV(void) { return this->v; } }; void setAttribPointers(AttribDesc *attribDescs, int32 numAttribs); diff --git a/src/gl/rwgl3impl.h b/src/gl/rwgl3impl.h index 27ceaf6..ecf7f8d 100644 --- a/src/gl/rwgl3impl.h +++ b/src/gl/rwgl3impl.h @@ -6,6 +6,12 @@ namespace gl3 { extern uint32 im2DVbo, im2DIbo; void openIm2D(void); void closeIm2D(void); +void im2DRenderLine(void *vertices, int32 numVertices, + int32 vert1, int32 vert2); +void im2DRenderTriangle(void *vertices, int32 numVertices, + int32 vert1, int32 vert2, int32 vert3); +void im2DRenderPrimitive(PrimitiveType primType, + void *vertices, int32 numVertices); void im2DRenderIndexedPrimitive(PrimitiveType primType, void *vertices, int32 numVertices, void *indices, int32 numIndices); diff --git a/src/ps2/ps2raster.cpp b/src/ps2/ps2raster.cpp index 94bc955..124770e 100644 --- a/src/ps2/ps2raster.cpp +++ b/src/ps2/ps2raster.cpp @@ -1454,7 +1454,7 @@ unswizzle16to4(uint8 *dst, uint8 *src, int32 w, int32 h) } } -static void +void expandPSMT4(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw) { int32 x, y; @@ -1465,7 +1465,7 @@ expandPSMT4(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw) } } -static void +void copyPSMT8(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw) { int32 x, y; @@ -1620,7 +1620,7 @@ createNativeRaster(void *object, int32 offset, int32) Ps2Raster *raster = PLUGINOFFSET(Ps2Raster, object, offset); raster->tex0 = 0; raster->paletteBase = 0; - raster->kl = 0xFC0; + raster->kl = defaultMipMapKL; raster->tex1low = 0; raster->unk2 = 0; raster->miptbp1 = 0; @@ -1668,8 +1668,10 @@ static Stream* writeMipmap(Stream *stream, int32, void *object, int32 offset, int32) { Texture *tex = (Texture*)object; - if(tex->raster) - return nil; + if(tex->raster){ + stream->writeI32(defaultMipMapKL); + return stream; + } Ps2Raster *raster = PLUGINOFFSET(Ps2Raster, tex->raster, offset); stream->writeI32(raster->kl); return stream; @@ -1873,6 +1875,10 @@ streamExt.mipmapVal); calcTEX1(raster, &tex1, tex->filterAddressing & 0xF); // printTEX1(tex1); + // TODO: GTA SA LD_OTB.txd loses here + assert(natras->pixelSize >= streamExt.pixelSize); + assert(natras->paletteSize >= streamExt.paletteSize); + natras->tex0 = streamExt.tex0; natras->paletteBase = streamExt.paletteOffset; natras->tex1low = streamExt.tex1low; diff --git a/src/ps2/rwps2.h b/src/ps2/rwps2.h index f580d5f..1efec2b 100755 --- a/src/ps2/rwps2.h +++ b/src/ps2/rwps2.h @@ -220,5 +220,8 @@ Texture *readNativeTexture(Stream *stream); void writeNativeTexture(Texture *tex, Stream *stream); uint32 getSizeNativeTexture(Texture *tex); +void expandPSMT4(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw); +void copyPSMT8(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw); + } } diff --git a/src/render.cpp b/src/render.cpp index 0bdefc8..53879da 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -25,10 +25,25 @@ namespace im2d { float32 GetNearZ(void) { return engine->device.zNear; } float32 GetFarZ(void) { return engine->device.zFar; } void +RenderLine(void *verts, int32 numVerts, int32 vert1, int32 vert2) +{ + engine->device.im2DRenderLine(verts, numVerts, vert1, vert2); +} +void +RenderTriangle(void *verts, int32 numVerts, int32 vert1, int32 vert2, int32 vert3) +{ + engine->device.im2DRenderTriangle(verts, numVerts, vert1, vert2, vert3); +} +void RenderIndexedPrimitive(PrimitiveType type, void *verts, int32 numVerts, void *indices, int32 numIndices) { engine->device.im2DRenderIndexedPrimitive(type, verts, numVerts, indices, numIndices); } +void +RenderPrimitive(PrimitiveType type, void *verts, int32 numVerts) +{ + engine->device.im2DRenderPrimitive(type, verts, numVerts); +} } diff --git a/src/rwengine.h b/src/rwengine.h index d886b96..80530d0 100755 --- a/src/rwengine.h +++ b/src/rwengine.h @@ -36,9 +36,10 @@ struct Device void (*setRenderState)(int32 state, void *value); void *(*getRenderState)(int32 state); - // TODO: render line - // TODO: render triangle - // TODO: render primitive + void (*im2DRenderLine)(void*, int32, int32, int32); + void (*im2DRenderTriangle)(void*, int32, int32, int32, int32); + void (*im2DRenderPrimitive)(PrimitiveType, + void*, int32); void (*im2DRenderIndexedPrimitive)(PrimitiveType, void*, int32, void*, int32); @@ -163,6 +164,9 @@ namespace null { void rasterFromImage(Raster*, Image*); Image *rasterToImage(Raster*); + void im2DRenderLine(void*, int32, int32, int32); + void im2DRenderTriangle(void*, int32, int32, int32, int32); + void im2DRenderPrimitive(PrimitiveType, void*, int32); void im2DRenderIndexedPrimitive(PrimitiveType, void*, int32, void*, int32); diff --git a/src/rwrender.h b/src/rwrender.h index 207c232..6b045ef 100644 --- a/src/rwrender.h +++ b/src/rwrender.h @@ -68,7 +68,10 @@ namespace im2d { float32 GetNearZ(void); float32 GetFarZ(void); +void RenderLine(void *verts, int32 numVerts, int32 vert1, int32 vert2); +void RenderTriangle(void *verts, int32 numVerts, int32 vert1, int32 vert2, int32 vert3); void RenderIndexedPrimitive(PrimitiveType, void *verts, int32 numVerts, void *indices, int32 numIndices); +void RenderPrimitive(PrimitiveType type, void *verts, int32 numVerts); } diff --git a/tools/clumpview/main.cpp b/tools/clumpview/main.cpp index 32ef445..e0f229a 100644 --- a/tools/clumpview/main.cpp +++ b/tools/clumpview/main.cpp @@ -11,9 +11,14 @@ struct SceneGlobals { rw::Clump *clump; } Scene; rw::Texture *tex, *tex2; +rw::Raster *testras; rw::EngineStartParams engineStartParams; +bool dosoftras = 1; + +namespace gen { void tlTest(rw::Clump *clump); +} void genIm3DTransform(void *vertices, rw::int32 numVertices, rw::Matrix *xform); void genIm3DRenderIndexed(rw::PrimitiveType prim, void *indices, rw::int32 numIndices); void genIm3DEnd(void); @@ -25,7 +30,7 @@ Init(void) { sk::globals.windowtitle = "Clump viewer"; sk::globals.width = 640; - sk::globals.height = 480; + sk::globals.height = 448; sk::globals.quit = 0; } @@ -168,7 +173,7 @@ InitRW(void) tex = rw::Texture::read("maze", nil); tex2 = rw::Texture::read("checkers", nil); - const char *filename = "teapot.dff"; + const char *filename = "teapot2.dff"; if(sk::args.argc > 1) filename = sk::args.argv[1]; rw::StreamFile in; @@ -196,7 +201,7 @@ InitRW(void) Scene.world = rw::World::create(); rw::Light *ambient = rw::Light::create(rw::Light::AMBIENT); - ambient->setColor(0.2f, 0.2f, 0.2f); + ambient->setColor(0.3f, 0.3f, 0.3f); Scene.world->addLight(ambient); rw::V3d xaxis = { 1.0f, 0.0f, 0.0f }; @@ -209,9 +214,10 @@ InitRW(void) camera = new Camera; Scene.camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1); camera->m_rwcam = Scene.camera; - camera->m_aspectRatio = 640.0f/480.0f; - camera->m_near = 0.1f; - camera->m_far = 450.0f; + camera->m_aspectRatio = 640.0f/448.0f; + camera->m_near = 5.0f; +// camera->m_far = 450.0f; + camera->m_far = 15.0f; camera->m_target.set(0.0f, 0.0f, 0.0f); camera->m_position.set(0.0f, -10.0f, 0.0f); // camera->setPosition(Vec3(0.0f, 5.0f, 0.0f)); @@ -235,16 +241,16 @@ im2dtest(void) rw::uint8 r, g, b, a; float u, v; } vs[4] = { -/* { 0.0f, 0.0f, 255, 0, 0, 128, 0.0f, 0.0f }, { 640.0f, 0.0f, 0, 255, 0, 128, 1.0f, 0.0f }, - { 0.0f, 480.0f, 0, 0, 255, 128, 0.0f, 1.0f }, - { 640.0f, 480.0f, 0, 255, 255, 128, 1.0f, 1.0f }, -*/ + { 0.0f, 448.0f, 0, 0, 255, 128, 0.0f, 1.0f }, + { 640.0f, 448.0f, 0, 255, 255, 128, 1.0f, 1.0f }, +/* { 0.0f, 0.0f, 255, 0, 0, 128, 0.0f, 1.0f }, { 640.0f, 0.0f, 0, 255, 0, 128, 0.0f, 0.0f }, - { 0.0f, 480.0f, 0, 0, 255, 128, 1.0f, 1.0f }, - { 640.0f, 480.0f, 0, 255, 255, 128, 1.0f, 0.0f }, + { 0.0f, 448.0f, 0, 0, 255, 128, 1.0f, 1.0f }, + { 640.0f, 448.0f, 0, 255, 255, 128, 1.0f, 0.0f }, +*/ }; Im2DVertex verts[4]; static short indices[] = { @@ -258,12 +264,14 @@ im2dtest(void) verts[i].setScreenZ(rw::im2d::GetNearZ()); verts[i].setCameraZ(Scene.camera->nearPlane); verts[i].setRecipCameraZ(recipZ); - verts[i].setColor(vs[i].r, vs[i].g, vs[i].b, vs[i].a); - verts[i].setU(vs[i].u, recipZ); - verts[i].setV(vs[i].v, recipZ); +// verts[i].setColor(vs[i].r, vs[i].g, vs[i].b, vs[i].a); + verts[i].setColor(255, 255, 255, 255); + verts[i].setU(vs[i].u + 0.5f/640.0f, recipZ); + verts[i].setV(vs[i].v + 0.5f/448.0f, recipZ); } - rw::SetRenderStatePtr(rw::TEXTURERASTER, tex2->raster); +// rw::SetRenderStatePtr(rw::TEXTURERASTER, tex2->raster); + rw::SetRenderStatePtr(rw::TEXTURERASTER, testras); rw::SetRenderState(rw::TEXTUREADDRESS, rw::Texture::WRAP); rw::SetRenderState(rw::TEXTUREFILTER, rw::Texture::NEAREST); rw::SetRenderState(rw::VERTEXALPHA, 1); @@ -329,12 +337,24 @@ Draw(float timeDelta) camera->update(); camera->m_rwcam->beginUpdate(); - Scene.clump->render(); -// im2dtest(); -// tlTest(Scene.clump); +extern void beginSoftras(void); + beginSoftras(); + + gen::tlTest(Scene.clump); +void drawtest(void); +// drawtest(); + +extern void endSoftras(void); + if(dosoftras){ + endSoftras(); + im2dtest(); + } + +// Scene.clump->render(); // im3dtest(); // printScreen("Hello, World!", 10, 10); + camera->m_rwcam->endUpdate(); camera->m_rwcam->showRaster(); } @@ -379,6 +399,9 @@ KeyDown(int key) case 'F': camera->zoom(-0.1f); break; + case 'V': + dosoftras = !dosoftras; + break; case sk::KEY_ESC: sk::globals.quit = 1; break; @@ -432,7 +455,8 @@ AppEventHandler(sk::Event e, void *param) sk::globals.width = r->w; sk::globals.height = r->h; - // TODO: set aspect ratio + if(camera) + camera->m_aspectRatio = (float)r->w/r->h; if(Scene.camera) sk::CameraSize(Scene.camera, r); break; diff --git a/tools/clumpview/ras_test.cpp b/tools/clumpview/ras_test.cpp new file mode 100644 index 0000000..03621dc --- /dev/null +++ b/tools/clumpview/ras_test.cpp @@ -0,0 +1,900 @@ +#include +#include + +namespace rs { + +typedef int8_t i8; +typedef uint8_t u8; +typedef int16_t i16; +typedef uint16_t u16; +typedef int32_t i32; +typedef uint32_t u32; +typedef int64_t i64; +typedef uint64_t u64; + +typedef struct Canvas Canvas; +struct Canvas +{ + u8 *fb; + u32 *zbuf; + int w, h; +}; +extern Canvas *canvas; + +typedef struct Texture Texture; +struct Texture +{ + u8 *pixels; + int w, h; + int wrap; +}; + +typedef struct Point3 Point3; +struct Point3 +{ + int x, y, z; +}; + +typedef struct Color Color; +struct Color +{ + u8 r, g, b, a; +}; + +typedef struct Vertex Vertex; +struct Vertex +{ + i32 x, y, z; + float q; // 1/z + u8 r, g, b, a; + u8 f; // fog + float s, t; +}; + +Canvas *makecanvas(int w, int h); +Texture *maketexture(int w, int h); +void putpixel(Canvas *canvas, Point3 p, Color c); +void clearcanvas(Canvas *canvas); +void drawTriangle(Canvas *canvas, Vertex p1, Vertex p2, Vertex p3); + +// not good +void drawRect(Canvas *canvas, Point3 p1, Point3 p2, Color c); +void drawLine(Canvas *canvas, Point3 p1, Point3 p2, Color c); + +//#define trace(...) printf(__VA_ARGS__) +#define trace(...) + + +int clamp(int x); + + +/* + * Render States + */ +enum TextureWrap { + WRAP_REPEAT, + WRAP_CLAMP, + WRAP_BORDER, +}; + +enum TextureFunction { + TFUNC_MODULATE, + TFUNC_DECAL, + TFUNC_HIGHLIGHT, + TFUNC_HIGHLIGHT2, +}; + +enum AlphaTestFunc { + ALPHATEST_NEVER, + ALPHATEST_ALWAYS, + ALPHATEST_LESS, + ALPHATEST_LEQUAL, + ALPHATEST_EQUAL, + ALPHATEST_GEQUAL, + ALPHATEST_GREATER, + ALPHATEST_NOTEQUAL, +}; + +enum AlphaTestFail { + ALPHAFAIL_KEEP, + ALPHAFAIL_FB_ONLY, + ALPHAFAIL_ZB_ONLY, +}; + +enum DepthTestFunc { + DEPTHTEST_NEVER, + DEPTHTEST_ALWAYS, + DEPTHTEST_GEQUAL, + DEPTHTEST_GREATER, +}; + +// The blend equation is +// out = ((A - B) * C >> 7) + D +// A, B and D select the color, C the alpha value +enum AlphaBlendOp { + ALPHABLEND_SRC, + ALPHABLEND_DST, + ALPHABLEND_ZERO, + ALPHABLEND_FIX = ALPHABLEND_ZERO, +}; + +extern int srScissorX0, srScissorX1; +extern int srScissorY0, srScissorY1; +extern int srDepthTestEnable; +extern int srDepthTestFunction; +extern int srWriteZ; +extern int srAlphaTestEnable; +extern int srAlphaTestFunction; +extern int srAlphaTestReference; +extern int srAlphaTestFail; +extern int srAlphaBlendEnable; +extern int srAlphaBlendA; +extern int srAlphaBlendB; +extern int srAlphaBlendC; +extern int srAlphaBlendD; +extern int srAlphaBlendFix; +extern int srTexEnable; +extern Texture *srTexture; +extern int srWrapU; +extern int srWrapV; +extern Color srBorder; +extern int srTexUseAlpha; +extern int srTexFunc; +extern int srFogEnable; +extern Color srFogCol; + + + +// end header + + + + +#define CEIL(p) (((p)+15) >> 4) + +// render states +int srScissorX0, srScissorX1; +int srScissorY0, srScissorY1; +int srDepthTestEnable = 1; +int srDepthTestFunction = DEPTHTEST_GEQUAL; +int srWriteZ = 1; +int srAlphaTestEnable = 1; +int srAlphaTestFunction = ALPHATEST_ALWAYS; +int srAlphaTestReference; +int srAlphaTestFail = ALPHAFAIL_FB_ONLY; +int srAlphaBlendEnable = 1; +int srAlphaBlendA = ALPHABLEND_SRC; +int srAlphaBlendB = ALPHABLEND_DST; +int srAlphaBlendC = ALPHABLEND_SRC; +int srAlphaBlendD = ALPHABLEND_DST; +int srAlphaBlendFix = 0x80; +int srTexEnable = 0; +Texture *srTexture; +int srWrapU = WRAP_REPEAT; +int srWrapV = WRAP_REPEAT; +Color srBorder = { 255, 0, 0, 255 }; +int srTexUseAlpha = 1; +int srTexFunc = TFUNC_MODULATE; +int srFogEnable = 0; +Color srFogCol = { 0, 0, 0, 0 }; + +int clamp(int x) { if(x < 0) return 0; if(x > 255) return 255; return x; } + +Canvas* +makecanvas(int w, int h) +{ + Canvas *canv; + canv = (Canvas*)malloc(sizeof(*canv) + w*h*(4+4)); + canv->w = w; + canv->h = h; + canv->fb = ((u8*)canv + sizeof(*canv)); + canv->zbuf = (u32*)(canv->fb + w*h*4); + return canv; +} + +Texture* +maketexture(int w, int h) +{ + Texture *t; + t = (Texture*)malloc(sizeof(*t) + w*h*4); + t->w = w; + t->h = h; + t->pixels = (u8*)t + sizeof(*t); + t->wrap = 0x11; // wrap u and v + return t; +} + +void +clearcanvas(Canvas *canvas) +{ + memset(canvas->fb, 0, canvas->w*canvas->h*4); + memset(canvas->zbuf, 0, canvas->w*canvas->h*4); +} + +void +writefb(Canvas *canvas, int x, int y, Color c) +{ + u8 *px = &canvas->fb[(y*canvas->w + x)*4]; + u32 *z = &canvas->zbuf[y*canvas->w + x]; + + px[3] = c.r; + px[2] = c.g; + px[1] = c.b; + px[0] = c.a; +} + +void +putpixel(Canvas *canvas, Point3 p, Color c) +{ + // scissor test + if(p.x < srScissorX0 || p.x > srScissorX1 || + p.y < srScissorY0 || p.y > srScissorY1) + return; + + u8 *px = &canvas->fb[(p.y*canvas->w + p.x)*4]; + u32 *z = &canvas->zbuf[p.y*canvas->w + p.x]; + + int fbwrite = 1; + int zbwrite = srWriteZ; + + // alpha test + if(srAlphaTestEnable){ + int fail; + switch(srAlphaTestFunction){ + case ALPHATEST_NEVER: + fail = 1; + break; + case ALPHATEST_ALWAYS: + fail = 0; + break; + case ALPHATEST_LESS: + fail = c.a >= srAlphaTestReference; + break; + case ALPHATEST_LEQUAL: + fail = c.a > srAlphaTestReference; + break; + case ALPHATEST_EQUAL: + fail = c.a != srAlphaTestReference; + break; + case ALPHATEST_GEQUAL: + fail = c.a < srAlphaTestReference; + break; + case ALPHATEST_GREATER: + fail = c.a <= srAlphaTestReference; + break; + case ALPHATEST_NOTEQUAL: + fail = c.a == srAlphaTestReference; + break; + } + if(fail){ + switch(srAlphaTestFail){ + case ALPHAFAIL_KEEP: + return; + case ALPHAFAIL_FB_ONLY: + zbwrite = 0; + break; + case ALPHAFAIL_ZB_ONLY: + fbwrite = 0; + } + } + } + + // ztest + if(srDepthTestEnable){ + switch(srDepthTestFunction){ + case DEPTHTEST_NEVER: + return; + case DEPTHTEST_ALWAYS: + break; + case DEPTHTEST_GEQUAL: + if(p.z < *z) + return; + break; + case DEPTHTEST_GREATER: + if(p.z <= *z) + return; + break; + } + } + + Color d = { px[3], px[2], px[1], px[0] }; + + // blend + if(srAlphaBlendEnable){ + int ar, ag, ab; + int br, bg, bb; + int dr, dg, db; + int ca; + switch(srAlphaBlendA){ + case ALPHABLEND_SRC: + ar = c.r; + ag = c.g; + ab = c.b; + break; + case ALPHABLEND_DST: + ar = d.r; + ag = d.g; + ab = d.b; + break; + case ALPHABLEND_ZERO: + ar = 0; + ag = 0; + ab = 0; + break; + default: assert(0); + } + switch(srAlphaBlendB){ + case ALPHABLEND_SRC: + br = c.r; + bg = c.g; + bb = c.b; + break; + case ALPHABLEND_DST: + br = d.r; + bg = d.g; + bb = d.b; + break; + case ALPHABLEND_ZERO: + br = 0; + bg = 0; + bb = 0; + break; + default: assert(0); + } + switch(srAlphaBlendC){ + case ALPHABLEND_SRC: + ca = c.a; + break; + case ALPHABLEND_DST: + ca = d.a; + break; + case ALPHABLEND_FIX: + ca = srAlphaBlendFix; + break; + default: assert(0); + } + switch(srAlphaBlendD){ + case ALPHABLEND_SRC: + dr = c.r; + dg = c.g; + db = c.b; + break; + case ALPHABLEND_DST: + dr = d.r; + dg = d.g; + db = d.b; + break; + case ALPHABLEND_ZERO: + dr = 0; + dg = 0; + db = 0; + break; + default: assert(0); + } + + int r, g, b; + r = ((ar - br) * ca >> 7) + dr; + g = ((ag - bg) * ca >> 7) + dg; + b = ((ab - bb) * ca >> 7) + db; + + c.r = clamp(r); + c.g = clamp(g); + c.b = clamp(b); + } + + if(fbwrite) + writefb(canvas, p.x, p.y, c); + if(zbwrite) + *z = p.z; +} + +Color +sampletex_nearest(int u, int v) +{ + Texture *tex = srTexture; + + const int usize = tex->w; + const int vsize = tex->h; + + int iu = u >> 4; + int iv = v >> 4; + + switch(srWrapU){ + case WRAP_REPEAT: + iu %= usize; + break; + case WRAP_CLAMP: + if(iu < 0) iu = 0; + if(iu >= usize) iu = usize-1; + break; + case WRAP_BORDER: + if(iu < 0 || iu >= usize) + return srBorder; + } + + switch(srWrapV){ + case WRAP_REPEAT: + iv %= vsize; + break; + case WRAP_CLAMP: + if(iv < 0) iv = 0; + if(iv >= vsize) iv = vsize-1; + break; + case WRAP_BORDER: + if(iv < 0 || iv >= vsize) + return srBorder; + } + + u8 *cp = &tex->pixels[(iv*tex->w + iu)*4]; + Color c = { cp[0], cp[1], cp[2], cp[3] }; + return c; +} + +// t is texture, f is fragment +Color +texfunc(Color t, Color f) +{ + int r, g, b, a; + switch(srTexFunc){ + case TFUNC_MODULATE: + r = t.r * f.r >> 7; + g = t.g * f.g >> 7; + b = t.b * f.b >> 7; + a = srTexUseAlpha ? + t.a * f.a >> 7 : + f.a; + break; + case TFUNC_DECAL: + r = t.r; + g = t.g; + b = t.b; + a = srTexUseAlpha ? t.a : f.a; + break; + case TFUNC_HIGHLIGHT: + r = (t.r * f.r >> 7) + f.a; + g = (t.g * f.g >> 7) + f.a; + b = (t.b * f.b >> 7) + f.a; + a = srTexUseAlpha ? + t.a + f.a : + f.a; + break; + case TFUNC_HIGHLIGHT2: + r = (t.r * f.r >> 7) + f.a; + g = (t.g * f.g >> 7) + f.a; + b = (t.b * f.b >> 7) + f.a; + a = srTexUseAlpha ? t.a : f.a; + break; + } + r = clamp(r); + g = clamp(g); + b = clamp(b); + a = clamp(a); + Color v = { r, g, b, a }; + return v; +} + +Point3 mkpnt(int x, int y, int z) { Point3 p = { x, y, z}; return p; } + +void +drawRect(Canvas *canvas, Point3 p1, Point3 p2, Color c) +{ + int x, y; + for(y = p1.y; y <= p2.y; y++) + for(x = p1.x; x <= p2.x; x++) + putpixel(canvas, mkpnt(x, y, 0), c); +} + +void +drawLine(Canvas *canvas, Point3 p1, Point3 p2, Color c) +{ + int dx, dy; + int incx, incy; + int e; + int x, y; + + dx = abs(p2.x-p1.x); + incx = p2.x > p1.x ? 1 : -1; + dy = abs(p2.y-p1.y); + incy = p2.y > p1.y ? 1 : -1; + e = 0; + if(dx == 0){ + for(y = p1.y; y != p2.y; y += incy) + putpixel(canvas, mkpnt(p1.x, y, 0), c); + }else if(dx > dy){ + y = p1.y; + for(x = p1.x; x != p2.x; x += incx){ + putpixel(canvas, mkpnt(x, y, 0), c); + e += dy; + if(2*e >= dx){ + e -= dx; + y += incy; + } + } + }else{ + x = p1.x; + for(y = p1.y; y != p2.y; y += incy){ + putpixel(canvas, mkpnt(x, y, 0), c); + e += dx; + if(2*e >= dy){ + e -= dy; + x += incx; + } + } + } +} + +/* + attibutes we want to interpolate: + R G B A + U V / S T Q + X Y Z F +*/ + +struct TriAttribs +{ + i64 z; + i32 r, g, b, a; + i32 f; + float s, t; + float q; +}; + +static void +add1(struct TriAttribs *a, struct TriAttribs *b) +{ + a->z += b->z; + a->r += b->r; + a->g += b->g; + a->b += b->b; + a->a += b->a; + a->f += b->f; + a->s += b->s; + a->t += b->t; + a->q += b->q; +} + +static void +sub1(struct TriAttribs *a, struct TriAttribs *b) +{ + a->z -= b->z; + a->r -= b->r; + a->g -= b->g; + a->b -= b->b; + a->a -= b->a; + a->f -= b->f; + a->s -= b->s; + a->t -= b->t; + a->q -= b->q; +} + +static void +guard(struct TriAttribs *a) +{ + if(a->z < 0) a->z = 0; + else if(a->z > 0x3FFFFFFFC000LL) a->z = 0x3FFFFFFFC000LL; + if(a->r < 0) a->r = 0; + else if(a->r > 0xFF000) a->r = 0xFF000; + if(a->g < 0) a->g = 0; + else if(a->g > 0xFF000) a->g = 0xFF000; + if(a->b < 0) a->b = 0; + else if(a->b > 0xFF000) a->b = 0xFF000; + if(a->a < 0) a->a = 0; + else if(a->a > 0xFF000) a->a = 0xFF000; + if(a->f < 0) a->f = 0; + else if(a->f > 0xFF000) a->f = 0xFF000; +} + +struct RasTri +{ + int x, y; + int ymid, yend; + int right; + int e[2], dx[3], dy[3]; + struct TriAttribs gx, gy, v, s; +}; + +static int +triangleSetup(struct RasTri *tri, Vertex v1, Vertex v2, Vertex v3) +{ + int dx1, dx2, dx3; + int dy1, dy2, dy3; + + dy1 = v3.y - v1.y; // long edge + if(dy1 == 0) return 1; + dx1 = v3.x - v1.x; + dx2 = v2.x - v1.x; // first small edge + dy2 = v2.y - v1.y; + dx3 = v3.x - v2.x; // second small edge + dy3 = v3.y - v2.y; + + // this is twice the triangle area + const int area = dx2*dy1 - dx1*dy2; + if(area == 0) return 1; + // figure out if 0 or 1 is the right edge + tri->right = area < 0; + + /* The gradients are to step whole pixels, + * so they are pre-multiplied by 16. */ + + float denom = 16.0f/area; + // gradients x +#define GX(p) ((v2.p - v1.p)*dy1 - (v3.p - v1.p)*dy2) + tri->gx.z = GX(z)*denom * 16384; + tri->gx.r = GX(r)*denom * 4096; + tri->gx.g = GX(g)*denom * 4096; + tri->gx.b = GX(b)*denom * 4096; + tri->gx.a = GX(a)*denom * 4096; + tri->gx.f = GX(f)*denom * 4096; + tri->gx.s = GX(s)*denom; + tri->gx.t = GX(t)*denom; + tri->gx.q = GX(q)*denom; + + // gradients y + denom = -denom; +#define GY(p) ((v2.p - v1.p)*dx1 - (v3.p - v1.p)*dx2) + tri->gy.z = GY(z)*denom * 16384; + tri->gy.r = GY(r)*denom * 4096; + tri->gy.g = GY(g)*denom * 4096; + tri->gy.b = GY(b)*denom * 4096; + tri->gy.a = GY(a)*denom * 4096; + tri->gy.f = GY(f)*denom * 4096; + tri->gy.s = GY(s)*denom; + tri->gy.t = GY(t)*denom; + tri->gy.q = GY(q)*denom; + + tri->ymid = CEIL(v2.y); + tri->yend = CEIL(v3.y); + + tri->y = CEIL(v1.y); + tri->x = CEIL(v1.x); + + tri->dy[0] = dy2<<4; // upper edge + tri->dy[1] = dy1<<4; // lower edge + tri->dy[2] = dy3<<4; // long edge + tri->dx[0] = dx2<<4; + tri->dx[1] = dx1<<4; + tri->dx[2] = dx3<<4; + + // prestep to land on pixel center + + int stepx = v1.x - (tri->x<<4); + int stepy = v1.y - (tri->y<<4); + tri->e[0] = (-stepy*tri->dx[0] + stepx*tri->dy[0]) >> 4; + tri->e[1] = (-stepy*tri->dx[1] + stepx*tri->dy[1]) >> 4; + + // attributes along interpolated edge + // why is this cast needed? (mingw) + tri->v.z = (i64)v1.z*16384 - (stepy*tri->gy.z + stepx*tri->gx.z)/16; + tri->v.r = v1.r*4096 - (stepy*tri->gy.r + stepx*tri->gx.r)/16; + tri->v.g = v1.g*4096 - (stepy*tri->gy.g + stepx*tri->gx.g)/16; + tri->v.b = v1.b*4096 - (stepy*tri->gy.b + stepx*tri->gx.b)/16; + tri->v.a = v1.a*4096 - (stepy*tri->gy.a + stepx*tri->gx.a)/16; + tri->v.f = v1.f*4096 - (stepy*tri->gy.f + stepx*tri->gx.f)/16; + tri->v.s = v1.s - (stepy*tri->gy.s + stepx*tri->gx.s)/16.0f; + tri->v.t = v1.t - (stepy*tri->gy.t + stepx*tri->gx.t)/16.0f; + tri->v.q = v1.q - (stepy*tri->gy.q + stepx*tri->gx.q)/16.0f; + + return 0; +} + +void +drawTriangle(Canvas *canvas, Vertex v1, Vertex v2, Vertex v3) +{ + Color c; + struct RasTri tri; + int stepx, stepy; + + // Sort such that we have from top to bottom v1,v2,v3 + if(v2.y < v1.y){ Vertex tmp = v1; v1 = v2; v2 = tmp; } + if(v3.y < v1.y){ Vertex tmp = v1; v1 = v3; v3 = tmp; } + if(v3.y < v2.y){ Vertex tmp = v2; v2 = v3; v3 = tmp; } + + if(triangleSetup(&tri, v1, v2, v3)) + return; + + // Current scanline start and end + int xn[2] = { tri.x, tri.x }; + int a = !tri.right; // left edge + int b = tri.right; // right edge + + // If upper triangle has no height, only do the lower part + if(tri.dy[0] == 0) + goto secondtri; + while(tri.y < tri.yend){ + /* TODO: is this the righ way to step the edges? */ + + /* Step x and interpolated value down left edge */ + while(tri.e[a] <= -tri.dy[a]){ + xn[a]--; + tri.e[a] += tri.dy[a]; + sub1(&tri.v, &tri.gx); + } + while(tri.e[a] > 0){ + xn[a]++; + tri.e[a] -= tri.dy[a]; + add1(&tri.v, &tri.gx); + } + + /* Step x down right edge */ + while(tri.e[b] <= -tri.dy[b]){ + xn[b]--; + tri.e[b] += tri.dy[b]; + } + while(tri.e[b] > 0){ + xn[b]++; + tri.e[b] -= tri.dy[b]; + } + + // When we reach the mid vertex, change state and jump to start of loop again + // TODO: this is a bit ugly in here...can we fix it? + if(tri.y == tri.ymid){ + secondtri: + tri.dx[0] = tri.dx[2]; + tri.dy[0] = tri.dy[2]; + // Either the while prevents this or we returned early because dy1 == 0 + assert(tri.dy[0] != 0); + stepx = v2.x - (xn[0]<<4); + stepy = v2.y - (tri.y<<4); + tri.e[0] = (-stepy*tri.dx[0] + stepx*tri.dy[0]) >> 4; + + tri.ymid = -1; // so we don't do this again + continue; + } + + /* Rasterize one line */ + tri.s = tri.v; + for(tri.x = xn[a]; tri.x < xn[b]; tri.x++){ + guard(&tri.s); + c.r = tri.s.r >> 12; + c.g = tri.s.g >> 12; + c.b = tri.s.b >> 12; + c.a = tri.s.a >> 12; + if(srTexEnable && srTexture){ + float w = 1.0f/tri.s.q; + float s = tri.s.s * w; + float t = tri.s.t * w; + int u = s * srTexture->w * 16; + int v = t * srTexture->h * 16; + Color texc = sampletex_nearest(u, v); + c = texfunc(texc, c); + } + if(srFogEnable){ + const int f = tri.s.f >> 12; + c.r = (f*c.r >> 8) + ((255 - f)*srFogCol.r >> 8); + c.g = (f*c.g >> 8) + ((255 - f)*srFogCol.g >> 8); + c.b = (f*c.b >> 8) + ((255 - f)*srFogCol.b >> 8); + } + putpixel(canvas, mkpnt(tri.x, tri.y, tri.s.z>>14), c); + add1(&tri.s, &tri.gx); + } + + /* Step in y */ + tri.y++; + tri.e[a] += tri.dx[a]; + tri.e[b] += tri.dx[b]; + add1(&tri.v, &tri.gy); + } +} + +Canvas *canvas; + +} + +using namespace rw; + +void +rastest_renderTriangles(RWDEVICE::Im2DVertex *scrverts, int32 numVerts, uint16 *indices, int32 numTris) +{ + int i; + RGBA col; + rs::Vertex v[3]; + RWDEVICE::Im2DVertex *iv; + + rs::srDepthTestEnable = 1; + rs::srAlphaTestEnable = 0; + rs::srTexEnable = 0; + rs::srAlphaBlendEnable = 0; + + while(numTris--){ + for(i = 0; i < 3; i++){ + iv = &scrverts[indices[i]]; + v[i].x = iv->x * 16.0f; + v[i].y = iv->y * 16.0f; + v[i].z = 16777216*(1.0f-iv->z); + v[i].q = iv->w; + col = iv->getColor(); + v[i].r = col.red; + v[i].g = col.green; + v[i].b = col.blue; + v[i].a = col.alpha; + v[i].f = 0; + v[i].s = iv->u*iv->w; + v[i].t = iv->v*iv->w; + } + drawTriangle(rs::canvas, v[0], v[1], v[2]); + + indices += 3; + } +} + +extern rw::Raster *testras; + +void +beginSoftras(void) +{ + Camera *cam = (Camera*)engine->currentCamera; + + if(rs::canvas == nil || + cam->frameBuffer->width != rs::canvas->w || + cam->frameBuffer->height != rs::canvas->h){ + rs::canvas = rs::makecanvas(cam->frameBuffer->width, cam->frameBuffer->height); + testras = rw::Raster::create(rs::canvas->w, rs::canvas->h, 32, rw::Raster::C8888); + } + + clearcanvas(rs::canvas); + rs::srScissorX0 = 0; + rs::srScissorX1 = rs::canvas->w-1; + rs::srScissorY0 = 0; + rs::srScissorY1 = rs::canvas->h-1; +} + +void +endSoftras(void) +{ + int i; + uint8 *dst = testras->lock(0); + uint8 *src = rs::canvas->fb; + for(i = 0; i < rs::canvas->w*rs::canvas->h; i++){ + dst[0] = src[1]; + dst[1] = src[2]; + dst[2] = src[3]; + dst[3] = src[0]; + dst += 4; + src += 4; + } + // abgr in canvas + // bgra in raster + testras->unlock(0); +} + + +/* +typedef struct PixVert PixVert; +struct PixVert +{ + float x, y, z, q; + int r, g, b, a; + float u, v; +}; +#include "test.inc" + +void +drawtest(void) +{ + int i, j; + rs::Vertex v[3]; + + rs::srDepthTestEnable = 1; + rs::srAlphaTestEnable = 0; + rs::srTexEnable = 0; + rs::srAlphaBlendEnable = 0; + + for(i = 0; i < nelem(verts); i += 3){ + for(j = 0; j < 3; j++){ + v[j].x = verts[i+j].x * 16.0f; + v[j].y = verts[i+j].y * 16.0f; + v[j].z = 16777216*(1.0f - verts[i+j].z); + v[j].q = verts[i+j].q; + v[j].r = verts[i+j].r; + v[j].g = verts[i+j].g; + v[j].b = verts[i+j].b; + v[j].a = verts[i+j].a; + v[j].f = 0; + v[j].s = verts[i+j].u*v[j].q; + v[j].t = verts[i+j].v*v[j].q; + } + drawTriangle(rs::canvas, v[0], v[1], v[2]); + } +//exit(0); +} +*/ diff --git a/tools/clumpview/tests.cpp b/tools/clumpview/tests.cpp deleted file mode 100644 index 2e52d7e..0000000 --- a/tools/clumpview/tests.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include -#include - -using namespace rw; - -// -// This is a test to implement T&L in software and render with Im2D -// - -#define MAX_LIGHTS 8 - -struct Directional { - V3d at; - RGBAf color; -}; -static Directional directionals[MAX_LIGHTS]; -static int32 numDirectionals; -static RGBAf ambLight; - -static void -enumLights(Matrix *lightmat) -{ - int32 n; - World *world; - - world = (World*)engine->currentWorld; - ambLight.red = 0.0; - ambLight.green = 0.0; - ambLight.blue = 0.0; - ambLight.alpha = 0.0; - numDirectionals = 0; - // only unpositioned lights right now - FORLIST(lnk, world->directionalLights){ - Light *l = Light::fromWorld(lnk); - if(l->getType() == Light::DIRECTIONAL){ - if(numDirectionals >= MAX_LIGHTS) - continue; - n = numDirectionals++; - V3d::transformVectors(&directionals[n].at, &l->getFrame()->getLTM()->at, 1, lightmat); - directionals[n].color = l->color; - directionals[n].color.alpha = 0.0f; - }else if(l->getType() == Light::AMBIENT){ - ambLight.red += l->color.red; - ambLight.green += l->color.green; - ambLight.blue += l->color.blue; - } - } -} - -static void -drawAtomic(Atomic *a) -{ - using namespace RWDEVICE; - Im2DVertex *im2dverts; - V3d *xvert; - Matrix xform; - Matrix lightmat; - Camera *cam = (Camera*)engine->currentCamera; - Geometry *g = a->geometry; - MeshHeader *mh = g->meshHeader; - Mesh *m = mh->getMeshes(); - int32 width = cam->frameBuffer->width; - int32 height = cam->frameBuffer->height; - RGBA *prelight; - V3d *normals; - TexCoords *texcoords; - - Matrix::mult(&xform, a->getFrame()->getLTM(), &cam->viewMatrix); - Matrix::invert(&lightmat, a->getFrame()->getLTM()); - - enumLights(&lightmat); - - xvert = rwNewT(V3d, g->numVertices, MEMDUR_FUNCTION); - im2dverts = rwNewT(Im2DVertex, g->numVertices, MEMDUR_FUNCTION); - - prelight = g->colors; - normals = g->morphTargets[0].normals; - texcoords = g->texCoords[0]; - - V3d::transformPoints(xvert, g->morphTargets[0].vertices, g->numVertices, &xform); - for(int32 i = 0; i < g->numVertices; i++){ - float32 recipZ = 1.0f/xvert[i].z; - - im2dverts[i].setScreenX(xvert[i].x * recipZ * width); - im2dverts[i].setScreenY((xvert[i].y * recipZ * height)); - im2dverts[i].setScreenZ(recipZ * cam->zScale + cam->zShift); - im2dverts[i].setCameraZ(xvert[i].z); - im2dverts[i].setRecipCameraZ(recipZ); - im2dverts[i].setColor(255, 0, 0, 255); - im2dverts[i].setU(texcoords[i].u, recipZ); - im2dverts[i].setV(texcoords[i].v, recipZ); - } - for(int32 i = 0; i < mh->numMeshes; i++){ - for(uint32 j = 0; j < m[i].numIndices; j++){ - int32 idx = m[i].indices[j]; - RGBA col; - RGBAf colf, color; - if(prelight) - convColor(&color, &prelight[idx]); - else{ - color.red = color.green = color.blue = 0.0f; - color.alpha = 1.0f; - } - color = add(color, ambLight); - if(normals) - for(int32 k = 0; k < numDirectionals; k++){ - float32 f = dot(normals[idx], neg(directionals[k].at)); - if(f <= 0.0f) continue; - colf = scale(directionals[k].color, f); - color = add(color, colf); - } - convColor(&colf, &m[i].material->color); - color = modulate(color, colf); - clamp(&color); - convColor(&col, &color); - im2dverts[idx].setColor(col.red, col.green, col.blue, col.alpha); - } - - rw::Texture *tex = m[i].material->texture; - if(tex && tex->raster){ - rw::SetRenderStatePtr(rw::TEXTURERASTER, tex->raster); - rw::SetRenderState(rw::TEXTUREADDRESSU, tex->getAddressU()); - rw::SetRenderState(rw::TEXTUREADDRESSV, tex->getAddressV()); - rw::SetRenderState(rw::TEXTUREFILTER, tex->getFilter()); - }else - rw::SetRenderStatePtr(rw::TEXTURERASTER, nil); - - im2d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST, - im2dverts, g->numVertices, m[i].indices, m[i].numIndices); - } - - rwFree(xvert); - rwFree(im2dverts); -} - -void -tlTest(Clump *clump) -{ - FORLIST(lnk, clump->atomics){ - Atomic *a = Atomic::fromClump(lnk); - drawAtomic(a); - } -} - -static RWDEVICE::Im2DVertex *clipverts; -static int32 numClipverts; - -void -genIm3DTransform(void *vertices, int32 numVertices, Matrix *world) -{ - using namespace RWDEVICE; - Im3DVertex *objverts; - V3d pos; - Matrix xform; - Camera *cam; - int32 i; - objverts = (Im3DVertex*)vertices; - - cam = (Camera*)engine->currentCamera; - int32 width = cam->frameBuffer->width; - int32 height = cam->frameBuffer->height; - - - xform = cam->viewMatrix; - if(world) - xform.transform(world, COMBINEPRECONCAT); - - clipverts = rwNewT(Im2DVertex, numVertices, MEMDUR_EVENT); - numClipverts = numVertices; - - for(i = 0; i < numVertices; i++){ - V3d::transformPoints(&pos, &objverts[i].position, 1, &xform); - - float32 recipZ = 1.0f/pos.z; - RGBA c = objverts[i].getColor(); - - clipverts[i].setScreenX(pos.x * recipZ * width); - clipverts[i].setScreenY((pos.y * recipZ * height)); - clipverts[i].setScreenZ(recipZ * cam->zScale + cam->zShift); - clipverts[i].setCameraZ(pos.z); - clipverts[i].setRecipCameraZ(recipZ); - clipverts[i].setColor(c.red, c.green, c.blue, c.alpha); - clipverts[i].setU(objverts[i].u, recipZ); - clipverts[i].setV(objverts[i].v, recipZ); - } -} - -void -genIm3DRenderIndexed(PrimitiveType prim, void *indices, int32 numIndices) -{ - im2d::RenderIndexedPrimitive(prim, clipverts, numClipverts, indices, numIndices); -} - -void -genIm3DEnd(void) -{ - rwFree(clipverts); - clipverts = nil; - numClipverts = 0; -} diff --git a/tools/clumpview/tl_tests.cpp b/tools/clumpview/tl_tests.cpp new file mode 100644 index 0000000..cbcf83b --- /dev/null +++ b/tools/clumpview/tl_tests.cpp @@ -0,0 +1,661 @@ +#include +#include + +extern bool dosoftras; + +using namespace rw; +using namespace RWDEVICE; + +// +// This is a test to implement T&L in software and render with Im2D +// + +namespace gen { + +#define MAX_LIGHTS 8 + +struct Directional { + V3d at; + RGBAf color; +}; +static Directional directionals[MAX_LIGHTS]; +static int32 numDirectionals; +static RGBAf ambLight; + +static void +enumLights(Matrix *lightmat) +{ + int32 n; + World *world; + + world = (World*)engine->currentWorld; + ambLight.red = 0.0; + ambLight.green = 0.0; + ambLight.blue = 0.0; + ambLight.alpha = 0.0; + numDirectionals = 0; + // only unpositioned lights right now + FORLIST(lnk, world->directionalLights){ + Light *l = Light::fromWorld(lnk); + if(l->getType() == Light::DIRECTIONAL){ + if(numDirectionals >= MAX_LIGHTS) + continue; + n = numDirectionals++; + V3d::transformVectors(&directionals[n].at, &l->getFrame()->getLTM()->at, 1, lightmat); + directionals[n].color = l->color; + directionals[n].color.alpha = 0.0f; + }else if(l->getType() == Light::AMBIENT){ + ambLight.red += l->color.red; + ambLight.green += l->color.green; + ambLight.blue += l->color.blue; + } + } +} + +struct ObjSpace3DVertex +{ + V3d objVertex; + V3d objNormal; + RGBA color; + TexCoords texCoords; +}; + +enum { + CLIPXLO = 0x01, + CLIPXHI = 0x02, + CLIPX = 0x03, + CLIPYLO = 0x04, + CLIPYHI = 0x08, + CLIPY = 0x0C, + CLIPZLO = 0x10, + CLIPZHI = 0x20, + CLIPZ = 0x30, +}; + +struct CamSpace3DVertex +{ + V3d camVertex; + uint8 clipFlags; + RGBAf color; + TexCoords texCoords; +}; + +struct InstanceData +{ + uint16 *indices; + int32 numIndices; + ObjSpace3DVertex *vertices; + int32 numVertices; + // int vertStride; // not really needed right now + Material *material; + Mesh *mesh; +}; + +struct InstanceDataHeader : public rw::InstanceDataHeader +{ + uint32 serialNumber; + ObjSpace3DVertex *vertices; + uint16 *indices; + InstanceData *inst; +}; + +static void +instanceAtomic(Atomic *atomic) +{ + static V3d zeroNorm = { 0.0f, 0.0f, 0.0f }; + static RGBA black = { 0, 0, 0, 255 }; + static TexCoords zeroTex = { 0.0f, 0.0f }; + int i; + uint j; + int x, x1, x2, x3; + Geometry *geo; + MeshHeader *header; + Mesh *mesh; + InstanceDataHeader *insthead; + InstanceData *inst; + uint32 firstVert; + uint16 *srcindices, *dstindices; + + geo = atomic->geometry; + if(geo->instData) + return; + header = geo->meshHeader; + int numTris; + if(header->flags & MeshHeader::TRISTRIP) + numTris = header->totalIndices - 2*header->numMeshes; + else + numTris = header->totalIndices / 3; + int size; + size = sizeof(InstanceDataHeader) + header->numMeshes*sizeof(InstanceData) + + geo->numVertices*sizeof(ObjSpace3DVertex) + numTris*6*sizeof(uint16); + insthead = (InstanceDataHeader*)rwNew(size, ID_GEOMETRY); + geo->instData = insthead; + insthead->platform = 0; + insthead->serialNumber = header->serialNum; + inst = (InstanceData*)(insthead+1); + insthead->inst = inst; + insthead->vertices = (ObjSpace3DVertex*)(inst+header->numMeshes); + dstindices = (uint16*)(insthead->vertices+geo->numVertices); + insthead->indices = dstindices; + + // TODO: morphing + MorphTarget *mt = geo->morphTargets; + for(i = 0; i < geo->numVertices; i++){ + insthead->vertices[i].objVertex = mt->vertices[i]; + if(geo->flags & Geometry::NORMALS) + insthead->vertices[i].objNormal = mt->normals[i]; + else + insthead->vertices[i].objNormal = zeroNorm; + if(geo->flags & Geometry::PRELIT) + insthead->vertices[i].color = geo->colors[i]; + else + insthead->vertices[i].color = black; + if(geo->numTexCoordSets > 0) + insthead->vertices[i].texCoords = geo->texCoords[0][i]; + else + insthead->vertices[i].texCoords = zeroTex; + } + + mesh = header->getMeshes(); + for(i = 0; i < header->numMeshes; i++){ + findMinVertAndNumVertices(mesh->indices, mesh->numIndices, + &firstVert, &inst->numVertices); + inst->indices = dstindices; + inst->vertices = &insthead->vertices[firstVert]; + inst->mesh = mesh; + inst->material = mesh->material; + srcindices = mesh->indices; + if(header->flags & MeshHeader::TRISTRIP){ + inst->numIndices = 0; + x = 0; + for(j = 0; j < mesh->numIndices-2; j++){ + x1 = srcindices[j+x]; + x ^= 1; + x2 = srcindices[j+x]; + x3 = srcindices[j+2]; + if(x1 != x2 && x2 != x3 && x1 != x3){ + dstindices[0] = x1; + dstindices[1] = x2; + dstindices[2] = x3; + dstindices += 3; + inst->numIndices += 3; + } + } + }else{ + inst->numIndices = mesh->numIndices; + for(j = 0; j < mesh->numIndices; j += 3){ + dstindices[0] = srcindices[j+0] - firstVert; + dstindices[1] = srcindices[j+1] - firstVert; + dstindices[2] = srcindices[j+2] - firstVert; + dstindices += 3; + } + } + + inst++; + mesh++; + } +} + +struct MeshState +{ + int32 flags; + Matrix obj2cam; + Matrix obj2world; + int32 numVertices; + int32 numPrimitives; + SurfaceProperties surfProps; + RGBA matCol; +}; + +static void +cam2screen(Im2DVertex *scrvert, CamSpace3DVertex *camvert) +{ + RGBA col; + float32 recipZ; + Camera *cam = (Camera*)engine->currentCamera; + int32 width = cam->frameBuffer->width; + int32 height = cam->frameBuffer->height; + recipZ = 1.0f/camvert->camVertex.z; + + scrvert->setScreenX(camvert->camVertex.x * recipZ * width); + scrvert->setScreenY(camvert->camVertex.y * recipZ * height); +// scrvert->setScreenX(camvert->camVertex.x * recipZ * width/2 + width/4); +// scrvert->setScreenY(camvert->camVertex.y * recipZ * height/2 + height/4); + scrvert->setScreenZ(recipZ * cam->zScale + cam->zShift); + scrvert->setCameraZ(camvert->camVertex.z); + scrvert->setRecipCameraZ(recipZ); + scrvert->setU(camvert->texCoords.u, recipZ); + scrvert->setV(camvert->texCoords.v, recipZ); + convColor(&col, &camvert->color); + scrvert->setColor(col.red, col.green, col.blue, col.alpha); +} + +static void +transform(MeshState *mstate, ObjSpace3DVertex *objverts, CamSpace3DVertex *camverts, Im2DVertex *scrverts) +{ + int32 i; + float32 z; + Camera *cam = (Camera*)engine->currentCamera; + + for(i = 0; i < mstate->numVertices; i++){ + V3d::transformPoints(&camverts[i].camVertex, &objverts[i].objVertex, 1, &mstate->obj2cam); + convColor(&camverts[i].color, &objverts[i].color); + camverts[i].texCoords = objverts[i].texCoords; + + camverts[i].clipFlags = 0; + z = camverts[i].camVertex.z; + // 0 < x < z + if(camverts[i].camVertex.x >= z) camverts[i].clipFlags |= CLIPXHI; + if(camverts[i].camVertex.x <= 0) camverts[i].clipFlags |= CLIPXLO; + // 0 < y < z + if(camverts[i].camVertex.y >= z) camverts[i].clipFlags |= CLIPYHI; + if(camverts[i].camVertex.y <= 0) camverts[i].clipFlags |= CLIPYLO; + // near < z < far + if(z >= cam->farPlane) camverts[i].clipFlags |= CLIPZHI; + if(z <= cam->nearPlane) camverts[i].clipFlags |= CLIPZLO; + + cam2screen(&scrverts[i], &camverts[i]); + } +} + +static void +light(MeshState *mstate, ObjSpace3DVertex *objverts, CamSpace3DVertex *camverts) +{ + int32 i; + RGBAf colf; + RGBAf amb = ambLight; + amb = scale(ambLight, mstate->surfProps.ambient); + for(i = 0; i < mstate->numVertices; i++){ + camverts[i].color = add(camverts[i].color, amb); + if((mstate->flags & Geometry::NORMALS) == 0) + continue; + for(int32 k = 0; k < numDirectionals; k++){ + float32 f = dot(objverts[i].objNormal, neg(directionals[k].at)); + if(f <= 0.0f) continue; + f *= mstate->surfProps.diffuse; + colf = scale(directionals[k].color, f); + camverts[i].color = add(camverts[i].color, colf); + } + } +} + +static void +postlight(MeshState *mstate, CamSpace3DVertex *camverts, Im2DVertex *scrverts) +{ + int32 i; + RGBA col; + RGBAf colf; + for(i = 0; i < mstate->numVertices; i++){ + convColor(&colf, &mstate->matCol); + camverts[i].color = modulate(camverts[i].color, colf); + clamp(&camverts[i].color); + convColor(&col, &camverts[i].color); + scrverts[i].setColor(col.red, col.green, col.blue, col.alpha); + } +} + +static int32 +cullTriangles(MeshState *mstate, CamSpace3DVertex *camverts, uint16 *indices, uint16 *clipindices) +{ + int32 i; + int32 x1, x2, x3; + int32 newNumPrims; + int32 numClip; + + newNumPrims = 0; + numClip = 0; + for(i = 0; i < mstate->numPrimitives; i++, indices += 3){ + x1 = indices[0]; + x2 = indices[1]; + x3 = indices[2]; + // Only a simple frustum call + if(camverts[x1].clipFlags & + camverts[x2].clipFlags & + camverts[x3].clipFlags) + continue; + if(camverts[x1].clipFlags | + camverts[x2].clipFlags | + camverts[x3].clipFlags) + numClip++; + // The Triangle is in, probably + clipindices[0] = x1; + clipindices[1] = x2; + clipindices[2] = x3; + clipindices += 3; + newNumPrims++; + } + mstate->numPrimitives = newNumPrims; + return numClip; +} + +static void +interpVertex(CamSpace3DVertex *out, CamSpace3DVertex *v1, CamSpace3DVertex *v2, float32 t) +{ + float32 z; + float32 invt; + Camera *cam = (Camera*)engine->currentCamera; + + invt = 1.0f - t; + out->camVertex = add(scale(v1->camVertex, invt), scale(v2->camVertex, t)); + out->color = add(scale(v1->color, invt), scale(v2->color, t)); + out->texCoords.u = v1->texCoords.u*invt + v2->texCoords.u*t; + out->texCoords.v = v1->texCoords.v*invt + v2->texCoords.v*t; + + out->clipFlags = 0; + z = out->camVertex.z; + // 0 < x < z + if(out->camVertex.x >= z) out->clipFlags |= CLIPXHI; + if(out->camVertex.x <= 0) out->clipFlags |= CLIPXLO; + // 0 < y < z + if(out->camVertex.y >= z) out->clipFlags |= CLIPYHI; + if(out->camVertex.y <= 0) out->clipFlags |= CLIPYLO; + // near < z < far + if(z >= cam->farPlane) out->clipFlags |= CLIPZHI; + if(z <= cam->nearPlane) out->clipFlags |= CLIPZLO; +} + +static void +clipTriangles(MeshState *mstate, CamSpace3DVertex *camverts, Im2DVertex *scrverts, uint16 *indices, uint16 *clipindices) +{ + int32 i, j; + int32 x1, x2, x3; + int32 newNumPrims; + CamSpace3DVertex buf[18]; + CamSpace3DVertex *in, *out, *tmp; + int32 nin, nout; + float32 t; + Camera *cam = (Camera*)engine->currentCamera; + + newNumPrims = 0; + for(i = 0; i < mstate->numPrimitives; i++, indices += 3){ + x1 = indices[0]; + x2 = indices[1]; + x3 = indices[2]; + + if((camverts[x1].clipFlags | + camverts[x2].clipFlags | + camverts[x3].clipFlags) == 0){ + // all inside + clipindices[0] = x1; + clipindices[1] = x2; + clipindices[2] = x3; + clipindices += 3; + newNumPrims++; + continue; + } + + // set up triangle + in = &buf[0]; + out = &buf[9]; + in[0] = camverts[x1]; + in[1] = camverts[x2]; + in[2] = camverts[x3]; + nin = 3; + nout = 0; + +#define V(a) in[a].camVertex. + + // clip z near + for(j = 0; j < nin; j++){ + x1 = j; + x2 = (j+1) % nin; + if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPZLO){ + t = (cam->nearPlane - V(x1)z)/(V(x2)z - V(x1)z); + interpVertex(&out[nout++], &in[x1], &in[x2], t); + } + if((in[x2].clipFlags & CLIPZLO) == 0) + out[nout++] = in[x2]; + } + // clip z far + nin = nout; nout = 0; + tmp = in; in = out; out = tmp; + for(j = 0; j < nin; j++){ + x1 = j; + x2 = (j+1) % nin; + if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPZHI){ + t = (cam->farPlane - V(x1)z)/(V(x2)z - V(x1)z); + interpVertex(&out[nout++], &in[x1], &in[x2], t); + } + if((in[x2].clipFlags & CLIPZHI) == 0) + out[nout++] = in[x2]; + } + // clip y 0 + nin = nout; nout = 0; + tmp = in; in = out; out = tmp; + for(j = 0; j < nin; j++){ + x1 = j; + x2 = (j+1) % nin; + if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPYLO){ + t = -V(x1)y/(V(x2)y - V(x1)y); + interpVertex(&out[nout++], &in[x1], &in[x2], t); + } + if((in[x2].clipFlags & CLIPYLO) == 0) + out[nout++] = in[x2]; + } + // clip y z + nin = nout; nout = 0; + tmp = in; in = out; out = tmp; + for(j = 0; j < nin; j++){ + x1 = j; + x2 = (j+1) % nin; + if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPYHI){ + t = (V(x1)z - V(x1)y)/(V(x1)z - V(x1)y + V(x2)y - V(x2)z); + interpVertex(&out[nout++], &in[x1], &in[x2], t); + } + if((in[x2].clipFlags & CLIPYHI) == 0) + out[nout++] = in[x2]; + } + // clip x 0 + nin = nout; nout = 0; + tmp = in; in = out; out = tmp; + for(j = 0; j < nin; j++){ + x1 = j; + x2 = (j+1) % nin; + if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPXLO){ + t = -V(x1)x/(V(x2)x - V(x1)x); + interpVertex(&out[nout++], &in[x1], &in[x2], t); + } + if((in[x2].clipFlags & CLIPXLO) == 0) + out[nout++] = in[x2]; + } + // clip x z + nin = nout; nout = 0; + tmp = in; in = out; out = tmp; + for(j = 0; j < nin; j++){ + x1 = j; + x2 = (j+1) % nin; + if((in[x1].clipFlags ^ in[x2].clipFlags) & CLIPXHI){ + t = (V(x1)z - V(x1)x)/(V(x1)z - V(x1)x + V(x2)x - V(x2)z); + interpVertex(&out[nout++], &in[x1], &in[x2], t); + } + if((in[x2].clipFlags & CLIPXHI) == 0) + out[nout++] = in[x2]; + } + + // Insert new triangles + x1 = mstate->numVertices; + for(j = 0; j < nout; j++){ + x2 = mstate->numVertices++; + camverts[x2] = out[j]; + cam2screen(&scrverts[x2], &camverts[x2]); + } + x2 = x1+1; + for(j = 0; j < nout-2; j++){ + clipindices[0] = x1; + clipindices[1] = x2++; + clipindices[2] = x2; + clipindices += 3; + newNumPrims++; + } + } + mstate->numPrimitives = newNumPrims; +} + +static void +submitTriangles(RWDEVICE::Im2DVertex *scrverts, int32 numVerts, uint16 *indices, int32 numTris) +{ +void rastest_renderTriangles(RWDEVICE::Im2DVertex *scrverts, int32 verts, uint16 *indices, int32 numTris); + rw::SetRenderStatePtr(rw::TEXTURERASTER, nil); + if(dosoftras) + rastest_renderTriangles(scrverts, numVerts, indices, numTris); + else{ + //int i; + //for(i = 0; i < numVerts; i++){ + // scrverts[i].x = (int)(scrverts[i].x*16.0f) / 16.0f; + // scrverts[i].y = (int)(scrverts[i].y*16.0f) / 16.0f; + //} + im2d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST, scrverts, numVerts, + indices, numTris*3); + } +} + + +static void +drawMesh(MeshState *mstate, ObjSpace3DVertex *objverts, uint16 *indices) +{ + CamSpace3DVertex *camverts; + Im2DVertex *scrverts; + uint16 *cullindices, *clipindices; + uint32 numClip; + + camverts = rwNewT(CamSpace3DVertex, mstate->numVertices, MEMDUR_FUNCTION); + scrverts = rwNewT(Im2DVertex, mstate->numVertices, MEMDUR_FUNCTION); + cullindices = rwNewT(uint16, mstate->numPrimitives*3, MEMDUR_FUNCTION); + + transform(mstate, objverts, camverts, scrverts); + + numClip = cullTriangles(mstate, camverts, indices, cullindices); + +// int32 i; +// for(i = 0; i < mstate->numVertices; i++){ +// if(camverts[i].clipFlags & CLIPX) +// camverts[i].color.red = 255; +// if(camverts[i].clipFlags & CLIPY) +// camverts[i].color.green = 255; +// if(camverts[i].clipFlags & CLIPZ) +// camverts[i].color.blue = 255; +// } + + light(mstate, objverts, camverts); + +// mstate->matCol.red = 255; +// mstate->matCol.green = 255; +// mstate->matCol.blue = 255; + + postlight(mstate, camverts, scrverts); + + // each triangle can have a maximum of 9 vertices (7 triangles) after clipping + // so resize to whatever we may need + camverts = rwResizeT(CamSpace3DVertex, camverts, mstate->numVertices + numClip*9, MEMDUR_FUNCTION); + scrverts = rwResizeT(Im2DVertex, scrverts, mstate->numVertices + numClip*9, MEMDUR_FUNCTION); + clipindices = rwNewT(uint16, mstate->numPrimitives*3 + numClip*7*3, MEMDUR_FUNCTION); + + clipTriangles(mstate, camverts, scrverts, cullindices, clipindices); + + submitTriangles(scrverts, mstate->numVertices, clipindices, mstate->numPrimitives); + + rwFree(camverts); + rwFree(scrverts); + rwFree(cullindices); + rwFree(clipindices); +} + +static void +drawAtomic(Atomic *atomic) +{ + MeshState mstate; + Matrix lightmat; + Geometry *geo; + MeshHeader *header; + InstanceData *inst; + int i; + Camera *cam = (Camera*)engine->currentCamera; + + instanceAtomic(atomic); + + mstate.obj2world = *atomic->getFrame()->getLTM(); + mstate.obj2cam = mstate.obj2world; + mstate.obj2cam.transform(&cam->viewMatrix, COMBINEPOSTCONCAT); + Matrix::invert(&lightmat, &mstate.obj2world); + enumLights(&lightmat); + + geo = atomic->geometry; + header = geo->meshHeader; + inst = ((InstanceDataHeader*)geo->instData)->inst; + for(i = 0; i < header->numMeshes; i++){ + mstate.flags = geo->flags; + mstate.numVertices = inst->numVertices; + mstate.numPrimitives = inst->numIndices / 3; + mstate.surfProps = inst->material->surfaceProps; + mstate.matCol = inst->material->color; + drawMesh(&mstate, inst->vertices, inst->indices); + inst++; + } +} + +void +tlTest(Clump *clump) +{ + FORLIST(lnk, clump->atomics){ + Atomic *a = Atomic::fromClump(lnk); + drawAtomic(a); + } +} + +} + +static Im2DVertex *clipverts; +static int32 numClipverts; + +void +genIm3DTransform(void *vertices, int32 numVertices, Matrix *world) +{ + Im3DVertex *objverts; + V3d pos; + Matrix xform; + Camera *cam; + int32 i; + objverts = (Im3DVertex*)vertices; + + cam = (Camera*)engine->currentCamera; + int32 width = cam->frameBuffer->width; + int32 height = cam->frameBuffer->height; + + + xform = cam->viewMatrix; + if(world) + xform.transform(world, COMBINEPRECONCAT); + + clipverts = rwNewT(Im2DVertex, numVertices, MEMDUR_EVENT); + numClipverts = numVertices; + + for(i = 0; i < numVertices; i++){ + V3d::transformPoints(&pos, &objverts[i].position, 1, &xform); + + float32 recipZ = 1.0f/pos.z; + RGBA c = objverts[i].getColor(); + + clipverts[i].setScreenX(pos.x * recipZ * width); + clipverts[i].setScreenY(pos.y * recipZ * height); + clipverts[i].setScreenZ(recipZ * cam->zScale + cam->zShift); + clipverts[i].setCameraZ(pos.z); + clipverts[i].setRecipCameraZ(recipZ); + clipverts[i].setColor(c.red, c.green, c.blue, c.alpha); + clipverts[i].setU(objverts[i].u, recipZ); + clipverts[i].setV(objverts[i].v, recipZ); + } +} + +void +genIm3DRenderIndexed(PrimitiveType prim, void *indices, int32 numIndices) +{ + im2d::RenderIndexedPrimitive(prim, clipverts, numClipverts, indices, numIndices); +} + +void +genIm3DEnd(void) +{ + rwFree(clipverts); + clipverts = nil; + numClipverts = 0; +}