LuxCore  2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
cyHairFile.h
Go to the documentation of this file.
1 // cyCodeBase by Cem Yuksel
2 // [www.cemyuksel.com]
3 //-------------------------------------------------------------------------------
14 //-------------------------------------------------------------------------------
15 
16 // NOTE: this file is included in LuxCore so any external dependency must be
17 // avoided here
18 
19 #ifndef _CY_HAIR_FILE_H_INCLUDED_
20 #define _CY_HAIR_FILE_H_INCLUDED_
21 
22 //-------------------------------------------------------------------------------
23 
24 #include <stdio.h>
25 #include <math.h>
26 #include <string.h>
27 
28 #include <luxrays/utils/exportdefs.h>
29 
30 namespace luxrays {
31 
32 //-------------------------------------------------------------------------------
33 
34 #define CY_HAIR_FILE_SEGMENTS_BIT 1
35 #define CY_HAIR_FILE_POINTS_BIT 2
36 #define CY_HAIR_FILE_THICKNESS_BIT 4
37 #define CY_HAIR_FILE_TRANSPARENCY_BIT 8
38 #define CY_HAIR_FILE_COLORS_BIT 16
39 #define CY_HAIR_FILE_UVS_BIT 32
40 
41 #define CY_HAIR_FILE_INFO_SIZE 88
42 
43 // File read errors
44 #define CY_HAIR_FILE_ERROR_CANT_OPEN_FILE -1
45 #define CY_HAIR_FILE_ERROR_CANT_READ_HEADER -2
46 #define CY_HAIR_FILE_ERROR_WRONG_SIGNATURE -3
47 #define CY_HAIR_FILE_ERROR_READING_SEGMENTS -4
48 #define CY_HAIR_FILE_ERROR_READING_POINTS -5
49 #define CY_HAIR_FILE_ERROR_READING_THICKNESS -6
50 #define CY_HAIR_FILE_ERROR_READING_TRANSPARENCY -7
51 #define CY_HAIR_FILE_ERROR_READING_COLORS -8
52 #define CY_HAIR_FILE_ERROR_READING_UVS -9
53 
54 //-------------------------------------------------------------------------------
55 
58 {
59  char signature[4];
60  unsigned int hair_count;
61  unsigned int point_count;
62  unsigned int arrays;
63 
64  unsigned int d_segments;
65  float d_thickness;
67  float d_color[3];
68 
70 };
71 
72 //-------------------------------------------------------------------------------
73 
75 CPP_EXPORT class CPP_API cyHairFile
76 {
77 public:
78  cyHairFile() : segments(NULL), points(NULL), thickness(NULL), transparency(NULL), colors(NULL), uvs(NULL) { Initialize(); }
79  ~cyHairFile() { Initialize(); }
80 
81 
84 
85  const cyHairFileHeader& GetHeader() const { return header; }
86  const unsigned short* GetSegmentsArray() const { return segments; }
87  const float* GetPointsArray() const { return points; }
88  const float* GetThicknessArray() const { return thickness; }
89  const float* GetTransparencyArray() const { return transparency; }
90  const float* GetColorsArray() const { return colors; }
91  const float* GetUVsArray() const { return uvs; }
92 
93 
96 
97  unsigned short* GetSegmentsArray() { return segments; }
98  float* GetPointsArray() { return points; }
99  float* GetThicknessArray() { return thickness; }
100  float* GetTransparencyArray() { return transparency; }
101  float* GetColorsArray() { return colors; }
102  float* GetUVsArray() { return uvs; }
103 
104 
107 
109  void Initialize()
110  {
111  if ( segments ) delete [] segments;
112  if ( points ) delete [] points;
113  if ( colors ) delete [] colors;
114  if ( thickness ) delete [] thickness;
115  if ( transparency ) delete [] transparency;
116  if ( uvs ) delete [] uvs;
117  header.signature[0] = 'H';
118  header.signature[1] = 'A';
119  header.signature[2] = 'I';
120  header.signature[3] = 'R';
121  header.hair_count = 0;
122  header.point_count = 0;
123  header.arrays = 0; // no arrays
124  header.d_segments = 0;
125  header.d_thickness = 1.0f;
126  header.d_transparency = 0.0f;
127  header.d_color[0] = 1.0f;
128  header.d_color[1] = 1.0f;
129  header.d_color[2] = 1.0f;
130  memset( header.info, '\0', CY_HAIR_FILE_INFO_SIZE );
131  }
132 
134  void SetHairCount( int count )
135  {
136  header.hair_count = count;
137  if ( segments ) {
138  delete [] segments;
139  segments = new unsigned short[ header.hair_count ];
140  }
141  }
142 
143  // Sets the point count, re-allocates points, thickness, transparency, and colors arrays if necessary.
144  void SetPointCount( int count )
145  {
146  header.point_count = count;
147  if ( points ) {
148  delete [] points;
149  points = new float[ header.point_count*3 ];
150  }
151  if ( thickness ) {
152  delete [] thickness;
153  thickness = new float[ header.point_count ];
154  }
155  if ( transparency ) {
156  delete [] transparency;
157  transparency = new float[ header.point_count ];
158  }
159  if ( colors ) {
160  delete [] colors;
161  colors = new float[ header.point_count*3 ];
162  }
163  if ( uvs ) {
164  delete [] uvs;
165  uvs = new float[ header.point_count*2 ];
166  }
167  }
168 
172  void SetArrays( int array_types )
173  {
174  header.arrays = array_types;
175  if ( header.arrays & CY_HAIR_FILE_SEGMENTS_BIT && !segments ) segments = new unsigned short[header.hair_count];
176  if ( ! (header.arrays & CY_HAIR_FILE_SEGMENTS_BIT) && segments ) { delete [] segments; segments=NULL; }
177  if ( header.arrays & CY_HAIR_FILE_POINTS_BIT && !points ) points = new float[header.point_count*3];
178  if ( ! (header.arrays & CY_HAIR_FILE_POINTS_BIT) && points ) { delete [] points; points=NULL; }
179  if ( header.arrays & CY_HAIR_FILE_THICKNESS_BIT && !thickness ) thickness = new float[header.point_count];
180  if ( ! (header.arrays & CY_HAIR_FILE_THICKNESS_BIT) && thickness ) { delete [] thickness; thickness=NULL; }
181  if ( header.arrays & CY_HAIR_FILE_TRANSPARENCY_BIT && !transparency ) transparency = new float[header.point_count];
182  if ( ! (header.arrays & CY_HAIR_FILE_TRANSPARENCY_BIT) && transparency ) { delete [] transparency; transparency=NULL; }
183  if ( header.arrays & CY_HAIR_FILE_COLORS_BIT && !colors ) colors = new float[header.point_count*3];
184  if ( ! (header.arrays & CY_HAIR_FILE_COLORS_BIT) && colors ) { delete [] colors; colors=NULL; }
185  if ( header.arrays & CY_HAIR_FILE_UVS_BIT && !uvs ) uvs = new float[header.point_count*2];
186  if ( ! (header.arrays & CY_HAIR_FILE_UVS_BIT) && uvs ) { delete [] uvs; uvs=NULL; }
187  }
188 
190  void SetDefaultSegmentCount( int s ) { header.d_segments = s; }
191 
193  void SetDefaultThickness( float t ) { header.d_thickness = t; }
194 
196  void SetDefaultTransparency( float t ) { header.d_transparency = t; }
197 
199  void SetDefaultColor( float r, float g, float b ) { header.d_color[0]=r; header.d_color[1]=g; header.d_color[2]=b; }
200 
203 
205  int LoadFromFile( const char *filename )
206  {
207  Initialize();
208 
209  FILE *fp;
210  fp = fopen( filename, "rb" );
211  if ( fp == NULL ) return CY_HAIR_FILE_ERROR_CANT_OPEN_FILE;
212 
213  // read the header
214  size_t headread = fread( &header, sizeof(cyHairFileHeader), 1, fp );
215 
216  #define _CY_FAILED_RETURN(errorno) { Initialize(); fclose( fp ); return errorno; }
217 
218 
219  // Check if header is correctly read
221 
222  // Check if this is a hair file
223  if ( strncmp( header.signature, "HAIR", 4) != 0 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_WRONG_SIGNATURE);
224 
225  // Read segments array
226  if ( header.arrays & CY_HAIR_FILE_SEGMENTS_BIT ) {
227  segments = new unsigned short[ header.hair_count ];
228  size_t readcount = fread( segments, sizeof(unsigned short), header.hair_count, fp );
229  if ( readcount < header.hair_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_SEGMENTS);
230  }
231 
232  // Read points array
233  if ( header.arrays & CY_HAIR_FILE_POINTS_BIT ) {
234  points = new float[ header.point_count*3 ];
235  size_t readcount = fread( points, sizeof(float), header.point_count*3, fp );
236  if ( readcount < header.point_count*3 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_POINTS);
237  }
238 
239  // Read thickness array
240  if ( header.arrays & CY_HAIR_FILE_THICKNESS_BIT ) {
241  thickness = new float[ header.point_count ];
242  size_t readcount = fread( thickness, sizeof(float), header.point_count, fp );
243  if ( readcount < header.point_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_THICKNESS);
244  }
245 
246  // Read transparency array
247  if ( header.arrays & CY_HAIR_FILE_TRANSPARENCY_BIT ) {
248  transparency = new float[ header.point_count ];
249  size_t readcount = fread( transparency, sizeof(float), header.point_count, fp );
250  if ( readcount < header.point_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_TRANSPARENCY);
251  }
252 
253  // Read colors array
254  if ( header.arrays & CY_HAIR_FILE_COLORS_BIT ) {
255  colors = new float[ header.point_count*3 ];
256  size_t readcount = fread( colors, sizeof(float), header.point_count*3, fp );
257  if ( readcount < header.point_count*3 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_COLORS);
258  }
259 
260  // Read UVs array
261  if ( header.arrays & CY_HAIR_FILE_UVS_BIT ) {
262  uvs = new float[ header.point_count*2 ];
263  size_t readcount = fread( uvs, sizeof(float), header.point_count*2, fp );
264  if ( readcount < header.point_count*2 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_UVS);
265  }
266 
267  fclose( fp );
268 
269  return header.hair_count;
270  }
271 
273  int SaveToFile( const char *filename ) const
274  {
275  FILE *fp;
276  fp = fopen( filename, "wb" );
277  if ( fp == NULL ) return -1;
278 
279  // Write header
280  fwrite( &header, sizeof(cyHairFileHeader), 1, fp );
281 
282  // Write arrays
283  if ( header.arrays & CY_HAIR_FILE_SEGMENTS_BIT ) fwrite( segments, sizeof(unsigned short), header.hair_count, fp );
284  if ( header.arrays & CY_HAIR_FILE_POINTS_BIT ) fwrite( points, sizeof(float), header.point_count*3, fp );
285  if ( header.arrays & CY_HAIR_FILE_THICKNESS_BIT ) fwrite( thickness, sizeof(float), header.point_count, fp );
286  if ( header.arrays & CY_HAIR_FILE_TRANSPARENCY_BIT ) fwrite( transparency, sizeof(float), header.point_count, fp );
287  if ( header.arrays & CY_HAIR_FILE_COLORS_BIT ) fwrite( colors, sizeof(float), header.point_count*3, fp );
288  if ( header.arrays & CY_HAIR_FILE_UVS_BIT ) fwrite( uvs, sizeof(float), header.point_count*2, fp );
289 
290  fclose( fp );
291 
292  return header.hair_count;
293  }
294 
295 
298 
303  int FillDirectionArray( float *dir )
304  {
305  if ( dir==NULL || header.point_count<=0 || points==NULL ) return 0;
306 
307  int p = 0; // point index
308  for ( unsigned int i=0; i<header.hair_count; i++ ) {
309  int s = (segments) ? segments[i] : header.d_segments;
310  if ( s > 1 ) {
311  // direction at point1
312  float len0, len1;
313  ComputeDirection( &dir[(p+1)*3], len0, len1, &points[p*3], &points[(p+1)*3], &points[(p+2)*3] );
314 
315  // direction at point0
316  float d0[3];
317  d0[0] = points[(p+1)*3] - dir[(p+1)*3] *len0*0.3333f - points[p*3];
318  d0[1] = points[(p+1)*3+1] - dir[(p+1)*3+1]*len0*0.3333f - points[p*3+1];
319  d0[2] = points[(p+1)*3+2] - dir[(p+1)*3+2]*len0*0.3333f - points[p*3+2];
320  float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2];
321  float d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f;
322  dir[p*3] = d0[0] / d0len;
323  dir[p*3+1] = d0[1] / d0len;
324  dir[p*3+2] = d0[2] / d0len;
325 
326  // We computed the first 2 points
327  p += 2;
328 
329  // Compute the direction for the rest
330  for ( int t=2; t<s; t++, p++ ) {
331  ComputeDirection( &dir[p*3], len0, len1, &points[(p-1)*3], &points[p*3], &points[(p+1)*3] );
332  }
333 
334  // direction at the last point
335  d0[0] = - points[(p-1)*3] + dir[(p-1)*3] *len1*0.3333f + points[p*3];
336  d0[1] = - points[(p-1)*3+1] + dir[(p-1)*3+1]*len1*0.3333f + points[p*3+1];
337  d0[2] = - points[(p-1)*3+2] + dir[(p-1)*3+2]*len1*0.3333f + points[p*3+2];
338  d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2];
339  d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f;
340  dir[p*3] = d0[0] / d0len;
341  dir[p*3+1] = d0[1] / d0len;
342  dir[p*3+2] = d0[2] / d0len;
343  p++;
344 
345  } else if ( s > 0 ) {
346  // if it has a single segment
347  float d0[3];
348  d0[0] = points[(p+1)*3] - points[p*3];
349  d0[1] = points[(p+1)*3+1] - points[p*3+1];
350  d0[2] = points[(p+1)*3+2] - points[p*3+2];
351  float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2];
352  float d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f;
353  dir[p*3] = d0[0] / d0len;
354  dir[p*3+1] = d0[1] / d0len;
355  dir[p*3+2] = d0[2] / d0len;
356  dir[(p+1)*3] = dir[p*3];
357  dir[(p+1)*3+1] = dir[p*3+1];
358  dir[(p+1)*3+2] = dir[p*3+2];
359  p += 2;
360  }
361  //*/
362  }
363  return p;
364  }
365 
366 
367 private:
370 
372  unsigned short *segments;
373  float *points;
374  float *thickness;
375  float *transparency;
376  float *colors;
377  float *uvs;
378 
379  // Given point before (p0) and after (p2), computes the direction (d) at p1.
380  float ComputeDirection( float *d, float &d0len, float &d1len, const float *p0, const float *p1, const float *p2 )
381  {
382  // line from p0 to p1
383  float d0[3];
384  d0[0] = p1[0] - p0[0];
385  d0[1] = p1[1] - p0[1];
386  d0[2] = p1[2] - p0[2];
387  float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2];
388  d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f;
389 
390  // line from p1 to p2
391  float d1[3];
392  d1[0] = p2[0] - p1[0];
393  d1[1] = p2[1] - p1[1];
394  d1[2] = p2[2] - p1[2];
395  float d1lensq = d1[0]*d1[0] + d1[1]*d1[1] + d1[2]*d1[2];
396  d1len = ( d1lensq > 0 ) ? (float) sqrt(d1lensq) : 1.0f;
397 
398  // make sure that d0 and d1 has the same length
399  d0[0] *= d1len / d0len;
400  d0[1] *= d1len / d0len;
401  d0[2] *= d1len / d0len;
402 
403  // direction at p1
404  d[0] = d0[0] + d1[0];
405  d[1] = d0[1] + d1[1];
406  d[2] = d0[2] + d1[2];
407  float dlensq = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
408  float dlen = ( dlensq > 0 ) ? (float) sqrt(dlensq) : 1.0f;
409  d[0] /= dlen;
410  d[1] /= dlen;
411  d[2] /= dlen;
412 
413  return d0len;
414  }
415 };
416 
417 //-------------------------------------------------------------------------------
418 
419 namespace cy {
422 }
423 
424 //-------------------------------------------------------------------------------
425 
426 }
427 
428 #endif
void SetDefaultTransparency(float t)
Sets default hair strand transparency, which is used if transparency array does not exist...
Definition: cyHairFile.h:196
#define CY_HAIR_FILE_UVS_BIT
Definition: cyHairFile.h:39
const float * GetPointsArray() const
Returns points array (xyz coordinates of each hair point).
Definition: cyHairFile.h:87
#define _CY_FAILED_RETURN(errorno)
void SetDefaultThickness(float t)
Sets default hair strand thickness, which is used if thickness array does not exist.
Definition: cyHairFile.h:193
const unsigned short * GetSegmentsArray() const
Returns segments array (segment count for each hair strand).
Definition: cyHairFile.h:86
#define CY_HAIR_FILE_ERROR_READING_POINTS
Definition: cyHairFile.h:48
void SetPointCount(int count)
Definition: cyHairFile.h:144
#define CY_HAIR_FILE_ERROR_CANT_READ_HEADER
Definition: cyHairFile.h:45
#define CY_HAIR_FILE_ERROR_CANT_OPEN_FILE
Definition: cyHairFile.h:44
const cyHairFileHeader & GetHeader() const
Use this method to access header data.
Definition: cyHairFile.h:85
HAIR file class.
Definition: cyHairFile.h:75
char signature[4]
This should be "HAIR".
Definition: cyHairFile.h:59
#define CY_HAIR_FILE_ERROR_READING_THICKNESS
Definition: cyHairFile.h:49
void Initialize()
Deletes all arrays and initializes the header data.
Definition: cyHairFile.h:109
#define CY_HAIR_FILE_THICKNESS_BIT
Definition: cyHairFile.h:36
#define CY_HAIR_FILE_TRANSPARENCY_BIT
Definition: cyHairFile.h:37
float * GetThicknessArray()
Returns thickness array (thickness at each hair point}.
Definition: cyHairFile.h:99
float * GetColorsArray()
Returns colors array (rgb color at each hair point).
Definition: cyHairFile.h:101
void SetDefaultColor(float r, float g, float b)
Sets default hair color, which is used if color array does not exist.
Definition: cyHairFile.h:199
float * GetTransparencyArray()
Returns transparency array (transparency at each hair point).
Definition: cyHairFile.h:100
const float * GetColorsArray() const
Returns colors array (rgb color at each hair point).
Definition: cyHairFile.h:90
float ComputeDirection(float *d, float &d0len, float &d1len, const float *p0, const float *p1, const float *p2)
Definition: cyHairFile.h:380
unsigned int hair_count
number of hair strands
Definition: cyHairFile.h:60
const float * GetTransparencyArray() const
Returns transparency array (transparency at each hair point).
Definition: cyHairFile.h:89
#define CY_HAIR_FILE_COLORS_BIT
Definition: cyHairFile.h:38
int LoadFromFile(const char *filename)
Loads hair data from the given HAIR file.
Definition: cyHairFile.h:205
#define CY_HAIR_FILE_ERROR_READING_UVS
Definition: cyHairFile.h:52
int FillDirectionArray(float *dir)
Definition: cyHairFile.h:303
#define CY_HAIR_FILE_ERROR_READING_SEGMENTS
Definition: cyHairFile.h:47
#define CY_HAIR_FILE_INFO_SIZE
Definition: cyHairFile.h:41
cyHairFileHeader header
Definition: cyHairFile.h:371
unsigned short * segments
Definition: cyHairFile.h:372
int SaveToFile(const char *filename) const
Saves hair data to the given HAIR file.
Definition: cyHairFile.h:273
void SetDefaultSegmentCount(int s)
Sets default number of segments for all hair strands, which is used if segments array does not exist...
Definition: cyHairFile.h:190
void SetArrays(int array_types)
Definition: cyHairFile.h:172
#define CY_HAIR_FILE_SEGMENTS_BIT
Definition: cyHairFile.h:34
unsigned int point_count
total number of points of all strands
Definition: cyHairFile.h:61
#define CY_HAIR_FILE_ERROR_WRONG_SIGNATURE
Definition: cyHairFile.h:46
char info[CY_HAIR_FILE_INFO_SIZE]
information about the file
Definition: cyHairFile.h:69
Hair file header.
Definition: cyHairFile.h:57
unsigned int d_segments
default number of segments of each strand
Definition: cyHairFile.h:64
unsigned short * GetSegmentsArray()
Returns segments array (segment count for each hair strand).
Definition: cyHairFile.h:97
unsigned int arrays
bit array of data in the file
Definition: cyHairFile.h:62
float d_transparency
default transparency of hair strands
Definition: cyHairFile.h:66
cyHairFileHeader HairFileHeader
Definition: cyHairFile.h:420
#define CY_HAIR_FILE_POINTS_BIT
Definition: cyHairFile.h:35
float * GetUVsArray()
Returns uvs array (uv at each hair point).
Definition: cyHairFile.h:102
cyHairFile HairFile
Definition: cyHairFile.h:421
float d_color[3]
default color of hair strands
Definition: cyHairFile.h:67
float d_thickness
default thickness of hair strands
Definition: cyHairFile.h:65
void SetHairCount(int count)
Sets the hair count, re-allocates segments array if necessary.
Definition: cyHairFile.h:134
const float * GetThicknessArray() const
Returns thickness array (thickness at each hair point}.
Definition: cyHairFile.h:88
float * GetPointsArray()
Returns points array (xyz coordinates of each hair point).
Definition: cyHairFile.h:98
#define CY_HAIR_FILE_ERROR_READING_COLORS
Definition: cyHairFile.h:51
const float * GetUVsArray() const
Returns uvs array (uv at each hair point).
Definition: cyHairFile.h:91
#define CY_HAIR_FILE_ERROR_READING_TRANSPARENCY
Definition: cyHairFile.h:50