1
1
const std = @import ("std" );
2
+ const tokenizeAny = std .mem .tokenizeAny ;
3
+ const Allocator = std .mem .Allocator ;
2
4
3
- const parseFloat = std .fmt .parseFloat ;
4
- const parseInt = std .fmt .parseInt ;
5
+ const lineIterator = @import ("utils.zig" ).lineIterator ;
5
6
6
7
pub const MaterialData = struct {
7
8
materials : std .StringHashMapUnmanaged (Material ),
8
9
9
10
pub fn deinit (self : * @This (), allocator : std .mem .Allocator ) void {
11
+ var iter = self .materials .iterator ();
12
+ while (iter .next ()) | m | {
13
+ m .value_ptr .deinit (allocator );
14
+ allocator .free (m .key_ptr .* );
15
+ }
10
16
self .materials .deinit (allocator );
11
17
}
18
+
19
+ const Builder = struct {
20
+ allocator : Allocator ,
21
+ current_material : Material = .{},
22
+ current_name : ? []const u8 = null ,
23
+ materials : std .StringHashMapUnmanaged (Material ) = .{},
24
+
25
+ fn onError (self : * Builder ) void {
26
+ var iter = self .materials .iterator ();
27
+ while (iter .next ()) | m | {
28
+ m .value_ptr .deinit (self .allocator );
29
+ self .allocator .free (m .key_ptr .* );
30
+ }
31
+ self .materials .deinit (self .allocator );
32
+ if (self .current_name ) | n |
33
+ self .allocator .free (n );
34
+ }
35
+
36
+ fn finish (self : * Builder ) ! MaterialData {
37
+ if (self .current_name ) | nm |
38
+ try self .materials .put (self .allocator , nm , self .current_material );
39
+ return MaterialData { .materials = self .materials };
40
+ }
41
+
42
+ fn new_material (self : * Builder , name : []const u8 ) ! void {
43
+ if (self .current_name ) | n | {
44
+ try self .materials .put (
45
+ self .allocator ,
46
+ n ,
47
+ self .current_material ,
48
+ );
49
+ self .current_material = Material {};
50
+ }
51
+ self .current_name = try self .allocator .dupe (u8 , name );
52
+ }
53
+ fn ambient_color (self : * Builder , rgb : [3 ]f32 ) ! void {
54
+ self .current_material .ambient_color = rgb ;
55
+ }
56
+ fn diffuse_color (self : * Builder , rgb : [3 ]f32 ) ! void {
57
+ self .current_material .diffuse_color = rgb ;
58
+ }
59
+ fn specular_color (self : * Builder , rgb : [3 ]f32 ) ! void {
60
+ self .current_material .specular_color = rgb ;
61
+ }
62
+ fn specular_highlight (self : * Builder , v : f32 ) ! void {
63
+ self .current_material .specular_highlight = v ;
64
+ }
65
+ fn emissive_coefficient (self : * Builder , rgb : [3 ]f32 ) ! void {
66
+ self .current_material .emissive_coefficient = rgb ;
67
+ }
68
+ fn optical_density (self : * Builder , v : f32 ) ! void {
69
+ self .current_material .optical_density = v ;
70
+ }
71
+ fn dissolve (self : * Builder , v : f32 ) ! void {
72
+ self .current_material .dissolve = v ;
73
+ }
74
+ fn illumination (self : * Builder , v : u8 ) ! void {
75
+ self .current_material .illumination = v ;
76
+ }
77
+ fn bump_map_path (self : * Builder , path : []const u8 ) ! void {
78
+ self .current_material .bump_map_path = try self .allocator .dupe (u8 , path );
79
+ }
80
+ fn diffuse_map_path (self : * Builder , path : []const u8 ) ! void {
81
+ self .current_material .diffuse_map_path = try self .allocator .dupe (u8 , path );
82
+ }
83
+ fn specular_map_path (self : * Builder , path : []const u8 ) ! void {
84
+ self .current_material .specular_map_path = try self .allocator .dupe (u8 , path );
85
+ }
86
+ };
12
87
};
13
88
14
- // NOTE: I'm not sure which material statements are optional. For now, I'm assuming all of them are.
89
+ // NOTE: I'm not sure which material statements are optional. For now, I'm
90
+ // assuming all of them are.
15
91
pub const Material = struct {
16
92
ambient_color : ? [3 ]f32 = null ,
17
93
diffuse_color : ? [3 ]f32 = null ,
@@ -25,6 +101,12 @@ pub const Material = struct {
25
101
bump_map_path : ? []const u8 = null ,
26
102
diffuse_map_path : ? []const u8 = null ,
27
103
specular_map_path : ? []const u8 = null ,
104
+
105
+ pub fn deinit (self : * Material , allocator : Allocator ) void {
106
+ if (self .bump_map_path ) | p | allocator .free (p );
107
+ if (self .diffuse_map_path ) | p | allocator .free (p );
108
+ if (self .specular_map_path ) | p | allocator .free (p );
109
+ }
28
110
};
29
111
30
112
const Keyword = enum {
@@ -43,73 +125,51 @@ const Keyword = enum {
43
125
specular_map_path ,
44
126
};
45
127
46
- pub fn parse (allocator : std.mem.Allocator , data : []const u8 ) ! MaterialData {
47
- var materials = std .StringHashMapUnmanaged (Material ){};
48
-
49
- var lines = std .mem .tokenize (u8 , data , "\r \n " );
50
- var current_material = Material {};
51
- var name : ? []const u8 = null ;
52
-
53
- while (lines .next ()) | line | {
54
- var words = std .mem .tokenize (u8 , line , " " );
55
- const keyword = try parseKeyword (words .next ().? );
128
+ pub fn parse (allocator : Allocator , data : []const u8 ) ! MaterialData {
129
+ var b = MaterialData.Builder { .allocator = allocator };
130
+ errdefer b .onError ();
131
+ var fbs = std .io .fixedBufferStream (data );
132
+ return try parseCustom (MaterialData , & b , fbs .reader ());
133
+ }
56
134
57
- switch (keyword ) {
135
+ pub fn parseCustom (comptime T : type , b : * T.Builder , reader : anytype ) ! T {
136
+ var buffer : [128 ]u8 = undefined ;
137
+ var lines = lineIterator (reader , & buffer );
138
+ while (try lines .next ()) | line | {
139
+ var iter = tokenizeAny (u8 , line , " " );
140
+ const def_type =
141
+ if (iter .next ()) | tok | try parseKeyword (tok ) else continue ;
142
+ switch (def_type ) {
58
143
.comment = > {},
59
- .new_material = > {
60
- if (name ) | n | {
61
- try materials .put (allocator , n , current_material );
62
- current_material = Material {};
63
- }
64
- name = words .next ().? ;
65
- },
66
- .ambient_color = > {
67
- current_material .ambient_color = try parseVec3 (& words );
68
- },
69
- .diffuse_color = > {
70
- current_material .diffuse_color = try parseVec3 (& words );
71
- },
72
- .specular_color = > {
73
- current_material .specular_color = try parseVec3 (& words );
74
- },
75
- .specular_highlight = > {
76
- current_material .specular_highlight = try parseFloat (f32 , words .next ().? );
77
- },
78
- .emissive_coefficient = > {
79
- current_material .emissive_coefficient = try parseVec3 (& words );
80
- },
81
- .optical_density = > {
82
- current_material .optical_density = try parseFloat (f32 , words .next ().? );
83
- },
84
- .dissolve = > {
85
- current_material .dissolve = try parseFloat (f32 , words .next ().? );
86
- },
87
- .illumination = > {
88
- current_material .illumination = try parseInt (u8 , words .next ().? , 10 );
89
- },
90
- .bump_map_path = > {
91
- current_material .bump_map_path = words .next ().? ;
92
- },
93
- .diffuse_map_path = > {
94
- current_material .diffuse_map_path = words .next ().? ;
95
- },
96
- .specular_map_path = > {
97
- current_material .specular_map_path = words .next ().? ;
98
- },
144
+ .new_material = > try b .new_material (iter .next ().? ),
145
+ .ambient_color = > try b .ambient_color (try parseVec3 (& iter )),
146
+ .diffuse_color = > try b .diffuse_color (try parseVec3 (& iter )),
147
+ .specular_color = > try b .specular_color (try parseVec3 (& iter )),
148
+ .specular_highlight = > try b .specular_highlight (try parseF32 (& iter )),
149
+ .emissive_coefficient = > try b .emissive_coefficient (try parseVec3 (& iter )),
150
+ .optical_density = > try b .optical_density (try parseF32 (& iter )),
151
+ .dissolve = > try b .dissolve (try parseF32 (& iter )),
152
+ .illumination = > try b .illumination (try parseU8 (& iter )),
153
+ .bump_map_path = > try b .bump_map_path (iter .next ().? ),
154
+ .diffuse_map_path = > try b .diffuse_map_path (iter .next ().? ),
155
+ .specular_map_path = > try b .specular_map_path (iter .next ().? ),
99
156
}
100
157
}
158
+ return try b .finish ();
159
+ }
101
160
102
- if ( name ) | n | {
103
- try materials . put ( allocator , n , current_material );
104
- }
161
+ fn parseU8 ( iter : * std . mem . TokenIterator ( u8 , .any )) ! u8 {
162
+ return try std . fmt . parseInt ( u8 , iter . next () .? , 10 );
163
+ }
105
164
106
- return MaterialData { .materials = materials };
165
+ fn parseF32 (iter : * std .mem .TokenIterator (u8 , .any )) ! f32 {
166
+ return try std .fmt .parseFloat (f32 , iter .next ().? );
107
167
}
108
168
109
169
fn parseVec3 (iter : * std .mem .TokenIterator (u8 , .any )) ! [3 ]f32 {
110
- const x = try parseFloat (f32 , iter .next ().? );
111
- const y = try parseFloat (f32 , iter .next ().? );
112
- const z = try parseFloat (f32 , iter .next ().? );
170
+ const x = try std . fmt . parseFloat (f32 , iter .next ().? );
171
+ const y = try std . fmt . parseFloat (f32 , iter .next ().? );
172
+ const z = try std . fmt . parseFloat (f32 , iter .next ().? );
113
173
return [_ ]f32 { x , y , z };
114
174
}
115
175
0 commit comments