31 static bool g_primListerMutex = false; |
31 static bool g_primListerMutex = false; |
32 vector<Primitive> g_primitives; |
32 vector<Primitive> g_primitives; |
33 |
33 |
34 static const str g_Other = QObject::tr( "Other" ); |
34 static const str g_Other = QObject::tr( "Other" ); |
35 |
35 |
36 static void populateCategories (); |
36 static void populateCategories(); |
37 static void loadPrimitiveCatgories (); |
37 static void loadPrimitiveCatgories(); |
38 |
38 |
39 // ============================================================================= |
39 // ============================================================================= |
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
41 // ============================================================================= |
41 // ============================================================================= |
42 void loadPrimitives () { |
42 void loadPrimitives() |
43 print ("Loading primitives...\n"); |
43 { |
44 |
44 print( "Loading primitives...\n" ); |
45 loadPrimitiveCatgories (); |
45 |
|
46 loadPrimitiveCatgories(); |
46 |
47 |
47 // Try to load prims.cfg |
48 // Try to load prims.cfg |
48 File conf (config::dirpath () + "prims.cfg", File::Read); |
49 File conf( config::dirpath() + "prims.cfg", File::Read ); |
49 if (!conf) { |
50 |
|
51 if( !conf ) |
|
52 { |
50 // No prims.cfg, build it |
53 // No prims.cfg, build it |
51 PrimitiveLister::start (); |
54 PrimitiveLister::start(); |
52 } else { |
55 } |
53 for (str line : conf) { |
56 else |
54 int space = line.indexOf (" "); |
57 { |
55 if (space == -1) |
58 for( str line : conf ) |
|
59 { |
|
60 int space = line.indexOf( " " ); |
|
61 |
|
62 if( space == -1 ) |
56 continue; |
63 continue; |
57 |
64 |
58 Primitive info; |
65 Primitive info; |
59 info.name = line.left (space); |
66 info.name = line.left( space ); |
60 info.title = line.mid (space + 1); |
67 info.title = line.mid( space + 1 ); |
61 g_primitives << info; |
68 g_primitives << info; |
62 } |
69 } |
63 |
70 |
64 populateCategories (); |
71 populateCategories(); |
65 } |
72 } |
66 } |
73 } |
67 |
74 |
68 // ============================================================================= |
75 // ============================================================================= |
69 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
76 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
70 // ============================================================================= |
77 // ============================================================================= |
71 void recursiveGetFilenames (QDir dir, vector<str>& fnames) { |
78 void recursiveGetFilenames( QDir dir, vector<str>& fnames ) |
72 QFileInfoList flist = dir.entryInfoList (); |
79 { |
73 for (const QFileInfo& info : flist) { |
80 QFileInfoList flist = dir.entryInfoList(); |
74 if (info.fileName () == "." || info.fileName () == "..") |
81 |
|
82 for( const QFileInfo & info : flist ) |
|
83 { |
|
84 if( info.fileName() == "." || info.fileName() == ".." ) |
75 continue; // skip . and .. |
85 continue; // skip . and .. |
76 |
86 |
77 if (info.isDir ()) |
87 if( info.isDir() ) |
78 recursiveGetFilenames (QDir (info.absoluteFilePath ()), fnames); |
88 recursiveGetFilenames( QDir( info.absoluteFilePath() ), fnames ); |
79 else |
89 else |
80 fnames << info.absoluteFilePath (); |
90 fnames << info.absoluteFilePath(); |
81 } |
91 } |
82 } |
92 } |
83 |
93 |
84 // ============================================================================= |
94 // ============================================================================= |
85 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
95 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
86 // ============================================================================= |
96 // ============================================================================= |
87 void PrimitiveLister::work () { |
97 void PrimitiveLister::work() |
|
98 { |
88 g_activePrimLister = this; |
99 g_activePrimLister = this; |
89 m_prims.clear (); |
100 m_prims.clear(); |
90 |
101 |
91 QDir dir (LDPaths::prims ()); |
102 QDir dir( LDPaths::prims() ); |
92 assert (dir.exists ()); |
103 ulong baselen = dir.absolutePath().length(); |
93 |
104 ulong i = 0; |
94 ulong baselen = dir.absolutePath ().length (); |
|
95 |
|
96 vector<str> fnames; |
105 vector<str> fnames; |
97 recursiveGetFilenames (dir, fnames); |
106 |
98 emit starting (fnames.size ()); |
107 assert( dir.exists() ); |
99 |
108 recursiveGetFilenames( dir, fnames ); |
100 ulong i = 0; |
109 emit starting( fnames.size() ); |
101 for (str fname : fnames) { |
110 |
102 File f (fname, File::Read); |
111 for( str fname : fnames ) |
|
112 { |
|
113 File f( fname, File::Read ); |
103 |
114 |
104 Primitive info; |
115 Primitive info; |
105 info.name = fname.mid (baselen + 1); // make full path relative |
116 info.name = fname.mid( baselen + 1 ); // make full path relative |
106 info.name.replace ('/', '\\'); // use DOS backslashes, they're expected |
117 info.name.replace( '/', '\\' ); // use DOS backslashes, they're expected |
107 |
118 info.cat = null; |
108 if (!f.readLine (info.title)) |
119 |
|
120 if( !f.readLine( info.title )) |
109 info.title = ""; |
121 info.title = ""; |
110 |
122 |
111 info.title = info.title.simplified (); |
123 info.title = info.title.simplified(); |
112 info.cat = null; |
124 |
113 |
125 if( info.title[0] == '0' ) |
114 if (info.title[0] == '0') { |
126 { |
115 info.title.remove (0, 1); // remove 0 |
127 info.title.remove( 0, 1 ); // remove 0 |
116 info.title = info.title.simplified (); |
128 info.title = info.title.simplified(); |
117 } |
129 } |
118 |
130 |
119 m_prims << info; |
131 m_prims << info; |
120 emit update (++i); |
132 emit update( ++i ); |
121 } |
133 } |
122 |
134 |
123 // Save to a config file |
135 // Save to a config file |
124 File conf (config::dirpath () + "prims.cfg", File::Write); |
136 File conf( config::dirpath() + "prims.cfg", File::Write ); |
125 for (Primitive& info : m_prims) |
137 |
126 fprint (conf, "%1 %2\n", info.name, info.title); |
138 for( Primitive & info : m_prims ) |
127 |
139 fprint( conf, "%1 %2\n", info.name, info.title ); |
128 conf.close (); |
140 |
|
141 conf.close(); |
129 |
142 |
130 g_primListerMutex = true; |
143 g_primListerMutex = true; |
131 g_primitives = m_prims; |
144 g_primitives = m_prims; |
132 populateCategories (); |
145 populateCategories(); |
133 g_primListerMutex = false; |
146 g_primListerMutex = false; |
134 g_activePrimLister = null; |
147 g_activePrimLister = null; |
135 emit workDone (); |
148 emit workDone(); |
136 } |
149 } |
137 |
150 |
138 // ============================================================================= |
151 // ============================================================================= |
139 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
152 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
140 // ============================================================================= |
153 // ============================================================================= |
141 void PrimitiveLister::start () { |
154 void PrimitiveLister::start() |
142 if (g_activePrimLister) |
155 { |
|
156 if( g_activePrimLister ) |
143 return; |
157 return; |
144 |
158 |
145 PrimitiveLister* lister = new PrimitiveLister; |
159 PrimitiveLister* lister = new PrimitiveLister; |
146 QThread* listerThread = new QThread; |
160 QThread* listerThread = new QThread; |
147 lister->moveToThread (listerThread); |
161 lister->moveToThread( listerThread ); |
148 connect (lister, SIGNAL (starting (ulong)), g_win, SLOT (primitiveLoaderStart (ulong))); |
162 connect( lister, SIGNAL( starting( ulong )), g_win, SLOT( primitiveLoaderStart( ulong )) ); |
149 connect (lister, SIGNAL (update (ulong)), g_win, SLOT (primitiveLoaderUpdate (ulong))); |
163 connect( lister, SIGNAL( update( ulong )), g_win, SLOT( primitiveLoaderUpdate( ulong )) ); |
150 connect (lister, SIGNAL (workDone ()), g_win, SLOT (primitiveLoaderEnd ())); |
164 connect( lister, SIGNAL( workDone() ), g_win, SLOT( primitiveLoaderEnd() )); |
151 connect (listerThread, SIGNAL (started ()), lister, SLOT (work ())); |
165 connect( listerThread, SIGNAL( started() ), lister, SLOT( work() )); |
152 connect (listerThread, SIGNAL (finished ()), lister, SLOT (deleteLater ())); |
166 connect( listerThread, SIGNAL( finished() ), lister, SLOT( deleteLater() )); |
153 listerThread->start (); |
167 listerThread->start(); |
154 } |
168 } |
155 |
169 |
156 static PrimitiveCategory* findCategory (str name) { |
170 static PrimitiveCategory* findCategory( str name ) |
157 for (PrimitiveCategory& cat : g_PrimitiveCategories) |
171 { |
158 if (cat.name () == name) |
172 for( PrimitiveCategory & cat : g_PrimitiveCategories ) |
|
173 if( cat.name() == name ) |
159 return &cat; |
174 return &cat; |
160 |
175 |
161 return null; |
176 return null; |
162 } |
177 } |
163 |
178 |
164 // ============================================================================= |
179 // ============================================================================= |
165 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
180 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
166 // ============================================================================= |
181 // ============================================================================= |
167 static void populateCategories () { |
182 static void populateCategories() |
168 for (PrimitiveCategory& cat : g_PrimitiveCategories) |
183 { |
169 cat.prims.clear (); |
184 for( PrimitiveCategory & cat : g_PrimitiveCategories ) |
|
185 cat.prims.clear(); |
170 |
186 |
171 PrimitiveCategory* unmatched = findCategory( g_Other ); |
187 PrimitiveCategory* unmatched = findCategory( g_Other ); |
172 |
188 |
173 if (!unmatched) { |
189 if( !unmatched ) |
|
190 { |
174 // Shouldn't happen.. but catch it anyway. |
191 // Shouldn't happen.. but catch it anyway. |
175 PrimitiveCategory cat; |
192 PrimitiveCategory cat; |
176 cat.setName( g_Other ); |
193 cat.setName( g_Other ); |
177 unmatched = &(g_PrimitiveCategories << cat); |
194 unmatched = &( g_PrimitiveCategories << cat ); |
178 } |
195 } |
179 |
196 |
180 for (Primitive& prim : g_primitives) { |
197 for( Primitive & prim : g_primitives ) |
|
198 { |
181 bool matched = false; |
199 bool matched = false; |
182 |
200 |
183 // Go over the categories and their regexes, if and when there's a match, |
201 // Go over the categories and their regexes, if and when there's a match, |
184 // the primitive's category is set to the category the regex beloings to. |
202 // the primitive's category is set to the category the regex beloings to. |
185 for (PrimitiveCategory& cat : g_PrimitiveCategories) { |
203 for( PrimitiveCategory & cat : g_PrimitiveCategories ) |
186 for (PrimitiveCategory::RegexEntry& entry : cat.regexes) { |
204 { |
187 switch (entry.type) { |
205 for( PrimitiveCategory::RegexEntry & entry : cat.regexes ) |
|
206 { |
|
207 switch( entry.type ) |
|
208 { |
188 case PrimitiveCategory::Filename: |
209 case PrimitiveCategory::Filename: |
189 // f-regex, check against filename |
210 // f-regex, check against filename |
190 matched = entry.regex.exactMatch (prim.name); |
211 matched = entry.regex.exactMatch( prim.name ); |
191 break; |
212 break; |
192 |
213 |
193 case PrimitiveCategory::Title: |
214 case PrimitiveCategory::Title: |
194 // t-regex, check against title |
215 // t-regex, check against title |
195 matched = entry.regex.exactMatch (prim.title); |
216 matched = entry.regex.exactMatch( prim.title ); |
196 break; |
217 break; |
197 } |
218 } |
198 |
219 |
199 if (matched) { |
220 if( matched ) |
|
221 { |
200 prim.cat = &cat; |
222 prim.cat = &cat; |
201 break; |
223 break; |
202 } |
224 } |
203 } |
225 } |
204 |
226 |
205 // Drop out if a category was decided on. |
227 // Drop out if a category was decided on. |
206 if (prim.cat) |
228 if( prim.cat ) |
207 break; |
229 break; |
208 } |
230 } |
209 |
231 |
210 // If there was a match, add the primitive to the category. |
232 // If there was a match, add the primitive to the category. |
211 // Otherwise, add it to the list of unmatched primitives. |
233 // Otherwise, add it to the list of unmatched primitives. |
212 if (prim.cat) |
234 if( prim.cat ) |
213 prim.cat->prims << prim; |
235 prim.cat->prims << prim; |
214 else |
236 else |
215 unmatched->prims << prim; |
237 unmatched->prims << prim; |
216 } |
238 } |
217 } |
239 } |
218 |
240 |
219 // ============================================================================= |
241 // ============================================================================= |
220 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
242 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
221 // ============================================================================= |
243 // ============================================================================= |
222 static void loadPrimitiveCatgories () { |
244 static void loadPrimitiveCatgories() |
223 g_PrimitiveCategories.clear (); |
245 { |
224 |
246 g_PrimitiveCategories.clear(); |
225 File f (config::dirpath () + "primregexps.cfg", File::Read); |
247 |
226 |
248 File f( config::dirpath() + "primregexps.cfg", File::Read ); |
227 if (!f) |
249 |
228 f.open (":/data/primitive-categories.cfg", File::Read); |
250 if( !f ) |
229 |
251 f.open( ":/data/primitive-categories.cfg", File::Read ); |
230 if (!f) |
252 |
|
253 if( !f ) |
231 critical( QObject::tr( "Failed to open primitive categories!" )); |
254 critical( QObject::tr( "Failed to open primitive categories!" )); |
232 |
255 |
233 if (f) { |
256 if( f ) |
|
257 { |
234 PrimitiveCategory cat; |
258 PrimitiveCategory cat; |
235 |
259 |
236 for (str line : f) { |
260 for( str line : f ) |
|
261 { |
237 int colon; |
262 int colon; |
238 |
263 |
239 if (line.length () == 0 || line[0] == '#') |
264 if( line.length() == 0 || line[0] == '#' ) |
240 continue; |
265 continue; |
241 |
266 |
242 if ((colon = line.indexOf (":")) == -1) { |
267 if( ( colon = line.indexOf( ":" )) == -1 ) |
243 if (cat.regexes.size () > 0) |
268 { |
|
269 if( cat.regexes.size() > 0 ) |
244 g_PrimitiveCategories << cat; |
270 g_PrimitiveCategories << cat; |
245 |
271 |
246 cat.regexes.clear (); |
272 cat.regexes.clear(); |
247 cat.prims.clear (); |
273 cat.prims.clear(); |
248 cat.setName (line); |
274 cat.setName( line ); |
249 } else { |
275 } |
250 str cmd = line.left (colon); |
276 else |
|
277 { |
|
278 str cmd = line.left( colon ); |
251 |
279 |
252 PrimitiveCategory::Type type = PrimitiveCategory::Filename; |
280 PrimitiveCategory::Type type = PrimitiveCategory::Filename; |
253 if (cmd == "f") { |
281 |
|
282 if( cmd == "f" ) |
254 type = PrimitiveCategory::Filename; |
283 type = PrimitiveCategory::Filename; |
255 } elif (cmd == "t") { |
284 elif( cmd == "t" ) |
256 type = PrimitiveCategory::Title; |
285 type = PrimitiveCategory::Title; |
257 } else |
286 else |
258 continue; |
287 continue; |
259 |
288 |
260 QRegExp regex (line.mid (colon + 1)); |
289 QRegExp regex( line.mid( colon + 1 )); |
261 PrimitiveCategory::RegexEntry entry = { regex, type }; |
290 PrimitiveCategory::RegexEntry entry = { regex, type }; |
262 cat.regexes << entry; |
291 cat.regexes << entry; |
263 } |
292 } |
264 } |
293 } |
265 |
294 |
266 if (cat.regexes.size () > 0) |
295 if( cat.regexes.size() > 0 ) |
267 g_PrimitiveCategories << cat; |
296 g_PrimitiveCategories << cat; |
268 } |
297 } |
269 |
298 |
270 // Add a category for unmatched primitives |
299 // Add a category for unmatched primitives |
271 PrimitiveCategory cat; |
300 PrimitiveCategory cat; |
283 { |
312 { |
284 vector<LDObject*> objs; |
313 vector<LDObject*> objs; |
285 |
314 |
286 for( int i = 0; i < segs; ++i ) |
315 for( int i = 0; i < segs; ++i ) |
287 { |
316 { |
288 double x0 = cos(( i * 2 * pi ) / divs ), |
317 double x0 = cos( ( i * 2 * pi ) / divs ), |
289 x1 = cos((( i + 1 ) * 2 * pi) / divs ), |
318 x1 = cos( ( ( i + 1 ) * 2 * pi ) / divs ), |
290 z0 = sin(( i * 2 * pi ) / divs ), |
319 z0 = sin( ( i * 2 * pi ) / divs ), |
291 z1 = sin((( i + 1 ) * 2 * pi ) / divs ); |
320 z1 = sin( ( ( i + 1 ) * 2 * pi ) / divs ); |
292 |
321 |
293 LDObject* obj = null; |
322 LDObject* obj = null; |
294 |
323 |
295 switch( type ) |
324 switch( type ) |
296 { |
325 { |
297 case Circle: |
326 case Circle: |
298 { |
327 { |
299 vertex v0( x0, 0.0f, z0 ), |
328 vertex v0( x0, 0.0f, z0 ), |
300 v1( x1, 0.0f, z1 ); |
329 v1( x1, 0.0f, z1 ); |
301 |
330 |
302 LDLine* line = new LDLine; |
331 LDLine* line = new LDLine; |
303 line->setVertex( 0, v0 ); |
332 line->setVertex( 0, v0 ); |
304 line->setVertex( 1, v1 ); |
333 line->setVertex( 1, v1 ); |
305 line->setColor( edgecolor ); |
334 line->setColor( edgecolor ); |
306 obj = line; |
335 obj = line; |
307 } |
336 } |
308 break; |
337 break; |
309 |
338 |
310 case Cylinder: |
339 case Cylinder: |
311 case Ring: |
340 case Ring: |
312 case Cone: |
341 case Cone: |
|
342 { |
|
343 double x2, x3, z2, z3; |
|
344 double y0, y1, y2, y3; |
|
345 |
|
346 if( type == Cylinder ) |
313 { |
347 { |
314 double x2, x3, z2, z3; |
348 x2 = x1; |
315 double y0, y1, y2, y3; |
349 x3 = x0; |
316 |
350 z2 = z1; |
317 if( type == Cylinder ) |
351 z3 = z0; |
|
352 |
|
353 y0 = y1 = 0.0f; |
|
354 y2 = y3 = 1.0f; |
|
355 } |
|
356 else |
|
357 { |
|
358 x2 = x1 * ( num + 1 ); |
|
359 x3 = x0 * ( num + 1 ); |
|
360 z2 = z1 * ( num + 1 ); |
|
361 z3 = z0 * ( num + 1 ); |
|
362 |
|
363 x0 *= num; |
|
364 x1 *= num; |
|
365 z0 *= num; |
|
366 z1 *= num; |
|
367 |
|
368 if( type == Ring ) |
|
369 y0 = y1 = y2 = y3 = 0.0f; |
|
370 else |
318 { |
371 { |
319 x2 = x1; |
372 y0 = y1 = 1.0f; |
320 x3 = x0; |
373 y2 = y3 = 0.0f; |
321 z2 = z1; |
|
322 z3 = z0; |
|
323 |
|
324 y0 = y1 = 0.0f; |
|
325 y2 = y3 = 1.0f; |
|
326 } else { |
|
327 x2 = x1 * (num + 1); |
|
328 x3 = x0 * (num + 1); |
|
329 z2 = z1 * (num + 1); |
|
330 z3 = z0 * (num + 1); |
|
331 |
|
332 x0 *= num; |
|
333 x1 *= num; |
|
334 z0 *= num; |
|
335 z1 *= num; |
|
336 |
|
337 if( type == Ring ) |
|
338 y0 = y1 = y2 = y3 = 0.0f; |
|
339 else |
|
340 { |
|
341 y0 = y1 = 1.0f; |
|
342 y2 = y3 = 0.0f; |
|
343 } |
|
344 } |
374 } |
345 |
|
346 vertex v0( x0, y0, z0 ), |
|
347 v1( x1, y1, z1 ), |
|
348 v2( x2, y2, z2 ), |
|
349 v3( x3, y3, z3 ); |
|
350 |
|
351 LDQuad* quad = new LDQuad; |
|
352 quad->setColor( maincolor ); |
|
353 quad->setVertex( 0, v0 ); |
|
354 quad->setVertex( 1, v1 ); |
|
355 quad->setVertex( 2, v2 ); |
|
356 quad->setVertex( 3, v3 ); |
|
357 obj = quad; |
|
358 } |
375 } |
359 break; |
376 |
|
377 vertex v0( x0, y0, z0 ), |
|
378 v1( x1, y1, z1 ), |
|
379 v2( x2, y2, z2 ), |
|
380 v3( x3, y3, z3 ); |
|
381 |
|
382 LDQuad* quad = new LDQuad; |
|
383 quad->setColor( maincolor ); |
|
384 quad->setVertex( 0, v0 ); |
|
385 quad->setVertex( 1, v1 ); |
|
386 quad->setVertex( 2, v2 ); |
|
387 quad->setVertex( 3, v3 ); |
|
388 obj = quad; |
|
389 } |
|
390 break; |
360 |
391 |
361 case Disc: |
392 case Disc: |
362 case DiscNeg: |
393 case DiscNeg: |
|
394 { |
|
395 double x2, z2; |
|
396 |
|
397 if( type == Disc ) |
|
398 x2 = z2 = 0.0f; |
|
399 else |
363 { |
400 { |
364 double x2, z2; |
401 x2 = ( x0 >= 0.0f ) ? 1.0f : -1.0f; |
365 |
402 z2 = ( z0 >= 0.0f ) ? 1.0f : -1.0f; |
366 if( type == Disc ) |
|
367 x2 = z2 = 0.0f; |
|
368 else |
|
369 { |
|
370 x2 = ( x0 >= 0.0f ) ? 1.0f : -1.0f; |
|
371 z2 = ( z0 >= 0.0f ) ? 1.0f : -1.0f; |
|
372 } |
|
373 |
|
374 vertex v0( x0, 0.0f, z0 ), |
|
375 v1( x1, 0.0f, z1 ), |
|
376 v2( x2, 0.0f, z2 ); |
|
377 |
|
378 // Disc negatives need to go the other way around, otherwise |
|
379 // they'll end up upside-down. |
|
380 LDTriangle* seg = new LDTriangle; |
|
381 seg->setColor( maincolor ); |
|
382 seg->setVertex( type == Disc ? 0 : 2, v0 ); |
|
383 seg->setVertex( 1, v1 ); |
|
384 seg->setVertex( type == Disc ? 2 : 0, v2 ); |
|
385 obj = seg; |
|
386 } |
403 } |
387 break; |
404 |
|
405 vertex v0( x0, 0.0f, z0 ), |
|
406 v1( x1, 0.0f, z1 ), |
|
407 v2( x2, 0.0f, z2 ); |
|
408 |
|
409 // Disc negatives need to go the other way around, otherwise |
|
410 // they'll end up upside-down. |
|
411 LDTriangle* seg = new LDTriangle; |
|
412 seg->setColor( maincolor ); |
|
413 seg->setVertex( type == Disc ? 0 : 2, v0 ); |
|
414 seg->setVertex( 1, v1 ); |
|
415 seg->setVertex( type == Disc ? 2 : 0, v2 ); |
|
416 obj = seg; |
|
417 } |
|
418 break; |
388 |
419 |
389 default: |
420 default: |
390 break; |
421 break; |
391 } |
422 } |
392 |
423 |