Triangle RandomTriangleNearOrigin(float maxDistanceFromOrigin) { return Triangle(RandomPointNearOrigin(maxDistanceFromOrigin), RandomPointNearOrigin(maxDistanceFromOrigin), RandomPointNearOrigin(maxDistanceFromOrigin)); }
void ModelContainerView::generateHeightMap(int pMapId, int x, int y) { //TODO: Fix this in general. //Here we need to load the GridMap from .map file. then generate vertex map from heigh points. GridMap mapArray[64][64]; //TODO: make smaller array and recalculate matching gridmap. for (int x1 = x-1; x1 <= x+1; ++x1) for (int y1 = y-1; y1 <= y+1; ++y1) { mapArray[x1][y1] = GridMap(); char tmp[12]; sprintf(tmp, "%03u%02u%02u.map",pMapId,x1,y1); std::string gmap = gMapDataDir + "/" + tmp; if (mapArray[x1][y1].loadData(gmap.c_str())) printf("Loaded %s\n", gmap.c_str()); } float x_min,y_min,x_max, y_max; x_max = (32-x)*SIZE_OF_GRIDS + 50; y_max = (32-y)*SIZE_OF_GRIDS + 50; x_min = (32-x)*SIZE_OF_GRIDS - 533 - 50; y_min = (32-y)*SIZE_OF_GRIDS - 533 - 50; for (float x = x_min; x < x_max-2;x += 2) for (float y = y_min; y < y_max-2;y += 2) { int gx,gy; // Here we need to add vertexes. so 3 Vector3 for each triangle. // FIXME: This is overly efficient since we visit each vector3 multipletimes during loop. gx = (int)(32 - x / SIZE_OF_GRIDS); gy = (int)(32 - y / SIZE_OF_GRIDS); float heightxy = mapArray[gx][gy].getHeight(x,y); gx = (int)(32 - (x+2) / SIZE_OF_GRIDS); float heightx1y = mapArray[gx][gy].getHeight(x+2,y); gx = (int)(32 - x / SIZE_OF_GRIDS); gy = (int)(32 - (y+2) / SIZE_OF_GRIDS); float heightxy1 = mapArray[gx][gy].getHeight(x,y+2); gx = (int)(32 - (x+2) / SIZE_OF_GRIDS); float heightx1y1 = mapArray[gx][gy].getHeight(x+2,y+2); Vector3 vector1(x,y,heightxy); Vector3 vector2(x+2,y,heightx1y); Vector3 vector3(x,y+2,heightxy1); Vector3 vector4(x+2,y+2,heightx1y1); /* * vector1 ------ vector2 * | \ / | * | \ / | * | \ / | * | X | * | / \ | * | / \ | * | / \ | * vector3 -------- vector4 */ Triangle t1 = Triangle(vector1,vector4,vector3); Triangle t2 = Triangle(vector1,vector2,vector4); // Check if the center of this Triangle is deep under water. (here: 1 meter) Vector3 center = t1.center(); if (mapArray[(int)(32 - center.x / SIZE_OF_GRIDS)][(int)(32 - center.y / SIZE_OF_GRIDS)].getLiquidLevel(center.x,center.y) < center.z - 1.f) globalTriangleArray.append(t1); center = t2.center(); if (mapArray[(int)(32 - center.x / SIZE_OF_GRIDS)][(int)(32 - center.y / SIZE_OF_GRIDS)].getLiquidLevel(center.x,center.y) < center.z - 1.f) globalTriangleArray.append(t2); } }
//================================================================= bool TileAssembler::readRawFile(std::string& pModelFilename, ModelPosition& pModelPosition, AABSPTree<SubModel *> *pMainTree) { bool result = false; std::string filename = iSrcDir; if(filename.length() >0) filename.append("/"); filename.append(pModelFilename); FILE *rf = fopen(filename.c_str(), "rb"); if(!rf) { // depending on the extractor version, the data could be located in the root dir std::string baseModelFilename = pModelFilename.substr((pModelFilename.find_first_of("/")+1),pModelFilename.length()); filename = iSrcDir; if(filename.length() >0) filename.append("/"); filename.append(baseModelFilename); rf = fopen(filename.c_str(), "rb"); } char ident[8]; int trianglecount =0; #ifdef _ASSEMBLER_DEBUG int startgroup = 0; //2; int endgroup = INT_MAX; //2; fprintf(::g_df,"-------------------------------------------------\n"); fprintf(::g_df,"%s\n", pModelFilename.c_str()); fprintf(::g_df,"-------------------------------------------------\n"); #else int startgroup = 0; int endgroup = INT_MAX; #endif if(rf) { if(fread(&ident, 8, 1, rf) != 1) { fclose(rf); return(false); } if(strcmp(ident, "VMAP001") == 0) { // OK, do nothing } else if(strcmp(ident, "VMAP002") == 0) { // we have to read one int. This is needed during the export and we have to skip it here int tempNVectors; if(fread(&tempNVectors, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } } else { // wrong version fclose(rf); return(false); } uint32 groups; char blockId[5]; blockId[4] = 0; int blocksize; if(fread(&groups, sizeof(uint32), 1, rf) != 1) { fclose(rf); return(false); } for(int g=0;g<(int)groups;g++) { // group MUST NOT have more then 65536 indexes !! Array will have a problem with that !! (strange ...) Array<int> tempIndexArray; Array<Vector3> tempVertexArray; AABSPTree<Triangle> *gtree = new AABSPTree<Triangle>(); uint32 flags; uint32 isindoor; if(fread(&isindoor, sizeof(uint32), 1, rf) != 1) { fclose(rf); return(false); } if(fread(&flags, sizeof(uint32), 1, rf) != 1) { fclose(rf); return(false); } uint32 branches; if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); } if(strcmp(blockId, "GRP ") != 0) { fclose(rf); return(false); } if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } if(fread(&branches, sizeof(uint32), 1, rf) != 1) { fclose(rf); return(false); } for(int b=0;b<(int)branches; b++) { uint32 indexes; // indexes for each branch (not used jet) if(fread(&indexes, sizeof(uint32), 1, rf) != 1) { fclose(rf); return(false); } } // ---- indexes if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); } if(strcmp(blockId, "INDX") != 0) { fclose(rf); return(false); } if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } unsigned int nindexes; if(fread(&nindexes, sizeof(uint32), 1, rf) != 1) { fclose(rf); return(false); } if(nindexes >0) { unsigned short *indexarray = new unsigned short[nindexes*sizeof(unsigned short)]; if(fread(indexarray, sizeof(unsigned short), nindexes, rf) != nindexes) { fclose(rf); return(false); } for(int i=0;i<(int)nindexes; i++) { unsigned short val = indexarray[i]; tempIndexArray.append(val); } delete indexarray; } // ---- vectors if(fread(&blockId, 4, 1, rf) != 1) {fclose(rf); return(false); } if(strcmp(blockId, "VERT") != 0) { fclose(rf); return(false); } if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } unsigned int nvectors; if(fread(&nvectors, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } float *vectorarray = 0; if(nvectors >0) { vectorarray = new float[nvectors*sizeof(float)*3]; if(fread(vectorarray, sizeof(float)*3, nvectors, rf) != nvectors) { fclose(rf); return(false); } } // ----- liquit if(flags & 1) { // we have liquit -> not handled yet ... skip if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); } if(strcmp(blockId, "LIQU") != 0) { fclose(rf); return(false); } if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } fseek(rf, blocksize, SEEK_CUR); } for(unsigned int i=0, indexNo=0; indexNo<nvectors; indexNo++) { Vector3 v = Vector3(vectorarray[i+2], vectorarray[i+1], vectorarray[i+0]); i+=3; v = pModelPosition.transform(v); float swapy = v.y; v.y = v.x; v.x = swapy; tempVertexArray.append(v); } // ---- calculate triangles int rest = nindexes%3; if(rest != 0) { nindexes -= rest; } for(unsigned int i=0;i<(nindexes);) { Triangle t = Triangle(tempVertexArray[tempIndexArray[i+2]], tempVertexArray[tempIndexArray[i+1]], tempVertexArray[tempIndexArray[i+0]] ); i+=3; trianglecount++; if(g>= startgroup && g <= endgroup) { gtree->insert(t); } } if(vectorarray != 0) { delete vectorarray; } if(gtree->size() >0) { gtree->balance(); SubModel *sm = new SubModel(gtree); sm->setIndoorFlag( isindoor ); #ifdef _ASSEMBLER_DEBUG if(::g_df) fprintf(::g_df,"group trianglies: %d, Tris: %d, Nodes: %d, gtree.triangles: %d\n", g, sm->getNTriangles(), sm->getNNodes(), gtree->memberTable.size()); if(sm->getNTriangles() != gtree->memberTable.size()) { if(::g_df) fprintf(::g_df,"ERROR !!!! group trianglies: %d, Tris: %d, Nodes: %d, gtree.triangles: %d\n", g, sm->getNTriangles(), sm->getNNodes(), gtree->memberTable.size()); } #endif sm->setBasePosition(pModelPosition.iPos); pMainTree->insert(sm); } delete gtree; } fclose(rf); result = true; } return(result); }
void Polygon::AddTriangle(int a, int b, int c) { triangles.push_back(Triangle(a, b, c)); }
bool File::load_binarySTL(vector<Triangle> &triangles, uint max_triangles, bool readnormals) { ifstream file; ustring filename = _file->get_path(); file.open(filename.c_str(), ifstream::in | ifstream::binary); if(file.fail()) { cerr << _("Error: Unable to open stl file - ") << filename << endl; return false; } // cerr << "loading bin " << filename << endl; /* Binary STL files have a meaningless 80 byte header * followed by the number of triangles */ file.seekg(80, ios_base::beg); unsigned int num_triangles; unsigned char buffer[4]; file.read(reinterpret_cast <char *> (buffer), 4); // Read platform independent 32-bit little-endian int. num_triangles = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24; uint step = 1; if (max_triangles > 0 && max_triangles < num_triangles) { step = ceil(num_triangles/max_triangles); triangles.reserve(max_triangles); } else triangles.reserve(num_triangles); uint i = 0; for(; i < num_triangles; i+=step) { if (step>1) file.seekg(84 + 50*i, ios_base::beg); double a,b,c; a = read_double (file); b = read_double (file); c = read_double (file); Vector3d N(a,b,c); a = read_double (file); b = read_double (file); c = read_double (file); Vector3d Ax(a,b,c); a = read_double (file); b = read_double (file); c = read_double (file); Vector3d Bx(a,b,c); a = read_double (file); b = read_double (file); c = read_double (file); Vector3d Cx(a,b,c); if (file.eof()) { cerr << _("Unexpected EOF reading STL file - ") << filename << endl; break; } /* attribute byte count - sometimes contains face color information but is useless for our purposes */ unsigned short byte_count; file.read(reinterpret_cast <char *> (buffer), 2); byte_count = buffer[0] | buffer[1] << 8; // Repress unused variable warning. (void)&byte_count; Triangle T = Triangle(Ax,Bx,Cx); if (readnormals) if (T.Normal.dot(N) < 0) T.invertNormal(); // cout << "bin triangle "<< N << ":\n\t" << Ax << "/\n\t"<<Bx << "/\n\t"<<Cx << endl; triangles.push_back(T); } file.close(); return true; // cerr << "Read " << i << " triangles of " << num_triangles << " from file" << endl; }
void Mesh::addTriangle(dword v0, dword v1, dword v2, dword uv0, dword uv1, dword uv2) { addTriangle(Triangle(v0, v1, v2, uv0, uv1, uv2, material, texture)); }
void Terrain::GenerateHeightMap(int Iterations, double Height, double HDecay) { HeightMap.calculate(Iterations, Height, HDecay); int Select = 1 + rand() % (4 - 1 + 1); // Load .3DS file into model structure if(Select == 1) { GenerateTerrainObjects(50, 2 , 40, 10); g_Load3ds.Import3DS(&g_3DModel, "Textures/Tilesets/Desert/Models/PILLAR.3DS"); double Ratio = 0.25; O1Offset = 0.0f; BuildLists(Ratio, 1, g_3DModel); for(int i = 0; i < g_3DModel.numOfObjects; i++) { // Free the faces, normals, vertices, and texture coordinates. delete [] g_3DModel.pObject[i].pFaces; delete [] g_3DModel.pObject[i].pNormals; delete [] g_3DModel.pObject[i].pVerts; delete [] g_3DModel.pObject[i].pTexVerts; } g_Load3ds.Import3DS(&g_3DModel1, "Textures/Tilesets/Desert/Models/STATUE.3DS"); Ratio = 0.25; O1Offset = 0.0f; BuildLists(Ratio, 2, g_3DModel1); // Go through all the objects in the scene for(int i = 0; i < g_3DModel1.numOfObjects; i++) { // Free the faces, normals, vertices, and texture coordinates. delete [] g_3DModel1.pObject[i].pFaces; delete [] g_3DModel1.pObject[i].pNormals; delete [] g_3DModel1.pObject[i].pVerts; delete [] g_3DModel1.pObject[i].pTexVerts; } } else if(Select == 2) { GenerateTerrainObjects(100, 2 , 50, 50); g_Load3ds.Import3DS(&g_3DModel, "Textures/Tilesets/Mountains/Models/PINE.3DS"); double Ratio = 0.25; O1Offset = 15.5f; BuildLists(Ratio, 1, g_3DModel); for(int i = 0; i < g_3DModel.numOfObjects; i++) { // Free the faces, normals, vertices, and texture coordinates. delete [] g_3DModel.pObject[i].pFaces; delete [] g_3DModel.pObject[i].pNormals; delete [] g_3DModel.pObject[i].pVerts; delete [] g_3DModel.pObject[i].pTexVerts; } g_Load3ds.Import3DS(&g_3DModel1, "Textures/Tilesets/Mountains/Models/MAPLE.3DS"); Ratio = 5.0; O2Offset = 0.0f; BuildLists(Ratio, 2, g_3DModel1); // Go through all the objects in the scene for(int i = 0; i < g_3DModel1.numOfObjects; i++) { // Free the faces, normals, vertices, and texture coordinates. delete [] g_3DModel1.pObject[i].pFaces; delete [] g_3DModel1.pObject[i].pNormals; delete [] g_3DModel1.pObject[i].pVerts; delete [] g_3DModel1.pObject[i].pTexVerts; } } else if(Select == 3) { GenerateTerrainObjects(100, 2 , 50, 50); g_Load3ds.Import3DS(&g_3DModel, "Textures/Tilesets/Tropics/Models/TREE3.3DS"); double Ratio = 0.5; O1Offset = 0.0f; BuildLists(Ratio, 1, g_3DModel); for(int i = 0; i < g_3DModel.numOfObjects; i++) { // Free the faces, normals, vertices, and texture coordinates. delete [] g_3DModel.pObject[i].pFaces; delete [] g_3DModel.pObject[i].pNormals; delete [] g_3DModel.pObject[i].pVerts; delete [] g_3DModel.pObject[i].pTexVerts; } g_Load3ds.Import3DS(&g_3DModel1, "Textures/Tilesets/Tropics/Models/PALM.3DS"); Ratio = 0.75; O2Offset = 10.0f; BuildLists(Ratio, 2, g_3DModel1); // Go through all the objects in the scene for(int i = 0; i < g_3DModel1.numOfObjects; i++) { // Free the faces, normals, vertices, and texture coordinates. delete [] g_3DModel1.pObject[i].pFaces; delete [] g_3DModel1.pObject[i].pNormals; delete [] g_3DModel1.pObject[i].pVerts; delete [] g_3DModel1.pObject[i].pTexVerts; } } else if(Select == 4) { GenerateTerrainObjects(100, 2 , 75, 15); g_Load3ds.Import3DS(&g_3DModel, "Textures/Tilesets/Volcanic/Models/DEADTREE.3DS"); double Ratio = 0.1; O1Offset = -1.0f; BuildLists(Ratio, 1, g_3DModel); for(int i = 0; i < g_3DModel.numOfObjects; i++) { // Free the faces, normals, vertices, and texture coordinates. delete [] g_3DModel.pObject[i].pFaces; delete [] g_3DModel.pObject[i].pNormals; delete [] g_3DModel.pObject[i].pVerts; delete [] g_3DModel.pObject[i].pTexVerts; } g_Load3ds.Import3DS(&g_3DModel1, "Textures/Tilesets/Volcanic/Models/TREE1.3DS"); Ratio = 0.15; O2Offset = 2.0f; BuildLists(Ratio, 2, g_3DModel1); // Go through all the objects in the scene for(int i = 0; i < g_3DModel1.numOfObjects; i++) { // Free the faces, normals, vertices, and texture coordinates. delete [] g_3DModel1.pObject[i].pFaces; delete [] g_3DModel1.pObject[i].pNormals; delete [] g_3DModel1.pObject[i].pVerts; delete [] g_3DModel1.pObject[i].pTexVerts; } } SurfaceCreator s1 = SurfaceCreator(HeightMap.Height_Map, HeightMap.getTerrainSize() - 1, static_cast<float>(Height), Select); multitextureSupported = initMultitexture(); TriangleTree.ExpandNode(TriangleTree.root); Node* Current = TriangleTree.root; //Create Triangle t1 Vector Apex = Vector(0, 0, HeightMap.Height_Map[0][0]); Vector Left = Vector(0, static_cast<float>(HeightMap.getTerrainSize() - 1), HeightMap.Height_Map[0][HeightMap.getTerrainSize() - 1]); Vector Right = Vector(static_cast<float>(HeightMap.getTerrainSize() - 1), 0,HeightMap.Height_Map[HeightMap.getTerrainSize() - 1][0] ); Triangle t = Triangle(Apex, Left, Right); for(int i = 0; i < 100; i++) { if(PointInTriangle(Vector(Forests[i].x, Forests[i].y), Apex, Left, Right)) { t.Tree.push_back(Forests[i]); } } double E = CalculateError(Left, Right); Current->LeftChild->BaseNeighbour = Current->RightChild; TriangleTree.InsertAtNode(Current->LeftChild, t, E); // Create Triangle t2 Apex.set(static_cast<float>(HeightMap.getTerrainSize() - 1) , static_cast<float>(HeightMap.getTerrainSize() - 1), HeightMap.Height_Map[HeightMap.getTerrainSize() - 1][HeightMap.getTerrainSize() - 1]); Left.set(static_cast<float>(HeightMap.getTerrainSize() - 1), 0, HeightMap.Height_Map[HeightMap.getTerrainSize() - 1][0]); Right.set(0, static_cast<float>(HeightMap.getTerrainSize() - 1), HeightMap.Height_Map[0][HeightMap.getTerrainSize() - 1]); Triangle t2 = Triangle(Apex, Left, Right); for(int i = 0; i < 100; i++) { if(PointInTriangle(Vector(Forests[i].x, Forests[i].y), Apex, Left, Right)) { t2.Tree.push_back(Forests[i]); } } Current->RightChild->BaseNeighbour = Current->LeftChild; TriangleTree.InsertAtNode(Current->RightChild, t2, E); LoadTGA(&SkyBoxTexture, "SkyBox/CLOUDS.tga"); LoadGLTextures(&WaterTexture, "Textures/WATER1.bmp"); LoadGLTextures(&SurfaceTexture , "Data/Surface.bmp"); LoadGLTextures(&ShadowTexture , "Data/Shadows.bmp"); }
void Terrain::SplitTriangle(Node* T) { Triangle t = TriangleTree.getCurrentNode(T); TriangleTree.ExpandNode(T); // Step 1 : Get the old triangles points Vector Apex = t.Apex; Vector Left = t.Left; Vector Right = t.Right; // Step 2 : Get new Apex point which is the midpoint between Left and Right int lx = static_cast<int>(Left.x); int ly = static_cast<int>(Left.y); int rx = static_cast<int>(Right.x); int ry = static_cast<int>(Right.y); Vector newApex = Vector(static_cast<float>((lx + rx) / 2), static_cast<float>((ly + ry) / 2)); // Step 3 : Create first triangle and add to tree ( This is left half of old triangle ) double TriangleLeft = CalculateError(Apex , Left); Triangle NewTLeft = Triangle(newApex, Apex, Left); // Apex = new Apex, Left = old Left, Right = Old Apex for(int i = 0; (unsigned)i < t.Tree.size(); i++) { Vector Current = t.Tree[i]; if(PointInTriangle(Vector(Current.x, Current.y), Vector(newApex.x, newApex.y), Vector(Apex.x, Apex.y), Vector(Left.x, Left.y))) { NewTLeft.Tree.push_back(Current); } } // Step 4 : Create the second triangle and add to tree double TriangleRight = CalculateError(Right , Apex); Triangle NewTRight = Triangle(newApex, Right, Apex); for(int i = 0; (unsigned)i < t.Tree.size(); i++) { Vector Current = t.Tree[i]; if(PointInTriangle(Vector(Current.x, Current.y), Vector(newApex.x, newApex.y), Vector(Right.x, Right.y), Vector(Apex.x, Apex.y) )) { NewTRight.Tree.push_back(Current); } } T->LeftChild->LeftNeighbour = T->RightChild; T->RightChild->RightNeighbour = T->LeftChild; T->LeftChild->BaseNeighbour = T->LeftNeighbour; T->RightChild->BaseNeighbour = T->RightNeighbour; if(T->LeftNeighbour != NULL) { if(T->LeftNeighbour->BaseNeighbour == T) { T->LeftNeighbour->BaseNeighbour = T->LeftChild; T->LeftNeighbour->Parent->RightNeighbour = T->LeftChild; } else { T->LeftNeighbour->RightNeighbour = T->LeftChild; } } if(T->RightNeighbour != NULL) { if(T->RightNeighbour->BaseNeighbour == T) { T->RightNeighbour->BaseNeighbour = T->RightChild; T->RightNeighbour->Parent->LeftNeighbour = T->RightChild; } else { T->RightNeighbour->LeftNeighbour = T->RightChild; } } TriangleTree.InsertAtNode(T->LeftChild, NewTLeft, TriangleLeft); TriangleTree.InsertAtNode(T->RightChild, NewTRight, TriangleRight); }
//! Slower Ray intersection check, can return intersection point bool CollisionUtils::AABBox3DSlowRayIntersectionCheck(const AABBox3D& box, const Vector3& rayStart, const Vector3& rayEnd, Vector3* pIntersection) { Vector3 vTop1 = Vector3::Create(box.Min().X, box.Max().Y, box.Min().Z); Vector3 vTop2 = Vector3::Create(box.Max().X, box.Max().Y, box.Min().Z); Vector3 vTop3 = Vector3::Create(box.Min().X, box.Max().Y, box.Max().Z); Vector3 vTop4 = Vector3::Create(box.Max().X, box.Max().Y, box.Max().Z); Vector3 vBottom1 = Vector3::Create(box.Min().X, box.Min().Y, box.Min().Z); Vector3 vBottom2 = Vector3::Create(box.Max().X, box.Min().Y, box.Min().Z); Vector3 vBottom3 = Vector3::Create(box.Min().X, box.Min().Y, box.Max().Z); Vector3 vBottom4 = Vector3::Create(box.Max().X, box.Min().Y, box.Max().Z); Vector3 rayDir = (rayEnd - rayStart).Normalize(); Plane Planes[6] = { Plane(vTop1, vTop2, vTop3), Plane(vBottom1, vBottom2, vBottom3), Plane(vTop3, vTop4, vBottom3), Plane(vTop1, vTop2, vBottom1), Plane(vTop1, vTop3, vBottom1), Plane(vTop2, vTop4, vBottom2) }; Triangle Triangles[12] = { Triangle(vTop1, vTop2, vTop3), Triangle(vTop2, vTop3, vTop4), Triangle(vBottom1, vBottom2, vBottom3), Triangle(vBottom2, vBottom3, vBottom4), Triangle(vTop3, vTop4, vBottom3), Triangle(vBottom3, vTop4, vBottom4), Triangle(vTop1, vTop2, vBottom1), Triangle(vBottom1, vTop2, vBottom2), Triangle(vTop1, vTop3, vBottom1), Triangle(vBottom1, vTop3, vBottom3), Triangle(vTop2, vTop4, vBottom2), Triangle(vBottom2, vTop4, vBottom4) }; // TODO: register all intersections, sort them, and pick closest to ray start for(u32 i=0; i<6; ++i) { if(Planes[i].IntersectWithRay(rayStart, rayDir, pIntersection)) { if(Triangles[i*2+0].IsPointInside(*pIntersection) || Triangles[i*2+1].IsPointInside(*pIntersection)) { return true; } } } return false; }