#include "ls3d.h" #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) PointF::PointF() { x = y = z = 0.0; } PointF::PointF(float x, float y, float z) { this->x = x; this->y = y; this->z = z; } PointF operator+(const PointF& p1, const PointF& p2) { PointF r(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z); return r; } PointP::PointP() { x = y = 0; z = 0.0; } VectorF::VectorF() { } VectorF::VectorF(float i, float j, float k) { this->i = i; this->j = j; this->k = k; } float VectorF::Length() { return sqrt(i * i + j * j + k * k); } void VectorF::Normalize() { if (i != 0.0 || j != 0.0 || k != 0.0) { float factor = 1.0 / Length(); i *= factor; j *= factor; k *= factor; } } Camera *ThreeDRenderer::CreateCamera() { Camera *cam; cam = new Camera(); //entities.push_back(cam); return cam; } Model *ThreeDRenderer::CreateModel(Mesh *mesh) { Model *mdl; mdl = new Model(mesh); models.push_back(mdl); return mdl; } void waitstop(SDL_Surface *surf) { bool go = true; if (SDL_MUSTLOCK(surf)) { SDL_UnlockSurface(surf); } SDL_UpdateRect(surf, 0, 0, 640, 480); while (go) { SDL_Event event; SDL_WaitEvent(&event); switch (event.type) { case SDL_KEYDOWN: go = false; } } if (SDL_MUSTLOCK(surf)) { SDL_LockSurface(surf); } } ThreeDRenderer::ThreeDRenderer() { backfaceCulling = false; zbuffer = new float[640 * 480]; } void ThreeDRenderer::Render(SDL_Surface *surf, Camera *cam) { int width, height; int hwidth, hheight; Vertex *temp; Triangle *tri; Vertex **v; Model *mdl; Mesh *mesh; Vertex *vert; float sinrx, cosrx, sinry, cosry, sinrz, cosrz; float factor; PointF rpos; int y; // draw Uint8 *dp; // draw line pointer float *zbp; // z buffer pointer int dy, dx, dex; // drawx, drawy, draw endx float x1, x2, xs1, xs2; // xstep1, xstep2 float z1, z2, zs1, zs2; // zstep1, zstep2 float dz, dzs; // draw zstep float t, h, ph; // temp, height, partial height float light; int cr, cg, cb; // color components int color; // final color float nx, ny, nz; // new x, new y, new z VectorF viewVector(0.0, 0.0, 1.0); width = surf->w; height = surf->h; hwidth = width / 2; hheight = height / 2; float *p = zbuffer; for (int i = 0; i < width * height; i++, p++) { *p = (float)(1 << 16); } for (std::vector::iterator mdl_iter = models.begin(); mdl_iter != models.end(); mdl_iter++) { mdl = *mdl_iter; mesh = mdl->mesh; sinrx = sin(mdl->rotx); cosrx = cos(mdl->rotx); sinry = sin(mdl->roty); cosry = cos(mdl->roty); sinrz = sin(mdl->rotz); cosrz = cos(mdl->rotz); for (std::vector::iterator vert_iter = mesh->vertexes.begin(); vert_iter != mesh->vertexes.end(); vert_iter++) { PointF rpos; vert = *vert_iter; rpos.x = vert->pos.x; rpos.y = vert->pos.y; rpos.z = vert->pos.z; // X AXIS ny = (rpos.y * cosrx) - (rpos.z * sinrx); nz = (rpos.z * cosrx) + (rpos.y * sinrx); rpos.y = ny; rpos.z = nz; // Y AXIS nz = (rpos.z * cosry) - (rpos.x * sinry); nx = (rpos.x * cosry) + (rpos.z * sinry); rpos.z = nz; rpos.x = nx; // Z AXIS nx = (rpos.x * cosrz) - (rpos.y * sinrz); ny = (rpos.y * cosrz) + (rpos.x * sinrz); rpos.x = nx; rpos.y = ny; // Scale rpos.x *= mdl->scalex; rpos.y *= mdl->scaley; rpos.z *= mdl->scalez; // Translate rpos.x += mdl->pos.x; rpos.y += mdl->pos.y; rpos.z += mdl->pos.z; // Project if (rpos.z == 0.0) { factor = (float)10; // some big value } else { factor = UNIT_PIX_DISTANCE / rpos.z; } vert->ppos.x = hwidth + (int)(rpos.x * factor); vert->ppos.y = hheight - (int)(rpos.y * factor); vert->ppos.z = rpos.z; vert->rpos = rpos; //DrawVertex(surf, *vert_iter); } for (std::vector::iterator tri_iter = mesh->triangles.begin(); tri_iter != mesh->triangles.end(); tri_iter++) { tri = *tri_iter; // ROTATE NORMAL // X AXIS tri->rnormal = tri->normal; ny = (tri->rnormal.j * cosrx) - (tri->rnormal.k * sinrx); nz = (tri->rnormal.k * cosrx) + (tri->rnormal.j * sinrx); tri->rnormal.j = ny; tri->rnormal.k = nz; // Y AXIS nz = (tri->rnormal.k * cosry) - (tri->rnormal.i * sinry); nx = (tri->rnormal.i * cosry) + (tri->rnormal.k * sinry); tri->rnormal.k = nz; tri->rnormal.i = nx; // Z AXIS nx = (tri->rnormal.i * cosrz) - (tri->rnormal.j * sinrz); ny = (tri->rnormal.j * cosrz) + (tri->rnormal.i * sinrz); tri->rnormal.i = nx; tri->rnormal.j = ny; } for (std::vector::iterator tri_iter = mesh->triangles.begin(); tri_iter != mesh->triangles.end(); tri_iter++) { tri = *tri_iter; v = tri->verts; if (v[0]->ppos.z < 0.0 && v[1]->ppos.z < 0.0 && v[2]->ppos.z < 0.0) { continue; } /*VectorF v1(v[2]->rpos.x - v[0]->rpos.x, v[2]->rpos.y - v[0]->rpos.y, v[2]->rpos.z - v[0]->rpos.z); VectorF v2(v[1]->rpos.x - v[0]->rpos.x, v[1]->rpos.y - v[0]->rpos.y, v[1]->rpos.z - v[0]->rpos.z); VectorF normal(v1.j * v2.k - v1.k * v2.j, v1.k * v2.i - v1.i * v2.k, v1.i * v2.j - v1.j * v2.i);*/ light = viewVector.i * tri->rnormal.i + viewVector.j * tri->rnormal.j + viewVector.k * tri->rnormal.k; if (backfaceCulling && light < 0.0) { continue; } light = fabs(light) * 0.05 + 0.3; if (v[1]->ppos.y > v[2]->ppos.y) { temp = v[1]; v[1] = v[2]; v[2] = temp; } if (v[0]->ppos.y > v[2]->ppos.y) { temp = v[0]; v[0] = v[2]; v[2] = temp; } if (v[0]->ppos.y > v[1]->ppos.y) { temp = v[0]; v[0] = v[1]; v[1] = temp; } if (v[0]->ppos.y == v[2]->ppos.y) { continue; } //std::cout << "RENDER" << std::endl; y = v[0]->ppos.y; //std::cout << y << " -> " << v[2]->ppos.y << std::endl; x1 = x2 = (float)v[0]->ppos.x; z1 = z2 = v[0]->ppos.z; h = (float)(v[2]->ppos.y - v[0]->ppos.y); //if (h == 0.0) { //std::cout << ":E" << std::endl; // continue; //} // X STEPS ph = max((float)(v[1]->ppos.y - v[0]->ppos.y), 1); t = (float)(v[2]->ppos.x - v[0]->ppos.x); if (t == 0.0) { xs1 = 0.0; } else { xs1 = t / h; } t = (float)(v[1]->ppos.x - v[0]->ppos.x); if (t == 0.0) { xs2 = 0.0; } else { xs2 = t / ph; } // Z STEPS t = (float)(v[2]->ppos.z - v[0]->ppos.z); if (t == 0) { zs1 = 0.0; } else { zs1 = t / h; } t = (float)(v[1]->ppos.z - v[0]->ppos.z); if (t == 0) { zs2 = 0.0; } else { zs2 = t / ph; } cr = (tri->color >> 16) & 0xFF; cg = (tri->color >> 8) & 0xFF; cb = tri->color & 0xFF; cr = min((int)(cr * light), 255); cg = min((int)(cg * light), 255); cb = min((int)(cb * light), 255); color = (cr << 16) | (cg << 8) | cb; //std::cout << xs1 << xs2 << std::endl; //std::cout << v[0]->ppos.y << ", " << v[2]->ppos.y << std::endl; for (y = v[0]->ppos.y; y <= v[2]->ppos.y; ++y) { //std::cout << y << " "; if (y == v[1]->ppos.y) { x2 = (float)v[1]->ppos.x; z2 = (float)v[1]->ppos.z; ph = (float)(v[2]->ppos.y - v[1]->ppos.y); t = (float)(v[2]->ppos.x - v[1]->ppos.x); if (t == 0) { xs2 = 0.0; } else { xs2 = t / ph; } //std::cout << xs2 << std::endl; t = (float)(v[2]->ppos.z - v[1]->ppos.z); if (t == 0) { zs2 = 0.0; } else { zs2 = t / ph; } //waitstop(surf); } if ((int)x1 != (int)x2 && y >= 0 && y < height) { if (x1 < x2) { //dx = max((int)x1, 0); dx = (int)x1; dex = (int)x2; dz = z1; dzs = (z2 - z1) / (dex - dx); if (x1 < 0.0) { dz += -x1 * dzs; } } else { //dx = max((int)x2, 0); dx = (int)x2; dex = (int)x1; dz = z2; dzs = (z1 - z2) / (dex - dx); if (x2 < 0.0) { dz += -x2 * dzs; } } dx = max(dx, 0); dex = min(dex, width - 1); zbp = zbuffer + y * width + dx; dp = ((Uint8 *)surf->pixels) + y * surf->pitch + (dx * 4); dx = dex - dx; //std::cout << dx << std::endl; for (; (dx--) > 0; dp += 4, ++zbp) { if (dzs < 0.0 && dz < 0.0) { break; } if (dz > 0.0 && *zbp > dz) { //*(Uint32 *)dp = (mdl->color != -1 ? mdl->color : tri->color); *zbp = dz; *(Uint32 *)dp = color; } dz += dzs; } } x1 += xs1; x2 += xs2; z1 += zs1; z2 += zs2; } //waitstop(surf); } } //delete [] zbuffer; } void ThreeDRenderer::DrawVertex(SDL_Surface *surf, Vertex *v) { int color = 0x00FFFFFF; //td::cout << (int)surf->format->BytesPerPixel << std::endl; if (v->ppos.x >= 0 && v->ppos.y >= 0 && v->ppos.x < surf->w && v->ppos.y < surf->h) { *(Uint32 *)(((Uint8 *)surf->pixels) + v->ppos.y * surf->pitch + v->ppos.x * 4) = color; } } Entity::Entity() { rotx = roty = rotz = 0.0; } Model::Model(Mesh *mesh) { this->mesh = mesh; scalex = scaley = scalez = 1.0; } Vertex *Mesh::AddVertex(PointF p) { Vertex *v; v = new Vertex(p); vertexes.push_back(v); return v; } Vertex *Mesh::AddVertex(float x, float y, float z) { PointF p(x, y, z); return AddVertex(p); } Triangle *Mesh::AddTriangle(Vertex *v1, Vertex *v2, Vertex *v3, Uint32 color) { Triangle *tri; tri = new Triangle(v1, v2, v3); tri->color = color; triangles.push_back(tri); return tri; } void Mesh::UpdateNormals() { for (std::vector::iterator tri_iter = triangles.begin(); tri_iter != triangles.end(); tri_iter++) { (*tri_iter)->UpdateNormal(); } } #ifdef DEBUG void Mesh::DebugDump() { std::vector::const_iterator vert_iter; std::vector::const_iterator tri_iter; int i; std::cout << "Vertexes:" << std::endl; for (i = 0, vert_iter = vertexes.begin(); vert_iter != vertexes.end(); i++, vert_iter++) { std::cout << i << ": (" << (*vert_iter)->pos.x << ", " << (*vert_iter)->pos.y << ", " << (*vert_iter)->pos.z << ")" << std::endl; } } #endif Vertex::Vertex(PointF p) { this->pos = p; } Triangle::Triangle(Vertex *v1, Vertex *v2, Vertex *v3) { this->verts[0] = v1; this->verts[1] = v2; this->verts[2] = v3; } void Triangle::UpdateNormal() { VectorF v1(verts[2]->pos.x - verts[0]->pos.x, verts[2]->pos.y - verts[0]->pos.y, verts[2]->pos.z - verts[0]->pos.z); VectorF v2(verts[1]->pos.x - verts[0]->pos.x, verts[1]->pos.y - verts[0]->pos.y, verts[1]->pos.z - verts[0]->pos.z); VectorF n(v1.j * v2.k - v1.k * v2.j, v1.k * v2.i - v1.i * v2.k, v1.i * v2.j - v1.j * v2.i); normal = n; }