-
Notifications
You must be signed in to change notification settings - Fork 1
/
FaceElement.h
161 lines (142 loc) · 5.22 KB
/
FaceElement.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//
// Created by rthier on 2016.04.11..
//
#ifndef NFTSIMPLEPROJ_FACEELEMENT_H
#define NFTSIMPLEPROJ_FACEELEMENT_H
#include "FacePoint.h"
#include "objmasterlog.h"
#include <string>
namespace ObjMaster {
class FaceElement {
public:
int facePointCount;
// REMARK: Currently we handle faces with at most 3 points
// If you want to handle quads or other things(obj tristrips), never use alloc/dealloc all the way
// as it can result in contention for memory manager resorces and direct sizes are faster.
// If you need to handle other cases, just make the array able to hold the longest sequence
// that you want! The memory overuse is much less than the overhead of many release/aquire
// in my opinion...
static const int MAX_FACEPOINT_COUNT = 3;
FacePoint facePoints[MAX_FACEPOINT_COUNT];
// Copies are defeaulted
FaceElement(const FaceElement &other) = default;
FaceElement& operator=(const FaceElement &other) = default;
// Moves are defaulted
FaceElement(FaceElement &&other) = default;
FaceElement& operator=(FaceElement &&other) = default;
/** Create empty FaceElement */
FaceElement() {};
/** Create a triangle */
FaceElement(FacePoint a, FacePoint b, FacePoint c) {
facePointCount = 3;
facePoints[0] = a;
facePoints[1] = b;
facePoints[2] = c;
}
/** Create FaceElement by parsing the given string */
FaceElement(char *fields);
/** Create FaceElement by parsing the given string */
FaceElement(const char *fields);
static bool isParsable(const char *fields);
/** Gets the textual representation */
inline std::string asText() {
// Rem.: What to do if the facePointCount is 0? I better return an empty string then...
std::string faceStr = (facePointCount > 0) ? "f " : "";
for(int i = 0; i < facePointCount; ++i) {
faceStr += (facePoints[i].asText() + " ");
}
return faceStr;
}
private:
// Common parts of constructors
void constructionHelper(char* fields);
};
// Very simple unit-testing approach
// it is better to have these run on the device itself and callable as normal functions than to
// test it compile-time with some unit testing framework as this way we rule out architectural
// differences better. Tests will start by logging test starts to error (when #DEBUG is set!)
// and info logs and the method returns false when anything has failed...
/** testing output-related operations (like asText()) */
static int TEST_FaceElement_Output(){
const char *fetest = "f 1/2/3 4/5/6 7/8/9";
// Parse
FaceElement f(fetest);
// Get as string
auto str = f.asText();
// Reparse result
FaceElement fb(str.c_str());
auto f0 = f.facePoints[0];
auto f1 = f.facePoints[1];
auto f2 = f.facePoints[2];
auto fb0 = fb.facePoints[0];
auto fb1 = fb.facePoints[1];
auto fb2 = fb.facePoints[2];
// Compare original and reparsed - this should test output reasonably well
if(
((f0.vIndex == fb0.vIndex) && (f0.vtIndex == fb0.vtIndex) && (f0.vnIndex == fb0.vnIndex)) &&
((f1.vIndex == fb1.vIndex) && (f1.vtIndex == fb1.vtIndex) && (f1.vnIndex == fb1.vnIndex)) &&
((f2.vIndex == fb2.vIndex) && (f2.vtIndex == fb2.vtIndex) && (f2.vnIndex == fb2.vnIndex))
) {
// OK
return 0;
} else {
// ERROR
OMLOGE("Bad FaceElement output: %s instead of %s", str.c_str(), fetest);
return 1;
}
}
static bool TEST_FaceElement() {
#ifdef DEBUG
OMLOGI("TEST_FaceElement...");
#endif
// Should parse
const char *fetest = "f 1/2/3 4/5/6 7/8/9";
// Should not parse
const char *fetest2 = "vn 1.0 2.0 3.0";
const char *fetest3 = "v 1.0 2.0 3.0";
const char *fetest4 = "vt 1.0 2.0";
const char *fetest5 = nullptr;
const char *fetest6 = "";
OMLOGI("TEST_FaceElement testing: %s", fetest);
if(FaceElement::isParsable(fetest)) {
FaceElement f(fetest);
#ifdef DEBUG
OMLOGI("f(facePointCount): %d", f.facePointCount);
OMLOGI("Result of parse: %s", f.asText().c_str());
#endif
if(f.facePointCount != 3) { OMLOGE("Bad facePointCount value: %d", f.facePointCount); return false; }
if(f.facePoints[0].vnIndex != 2) { OMLOGE("Bad vnIndex value: %d", f.facePoints[0].vnIndex); return false; }
if(f.facePoints[1].vnIndex != 5) { OMLOGE("Bad vnIndex value: %d", f.facePoints[1].vnIndex); return false; }
if(f.facePoints[0].vIndex != 0) { OMLOGE("Bad vIndex value: %d", f.facePoints[0].vIndex); return false; }
if(f.facePoints[2].vtIndex != 7) { OMLOGE("Bad vtIndex value: %d", f.facePoints[0].vtIndex); return false; }
} else {
OMLOGE("Cannot parse: %s", fetest);
return false;
}
OMLOGI("TEST_FaceElement testing: %s", fetest2);
if(FaceElement::isParsable(fetest2)) {
OMLOGE("Mistakenly parsed: %s", fetest2);
}
OMLOGI("TEST_FaceElement testing: %s", fetest3);
if(FaceElement::isParsable(fetest3)) {
OMLOGE("Mistakenly parsed: %s", fetest3);
}
OMLOGI("TEST_FaceElement testing: %s", fetest4);
if(FaceElement::isParsable(fetest4)) {
OMLOGE("Mistakenly parsed: %s", fetest4);
}
OMLOGI("TEST_FaceElement testing: %s", fetest5);
if(FaceElement::isParsable(fetest5)) {
OMLOGE("Mistakenly parsed: %s", fetest5);
}
OMLOGI("TEST_FaceElement testing: %s", fetest6);
if(FaceElement::isParsable(fetest6)) {
OMLOGE("Mistakenly parsed: %s", fetest6);
}
#ifdef DEBUG
OMLOGI("...TEST_FaceElement completed (OK)");
#endif
return true;
}
} // end namespace ObjMaster
#endif //NFTSIMPLEPROJ_FACEELEMENT_H