summaryrefslogtreecommitdiff
path: root/tools/playground/tl_tests.cpp
diff options
context:
space:
mode:
authorclaude-bot <[email protected]>2026-07-13 12:40:03 +0000
committerclaude-bot <[email protected]>2026-07-13 12:40:03 +0000
commit847962910f0bff071f3bf07c9abb87764fb6cac3 (patch)
treeddcd429e134c7fd5f72ddc97ced175de8d66fcd0 /tools/playground/tl_tests.cpp
downloadlibrw-847962910f0bff071f3bf07c9abb87764fb6cac3.tar.gz
librw-847962910f0bff071f3bf07c9abb87764fb6cac3.zip
Import aap/librw @ masterHEADmaster
Snapshot for re3/reVC vendoring, per @lzcnt. Source: https://github.com/aap/librw (master).
Diffstat (limited to 'tools/playground/tl_tests.cpp')
-rw-r--r--tools/playground/tl_tests.cpp766
1 files changed, 766 insertions, 0 deletions
diff --git a/tools/playground/tl_tests.cpp b/tools/playground/tl_tests.cpp
new file mode 100644
index 0000000..7cfc59a
--- /dev/null
+++ b/tools/playground/tl_tests.cpp
@@ -0,0 +1,766 @@
+#include <rw.h>
+#include <skeleton.h>
+
+extern bool dosoftras;
+
+using namespace rw;
+using namespace RWDEVICE;
+
+void rastest_renderTriangles(RWDEVICE::Im2DVertex *scrverts, int32 verts, uint16 *indices, int32 numTris);
+
+//
+// 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->globalLights){
+ 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 int32
+clipPoly(CamSpace3DVertex *in, int32 nin, CamSpace3DVertex *out, Plane *plane)
+{
+ int32 j;
+ int32 nout;
+ int32 x1, x2;
+ float32 d1, d2, t;
+
+ nout = 0;
+ for(j = 0; j < nin; j++){
+ x1 = j;
+ x2 = (j+1) % nin;
+
+ d1 = dot(plane->normal, in[x1].camVertex) + plane->distance;
+ d2 = dot(plane->normal, in[x2].camVertex) + plane->distance;
+ if(d1*d2 < 0.0f){
+ t = d1/(d1 - d2);
+ interpVertex(&out[nout++], &in[x1], &in[x2], t);
+ }
+ if(d2 >= 0.0f)
+ out[nout++] = in[x2];
+ }
+ return nout;
+}
+
+static void
+clipTriangles2(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;
+ int32 nout;
+ Camera *cam = (Camera*)engine->currentCamera;
+
+ Plane planes[6] = {
+ { { 0.0f, 0.0f, 1.0f }, -cam->nearPlane }, // z = near
+ { { 0.0f, 0.0f, -1.0f }, cam->farPlane }, // z = far
+
+ { { -1.0f, 0.0f, 1.0f }, 0.0f }, // x = w
+// { { 1.0f, 0.0f, 1.0f }, 0.0f }, // x = -w
+ { { 1.0f, 0.0f, 0.0f }, 0.0f }, // x = 0
+
+ { { 0.0f, -1.0f, 1.0f }, 0.0f }, // y = w
+// { { 0.0f, 1.0f, 1.0f }, 0.0f } // y = -1
+ { { 0.0f, 1.0f, 0.0f }, 0.0f } // y = 0
+ };
+
+ 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];
+ nout = 0;
+
+ // clip here
+ if(nout = clipPoly(in, 3, out, &planes[0]), nout == 0) continue;
+ if(nout = clipPoly(out, nout, in, &planes[1]), nout == 0) continue;
+ if(nout = clipPoly(in, nout, out, &planes[2]), nout == 0) continue;
+ if(nout = clipPoly(out, nout, in, &planes[3]), nout == 0) continue;
+ if(nout = clipPoly(in, nout, out, &planes[4]), nout == 0) continue;
+ if(nout = clipPoly(out, nout, in, &planes[5]), nout == 0) continue;
+ out = in;
+
+ // 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)
+{
+ 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);
+ clipTriangles2(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;
+}