Panda3D
 All Classes Functions Variables Enumerations
pfmTrans.cxx
1 // Filename: pfmTrans.cxx
2 // Created by: drose (23Dec10)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pfmTrans.h"
16 #include "config_pfm.h"
17 #include "pfmFile.h"
18 #include "pfmVizzer.h"
19 #include "pystub.h"
20 #include "texture.h"
21 #include "texturePool.h"
22 #include "pointerTo.h"
23 #include "string_utils.h"
24 #include "pandaFileStream.h"
25 
26 ////////////////////////////////////////////////////////////////////
27 // Function: PfmTrans::Constructor
28 // Access: Public
29 // Description:
30 ////////////////////////////////////////////////////////////////////
31 PfmTrans::
32 PfmTrans() {
33  _no_data_nan_num_channels = 0;
34  _got_transform = false;
35  _transform = LMatrix4::ident_mat();
36  _rotate = 0;
37 
39 
40  set_program_brief("transform .pfm files");
41  set_program_description
42  ("pfm-trans reads an pfm file and transforms it, filters it, "
43  "operates on it, writing the output to another pfm file. A pfm "
44  "file contains a 2-d table of floating-point values.");
45 
46  add_option
47  ("z", "", 0,
48  "Treats (0,0,0) in the pfm file as a special don't-touch value.",
49  &PfmTrans::dispatch_none, &_got_zero_special);
50 
51  add_option
52  ("nan", "num_channels", 0,
53  "Treats a NaN in any of the first num_channels channels as a special don't-touch value.",
54  &PfmTrans::dispatch_int, &_got_no_data_nan, &_no_data_nan_num_channels);
55 
56  add_option
57  ("resize", "width,height", 0,
58  "Resamples the pfm file to scale it to the indicated grid size. "
59  "A simple box filter is applied during the scale. Don't confuse this "
60  "with -TS, which scales the individual point values, but doesn't "
61  "change the number of points.",
62  &PfmTrans::dispatch_int_pair, &_got_resize, &_resize);
63 
64  add_option
65  ("crop", "xbegin,xend,ybegin,yend", 0,
66  "Crops the pfm file to the indicated subregion.",
67  &PfmTrans::dispatch_int_quad, &_got_crop, &_crop);
68 
69  add_option
70  ("autocrop", "", 0,
71  "Automatically crops to the smallest possible rectangle that includes "
72  "all points. Requires -z or -nan.",
73  &PfmTrans::dispatch_none, &_got_autocrop);
74 
75  add_option
76  ("rotate", "degrees", 0,
77  "Rotates the pfm file the specified number of degrees counterclockwise, "
78  "which must be a multiple of 90.",
79  &PfmTrans::dispatch_int, NULL, &_rotate);
80 
81  add_option
82  ("mirror_x", "", 0,
83  "Flips the pfm file about the x axis.",
84  &PfmTrans::dispatch_none, &_got_mirror_x);
85 
86  add_option
87  ("mirror_y", "", 0,
88  "Flips the pfm file about the y axis.",
89  &PfmTrans::dispatch_none, &_got_mirror_y);
90 
91  add_option
92  ("o", "filename", 50,
93  "Specify the filename to which the resulting pfm file will be written. "
94  "This is only valid when there is only one input pfm file on the command "
95  "line. If you want to process multiple files simultaneously, you must "
96  "use -d.",
97  &PfmTrans::dispatch_filename, &_got_output_filename, &_output_filename);
98 
99  add_option
100  ("d", "dirname", 50,
101  "Specify the name of the directory in which to write the processed pfm "
102  "files. If you are processing only one pfm file, this may be omitted "
103  "in lieu of the -o option.",
104  &PfmTrans::dispatch_filename, &_got_output_dirname, &_output_dirname);
105 
106  add_option
107  ("vis", "filename.bam", 60,
108  "Generates a bam file that represents a visualization of the pfm file "
109  "as a 3-D geometric mesh. If -vistex is specified, the mesh is "
110  "textured.",
111  &PfmTrans::dispatch_filename, &_got_vis_filename, &_vis_filename);
112 
113  add_option
114  ("visinv", "", 60,
115  "Inverts the visualization, generating a uniform 2-d mesh with the "
116  "3-d depth values encoded in the texture coordinates.",
117  &PfmTrans::dispatch_none, &_got_vis_inverse);
118 
119  add_option
120  ("vis2d", "", 60,
121  "Respect only the first two components of each depth value, ignoring z.",
122  &PfmTrans::dispatch_none, &_got_vis_2d);
123 
124  add_option
125  ("vistex", "texture.jpg", 60,
126  "Specifies the name of the texture to apply to the visualization.",
127  &PfmTrans::dispatch_filename, &_got_vistex_filename, &_vistex_filename);
128 
129  add_option
130  ("ls", "filename.txt", 60,
131  "Lists the points in the file to the indicated text file.",
132  &PfmTrans::dispatch_filename, &_got_ls_filename, &_ls_filename);
133 }
134 
135 
136 ////////////////////////////////////////////////////////////////////
137 // Function: PfmTrans::run
138 // Access: Public
139 // Description:
140 ////////////////////////////////////////////////////////////////////
141 void PfmTrans::
142 run() {
143  if ((int)(_rotate / 90) * 90 != _rotate) {
144  nout << "-rotate can only accept a multiple of 90 degrees.\n";
145  exit(1);
146  }
147 
148  if (_got_vis_filename) {
149  _mesh_root = NodePath("mesh_root");
150  }
151 
152  Filenames::const_iterator fi;
153  for (fi = _input_filenames.begin(); fi != _input_filenames.end(); ++fi) {
154  PfmFile file;
155  if (!file.read(*fi)) {
156  nout << "Cannot read " << *fi << "\n";
157  exit(1);
158  }
159  if (!process_pfm(*fi, file)) {
160  exit(1);
161  }
162  }
163 
164  if (_got_vis_filename) {
165  _mesh_root.write_bam_file(_vis_filename);
166  }
167 }
168 
169 ////////////////////////////////////////////////////////////////////
170 // Function: PfmTrans::process_pfm
171 // Access: Public
172 // Description: Handles a single pfm file.
173 ////////////////////////////////////////////////////////////////////
174 bool PfmTrans::
175 process_pfm(const Filename &input_filename, PfmFile &file) {
176  PfmVizzer vizzer(file);
177  if (_got_no_data_nan) {
178  file.set_no_data_nan(_no_data_nan_num_channels);
179  } else if (_got_zero_special) {
180  file.set_zero_special(true);
181  }
182  vizzer.set_vis_inverse(_got_vis_inverse);
183  vizzer.set_vis_2d(_got_vis_2d);
184 
185  if (_got_autocrop) {
186  _got_crop = file.calc_autocrop(_crop[0], _crop[1], _crop[2], _crop[3]);
187  }
188 
189  if (_got_crop) {
190  file.apply_crop(_crop[0], _crop[1], _crop[2], _crop[3]);
191  }
192 
193  if (_got_resize) {
194  file.resize(_resize[0], _resize[1]);
195  }
196 
197  if (_rotate != 0) {
198  int r = (_rotate / 90) % 4;
199  if (r < 0) {
200  r += 4;
201  }
202  switch (r) {
203  case 0:
204  break;
205  case 1:
206  // Rotate 90 degrees ccw.
207  file.flip(true, false, true);
208  break;
209  case 2:
210  // Rotate 180 degrees.
211 
212  // Not sure right now why we can't flip both axes at once. But
213  // it works if we do one at a time.
214  //file.flip(true, true, false);
215  file.flip(true, false, false);
216  file.flip(false, true, false);
217  break;
218  case 3:
219  // Rotate 90 degrees cw.
220  file.flip(false, true, true);
221  break;
222  default:
223  nassertr(false, false);
224  }
225  }
226 
227  if (_got_mirror_x) {
228  file.flip(true, false, false);
229  }
230 
231  if (_got_mirror_y) {
232  file.flip(false, true, false);
233  }
234 
235  if (_got_transform) {
236  file.xform(LCAST(PN_float32, _transform));
237  }
238 
239  if (_got_vis_filename) {
240  NodePath mesh = vizzer.generate_vis_mesh(PfmVizzer::MF_both);
241  if (_got_vistex_filename) {
242  PT(Texture) tex = TexturePool::load_texture(_vistex_filename);
243  if (tex == NULL) {
244  nout << "Couldn't find " << _vistex_filename << "\n";
245  } else {
246  tex->set_minfilter(SamplerState::FT_linear_mipmap_linear);
247  mesh.set_texture(tex);
248  if (tex->has_alpha(tex->get_format())) {
249  mesh.set_transparency(TransparencyAttrib::M_dual);
250  }
251  }
252  }
253  mesh.set_name(input_filename.get_basename_wo_extension());
254  mesh.reparent_to(_mesh_root);
255  }
256 
257  if (_got_ls_filename) {
258  pofstream out;
259  _ls_filename.set_text();
260  if (_ls_filename.open_write(out, true)) {
261  for (int yi = 0; yi < file.get_y_size(); ++yi) {
262  for (int xi = 0; xi < file.get_x_size(); ++xi) {
263  if (file.has_point(xi, yi)) {
264  out << "(" << xi << ", " << yi << "):";
265  for (int ci = 0; ci < file.get_num_channels(); ++ci) {
266  out << " " << file.get_channel(xi, yi, ci);
267  }
268  out << "\n";
269  }
270  }
271  }
272  }
273  }
274 
275  Filename output_filename;
276  if (_got_output_filename) {
277  output_filename = _output_filename;
278  } else if (_got_output_dirname) {
279  output_filename = Filename(_output_dirname, input_filename.get_basename());
280  }
281 
282  if (!output_filename.empty()) {
283  return file.write(output_filename);
284  }
285 
286  return true;
287 }
288 
289 ////////////////////////////////////////////////////////////////////
290 // Function: PfmTrans::add_transform_options
291 // Access: Public
292 // Description: Adds -TS, -TT, etc. as valid options for this
293 // program. If the user specifies one of the options on
294 // the command line, the data will be transformed when
295 // the egg file is written out.
296 ////////////////////////////////////////////////////////////////////
297 void PfmTrans::
299  add_option
300  ("TS", "sx[,sy,sz]", 49,
301  "Scale the model uniformly by the given factor (if only one number "
302  "is given) or in each axis by sx, sy, sz (if three numbers are given).",
303  &PfmTrans::dispatch_scale, &_got_transform, &_transform);
304 
305  add_option
306  ("TR", "x,y,z", 49,
307  "Rotate the model x degrees about the x axis, then y degrees about the "
308  "y axis, and then z degrees about the z axis.",
309  &PfmTrans::dispatch_rotate_xyz, &_got_transform, &_transform);
310 
311  add_option
312  ("TA", "angle,x,y,z", 49,
313  "Rotate the model angle degrees counterclockwise about the given "
314  "axis.",
315  &PfmTrans::dispatch_rotate_axis, &_got_transform, &_transform);
316 
317  add_option
318  ("TT", "x,y,z", 49,
319  "Translate the model by the indicated amount.\n\n"
320  "All transformation options (-TS, -TR, -TA, -TT) are cumulative and are "
321  "applied in the order they are encountered on the command line.",
322  &PfmTrans::dispatch_translate, &_got_transform, &_transform);
323 }
324 
325 ////////////////////////////////////////////////////////////////////
326 // Function: PfmTrans::handle_args
327 // Access: Protected, Virtual
328 // Description: Does something with the additional arguments on the
329 // command line (after all the -options have been
330 // parsed). Returns true if the arguments are good,
331 // false otherwise.
332 ////////////////////////////////////////////////////////////////////
333 bool PfmTrans::
334 handle_args(ProgramBase::Args &args) {
335  if (args.empty()) {
336  nout << "You must specify the pfm file(s) to read on the command line.\n";
337  return false;
338  }
339 
340  if (_got_output_filename && args.size() == 1) {
341  if (_got_output_dirname) {
342  nout << "Cannot specify both -o and -d.\n";
343  return false;
344  }
345 
346  } else {
347  if (_got_output_filename) {
348  nout << "Cannot use -o when multiple pfm files are specified.\n";
349  return false;
350  }
351  }
352 
353  Args::const_iterator ai;
354  for (ai = args.begin(); ai != args.end(); ++ai) {
355  _input_filenames.push_back(Filename::from_os_specific(*ai));
356  }
357 
358  return true;
359 }
360 
361 ////////////////////////////////////////////////////////////////////
362 // Function: PfmTrans::dispatch_scale
363 // Access: Protected, Static
364 // Description: Handles -TS, which specifies a scale transform. Var
365 // is an LMatrix4.
366 ////////////////////////////////////////////////////////////////////
367 bool PfmTrans::
368 dispatch_scale(const string &opt, const string &arg, void *var) {
369  LMatrix4 *transform = (LMatrix4 *)var;
370 
371  vector_string words;
372  tokenize(arg, words, ",");
373 
374  PN_stdfloat sx, sy, sz;
375 
376  bool okflag = false;
377  if (words.size() == 3) {
378  okflag =
379  string_to_stdfloat(words[0], sx) &&
380  string_to_stdfloat(words[1], sy) &&
381  string_to_stdfloat(words[2], sz);
382 
383  } else if (words.size() == 1) {
384  okflag =
385  string_to_stdfloat(words[0], sx);
386  sy = sz = sx;
387  }
388 
389  if (!okflag) {
390  nout << "-" << opt
391  << " requires one or three numbers separated by commas.\n";
392  return false;
393  }
394 
395  *transform = (*transform) * LMatrix4::scale_mat(sx, sy, sz);
396 
397  return true;
398 }
399 
400 ////////////////////////////////////////////////////////////////////
401 // Function: PfmTrans::dispatch_rotate_xyz
402 // Access: Protected, Static
403 // Description: Handles -TR, which specifies a rotate transform about
404 // the three cardinal axes. Var is an LMatrix4.
405 ////////////////////////////////////////////////////////////////////
406 bool PfmTrans::
407 dispatch_rotate_xyz(ProgramBase *self, const string &opt, const string &arg, void *var) {
408  PfmTrans *base = (PfmTrans *)self;
409  return base->ns_dispatch_rotate_xyz(opt, arg, var);
410 }
411 
412 ////////////////////////////////////////////////////////////////////
413 // Function: PfmTrans::ns_dispatch_rotate_xyz
414 // Access: Protected
415 // Description: Handles -TR, which specifies a rotate transform about
416 // the three cardinal axes. Var is an LMatrix4.
417 ////////////////////////////////////////////////////////////////////
418 bool PfmTrans::
419 ns_dispatch_rotate_xyz(const string &opt, const string &arg, void *var) {
420  LMatrix4 *transform = (LMatrix4 *)var;
421 
422  vector_string words;
423  tokenize(arg, words, ",");
424 
425  LVecBase3 xyz;
426 
427  bool okflag = false;
428  if (words.size() == 3) {
429  okflag =
430  string_to_stdfloat(words[0], xyz[0]) &&
431  string_to_stdfloat(words[1], xyz[1]) &&
432  string_to_stdfloat(words[2], xyz[2]);
433  }
434 
435  if (!okflag) {
436  nout << "-" << opt
437  << " requires three numbers separated by commas.\n";
438  return false;
439  }
440 
441  LMatrix4 mat =
442  LMatrix4::rotate_mat(xyz[0], LVector3(1.0, 0.0, 0.0)) *
443  LMatrix4::rotate_mat(xyz[1], LVector3(0.0, 1.0, 0.0)) *
444  LMatrix4::rotate_mat(xyz[2], LVector3(0.0, 0.0, 1.0));
445 
446  *transform = (*transform) * mat;
447 
448  return true;
449 }
450 
451 ////////////////////////////////////////////////////////////////////
452 // Function: PfmTrans::dispatch_rotate_axis
453 // Access: Protected, Static
454 // Description: Handles -TA, which specifies a rotate transform about
455 // an arbitrary axis. Var is an LMatrix4.
456 ////////////////////////////////////////////////////////////////////
457 bool PfmTrans::
458 dispatch_rotate_axis(ProgramBase *self, const string &opt, const string &arg, void *var) {
459  PfmTrans *base = (PfmTrans *)self;
460  return base->ns_dispatch_rotate_axis(opt, arg, var);
461 }
462 
463 ////////////////////////////////////////////////////////////////////
464 // Function: PfmTrans::ns_dispatch_rotate_axis
465 // Access: Protected
466 // Description: Handles -TA, which specifies a rotate transform about
467 // an arbitrary axis. Var is an LMatrix4.
468 ////////////////////////////////////////////////////////////////////
469 bool PfmTrans::
470 ns_dispatch_rotate_axis(const string &opt, const string &arg, void *var) {
471  LMatrix4 *transform = (LMatrix4 *)var;
472 
473  vector_string words;
474  tokenize(arg, words, ",");
475 
476  PN_stdfloat angle;
477  LVecBase3 axis;
478 
479  bool okflag = false;
480  if (words.size() == 4) {
481  okflag =
482  string_to_stdfloat(words[0], angle) &&
483  string_to_stdfloat(words[1], axis[0]) &&
484  string_to_stdfloat(words[2], axis[1]) &&
485  string_to_stdfloat(words[3], axis[2]);
486  }
487 
488  if (!okflag) {
489  nout << "-" << opt
490  << " requires four numbers separated by commas.\n";
491  return false;
492  }
493 
494  *transform = (*transform) * LMatrix4::rotate_mat(angle, axis);
495 
496  return true;
497 }
498 
499 ////////////////////////////////////////////////////////////////////
500 // Function: PfmTrans::dispatch_translate
501 // Access: Protected, Static
502 // Description: Handles -TT, which specifies a translate transform.
503 // Var is an LMatrix4.
504 ////////////////////////////////////////////////////////////////////
505 bool PfmTrans::
506 dispatch_translate(const string &opt, const string &arg, void *var) {
507  LMatrix4 *transform = (LMatrix4 *)var;
508 
509  vector_string words;
510  tokenize(arg, words, ",");
511 
512  LVector3 trans;
513 
514  bool okflag = false;
515  if (words.size() == 3) {
516  okflag =
517  string_to_stdfloat(words[0], trans[0]) &&
518  string_to_stdfloat(words[1], trans[1]) &&
519  string_to_stdfloat(words[2], trans[2]);
520  }
521 
522  if (!okflag) {
523  nout << "-" << opt
524  << " requires three numbers separated by commas.\n";
525  return false;
526  }
527 
528  *transform = (*transform) * LMatrix4::translate_mat(trans);
529 
530  return true;
531 }
532 
533 
534 int main(int argc, char *argv[]) {
535  // A call to pystub() to force libpystub.so to be linked in.
536  pystub();
537 
538  PfmTrans prog;
539  prog.parse_command_line(argc, argv);
540  prog.run();
541  return 0;
542 }
This is intended to be the base class for most general-purpose utility programs in the PANDATOOL tree...
Definition: programBase.h:37
static const LMatrix4f & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:903
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
void set_vis_inverse(bool vis_inverse)
Sets the vis_inverse flag.
Definition: pfmVizzer.I:53
static LMatrix4f scale_mat(const LVecBase3f &scale)
Returns a matrix that applies the indicated scale in each of the three axes.
Definition: lmatrix.h:2456
static LMatrix4f translate_mat(const LVecBase3f &trans)
Returns a matrix that applies the indicated translation.
Definition: lmatrix.h:2397
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
int get_num_channels() const
Returns the number of channels in the image.
static LMatrix4f rotate_mat(float angle, const LVecBase3f &axis, CoordinateSystem cs=CS_default)
Returns a matrix that rotates by the given angle in degrees counterclockwise about the indicated vect...
Definition: lmatrix.h:2425
Operates on a pfm file.
Definition: pfmTrans.h:31
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
PN_float32 get_channel(int x, int y, int c) const
Returns the cth channel of the point value at the indicated point.
Definition: pfmFile.I:68
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:507
bool write_bam_file(const Filename &filename) const
Writes the contents of this node and below out to a bam file with the indicated filename.
Definition: nodePath.cxx:6408
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
int get_x_size() const
Returns the number of pixels in the X direction.
int get_y_size() const
Returns the number of pixels in the Y direction.
void set_vis_2d(bool vis_2d)
Sets the vis_2d flag.
Definition: pfmVizzer.I:126
void set_texture(Texture *tex, int priority=0)
Adds the indicated texture to the list of textures that will be rendered on the default texture stage...
Definition: nodePath.cxx:3346
void resize(int new_x_size, int new_y_size)
Applies a simple filter to resample the pfm file in-place to the indicated size.
Definition: pfmFile.cxx:996
bool read(const Filename &fullpath)
Reads the PFM data from the indicated file, returning true on success, false on failure.
Definition: pfmFile.cxx:130
bool write(const Filename &fullpath)
Writes the PFM data to the indicated file, returning true on success, false on failure.
Definition: pfmFile.cxx:222
void reparent_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread())
Removes the referenced node of the NodePath from its current parent and attaches it to the referenced...
Definition: nodePath.cxx:523
void apply_crop(int x_begin, int x_end, int y_begin, int y_end)
Reduces the PFM file to the cells in the rectangle bounded by (x_begin, x_end, y_begin, y_end), where the _end cells are not included.
Definition: pfmFile.cxx:1521
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component, or with a special extension, 2- or 4-component.
Definition: pfmFile.h:34
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
void set_name(const string &name)
Changes the name of the referenced node.
Definition: nodePath.I:2569
bool has_point(int x, int y) const
Returns true if there is a valid point at x, y.
Definition: pfmFile.I:57
static Texture * load_texture(const Filename &filename, int primary_file_num_channels=0, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads the given filename up into a texture, if it has not already been loaded, and returns the new te...
Definition: texturePool.I:58
void flip(bool flip_x, bool flip_y, bool transpose)
Reverses, transposes, and/or rotates the table in-place according to the specified parameters...
Definition: pfmFile.cxx:1222
string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:460
string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:436
void xform(const LMatrix4f &transform)
Applies the indicated transform matrix to all points in-place.
Definition: pfmFile.cxx:1273
void set_zero_special(bool zero_special)
Sets the zero_special flag.
Definition: pfmFile.I:459
bool process_pfm(const Filename &input_filename, PfmFile &file)
Handles a single pfm file.
Definition: pfmTrans.cxx:175
void set_transparency(TransparencyAttrib::Mode mode, int priority=0)
Specifically sets or disables transparent rendering mode on this particular node. ...
Definition: nodePath.cxx:5626
bool open_write(ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:2045
void add_transform_options()
Adds -TS, -TT, etc.
Definition: pfmTrans.cxx:298
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
void set_no_data_nan(int num_channels)
Sets the no_data_nan flag.
Definition: pfmFile.cxx:893
bool calc_autocrop(int &x_begin, int &x_end, int &y_begin, int &y_end) const
Computes the minimum range of x and y across the PFM file that include all points.
Definition: pfmFile.cxx:800
NodePath generate_vis_mesh(MeshFace face=MF_front) const
Creates a triangle mesh with the points of the pfm as 3-d coordinates in space, and texture coordinat...
Definition: pfmVizzer.cxx:351
This class aids in the visualization and manipulation of PfmFile objects.
Definition: pfmVizzer.h:33
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).
Definition: filename.cxx:332