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