1 /* bzflag
2  * Copyright (c) 1993-2021 Tim Riker
3  *
4  * This package is free software;  you can redistribute it and/or
5  * modify it under the terms of the license found in the file
6  * named COPYING that should have accompanied this file.
7  *
8  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 /* interface header */
14 #include "CustomMesh.h"
15 
16 /* bzfs implementation headers */
17 #include "CustomMeshFace.h"
18 #include "ParseMaterial.h"
19 
20 /* common implementation headers */
21 #include "PhysicsDriver.h"
22 #include "ObstacleMgr.h"
23 #include "MeshDrawInfo.h"
24 
25 
CustomMesh()26 CustomMesh::CustomMesh()
27 {
28     face = NULL;
29     phydrv = -1;
30     noclusters = false;
31     smoothBounce = false;
32     driveThrough = false;
33     shootThrough = false;
34     decorative = false;
35     drawInfo = NULL;
36     material.setTexture("mesh");
37 
38     return;
39 }
40 
41 
~CustomMesh()42 CustomMesh::~CustomMesh()
43 {
44     if (face != NULL)
45     {
46         std::cout << "discarded incomplete mesh face" << std::endl;
47         delete face;
48     }
49 
50     std::vector<CustomMeshFace*>::iterator face_it;
51     for (face_it = faces.begin(); face_it != faces.end(); ++face_it)
52     {
53         CustomMeshFace* _face = *face_it;
54         delete _face;
55     }
56 
57     return;
58 }
59 
60 
read(const char * cmd,std::istream & input)61 bool CustomMesh::read(const char *cmd, std::istream& input)
62 {
63     bool materror;
64 
65     if (strncasecmp(cmd, "lod", 3) == 0)
66     {
67         std::string line, option;
68         std::getline(input, line);
69         input.putback('\n');
70         option = cmd + line;
71         std::cout << option << std::endl;
72         lodOptions.push_back(option);
73     }
74     else if (strcasecmp(cmd, "endface") == 0)
75     {
76         if (face == NULL)
77             std::cout << "extra 'endface' keyword found" << std::endl;
78         else
79         {
80             faces.push_back(face);
81             face = NULL;
82         }
83     }
84     else if (face)
85     {
86         // currently processing a face
87         return face->read(cmd, input);
88     }
89     else if (strcasecmp(cmd, "face") == 0)
90     {
91         if (face != NULL)
92         {
93             std::cout << "discarding incomplete mesh face" << std::endl;
94             delete face;
95         }
96         face = new CustomMeshFace (material, phydrv, noclusters,
97                                    smoothBounce, driveThrough, shootThrough);
98     }
99     else if (strcasecmp(cmd, "inside") == 0)
100     {
101         cfvec3 inside;
102         if (!(input >> inside[0] >> inside[1] >> inside[2]))
103             return false;
104         checkTypes.push_back(MeshObstacle::CheckInside);
105         checkPoints.push_back(inside);
106     }
107     else if (strcasecmp(cmd, "outside") == 0)
108     {
109         cfvec3 outside;
110         if (!(input >> outside[0] >> outside[1] >> outside[2]))
111             return false;
112         checkTypes.push_back(MeshObstacle::CheckOutside);
113         checkPoints.push_back(outside);
114     }
115     else if (strcasecmp(cmd, "vertex") == 0)
116     {
117         cfvec3 vertex;
118         if (!(input >> vertex[0] >> vertex[1] >> vertex[2]))
119             return false;
120         vertices.push_back(vertex);
121     }
122     else if (strcasecmp(cmd, "normal") == 0)
123     {
124         cfvec3 normal;
125         if (!(input >> normal[0] >> normal[1] >> normal[2]))
126             return false;
127         normals.push_back(normal);
128     }
129     else if (strcasecmp(cmd, "texcoord") == 0)
130     {
131         cfvec2 texcoord;
132         if (!(input >> texcoord[0] >> texcoord[1]))
133             return false;
134         texcoords.push_back(texcoord);
135     }
136     else if (strcasecmp(cmd, "phydrv") == 0)
137     {
138         std::string drvname;
139         if (!(input >> drvname))
140         {
141             std::cout << "missing Physics Driver parameter" << std::endl;
142             return false;
143         }
144         phydrv = PHYDRVMGR.findDriver(drvname);
145         if ((phydrv == -1) && (drvname != "-1"))
146             std::cout << "couldn't find PhysicsDriver: " << drvname << std::endl;
147     }
148     else if (strcasecmp(cmd, "smoothbounce") == 0)
149         smoothBounce = true;
150     else if (strcasecmp(cmd, "noclusters") == 0)
151         noclusters = true;
152     else if (strcasecmp(cmd, "decorative") == 0)
153         decorative = true;
154     else if (strcasecmp(cmd, "drawInfo") == 0)
155     {
156         if (drawInfo != NULL)
157             std::cout << "WARNING: multiple drawInfo, using first" << std::endl;
158         else
159         {
160             drawInfo = new MeshDrawInfo();
161 
162             bool parseSuccess = drawInfo->parse(input);
163             lines += drawInfo->getLineCount();
164 
165             if (!parseSuccess)
166             {
167                 std::cout << "WARNING: invalid drawInfo" << std::endl;
168                 delete drawInfo;
169                 drawInfo = NULL;
170             }
171         }
172     }
173     else if (parseMaterials(cmd, input, &material, 1, materror))
174     {
175         if (materror)
176             return false;
177     }
178     else
179     {
180         // NOTE: the position, size, and rotation
181         //       parameters are currently ignored
182         return WorldFileObstacle::read(cmd, input);
183     }
184 
185     return true;
186 }
187 
188 
writeToGroupDef(GroupDefinition * groupdef) const189 void CustomMesh::writeToGroupDef(GroupDefinition *groupdef) const
190 {
191     // include the old style parameters
192     MeshTransform xform;
193     if ((size[0] != 1.0f) || (size[1] != 1.0f) || (size[2] != 1.0f))
194         xform.addScale(size);
195     if (rotation != 0.0f)
196     {
197         const float zAxis[3] = {0.0f, 0.0f, 1.0f};
198         xform.addSpin((float)(rotation * (180.0 / M_PI)), zAxis);
199     }
200     if ((pos[0] != 0.0f) || (pos[1] != 0.0f) || (pos[2] != 0.0f))
201         xform.addShift(pos);
202     xform.append(transform);
203 
204     // hack to invalidate decorative meshes on older clients
205     bool forcePassable = false;
206     if (drawInfo)
207     {
208         cfvec3 vert;
209         if (decorative)
210         {
211             vert[0] = vert[1] = vert[2] = (Obstacle::maxExtent * 2.0f);
212             if (!faces.empty() && !(driveThrough && shootThrough))
213             {
214                 logDebugMessage(0,"WARNING: mesh is supposed to be decorative, setting to passable\n");
215                 forcePassable = true;
216             }
217         }
218         else
219             vert[0] = vert[1] = vert[2] = 0.0f;
220         const_cast<std::vector<cfvec3>*>(&vertices)->push_back(vert);
221     }
222 
223     MeshObstacle* mesh =
224         new MeshObstacle(xform, checkTypes, checkPoints,
225                          vertices, normals, texcoords, faces.size(),
226                          noclusters, smoothBounce,
227                          driveThrough || forcePassable,
228                          shootThrough || forcePassable,
229                          ricochet);
230 
231     mesh->setName(name);
232 
233     // add the faces
234     std::vector<CustomMeshFace*>::const_iterator face_it;
235     for (face_it = faces.begin(); face_it != faces.end(); ++face_it)
236     {
237         const CustomMeshFace* customFace = *face_it;
238         customFace->write(mesh);
239     }
240 
241     mesh->finalize();
242 
243     if (drawInfo)
244     {
245         ((MeshDrawInfo*)drawInfo)->serverSetup(mesh);
246         if (drawInfo->isValid())
247             mesh->setDrawInfo(drawInfo);
248         else
249             delete ((MeshDrawInfo*)drawInfo);
250     }
251 
252     groupdef->addObstacle(mesh);
253 
254     return;
255 }
256 
257 
258 // Local variables: ***
259 // mode: C++ ***
260 // tab-width: 4***
261 // c-basic-offset: 4 ***
262 // indent-tabs-mode: nil ***
263 // End: ***
264 // ex: shiftwidth=4 tabstop=4
265