int objLoad(char* filePath) { FILE* file = fopen(filePath, "r"); char* line = (char*)calloc(LINE_SIZE, sizeof(char)); char* token = NULL, * delim = " \n\t"; int vertexCount = 0, textureCount = 0, normalCount = 0, faceCount = 0; while(fgets(line, LINE_SIZE, file) != NULL) { if(prefix("vt", line)) ++textureCount; else if(prefix("vn", line)) ++normalCount; else if(prefix("v", line)) ++vertexCount; else if(prefix("f", line)) ++faceCount; } rewind(file); obj* object = (obj*)calloc(1, sizeof(obj)); object->faceCount = faceCount; object->vertexCount = vertexCount; object->vertices = (vec3*)calloc(vertexCount, sizeof(vec3)); object->shared = (int*)calloc(vertexCount, sizeof(int)); object->normals = (vec3*)calloc(normalCount, sizeof(vec3)); object->tangents = (vec3*)calloc(vertexCount, sizeof(vec3)); object->bitangents = (vec3*)calloc(vertexCount, sizeof(vec3)); object->textures = (vec2*)calloc(textureCount, sizeof(vec2)); object->faces = (face*)calloc(faceCount, sizeof(face)); int vertexTally = 0, normalTally = 0, textureTally = 0, faceTally = 0; while(fgets(line, LINE_SIZE, file) != NULL) { if(prefix("vt", line)) { parseVec2(line, &object->textures[textureTally]); object->textures[textureTally].y = 1.0 - object->textures[textureTally].y; ++textureTally; } else if(prefix("vn", line)) parseVec3(line, &object->normals[normalTally++]); else if(prefix("v", line)) parseVec3(line, &object->vertices[vertexTally++]); else if(prefix("f", line)) parseFace(line, object->faces[faceTally++]); } uniqueMap(object); free(line); fclose(file); int index = nextIndex(); objects[index] = object; return index; }
bool Properties::getVec2(const char* name, Vec2* out) const { return parseVec2(getString(name), out); }
StyleParam::Value StyleParam::parseString(StyleParamKey key, const std::string& _value) { switch (key) { case StyleParamKey::extrude: { return parseExtrudeString(_value); } case StyleParamKey::text_wrap: { int textWrap; if (_value == "false") { return std::numeric_limits<uint32_t>::max(); } if (_value == "true") { return 15; // DEFAULT } if (parseInt(_value, textWrap) > 0 && textWrap > 0) { return static_cast<uint32_t>(textWrap); } return std::numeric_limits<uint32_t>::max(); } case StyleParamKey::text_offset: case StyleParamKey::offset: { UnitVec<glm::vec2> vec; if (!parseVec2(_value, { Unit::pixel }, vec) || std::isnan(vec.value.y)) { LOGW("Invalid offset parameter '%s'.", _value.c_str()); } return vec.value; } case StyleParamKey::size: { UnitVec<glm::vec2> vec; if (!parseVec2(_value, { Unit::pixel }, vec)) { LOGW("Invalid size parameter '%s'.", _value.c_str()); } return vec.value; } case StyleParamKey::transition_hide_time: case StyleParamKey::transition_show_time: case StyleParamKey::transition_selected_time: case StyleParamKey::text_transition_hide_time: case StyleParamKey::text_transition_show_time: case StyleParamKey::text_transition_selected_time: { float time = 0.0f; if (!parseTime(_value, time)) { LOGW("Invalid time param '%s'", _value.c_str()); } return time; } case StyleParamKey::text_font_family: case StyleParamKey::text_font_weight: case StyleParamKey::text_font_style: { std::string normalized = _value; std::transform(normalized.begin(), normalized.end(), normalized.begin(), ::tolower); return normalized; } case StyleParamKey::text_align: case StyleParamKey::anchor: case StyleParamKey::text_anchor: case StyleParamKey::text_source: case StyleParamKey::text_transform: case StyleParamKey::sprite: case StyleParamKey::sprite_default: case StyleParamKey::style: case StyleParamKey::outline_style: case StyleParamKey::text_repeat_group: return _value; case StyleParamKey::text_font_size: { float fontSize = 0.f; if (!parseFontSize(_value, fontSize)) { LOGW("Invalid font-size '%s'.", _value.c_str()); } return fontSize; } case StyleParamKey::centroid: case StyleParamKey::interactive: case StyleParamKey::text_interactive: case StyleParamKey::tile_edges: case StyleParamKey::visible: case StyleParamKey::collide: case StyleParamKey::text_collide: if (_value == "true") { return true; } if (_value == "false") { return false; } LOGW("Bool value required for capitalized/visible. Using Default."); break; case StyleParamKey::order: case StyleParamKey::outline_order: case StyleParamKey::priority: case StyleParamKey::text_priority: { int num; if (parseInt(_value, num) > 0) { if (num >= 0) { return static_cast<uint32_t>(num); } } LOGW("Invalid '%s' value '%s'", keyName(key).c_str(), _value.c_str()); break; } case StyleParamKey::text_repeat_distance: { ValueUnitPair repeatDistance; repeatDistance.unit = Unit::pixel; int pos = parseValueUnitPair(_value, 0, repeatDistance); if (pos < 0) { LOGW("Invalid repeat distance value '%s'", _value.c_str()); repeatDistance.value = 256.0f; repeatDistance.unit = Unit::pixel; } else { if (repeatDistance.unit != Unit::pixel) { LOGW("Invalid unit provided for repeat distance"); } } return Width(repeatDistance); } case StyleParamKey::width: case StyleParamKey::outline_width: { ValueUnitPair width; width.unit = Unit::meter; int pos = parseValueUnitPair(_value, 0, width); if (pos < 0) { LOGW("Invalid width value '%s'", _value.c_str()); width.value = 2.0f; width.unit = Unit::pixel; } return Width(width); } case StyleParamKey::miter_limit: case StyleParamKey::outline_miter_limit: case StyleParamKey::text_font_stroke_width: { double num; if (parseFloat(_value, num) > 0) { return static_cast<float>(num); } break; } case StyleParamKey::color: case StyleParamKey::outline_color: case StyleParamKey::text_font_fill: case StyleParamKey::text_font_stroke_color: return parseColor(_value); case StyleParamKey::cap: case StyleParamKey::outline_cap: return static_cast<uint32_t>(CapTypeFromString(_value)); case StyleParamKey::join: case StyleParamKey::outline_join: return static_cast<uint32_t>(JoinTypeFromString(_value)); default: break; } return none_type{}; }
StyleParam::Value StyleParam::parseString(StyleParamKey key, const std::string& _value) { switch (key) { case StyleParamKey::extrude: { return parseExtrudeString(_value); } case StyleParamKey::text_wrap: { int textWrap; if (_value == "false") { return std::numeric_limits<uint32_t>::max(); } if (_value == "true") { return uint32_t(15); // DEFAULT } if (parseInt(_value, textWrap) > 0 && textWrap > 0) { return static_cast<uint32_t>(textWrap); } return std::numeric_limits<uint32_t>::max(); } case StyleParamKey::text_offset: case StyleParamKey::offset: { UnitVec<glm::vec2> vec; if (!parseVec2(_value, { Unit::pixel }, vec) || std::isnan(vec.value.y)) { LOGW("Invalid offset parameter '%s'.", _value.c_str()); } return vec.value; } case StyleParamKey::size: { UnitVec<glm::vec2> vec; if (!parseVec2(_value, { Unit::pixel }, vec)) { LOGW("Invalid size parameter '%s'.", _value.c_str()); } return vec.value; } case StyleParamKey::transition_hide_time: case StyleParamKey::transition_show_time: case StyleParamKey::transition_selected_time: case StyleParamKey::text_transition_hide_time: case StyleParamKey::text_transition_show_time: case StyleParamKey::text_transition_selected_time: { float time = 0.0f; if (!parseTime(_value, time)) { LOGW("Invalid time param '%s'", _value.c_str()); } return time; } case StyleParamKey::text_font_family: case StyleParamKey::text_font_weight: case StyleParamKey::text_font_style: { std::string normalized = _value; std::transform(normalized.begin(), normalized.end(), normalized.begin(), ::tolower); return normalized; } case StyleParamKey::anchor: case StyleParamKey::text_anchor: { LabelProperty::Anchors anchors; for (auto& anchor : splitString(_value, ',')) { if (anchors.count == LabelProperty::max_anchors) { break; } LabelProperty::Anchor labelAnchor; if (LabelProperty::anchor(anchor, labelAnchor)) { anchors.anchor[anchors.count++] = labelAnchor; } else { LOG("Invalid anchor %s", anchor.c_str()); } } return anchors; } case StyleParamKey::placement: { LabelProperty::Placement placement = LabelProperty::Placement::vertex; if (!LabelProperty::placement(_value, placement)) { LOG("Invalid placement parameter, Setting vertex as default."); } return placement; } case StyleParamKey::text_align: case StyleParamKey::text_source: case StyleParamKey::text_transform: case StyleParamKey::sprite: case StyleParamKey::sprite_default: case StyleParamKey::style: case StyleParamKey::outline_style: case StyleParamKey::repeat_group: case StyleParamKey::text_repeat_group: return _value; case StyleParamKey::text_font_size: { float fontSize = 0.f; if (!parseFontSize(_value, fontSize)) { LOGW("Invalid font-size '%s'.", _value.c_str()); } return fontSize; } case StyleParamKey::flat: case StyleParamKey::interactive: case StyleParamKey::text_interactive: case StyleParamKey::tile_edges: case StyleParamKey::visible: case StyleParamKey::text_visible: case StyleParamKey::outline_visible: case StyleParamKey::collide: case StyleParamKey::text_optional: case StyleParamKey::text_collide: if (_value == "true") { return true; } if (_value == "false") { return false; } LOGW("Invalid boolean value %s for key %s", _value.c_str(), StyleParam::keyName(key).c_str()); break; case StyleParamKey::text_order: LOGW("text:order parameter is ignored."); break; case StyleParamKey::order: case StyleParamKey::outline_order: case StyleParamKey::priority: case StyleParamKey::text_priority: { int num; if (parseInt(_value, num) > 0) { if (num >= 0) { return static_cast<uint32_t>(num); } } LOGW("Invalid '%s' value '%s'", keyName(key).c_str(), _value.c_str()); break; } case StyleParamKey::placement_spacing: { ValueUnitPair placementSpacing; placementSpacing.unit = Unit::pixel; int pos = parseValueUnitPair(_value, 0, placementSpacing); if (pos < 0) { LOGW("Invalid placement spacing value '%s'", _value.c_str()); placementSpacing.value = 80.0f; placementSpacing.unit = Unit::pixel; } else { if (placementSpacing.unit != Unit::pixel) { LOGW("Invalid unit provided for placement spacing"); } } return Width(placementSpacing); } case StyleParamKey::repeat_distance: case StyleParamKey::text_repeat_distance: { ValueUnitPair repeatDistance; repeatDistance.unit = Unit::pixel; int pos = parseValueUnitPair(_value, 0, repeatDistance); if (pos < 0) { LOGW("Invalid repeat distance value '%s'", _value.c_str()); repeatDistance.value = 256.0f; repeatDistance.unit = Unit::pixel; } else { if (repeatDistance.unit != Unit::pixel) { LOGW("Invalid unit provided for repeat distance"); } } return Width(repeatDistance); } case StyleParamKey::width: case StyleParamKey::outline_width: { ValueUnitPair width; width.unit = Unit::meter; int pos = parseValueUnitPair(_value, 0, width); if (pos < 0) { LOGW("Invalid width value '%s'", _value.c_str()); width.value = 2.0f; width.unit = Unit::pixel; } return Width(width); } case StyleParamKey::angle: { double num; if (_value == "auto") { return std::nanf("1"); } else if (parseFloat(_value, num) > 0) { return static_cast<float>(num); } break; } case StyleParamKey::miter_limit: case StyleParamKey::outline_miter_limit: case StyleParamKey::placement_min_length_ratio: case StyleParamKey::text_font_stroke_width: { double num; if (parseFloat(_value, num) > 0) { return static_cast<float>(num); } break; } case StyleParamKey::color: case StyleParamKey::outline_color: case StyleParamKey::text_font_fill: case StyleParamKey::text_font_stroke_color: return parseColor(_value); case StyleParamKey::cap: case StyleParamKey::outline_cap: return static_cast<uint32_t>(CapTypeFromString(_value)); case StyleParamKey::join: case StyleParamKey::outline_join: return static_cast<uint32_t>(JoinTypeFromString(_value)); default: break; } return none_type{}; }
void OBJFileReader::parseLine(const char*& current, const char* endOfLine) { if(matchCommand(current, "v")) positions.push_back(parseVec3(current)); else if(matchCommand(current, "vn")) normals.push_back(parseVec3(current)); else if(matchCommand(current, "vt")) texcoords.push_back(parseVec2(current)); else if(matchCommand(current, "f")) // face { int count = 0; while(!errThisLine && *current) { VertInfo nfo; nfo.pos = parseIndex(current, positions.size()); if(*current == '/') nfo.tex = parseIndex(++current, texcoords.size()); else nfo.tex = -1; if(*current == '/') nfo.norm = parseIndex(++current, normals.size()); else nfo.norm = -1; if(*current && !isspace(*current)) diagnostic(false, current, "unexpected character after vertex indices"); vertices.push_back(nfo); count++; } if(count < 3) diagnostic(false, current, "need at least 3 vertices for a face"); else if(count > 4) diagnostic(true, current, "non-tri/quad face"); FaceInfo nfo; nfo.start = vertices.size() - count; nfo.count = count; nfo.mtrl = currentMaterial; nfo.smoothing_group = currentSmoothingGroup; faces.push_back(nfo); } else if(matchCommand(current, "g")) // group { current = endOfLine; } else if(matchCommand(current, "o")) // object { current = endOfLine; } else if(matchCommand(current, "s")) // smooth shading { if(matchCommand(current, "off")) currentSmoothingGroup = -1; else currentSmoothingGroup = parseInt(current) - 1; } else if(matchCommand(current, "usemtl")) { currentMaterial = findMaterial(current); current = endOfLine; } else if(matchCommand(current, "mtllib")) { MTLFileReader mtlreader; if(!mtlreader.read((basepath + current).c_str())) diagnostic(false, current, "error reading material library"); else { materials.swap(mtlreader.materials); current = endOfLine; defaultMaterial = -1; defaultMaterial = findMaterial("default"); sVERIFY(defaultMaterial != -1); currentMaterial = defaultMaterial; } } else diagnostic(false, current, "unknown command"); }
StyleParam::Value StyleParam::parseString(StyleParamKey key, const std::string& _value) { switch (key) { case StyleParamKey::extrude: { if (_value == "true") { return glm::vec2(NAN, NAN); } if (_value == "false") { return glm::vec2(0, 0) ; } auto vec2 = glm::vec2(NAN, NAN); if (!parseVec2(_value, { Unit::meter, Unit::pixel }, vec2)) { LOGW("Invalid extrude parameter '%s'.", _value.c_str()); } return vec2; } case StyleParamKey::text_wrap: { int textWrap; if (_value == "true") return textWrap; if (_value == "false") return std::numeric_limits<uint32_t>::max(); if (parseInt(_value, textWrap) > 0) { return static_cast<uint32_t>(textWrap); } } case StyleParamKey::offset: { auto vec2 = glm::vec2(0.f, 0.f); if (!parseVec2(_value, { Unit::pixel }, vec2) || isnan(vec2.y)) { LOGW("Invalid offset parameter '%s'.", _value.c_str()); } return vec2; } case StyleParamKey::size: { auto vec2 = glm::vec2(0.f, 0.f); if (!parseVec2(_value, { Unit::pixel }, vec2)) { LOGW("Invalid size parameter '%s'.", _value.c_str()); } return vec2; } case StyleParamKey::transition_hide_time: case StyleParamKey::transition_show_time: case StyleParamKey::transition_selected_time: { float time = 0.0f; if (!parseTime(_value, time)) { LOGW("Invalid time param '%s'", _value.c_str()); } return time; } case StyleParamKey::align: case StyleParamKey::anchor: case StyleParamKey::font_family: case StyleParamKey::font_weight: case StyleParamKey::font_style: case StyleParamKey::text_source: case StyleParamKey::transform: case StyleParamKey::sprite: case StyleParamKey::sprite_default: case StyleParamKey::style: return _value; case StyleParamKey::font_size: { float fontSize = 0.f; if (!parseFontSize(_value, fontSize)) { LOGW("Invalid font-size '%s'.", _value.c_str()); } return fontSize; } case StyleParamKey::centroid: case StyleParamKey::interactive: case StyleParamKey::visible: case StyleParamKey::collide: if (_value == "true") { return true; } if (_value == "false") { return false; } LOGW("Bool value required for capitalized/visible. Using Default."); break; case StyleParamKey::order: case StyleParamKey::outline_order: case StyleParamKey::priority: { int num; if (parseInt(_value, num) > 0) { return static_cast<uint32_t>(num); } break; } case StyleParamKey::width: case StyleParamKey::outline_width: { ValueUnitPair width; width.unit = Unit::meter; int pos = parseValueUnitPair(_value, 0, width); if (pos < 0) { logMsg("Warning: Invalid width value '%s'\n", _value.c_str()); width.value = 2.0f; width.unit = Unit::pixel; } return Width(width); } case StyleParamKey::font_stroke_width: { double num; if (parseFloat(_value, num) > 0) { return static_cast<float>(num); } break; } case StyleParamKey::color: case StyleParamKey::outline_color: case StyleParamKey::font_fill: case StyleParamKey::font_stroke_color: return parseColor(_value); case StyleParamKey::cap: case StyleParamKey::outline_cap: return static_cast<uint32_t>(CapTypeFromString(_value)); case StyleParamKey::join: case StyleParamKey::outline_join: return static_cast<uint32_t>(JoinTypeFromString(_value)); case StyleParamKey::none: break; } return none_type{}; }
StyleParam::Value StyleParam::parseString(StyleParamKey key, const std::string& _value) { switch (key) { case StyleParamKey::extrude: { if (_value == "true") { return glm::vec2(NAN, NAN); } if (_value == "false") { return glm::vec2(0, 0) ; } auto vec2 = glm::vec2(NAN, NAN); if (!parseVec2(_value, {"m", "px"}, vec2)) { logMsg("Warning: Badly formed extrude parameter %s.\n", _value.c_str()); } return vec2; } case StyleParamKey::offset: case StyleParamKey::size: { auto vec2 = glm::vec2(0.f, 0.f); if (!parseVec2(_value, {"px"}, vec2)) { logMsg("Warning: Badly formed offset parameter %s.\n", _value.c_str()); } return vec2; } case StyleParamKey::font_family: case StyleParamKey::font_weight: case StyleParamKey::font_style: case StyleParamKey::text_source: case StyleParamKey::transform: case StyleParamKey::sprite: case StyleParamKey::sprite_default: return _value; case StyleParamKey::font_size: { float fontSize = 16; if (!parseFontSize(_value, fontSize)) { logMsg("Warning: Invalid font-size '%s'.\n", _value.c_str()); } return fontSize; } case StyleParamKey::visible: if (_value == "true") { return true; } if (_value == "false") { return false; } logMsg("Warning: Bool value required for capitalized/visible. Using Default."); break; case StyleParamKey::order: case StyleParamKey::priority: { try { return static_cast<uint32_t>(std::stoi(_value)); } catch (std::invalid_argument) { } catch (std::out_of_range) {} logMsg("Warning: Not an Integer '%s', key: '%s'", _value.c_str(), keyName(key)); break; } case StyleParamKey::width: case StyleParamKey::outline_width: case StyleParamKey::font_stroke_width: { try { return static_cast<float>(std::stof(_value)); } catch (std::invalid_argument) { } catch (std::out_of_range) {} logMsg("Warning: Not a Float '%s', key: '%s'", _value.c_str(), keyName(key)); break; } case StyleParamKey::color: case StyleParamKey::outline_color: case StyleParamKey::font_fill: case StyleParamKey::font_stroke: case StyleParamKey::font_stroke_color: return parseColor(_value); case StyleParamKey::cap: case StyleParamKey::outline_cap: return static_cast<uint32_t>(CapTypeFromString(_value)); case StyleParamKey::join: case StyleParamKey::outline_join: return static_cast<uint32_t>(JoinTypeFromString(_value)); case StyleParamKey::none: break; } return none_type{}; }