absence_thelab
diff src/3deng/3dgeom.cpp @ 0:1cffe3409164
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 23 Oct 2014 01:46:07 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/3deng/3dgeom.cpp Thu Oct 23 01:46:07 2014 +0300 1.3 @@ -0,0 +1,478 @@ 1.4 +#include <cassert> 1.5 +#include "3dgeom.h" 1.6 +#include "3dengine.h" 1.7 + 1.8 +using std::vector; 1.9 + 1.10 +TexCoord::TexCoord(float u, float v) { 1.11 + this->u = u; 1.12 + this->v = v; 1.13 +} 1.14 + 1.15 +// Vertex class implementation 1.16 + 1.17 +Vertex::Vertex() { 1.18 + color = 0x00ffffff; 1.19 + memset(tex, 0, 4*sizeof(TexCoord)); 1.20 +} 1.21 + 1.22 +Vertex::Vertex(const Vector3 &position, float tu, float tv, dword color) { 1.23 + pos = position; 1.24 + tex[0].u = tex[1].u = tex[2].u = tex[3].u = tu; 1.25 + tex[0].v = tex[1].v = tex[2].v = tex[3].v = tv; 1.26 + this->color = color; 1.27 +} 1.28 + 1.29 +void Vertex::CalculateNormal(const Vertex *vbuffer, const Triangle *triangles, long trinum) { 1.30 + 1.31 + // find the position of the curent vertex in the vertex buffer 1.32 + dword index = (dword)(this - vbuffer); 1.33 + 1.34 + normal = Vector3(0, 0, 0); 1.35 + const Triangle *tri = triangles; 1.36 + for(int i=0; i<trinum; i++, tri++) { 1.37 + if(tri->vertices[0] == index || tri->vertices[1] == index || tri->vertices[2] == index) { 1.38 + normal += tri->normal; 1.39 + } 1.40 + } 1.41 + 1.42 + normal.Normalize(); 1.43 +} 1.44 + 1.45 +/////////// Edge class implementation /////////// 1.46 + 1.47 +Edge::Edge() { 1.48 + vertices[0] = vertices[1] = adjfaces[0] = adjfaces[1] = 0; 1.49 +} 1.50 + 1.51 +Edge::Edge(Index v1, Index v2, Index af1, Index af2) { 1.52 + vertices[0] = v1; 1.53 + vertices[1] = v2; 1.54 + adjfaces[0] = af1; 1.55 + adjfaces[1] = af2; 1.56 +} 1.57 + 1.58 +/////////// Triangle class implementation ///////////// 1.59 +Triangle::Triangle(Index v1, Index v2, Index v3) { 1.60 + vertices[0] = v1; 1.61 + vertices[1] = v2; 1.62 + vertices[2] = v3; 1.63 +} 1.64 + 1.65 +void Triangle::CalculateNormal(Vertex *vbuffer, bool normalize) { 1.66 + Vector3 v1 = vbuffer[vertices[1]].pos - vbuffer[vertices[0]].pos; 1.67 + Vector3 v2 = vbuffer[vertices[2]].pos - vbuffer[vertices[0]].pos; 1.68 + normal = v1.CrossProduct(v2); 1.69 + if(normalize) normal.Normalize(); 1.70 +} 1.71 + 1.72 + 1.73 +/////////////// Triangular Mesh implementation ///////////// 1.74 + 1.75 +TriMesh::TriMesh(byte LODLevels, GraphicsContext *gc) { 1.76 + memset(this, 0, sizeof(TriMesh)); 1.77 + this->gc = gc; 1.78 + Levels = LODLevels; 1.79 + 1.80 + varray = new Vertex*[Levels]; 1.81 + memset(varray, 0, Levels * sizeof(Vertex*)); 1.82 + 1.83 + triarray = new Triangle*[Levels]; 1.84 + memset(triarray, 0, Levels * sizeof(Triangle*)); 1.85 + 1.86 + vbuffer = new VertexBuffer*[Levels]; 1.87 + memset(vbuffer, 0, Levels * sizeof(VertexBuffer*)); 1.88 + 1.89 + ibuffer = new IndexBuffer*[Levels]; 1.90 + memset(ibuffer, 0, Levels * sizeof(IndexBuffer*)); 1.91 + 1.92 + AdjTriangles = new std::vector<dword>*[Levels]; 1.93 + memset(AdjTriangles, 0, Levels * sizeof(std::vector<dword>*)); 1.94 + 1.95 + VertexCount = new dword[Levels]; 1.96 + TriCount = new dword[Levels]; 1.97 + 1.98 + BuffersValid = new bool[Levels]; 1.99 + memset(BuffersValid, 0, Levels * sizeof(bool)); 1.100 + 1.101 + AdjValid = new bool[Levels]; 1.102 + memset(AdjValid, 0, Levels * sizeof(bool)); 1.103 +} 1.104 + 1.105 +TriMesh::TriMesh(const TriMesh &mesh) { 1.106 + 1.107 + memcpy(this, &mesh, sizeof(TriMesh)); 1.108 + 1.109 + BuffersValid = new bool[Levels]; 1.110 + memset(BuffersValid, 0, Levels * sizeof(bool)); 1.111 + 1.112 + varray = new Vertex*[Levels]; 1.113 + triarray = new Triangle*[Levels]; 1.114 + vbuffer = new VertexBuffer*[Levels]; 1.115 + ibuffer = new IndexBuffer*[Levels]; 1.116 + 1.117 + VertexCount = new dword[Levels]; 1.118 + TriCount = new dword[Levels]; 1.119 + 1.120 + for(int i=0; i<Levels; i++) { 1.121 + 1.122 + VertexCount[i] = mesh.VertexCount[i]; 1.123 + TriCount[i] = mesh.TriCount[i]; 1.124 + 1.125 + varray[i] = new Vertex[VertexCount[i]]; 1.126 + triarray[i] = new Triangle[TriCount[i]]; 1.127 + 1.128 + memcpy(varray[i], mesh.varray[i], VertexCount[i] * sizeof(Vertex)); 1.129 + memcpy(triarray[i], mesh.triarray[i], TriCount[i] * sizeof(Triangle)); 1.130 + 1.131 + vbuffer[i] = 0; 1.132 + ibuffer[i] = 0; 1.133 + 1.134 + UpdateSystemBuffers(i); 1.135 + } 1.136 +} 1.137 + 1.138 +TriMesh::~TriMesh() { 1.139 + if(varray) { 1.140 + for(int i=0; i<Levels; i++) { 1.141 + delete [] varray[i]; 1.142 + } 1.143 + delete [] varray; 1.144 + } 1.145 + 1.146 + if(triarray) { 1.147 + for(int i=0; i<Levels; i++) { 1.148 + delete [] triarray[i]; 1.149 + } 1.150 + delete triarray; 1.151 + } 1.152 + 1.153 + if(vbuffer) { 1.154 + for(int i=0; i<Levels; i++) { 1.155 + if(vbuffer[i]) vbuffer[i]->Release(); 1.156 + } 1.157 + } 1.158 + if(ibuffer) { 1.159 + for(int i=0; i<Levels; i++) { 1.160 + if(ibuffer[i]) ibuffer[i]->Release(); 1.161 + } 1.162 + } 1.163 + 1.164 + if(AdjTriangles) { 1.165 + for(int i=0; i<Levels; i++) { 1.166 + delete [] AdjTriangles[i]; 1.167 + } 1.168 + delete AdjTriangles; 1.169 + } 1.170 +} 1.171 + 1.172 +const TriMesh &TriMesh::operator =(const TriMesh &mesh) { 1.173 + memcpy(this, &mesh, sizeof(TriMesh)); 1.174 + 1.175 + BuffersValid = new bool[Levels]; 1.176 + memset(BuffersValid, 0, Levels * sizeof(bool)); 1.177 + 1.178 + varray = new Vertex*[Levels]; 1.179 + triarray = new Triangle*[Levels]; 1.180 + vbuffer = new VertexBuffer*[Levels]; 1.181 + ibuffer = new IndexBuffer*[Levels]; 1.182 + 1.183 + VertexCount = new dword[Levels]; 1.184 + TriCount = new dword[Levels]; 1.185 + 1.186 + for(int i=0; i<Levels; i++) { 1.187 + 1.188 + VertexCount[i] = mesh.VertexCount[i]; 1.189 + TriCount[i] = mesh.TriCount[i]; 1.190 + 1.191 + varray[i] = new Vertex[VertexCount[i]]; 1.192 + triarray[i] = new Triangle[TriCount[i]]; 1.193 + 1.194 + memcpy(varray[i], mesh.varray[i], VertexCount[i] * sizeof(Vertex)); 1.195 + memcpy(triarray[i], mesh.triarray[i], TriCount[i] * sizeof(Triangle)); 1.196 + 1.197 + vbuffer[i] = 0; 1.198 + ibuffer[i] = 0; 1.199 + 1.200 + UpdateSystemBuffers(i); 1.201 + } 1.202 + return mesh; 1.203 +} 1.204 + 1.205 + 1.206 +const Vertex *TriMesh::GetVertexArray(byte level) const { 1.207 + if(level >= Levels) return 0; 1.208 + return varray[level]; 1.209 +} 1.210 + 1.211 +const Triangle *TriMesh::GetTriangleArray(byte level) const { 1.212 + if(level >= Levels) return 0; 1.213 + return triarray[level]; 1.214 +} 1.215 + 1.216 + 1.217 +Vertex *TriMesh::GetModVertexArray() { 1.218 + memset(BuffersValid, 0, Levels * sizeof(bool)); 1.219 + return varray[0]; 1.220 +} 1.221 + 1.222 +Triangle *TriMesh::GetModTriangleArray() { 1.223 + memset(BuffersValid, 0, Levels * sizeof(bool)); 1.224 + memset(AdjValid, 0, Levels * sizeof(bool)); 1.225 + return triarray[0]; 1.226 +} 1.227 + 1.228 +const VertexBuffer *TriMesh::GetVertexBuffer(byte level) const { 1.229 + if(level >= Levels) return 0; 1.230 + 1.231 + if(!BuffersValid[level]) { 1.232 + const_cast<TriMesh*>(this)->UpdateSystemBuffers(level); 1.233 + } 1.234 + return vbuffer[level]; 1.235 +} 1.236 + 1.237 +const IndexBuffer *TriMesh::GetIndexBuffer(byte level) const { 1.238 + if(level >= Levels) return 0; 1.239 + 1.240 + if(!BuffersValid[level]) { 1.241 + const_cast<TriMesh*>(this)->UpdateSystemBuffers(level); 1.242 + } 1.243 + 1.244 + return ibuffer[level]; 1.245 +} 1.246 + 1.247 + 1.248 +dword TriMesh::GetVertexCount(byte level) const { 1.249 + if(level >= Levels) return 0xdeadbeef; 1.250 + return VertexCount[level]; 1.251 +} 1.252 + 1.253 +dword TriMesh::GetTriangleCount(byte level) const { 1.254 + if(level >= Levels) return 0xdeadbeef; 1.255 + return TriCount[level]; 1.256 +} 1.257 + 1.258 +byte TriMesh::GetLevelCount() const { 1.259 + return Levels; 1.260 +} 1.261 + 1.262 +void TriMesh::SetGraphicsContext(GraphicsContext *gc) { 1.263 + this->gc = gc; 1.264 + memset(BuffersValid, 0, Levels * sizeof(bool)); // invalidate all system buffers in all levels 1.265 +} 1.266 + 1.267 +void TriMesh::SetData(const Vertex *vdata, const Triangle *tridata, dword vcount, dword tricount) { 1.268 + 1.269 + memset(BuffersValid, 0, Levels * sizeof(bool)); 1.270 + memset(AdjValid, 0, Levels * sizeof(bool)); 1.271 + 1.272 + if(varray[0]) delete [] varray[0]; 1.273 + if(triarray[0]) delete [] triarray[0]; 1.274 + varray[0] = new Vertex[vcount]; 1.275 + triarray[0] = new Triangle[tricount]; 1.276 + 1.277 + if(vdata) memcpy(varray[0], vdata, vcount * sizeof(Vertex)); 1.278 + if(tridata) memcpy(triarray[0], tridata, tricount * sizeof(Triangle)); 1.279 + VertexCount[0] = vcount; 1.280 + TriCount[0] = tricount; 1.281 + 1.282 + UpdateLODChain(); 1.283 +} 1.284 + 1.285 +bool TriMesh::UpdateSystemBuffers(byte level) { 1.286 + 1.287 + if(!gc || level >= Levels) return false; 1.288 + 1.289 + if(vbuffer[level]) { 1.290 + D3DVERTEXBUFFER_DESC vbdesc; 1.291 + vbuffer[level]->GetDesc(&vbdesc); 1.292 + if(vbdesc.Size / sizeof(Vertex) != VertexCount[level]) { 1.293 + vbuffer[level]->Release(); 1.294 + 1.295 + if(gc->D3DDevice->CreateVertexBuffer(VertexCount[level] * sizeof(Vertex), dynamic ? D3DUSAGE_DYNAMIC : 0, VertexFormat, D3DPOOL_DEFAULT, &vbuffer[level]) != D3D_OK) { 1.296 + return false; 1.297 + } 1.298 + } 1.299 + } else { 1.300 + if(gc->D3DDevice->CreateVertexBuffer(VertexCount[level] * sizeof(Vertex), dynamic ? D3DUSAGE_DYNAMIC : 0, VertexFormat, D3DPOOL_DEFAULT, &vbuffer[level]) != D3D_OK) { 1.301 + return false; 1.302 + } 1.303 + } 1.304 + 1.305 + Vertex *vbdata; 1.306 + Lock(vbuffer[level], &vbdata); 1.307 + memcpy(vbdata, varray[level], VertexCount[level] * sizeof(Vertex)); 1.308 + Unlock(vbuffer[level]); 1.309 + 1.310 + if(ibuffer[level]) { 1.311 + D3DINDEXBUFFER_DESC ibdesc; 1.312 + ibuffer[level]->GetDesc(&ibdesc); 1.313 + if(ibdesc.Size / IndexSize != TriCount[level] * 3) { 1.314 + ibuffer[level]->Release(); 1.315 + 1.316 + if(gc->D3DDevice->CreateIndexBuffer(TriCount[level] * 3 * IndexSize, dynamic ? D3DUSAGE_DYNAMIC : 0, IndexFormat, D3DPOOL_DEFAULT, &ibuffer[level]) != D3D_OK) { 1.317 + return false; 1.318 + } 1.319 + } 1.320 + } else { 1.321 + if(gc->D3DDevice->CreateIndexBuffer(TriCount[level] * 3 * IndexSize, dynamic ? D3DUSAGE_DYNAMIC : 0, IndexFormat, D3DPOOL_DEFAULT, &ibuffer[level]) != D3D_OK) { 1.322 + return false; 1.323 + } 1.324 + } 1.325 + 1.326 + 1.327 + Index *ibdata; 1.328 + Lock(ibuffer[level], &ibdata); 1.329 + for(dword i=0; i<TriCount[level]; i++) { 1.330 + *ibdata++ = triarray[level][i].vertices[0]; 1.331 + *ibdata++ = triarray[level][i].vertices[1]; 1.332 + *ibdata++ = triarray[level][i].vertices[2]; 1.333 + } 1.334 + Unlock(ibuffer[level]); 1.335 + 1.336 + BuffersValid[level] = true; 1.337 + return true; 1.338 +} 1.339 + 1.340 +void TriMesh::UpdateLODChain() { 1.341 + for(byte i=1; i<Levels; i++) { 1.342 + // TODO: apply mesh optimization, for now, just copy as it is 1.343 + VertexCount[i] = VertexCount[0]; 1.344 + TriCount[i] = TriCount[0]; 1.345 + 1.346 + if(!varray[i]) varray[i] = new Vertex[VertexCount[i]]; 1.347 + memcpy(varray[i], varray[0], VertexCount[i] * sizeof(Vertex)); 1.348 + 1.349 + if(!triarray[i]) triarray[i] = new Triangle[TriCount[i]]; 1.350 + memcpy(triarray[i], triarray[0], TriCount[i] * sizeof(Triangle)); 1.351 + 1.352 + UpdateSystemBuffers(i); 1.353 + } 1.354 + 1.355 + if(!BuffersValid[0]) UpdateSystemBuffers(0); 1.356 +} 1.357 + 1.358 +// TODO: this will brake currently with multiple LOD levels, revise LOD normal calculation 1.359 +// and revise UpdateLODChain() too 1.360 +void TriMesh::CalculateNormals() { 1.361 + memset(BuffersValid, 0, Levels * sizeof(bool)); 1.362 + 1.363 + Triangle *tri = triarray[0]; 1.364 + Triangle *tend = tri + TriCount[0]; 1.365 + 1.366 + while(tri != tend) { 1.367 + (*tri++).CalculateNormal(varray[0], false); 1.368 + } 1.369 + 1.370 + /* 1.371 + Vertex *vert = varray[0]; 1.372 + Vertex *vend = vert + VertexCount[0]; 1.373 + 1.374 + while(vert != vend) { 1.375 + (*vert++).CalculateNormal(varray[0], triarray[0], TriCount[0]); 1.376 + } 1.377 + */ 1.378 + 1.379 + if(!AdjValid[0]) { 1.380 + if(AdjTriangles[0]) delete [] AdjTriangles[0]; 1.381 + AdjTriangles[0] = new std::vector<dword>[VertexCount[0]]; 1.382 + } 1.383 + 1.384 + for(dword i=0; i<VertexCount[0]; i++) { 1.385 + if(AdjValid[0]) { 1.386 + assert(AdjTriangles[0]); 1.387 + Vector3 normal(0.0f, 0.0f, 0.0f); 1.388 + for(dword j=0; j<AdjTriangles[0][i].size(); j++) { 1.389 + normal += triarray[0][AdjTriangles[0][i][j]].normal; 1.390 + } 1.391 + normal.Normalize(); 1.392 + varray[0][i].normal = normal; 1.393 + } else { 1.394 + 1.395 + AdjTriangles[0][i].erase(AdjTriangles[0][i].begin(), AdjTriangles[0][i].end()); 1.396 + Vector3 normal(0.0f, 0.0f, 0.0f); 1.397 + for(dword j=0; j<TriCount[0]; j++) { 1.398 + if(triarray[0][j].vertices[0] == i || triarray[0][j].vertices[1] == i || triarray[0][j].vertices[2] == i) { 1.399 + AdjTriangles[0][i].push_back(j); 1.400 + normal += triarray[0][j].normal; 1.401 + } 1.402 + } 1.403 + normal.Normalize(); 1.404 + varray[0][i].normal = normal; 1.405 + } 1.406 + } 1.407 + 1.408 + AdjValid[0] = true; 1.409 + 1.410 + UpdateLODChain(); 1.411 +} 1.412 + 1.413 +void TriMesh::CalculateNormalsFast() { 1.414 + memset(BuffersValid, 0, Levels * sizeof(bool)); 1.415 + 1.416 + Triangle *tri = triarray[0]; 1.417 + Triangle *tend = tri + TriCount[0]; 1.418 + 1.419 + while(tri != tend) { 1.420 + tri->CalculateNormal(varray[0], true); 1.421 + varray[0][tri->vertices[0]].normal = tri->normal; 1.422 + varray[0][tri->vertices[1]].normal = tri->normal; 1.423 + varray[0][tri->vertices[2]].normal = tri->normal; 1.424 + tri++; 1.425 + } 1.426 + 1.427 + UpdateLODChain(); 1.428 +} 1.429 + 1.430 +void TriMesh::ChangeMode(TriMeshMode mode) { 1.431 + dynamic = mode == TriMeshDynamic; 1.432 +} 1.433 + 1.434 +/* 1.435 + 1.436 +void TriMesh::CalculateEdges() { 1.437 + 1.438 + //build a list of triangles that share each vertex 1.439 + std::list<Triangle*> *ShareTris = new std::list<Triangle*>[VertexCount[0]]; 1.440 + 1.441 + for(dword i=0; i<VertexCount[0]; i++) { 1.442 + for(dword j=0; j<TriCount[0]; j++) { 1.443 + Index VertexIndex = (Index)((Vertex*)&varray[0][i] - (Vertex*)&varray[0][0]); 1.444 + if(triarray[0][j].vertices[0] == VertexIndex || triarray[0][j].vertices[1] == VertexIndex || triarray[0][j].vertices[2] == VertexIndex) { 1.445 + ShareTris[i].push_back(&triarray[0][j]); // if it references this vertex add it 1.446 + } 1.447 + } 1.448 + } 1.449 + 1.450 + // find the adjacent triangles of each edge 1.451 + for(dword i=0; i<TriCount[0]; i++) { 1.452 + Triangle *tri = &triarray[0][i]; 1.453 + 1.454 + for(int j=0; j<3; j++) { 1.455 + tri->edges[j].vertices[0] = tri->vertices[j]; 1.456 + tri->edges[j].vertices[1] = tri->vertices[(j+1) % 3]; 1.457 + tri->edges[j].adjfaces[0] = (Index)i; 1.458 + } 1.459 + 1.460 + for(int j=0; j<3; j++) { 1.461 + Index v0 = (Index)((Vertex*)&varray[0][tri->edges[j].vertices[0]] - (Vertex*)&varray[0][0]); 1.462 + Index v1 = (Index)((Vertex*)&varray[0][tri->edges[j].vertices[1]] - (Vertex*)&varray[0][0]); 1.463 + 1.464 + std::list<Triangle*>::iterator iter = ShareTris[v0].begin(); 1.465 + while(iter != ShareTris[v0].end()) { 1.466 + Index TriIndex = (Index)(*iter - &triarray[0][0]); 1.467 + 1.468 + if((TriIndex != i) && ((*iter)->vertices[0] == v1 || (*iter)->vertices[1] == v1 || (*iter)->vertices[2] == v1)) { 1.469 + tri->edges[j].adjfaces[1] = TriIndex; 1.470 + break; 1.471 + } 1.472 + iter++; 1.473 + } 1.474 + if(iter == ShareTris[v0].end()) tri->edges[j].adjfaces[1] = (Index)0xffffffff; 1.475 + } 1.476 + } 1.477 + 1.478 + // TODO: wield duplicate edges 1.479 +} 1.480 + 1.481 +*/ 1.482 \ No newline at end of file