/** * Parses Options and OZs from See You task file * @param reader. Points to first line of task after task "Waypoint list" line * @param task_info Loads this with CU task options info * @param turnpoint_infos Loads this with CU task tp info */ static void ParseCUTaskDetails(FileLineReader &reader, SeeYouTaskInformation *task_info, SeeYouTurnpointInformation turnpoint_infos[]) { // Read options/observation zones TCHAR params_buffer[1024]; const TCHAR *params[20]; TCHAR *line; int TPIndex = 0; const unsigned int max_params = ARRAY_SIZE(params); while ((line = reader.ReadLine()) != nullptr && line[0] != _T('\"') && line[0] != _T(',')) { const size_t n_params = ExtractParameters(line, params_buffer, params, max_params, true); if (StringIsEqual(params[0], _T("Options"))) { // Options line found ParseOptions(task_info, params, n_params); } else if (StringIsEqual(params[0], _T("ObsZone"), 7)) { // Observation zone line found if (_tcslen(params[0]) <= 8) continue; TPIndex = ParseOZs(turnpoint_infos, params, n_params); if (TPIndex == 0) task_info->max_start_altitude = turnpoint_infos[TPIndex].max_altitude; } } // end while }
bool WaypointReaderOzi::ParseLine(const TCHAR *line, Waypoints &way_points) { if (line[0] == '\0') return true; // Ignore first four header lines if (ignore_lines > 0) { --ignore_lines; return true; } TCHAR ctemp[255]; const TCHAR *params[20]; static constexpr unsigned int max_params = ARRAY_SIZE(params); size_t n_params; if (_tcslen(line) >= ARRAY_SIZE(ctemp)) /* line too long for buffer */ return false; // Get fields n_params = ExtractParameters(line, ctemp, params, max_params, true, _T('"')); // Check if the basic fields are provided if (n_params < 15) return false; GeoPoint location; // Latitude (e.g. 5115.900N) if (!ParseAngle(params[2], location.latitude)) return false; // Longitude (e.g. 00715.900W) if (!ParseAngle(params[3], location.longitude)) return false; location.Normalize(); // ensure longitude is within -180:180 Waypoint new_waypoint = factory.Create(location); long value; new_waypoint.original_id = (ParseNumber(params[0], value) ? value : 0); if (!ParseString(params[1], new_waypoint.name)) return false; if (ParseNumber(params[14], value) && value != -777) new_waypoint.elevation = Units::ToSysUnit(value, Unit::FEET); else if (!factory.FallbackElevation(new_waypoint)) return false; // Description (Characters 35-44) ParseString(params[11], new_waypoint.comment); way_points.Append(std::move(new_waypoint)); return true; }
/* * Same as ExtractParameters, but also validate the length of * the string and the NMEA checksum. */ size_t NMEAParser::ValidateAndExtract(const TCHAR *src, TCHAR *dst, size_t dstsz, TCHAR **arr, size_t arrsz) { int len = _tcslen(src); if (len <= 6 || len >= (int) dstsz) return 0; if (!NMEAChecksum(src)) return 0; return ExtractParameters(src, dst, arr, arrsz); }
// Create blocks from tags. void PopulateBlocks(const std::vector<RichTextTag>& tags) { // Create blocks using factories. for (const RichTextTag& tag : tags) { RichText::TAG_PARAMS params; // Extract the parameters from params_string to the tag_params map. ExtractParameters(tag.tag_params, params); BlockControl* block = FactoryMap()[tag.tag]->CreateFromTag(tag.tag, params, tag.content, m_font, m_color, m_format); if (block) { m_owner->AttachChild(block); m_blocks.push_back(block); } } DoLayout(); }
bool WaypointReaderSeeYou::ParseLine(const TCHAR* line, Waypoints &waypoints) { enum { iName = 0, iLatitude = 3, iLongitude = 4, iElevation = 5, iStyle = 6, iRWDir = 7, iRWLen = 8, iFrequency = 9, iDescription = 10, }; if (first) { first = false; /* skip first line if it doesn't begin with a quotation character (usually the field order line) */ if (line[0] != _T('\"')) return true; } // If (end-of-file or comment) if (StringIsEmpty(line) || StringStartsWith(line, _T("*"))) // -> return without error condition return true; TCHAR ctemp[4096]; if (_tcslen(line) >= ARRAY_SIZE(ctemp)) /* line too long for buffer */ return false; // If task marker is reached ignore all following lines if (StringStartsWith(line, _T("-----Related Tasks-----"))) ignore_following = true; if (ignore_following) return true; // Get fields const TCHAR *params[20]; size_t n_params = ExtractParameters(line, ctemp, params, ARRAY_SIZE(params), true, _T('"')); // Check if the basic fields are provided if (iName >= n_params || iLatitude >= n_params || iLongitude >= n_params) return false; GeoPoint location; // Latitude (e.g. 5115.900N) if (!ParseAngle(params[iLatitude], location.latitude, true)) return false; // Longitude (e.g. 00715.900W) if (!ParseAngle(params[iLongitude], location.longitude, false)) return false; location.Normalize(); // ensure longitude is within -180:180 Waypoint new_waypoint = factory.Create(location); // Name (e.g. "Some Turnpoint") if (*params[iName] == _T('\0')) return false; new_waypoint.name = params[iName]; // Elevation (e.g. 458.0m) /// @todo configurable behaviour if ((iElevation >= n_params || !ParseAltitude(params[iElevation], new_waypoint.elevation)) && !factory.FallbackElevation(new_waypoint)) return false; // Style (e.g. 5) if (iStyle < n_params) ParseStyle(params[iStyle], new_waypoint.type); new_waypoint.flags.turn_point = true; // Frequency & runway direction/length (for airports and landables) // and description (e.g. "Some Description") if (new_waypoint.IsLandable()) { if (iFrequency < n_params) new_waypoint.radio_frequency = RadioFrequency::Parse(params[iFrequency]); // Runway length (e.g. 546.0m) double rwlen = -1; if (iRWLen < n_params && ParseDistance(params[iRWLen], rwlen) && rwlen > 0) new_waypoint.runway.SetLength(uround(rwlen)); if (iRWDir < n_params && *params[iRWDir]) { TCHAR *end; int direction =_tcstol(params[iRWDir], &end, 10); if (end == params[iRWDir] || direction < 0 || direction > 360 || (direction == 0 && rwlen <= 0)) direction = -1; else if (direction == 360) direction = 0; if (direction >= 0) new_waypoint.runway.SetDirectionDegrees(direction); } } if (iDescription < n_params) { /* * This convention was introduced by the OpenAIP * project (http://www.openaip.net/), since no waypoint type * exists for thermal hotspots. */ if (StringStartsWith(params[iDescription], _T("Hotspot"))) new_waypoint.type = Waypoint::Type::THERMAL_HOTSPOT; new_waypoint.comment = params[iDescription]; } waypoints.Append(std::move(new_waypoint)); return true; }
bool WaypointReaderWinPilot::ParseLine(const TCHAR *line, Waypoints &waypoints) { TCHAR ctemp[4096]; const TCHAR *params[20]; static constexpr unsigned int max_params = ARRAY_SIZE(params); size_t n_params; // If (end-of-file) if (line[0] == '\0') // -> return without error condition return true; // If comment if (line[0] == _T('*')) { if (first) { first = false; welt2000_format = (_tcsstr(line, _T("WRITTEN BY WELT2000")) != nullptr); } // -> return without error condition return true; } if (_tcslen(line) >= ARRAY_SIZE(ctemp)) /* line too long for buffer */ return false; GeoPoint location; // Get fields n_params = ExtractParameters(line, ctemp, params, max_params, true); if (n_params < 6) return false; // Latitude (e.g. 51:15.900N) if (!ParseAngle(params[1], location.latitude, true)) return false; // Longitude (e.g. 00715.900W) if (!ParseAngle(params[2], location.longitude, false)) return false; location.Normalize(); // ensure longitude is within -180:180 Waypoint new_waypoint = factory.Create(location); // Name (e.g. KAMPLI) if (*params[5] == _T('\0')) return false; new_waypoint.name=params[5]; // Altitude (e.g. 458M) /// @todo configurable behaviour if (!ParseAltitude(params[3], new_waypoint.elevation) && !factory.FallbackElevation(new_waypoint)) return false; if (n_params > 6) { // Description (e.g. 119.750 Airport) new_waypoint.comment=params[6]; if (welt2000_format) ParseRunwayDirection(params[6], new_waypoint.runway); } // Waypoint Flags (e.g. AT) ParseFlags(params[4], new_waypoint); waypoints.Append(std::move(new_waypoint)); return true; }
VOID CRenoCommandFrame::OnReceive(INT nErrorCode,LPSTR buffer,ULONG received) { // TODO Write better error handling code here, maybe we do not have to panic on every error code if(nErrorCode) { // Write the error message PrintFormat(TEXT("* Error occurred during receive. Error code %d\r\n"),nErrorCode); // Make sure we disconnect CRenoCommandFrame::OnReceive(nErrorCode,buffer,received); return; } ASSERT(buffer); // Get the size of the translate buffer INT messageSize = MultiByteToWideChar(CP_UTF8,NULL,buffer,received,NULL,NULL); // Create the buffer that will hold the translated message LPTSTR message = new TCHAR[messageSize + 1]; ASSERT(message); // Translate the buffer messageSize = MultiByteToWideChar(CP_UTF8,NULL,buffer,received,message,messageSize); // Terminate the buffer message[messageSize] = NULL; CStringPtrArray messageElements; // Split the message buffer into individual messages SplitMessage(message,messageElements); // Do not need the translated buffer anymore delete[] message; // Process output for(LONG i = 0; i < messageElements.GetCount(); ++i) { // TODO Remove any unsupported characters //for(LONG j = 0; j < messageElements[i].GetLength(); ++j) // if(!_ismbcprint(messageElements[i].GetAt(j))) // messageElements[i].SetAt(j,TEXT('\v')); // Process the message element ULONG position = 0; CString prefix; // Is there a prefix if(messageElements[i].GetAt(0) == TEXT(':')) { // Extract the prefix prefix = messageElements[i].Mid(1, messageElements[i].Find(TEXT(' ')) - 1); position += prefix.GetLength() + 2; } CString command; // Are there any parameters after the command if(messageElements[i].Find(TEXT(' '), position)) { // Extract the command command = messageElements[i].Mid(position, messageElements[i].Find(TEXT(' '), position) - position); position += command.GetLength() + 1; } else { // The whole element is just a command command = messageElements[i].Mid(position); position += command.GetLength(); } CStringPtrArray parameterElements; // Extract parameters ExtractParameters(messageElements[i].GetBuffer() + position, parameterElements); // Find the reply handler const RENO_REPLY* replyMap = GetReplyMap(); ASSERT(replyMap); for(ULONG j = 0; replyMap[j].command ; ++j) { if(!_wcsicmp(replyMap[j].command,command) || !_wcsicmp(replyMap[j].command,TEXT("*"))) { // Execute the handler and stop further searching (this->*replyMap[j].handler)(prefix,command,parameterElements); break; } } } }
bool WaypointReaderSeeYou::ParseLine(const TCHAR* line, const unsigned linenum, Waypoints &waypoints) { enum { iName = 0, iLatitude = 3, iLongitude = 4, iElevation = 5, iStyle = 6, iRWDir = 7, iRWLen = 8, iFrequency = 9, iDescription = 10, }; if (linenum == 0) ignore_following = false; // If (end-of-file or comment) if (StringIsEmpty(line) || StringStartsWith(line, _T("**")) || StringStartsWith(line, _T("*"))) // -> return without error condition return true; TCHAR ctemp[4096]; if (_tcslen(line) >= ARRAY_SIZE(ctemp)) /* line too long for buffer */ return false; // Skip first line if it doesn't begin with a quotation character // (usually the field order line) if (linenum == 0 && line[0] != _T('\"')) return true; // If task marker is reached ignore all following lines if (_tcsstr(line, _T("-----Related Tasks-----")) == line) ignore_following = true; if (ignore_following) return true; // Get fields const TCHAR *params[20]; size_t n_params = ExtractParameters(line, ctemp, params, ARRAY_SIZE(params), true, _T('"')); // Check if the basic fields are provided if (iName >= n_params || iLatitude >= n_params || iLongitude >= n_params) return false; Waypoint new_waypoint; // Latitude (e.g. 5115.900N) if (!ParseAngle(params[iLatitude], new_waypoint.location.latitude, true)) return false; // Longitude (e.g. 00715.900W) if (!ParseAngle(params[iLongitude], new_waypoint.location.longitude, false)) return false; new_waypoint.location.Normalize(); // ensure longitude is within -180:180 new_waypoint.file_num = file_num; new_waypoint.original_id = 0; // Name (e.g. "Some Turnpoint") if (*params[iName] == _T('\0')) return false; new_waypoint.name = params[iName]; // Elevation (e.g. 458.0m) /// @todo configurable behaviour if ((iElevation >= n_params || !ParseAltitude(params[iElevation], new_waypoint.elevation)) && !CheckAltitude(new_waypoint)) return false; // Style (e.g. 5) if (iStyle < n_params) ParseStyle(params[iStyle], new_waypoint.type); new_waypoint.flags.turn_point = true; // Frequency & runway direction/length (for airports and landables) // and description (e.g. "Some Description") if (new_waypoint.IsLandable()) { if (iFrequency < n_params) new_waypoint.radio_frequency = RadioFrequency::Parse(params[iFrequency]); // Runway length (e.g. 546.0m) fixed rwlen = fixed_minus_one; if (iRWLen < n_params && ParseDistance(params[iRWLen], rwlen) && positive(rwlen)) new_waypoint.runway.SetLength(uround(rwlen)); if (iRWDir < n_params && *params[iRWDir]) { TCHAR *end; int direction =_tcstol(params[iRWDir], &end, 10); if (end == params[iRWDir] || direction < 0 || direction > 360 || (direction == 0 && !positive(rwlen))) direction = -1; else if (direction == 360) direction = 0; if (direction >= 0) new_waypoint.runway.SetDirectionDegrees(direction); } } if (iDescription < n_params) new_waypoint.comment = params[iDescription]; waypoints.Append(new_waypoint); return true; }
static void TestExtractParameters() { TCHAR buffer[1024]; const TCHAR *params[64]; unsigned n; // test basic functionality n = ExtractParameters(_T(""), buffer, params, 64); ok1(n == 1); ok1(StringIsEqual(params[0], _T(""))); n = ExtractParameters(_T("foo"), buffer, params, 64); ok1(n == 1); ok1(StringIsEqual(params[0], _T("foo"))); n = ExtractParameters(_T("foo,bar"), buffer, params, 64); ok1(n == 2); ok1(StringIsEqual(params[0], _T("foo"))); ok1(StringIsEqual(params[1], _T("bar"))); n = ExtractParameters(_T("foo,bar"), buffer, params, 1); ok1(n == 1); ok1(StringIsEqual(params[0], _T("foo"))); n = ExtractParameters(_T("foo,bar,"), buffer, params, 64); ok1(n == 3); ok1(StringIsEqual(params[0], _T("foo"))); ok1(StringIsEqual(params[1], _T("bar"))); ok1(StringIsEqual(params[2], _T(""))); n = ExtractParameters(_T("foo,bar,,"), buffer, params, 64); ok1(n == 4); ok1(StringIsEqual(params[0], _T("foo"))); ok1(StringIsEqual(params[1], _T("bar"))); ok1(StringIsEqual(params[2], _T(""))); ok1(StringIsEqual(params[3], _T(""))); // with qoutes but no quote handling n = ExtractParameters(_T("\"foo,comma\",\"bar\""), buffer, params, 64); ok1(n == 3); ok1(StringIsEqual(params[0], _T("\"foo"))); ok1(StringIsEqual(params[1], _T("comma\""))); ok1(StringIsEqual(params[2], _T("\"bar\""))); // quote handling n = ExtractParameters(_T("\"\""), buffer, params, 64, false, _T('"')); ok1(n == 1); ok1(StringIsEqual(params[0], _T(""))); n = ExtractParameters(_T("\"\"\""), buffer, params, 64, false, _T('"')); ok1(n == 1); ok1(StringIsEqual(params[0], _T("\""))); n = ExtractParameters(_T("\"\"\"\""), buffer, params, 64, false, _T('"')); ok1(n == 1); ok1(StringIsEqual(params[0], _T("\""))); n = ExtractParameters(_T("\"foo,comma\",\"bar\""), buffer, params, 64, false, _T('"')); ok1(n == 2); ok1(StringIsEqual(params[0], _T("foo,comma"))); ok1(StringIsEqual(params[1], _T("bar"))); // no quotes, whitespace removal n = ExtractParameters(_T("foo bar"), buffer, params, 64, true); ok1(n == 1); ok1(StringIsEqual(params[0], _T("foo bar"))); n = ExtractParameters(_T("foo , bar, baz"), buffer, params, 64, true); ok1(n == 3); ok1(StringIsEqual(params[0], _T("foo"))); ok1(StringIsEqual(params[1], _T("bar"))); ok1(StringIsEqual(params[2], _T("baz"))); n = ExtractParameters(_T(" foo , bar , baz "), buffer, params, 64, true); ok1(n == 3); ok1(StringIsEqual(params[0], _T("foo"))); ok1(StringIsEqual(params[1], _T("bar"))); ok1(StringIsEqual(params[2], _T("baz"))); n = ExtractParameters(_T(" foo\" , \" bar \" , \"baz "), buffer, params, 64, true); ok1(n == 3); ok1(StringIsEqual(params[0], _T("foo\""))); ok1(StringIsEqual(params[1], _T("\" bar \""))); ok1(StringIsEqual(params[2], _T("\"baz"))); // quote handling, whitespace removal n = ExtractParameters(_T("\"foo \" , \" bar\", \" baz\""), buffer, params, 64, true, _T('"')); ok1(n == 3); ok1(StringIsEqual(params[0], _T("foo "))); ok1(StringIsEqual(params[1], _T(" bar"))); ok1(StringIsEqual(params[2], _T(" baz"))); n = ExtractParameters(_T(" \" foo \" , \" bar \" , \" baz \" "), buffer, params, 64, true, _T('"')); ok1(n == 3); ok1(StringIsEqual(params[0], _T(" foo "))); ok1(StringIsEqual(params[1], _T(" bar "))); ok1(StringIsEqual(params[2], _T(" baz "))); n = ExtractParameters(_T("\"foo\",\"\",\"bar\""), buffer, params, 64, true, _T('"')); ok1(n == 3); ok1(StringIsEqual(params[0], _T("foo"))); ok1(StringIsEqual(params[1], _T(""))); ok1(StringIsEqual(params[2], _T("bar"))); // missing end quote n = ExtractParameters(_T("\"foo, bar"), buffer, params, 64, true, _T('"')); ok1(n == 1); ok1(StringIsEqual(params[0], _T("foo, bar"))); // embedded quotes and commas n = ExtractParameters(_T("\"foo, \"bar\"\""), buffer, params, 64, true, _T('"')); ok1(n == 1); ok1(StringIsEqual(params[0], _T("foo, \"bar\""))); n = ExtractParameters(_T("\"foo, \"\"bar\"\"\""), buffer, params, 64, true, _T('"')); ok1(n == 1); ok1(StringIsEqual(params[0], _T("foo, \"bar\""))); }
OrderedTask* TaskFileSeeYou::GetTask(const TaskBehaviour &task_behaviour, const Waypoints *waypoints, unsigned index) const { // Create FileReader for reading the task FileLineReader reader(path, IgnoreError(), Charset::AUTO); if (reader.error()) return nullptr; // Read waypoints from the CUP file Waypoints file_waypoints; { const WaypointFactory factory(WaypointOrigin::NONE); WaypointReaderSeeYou waypoint_file(factory); NullOperationEnvironment operation; waypoint_file.Parse(file_waypoints, reader, operation); } file_waypoints.Optimise(); if (!reader.Rewind()) return nullptr; TCHAR *line = AdvanceReaderToTask(reader, index); if (line == nullptr) return nullptr; // Read waypoint list // e.g. "Club day 4 Racing task","085PRI","083BOJ","170D_K","065SKY","0844YY", "0844YY" // TASK NAME , TAKEOFF, START , TP1 , TP2 , FINISH , LANDING TCHAR waypoints_buffer[1024]; const TCHAR *wps[30]; size_t n_waypoints = ExtractParameters(line, waypoints_buffer, wps, 30, true, _T('"')); // Some versions of StrePla append a trailing ',' without a following // WP name resulting an empty last entry. Remove it from the results if (n_waypoints > 0 && wps[n_waypoints - 1][0] == _T('\0')) n_waypoints --; // At least taskname and takeoff, start, finish and landing points are needed if (n_waypoints < 5) return nullptr; // Remove taskname, start point and landing point from count n_waypoints -= 3; SeeYouTaskInformation task_info; SeeYouTurnpointInformation turnpoint_infos[30]; WaypointPtr waypoints_in_task[30]; ParseCUTaskDetails(reader, &task_info, turnpoint_infos); OrderedTask *task = new OrderedTask(task_behaviour); task->SetFactory(task_info.wp_dis ? TaskFactoryType::RACING : TaskFactoryType::AAT); AbstractTaskFactory& fact = task->GetFactory(); const TaskFactoryType factType = task->GetFactoryType(); OrderedTaskSettings beh = task->GetOrderedTaskSettings(); if (factType == TaskFactoryType::AAT) { beh.aat_min_time = task_info.task_time; } if (factType == TaskFactoryType::AAT || factType == TaskFactoryType::RACING) { beh.start_constraints.max_height = (unsigned)task_info.max_start_altitude; beh.start_constraints.max_height_ref = AltitudeReference::MSL; } task->SetOrderedTaskSettings(beh); // mark task waypoints. Skip takeoff and landing point for (unsigned i = 0; i < n_waypoints; i++) { auto file_wp = file_waypoints.LookupName(wps[i + 2]); if (file_wp == nullptr) return nullptr; // Try to find waypoint by name auto wp = waypoints->LookupName(file_wp->name); // If waypoint by name found and closer than 10m to the original if (wp != nullptr && wp->location.DistanceS(file_wp->location) <= fixed(10)) { // Use this waypoint for the task waypoints_in_task[i] = wp; continue; } // Try finding the closest waypoint to the original one wp = waypoints->GetNearest(file_wp->location, fixed(10)); // If closest waypoint found and closer than 10m to the original if (wp != nullptr && wp->location.DistanceS(file_wp->location) <= fixed(10)) { // Use this waypoint for the task waypoints_in_task[i] = wp; continue; } // Use the original waypoint waypoints_in_task[i] = file_wp; } //now create TPs and OZs for (unsigned i = 0; i < n_waypoints; i++) { ObservationZonePoint* oz = CreateOZ(turnpoint_infos[i], i, n_waypoints, waypoints_in_task, factType); assert(waypoints_in_task[i]); OrderedTaskPoint *pt = CreatePoint(i, n_waypoints, WaypointPtr(waypoints_in_task[i]), fact, oz, factType); if (pt != nullptr) fact.Append(*pt, false); delete pt; } return task; }
//********************************************************************************* // Read OBJ file from disk // SCENE *ReadOBJFile(const char *sFileName, bool bGenerateMissingNormals) { FILE *pScene; char pcLine[512], pcMaterialLib[MAX_PATH], pcMaterialName[64]; const char *pcArgs; TAG_NAME Tag; SCENE *pS = NULL; unsigned int i, j; float fL; VERTEX FaceCenter, AB, AC, N; //--- Check parameters if (!sFileName) return(NULL); //--- Open scene file //pScene = fopen(sFileName, "r"); fopen_s(&pScene, sFileName, "r"); if (!pScene) return(NULL); //--- Create scene object pS = new SCENE; if (!pS) goto Exit; pS->pObjects = NULL; pS->u32ObjectsCount = 0; pS->pVertices = NULL; pS->u32VerticesCount = 0; pS->pNormals = NULL; pS->u32NormalsCount = 0; pS->pUV = NULL; pS->u32UVCount = 0; pS->pFaces = NULL; pS->u32FacesCount = 0; pS->pMaterials = NULL; pS->u32MaterialsCount = 0; //--- Parse scene file, first pass while (fgets(pcLine, sizeof(pcLine), pScene)) { //--- Parse file line pcArgs = TokenizeFileLine(pcLine, &Tag); //--- Process file line switch (Tag) { case TAGNAME_VERTEX: //--- Count vertex ++pS->u32VerticesCount; break; case TAGNAME_NORMAL: //--- Count normal ++pS->u32NormalsCount; break; case TAGNAME_TEXTURECOORDS: //--- Count UV pair ++pS->u32UVCount; break; case TAGNAME_FACE3: //--- Count face ++pS->u32FacesCount; break; case TAGNAME_FACE4: //--- Count 2 faces pS->u32FacesCount += 2; break; case TAGNAME_OBJECT: //--- Count object ++pS->u32ObjectsCount; break; case TAGNAME_MATLIB: //--- Parse materials library ExtractParameters(Tag, pcArgs, pcMaterialLib); ParseMaterialLibrary(pS, sFileName, pcMaterialLib, TRUE); break; } } if (!pS->u32VerticesCount || !pS->u32FacesCount) { ReleaseScene(pS); pS = NULL; goto Exit; } //--- Allocate scene buffers if (bGenerateMissingNormals && (pS->u32NormalsCount == 0)) pS->u32NormalsCount = pS->u32VerticesCount; else bGenerateMissingNormals = false; pS->pVertices = new VERTEX[pS->u32VerticesCount + pS->u32NormalsCount]; if (!pS->pVertices) { ReleaseScene(pS); pS = NULL; goto Exit; } if (pS->u32NormalsCount) pS->pNormals = pS->pVertices + pS->u32VerticesCount; else pS->pNormals = NULL; if (pS->u32UVCount) { pS->pUV = new TEXTURE_COORDS[pS->u32UVCount]; if (!pS->pUV) { ReleaseScene(pS); pS = NULL; goto Exit; } } pS->pFaces = new FACE[pS->u32FacesCount]; if (!pS->pFaces) { ReleaseScene(pS); pS = NULL; goto Exit; } pS->pMaterials = new MATERIAL[pS->u32MaterialsCount]; if (!pS->pMaterials) { ReleaseScene(pS); pS = NULL; goto Exit; } memset(pS->pMaterials, 0, sizeof(MATERIAL)*pS->u32MaterialsCount); //--- Init objects table pS->pObjects = new OBJECT[pS->u32ObjectsCount+1]; if (!pS->pObjects) { ReleaseScene(pS); pS = NULL; goto Exit; } pS->pObjects[0].u32FirstFace = 0; pS->pObjects[0].u32FacesCount = 0; pS->pObjects[0].u32Material = 0xFFFFFFFF; for (i=0; i<=pS->u32ObjectsCount; ++i) { memset(&pS->pObjects[i].Center, 0, sizeof(pS->pObjects[i].Center)); memset(pS->pObjects[i].pfMatrix, 0, sizeof(pS->pObjects[i].pfMatrix)); pS->pObjects[i].pfMatrix[0] = pS->pObjects[i].pfMatrix[5] = pS->pObjects[i].pfMatrix[10] = pS->pObjects[i].pfMatrix[15] = 1; } //--- Reparse scene file pS->u32VerticesCount = pS->u32NormalsCount = pS->u32UVCount = pS->u32FacesCount = pS->u32ObjectsCount = pS->u32MaterialsCount = 0; fseek(pScene, 0, SEEK_SET); while (fgets(pcLine, sizeof(pcLine), pScene)) { //--- Parse file line pcArgs = TokenizeFileLine(pcLine, &Tag); //--- Process file line switch (Tag) { case TAGNAME_VERTEX: //--- Retrieve vertex position ExtractParameters(Tag, pcArgs, &pS->pVertices[pS->u32VerticesCount++]); break; case TAGNAME_NORMAL: //--- Retrieve vertex normal ExtractParameters(Tag, pcArgs, &pS->pNormals[pS->u32NormalsCount++]); break; case TAGNAME_TEXTURECOORDS: //--- Retrieve UV coordinates ExtractParameters(Tag, pcArgs, &pS->pUV[pS->u32UVCount++]); break; case TAGNAME_FACE3: //--- Retrieve face description ExtractParameters(Tag, pcArgs, &pS->pFaces[pS->u32FacesCount++]); (pS->pObjects[pS->u32ObjectsCount].u32FacesCount)++; assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-1].pu32Normals[0] < pS->u32NormalsCount); assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-1].pu32Normals[1] < pS->u32NormalsCount); assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-1].pu32Normals[2] < pS->u32NormalsCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-1].pu32UV[0] < pS->u32UVCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-1].pu32UV[1] < pS->u32UVCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-1].pu32UV[2] < pS->u32UVCount); break; case TAGNAME_FACE4: //--- Retrieve faces description ExtractParameters(Tag, pcArgs, &pS->pFaces[pS->u32FacesCount]); pS->u32FacesCount += 2; pS->pObjects[pS->u32ObjectsCount].u32FacesCount += 2; assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-1].pu32Normals[0] < pS->u32NormalsCount); assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-1].pu32Normals[1] < pS->u32NormalsCount); assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-1].pu32Normals[2] < pS->u32NormalsCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-1].pu32UV[0] < pS->u32UVCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-1].pu32UV[1] < pS->u32UVCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-1].pu32UV[2] < pS->u32UVCount); assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-2].pu32Normals[0] < pS->u32NormalsCount); assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-2].pu32Normals[1] < pS->u32NormalsCount); assert(!pS->u32NormalsCount || pS->pFaces[pS->u32FacesCount-2].pu32Normals[2] < pS->u32NormalsCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-2].pu32UV[0] < pS->u32UVCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-2].pu32UV[1] < pS->u32UVCount); assert(!pS->u32UVCount || pS->pFaces[pS->u32FacesCount-2].pu32UV[2] < pS->u32UVCount); break; case TAGNAME_OBJECT: //--- Switch to next object pS->u32ObjectsCount++; pS->pObjects[pS->u32ObjectsCount].u32FirstFace = pS->u32FacesCount; pS->pObjects[pS->u32ObjectsCount].u32FacesCount = 0; //--- Retrieve material parameters ExtractParameters(Tag, pcArgs, pcMaterialName); //--- Look for material pS->pObjects[pS->u32ObjectsCount].u32Material = 0; for (; pS->pObjects[pS->u32ObjectsCount].u32Material<pS->u32MaterialsCount; pS->pObjects[pS->u32ObjectsCount].u32Material++) { if (!_stricmp(pS->pMaterials[pS->pObjects[pS->u32ObjectsCount].u32Material].pcName, pcMaterialName)) break; } if (pS->pObjects[pS->u32ObjectsCount].u32Material >= pS->u32MaterialsCount) pS->pObjects[pS->u32ObjectsCount].u32Material = 0xFFFFFFFF; break; case TAGNAME_MATLIB: //--- Parse materials library ExtractParameters(Tag, pcArgs, pcMaterialLib); ParseMaterialLibrary(pS, sFileName, pcMaterialLib, FALSE); break; } } pS->u32ObjectsCount++; //--- Initialize normals if (bGenerateMissingNormals) { pS->u32NormalsCount = pS->u32VerticesCount; for (i=0; i<pS->u32NormalsCount; ++i) pS->pNormals[i].fX = pS->pNormals[i].fY = pS->pNormals[i].fZ = 0; for (i=0; i<pS->u32FacesCount; ++i) { //--- Update normals indices pS->pFaces[i].pu32Normals[0] = pS->pFaces[i].pu32Vertices[0]; pS->pFaces[i].pu32Normals[1] = pS->pFaces[i].pu32Vertices[1]; pS->pFaces[i].pu32Normals[2] = pS->pFaces[i].pu32Vertices[2]; //--- Compute face normal AB.fX = pS->pVertices[pS->pFaces[i].pu32Vertices[1]].fX - pS->pVertices[pS->pFaces[i].pu32Vertices[0]].fX; AB.fY = pS->pVertices[pS->pFaces[i].pu32Vertices[1]].fY - pS->pVertices[pS->pFaces[i].pu32Vertices[0]].fY; AB.fZ = pS->pVertices[pS->pFaces[i].pu32Vertices[1]].fZ - pS->pVertices[pS->pFaces[i].pu32Vertices[0]].fZ; AC.fX = pS->pVertices[pS->pFaces[i].pu32Vertices[2]].fX - pS->pVertices[pS->pFaces[i].pu32Vertices[0]].fX; AC.fY = pS->pVertices[pS->pFaces[i].pu32Vertices[2]].fY - pS->pVertices[pS->pFaces[i].pu32Vertices[0]].fY; AC.fZ = pS->pVertices[pS->pFaces[i].pu32Vertices[2]].fZ - pS->pVertices[pS->pFaces[i].pu32Vertices[0]].fZ; N.fX = AB.fY*AC.fZ - AC.fY*AB.fZ; N.fY = AC.fX*AB.fZ - AB.fX*AC.fZ; N.fZ = AB.fX*AC.fY - AC.fX*AB.fY; //--- Normalize fL = sqrtf(N.fX*N.fX + N.fY*N.fY + N.fZ*N.fZ); if (fL > 0) { fL = 1.f/fL; N.fX *= fL; N.fY *= fL; N.fZ *= fL; } //--- Store for contribution to face's vertices pS->pNormals[pS->pFaces[i].pu32Normals[0]].fX += N.fX; pS->pNormals[pS->pFaces[i].pu32Normals[0]].fY += N.fY; pS->pNormals[pS->pFaces[i].pu32Normals[0]].fZ += N.fZ; pS->pNormals[pS->pFaces[i].pu32Normals[1]].fX += N.fX; pS->pNormals[pS->pFaces[i].pu32Normals[1]].fY += N.fY; pS->pNormals[pS->pFaces[i].pu32Normals[1]].fZ += N.fZ; pS->pNormals[pS->pFaces[i].pu32Normals[2]].fX += N.fX; pS->pNormals[pS->pFaces[i].pu32Normals[2]].fY += N.fY; pS->pNormals[pS->pFaces[i].pu32Normals[2]].fZ += N.fZ; } //--- Renormalize for (i=0; i<pS->u32NormalsCount; ++i) { fL = sqrtf(pS->pNormals[i].fX*pS->pNormals[i].fX + pS->pNormals[i].fY*pS->pNormals[i].fY + pS->pNormals[i].fZ*pS->pNormals[i].fZ); if (fL > 0) { fL = 1.f/fL; pS->pNormals[i].fX *= fL; pS->pNormals[i].fY *= fL; pS->pNormals[i].fZ *= fL; } } } //--- Compute centers for all objects for (i=0; i<pS->u32ObjectsCount; ++i) { for (j=0; j<pS->pObjects[i].u32FacesCount; ++j) { //--- Compute face center FaceCenter.fX = pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[0]].fX; FaceCenter.fX+= pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[1]].fX; FaceCenter.fX += pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[2]].fX; FaceCenter.fY = pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[0]].fY; FaceCenter.fY += pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[1]].fY; FaceCenter.fY += pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[2]].fY; FaceCenter.fZ = pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[0]].fZ; FaceCenter.fZ += pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[1]].fZ; FaceCenter.fZ += pS->pVertices[pS->pFaces[pS->pObjects[i].u32FirstFace + j].pu32Vertices[2]].fZ; pS->pObjects[i].Center.fX += FaceCenter.fX/3; pS->pObjects[i].Center.fY += FaceCenter.fY/3; pS->pObjects[i].Center.fZ += FaceCenter.fZ/3; } pS->pObjects[i].Center.fX /= pS->pObjects[i].u32FacesCount; pS->pObjects[i].Center.fY /= pS->pObjects[i].u32FacesCount; pS->pObjects[i].Center.fZ /= pS->pObjects[i].u32FacesCount; } Exit: //--- Close scene file fclose(pScene); return(pS); }
//********************************************************************************* // Parse materials library file // static void ParseMaterialLibrary(SCENE *pS, const char *sSceneFile, const char *sMatLib, BOOL bParseOnly) { FILE *pMat; char pcLine[512], pcPath[MAX_PATH], *pcPtr; const char *pcArgs; TAG_NAME Tag; if (!sMatLib) return; //--- Extract base path strcpy_s(pcPath, sSceneFile); pcPtr = pcPath + strlen(pcPath)-1; while ((pcPtr > pcPath) && (*(pcPtr-1) != '\\') && (*(pcPtr-1) != '/') && (*(pcPtr-1) != ':')) --pcPtr; *pcPtr = 0; strcat_s(pcPath, sMatLib); pcPtr = pcPath; while (*pcPtr) { if (*pcPtr == '/') *pcPtr = '\\'; pcPtr++; } //--- Open scene file fopen_s(&pMat, pcPath, "r"); if (!pMat) return; //--- Parse scene file, first pass while (fgets(pcLine, sizeof(pcLine), pMat)) { //--- Parse file line pcArgs = TokenizeFileLine(pcLine, &Tag); //--- Process file line switch (Tag) { case TAGNAME_MATERIAL: //--- Retrieve new material name if (!bParseOnly) { ExtractParameters(Tag, pcArgs, pS->pMaterials[pS->u32MaterialsCount].pcName); pS->pMaterials[pS->u32MaterialsCount].pfAmbient[0] = pS->pMaterials[pS->u32MaterialsCount].pfAmbient[1] = pS->pMaterials[pS->u32MaterialsCount].pfAmbient[2] = pS->pMaterials[pS->u32MaterialsCount].pfAmbient[3] = 0; pS->pMaterials[pS->u32MaterialsCount].pfDiffuse[0] = pS->pMaterials[pS->u32MaterialsCount].pfDiffuse[1] = pS->pMaterials[pS->u32MaterialsCount].pfDiffuse[2] = 0; pS->pMaterials[pS->u32MaterialsCount].pfDiffuse[3] = 1; pS->pMaterials[pS->u32MaterialsCount].pfSpecular[0] = pS->pMaterials[pS->u32MaterialsCount].pfSpecular[1] = pS->pMaterials[pS->u32MaterialsCount].pfSpecular[2] = pS->pMaterials[pS->u32MaterialsCount].pfSpecular[3] = 0; pS->pMaterials[pS->u32MaterialsCount].pfEmission[0] = pS->pMaterials[pS->u32MaterialsCount].pfEmission[1] = pS->pMaterials[pS->u32MaterialsCount].pfEmission[2] = pS->pMaterials[pS->u32MaterialsCount].pfEmission[3] = 0; pS->pMaterials[pS->u32MaterialsCount].fShininess = 128; pS->pMaterials[pS->u32MaterialsCount].pcTextureFile[0] = 0; pS->pMaterials[pS->u32MaterialsCount].pDiffuse = NULL; pS->pMaterials[pS->u32MaterialsCount].u32RenderFlags = 0; } pS->u32MaterialsCount++; break; case TAGNAME_OPACITY: //--- Retrieve opacity properties if (bParseOnly) break; ExtractParameters(Tag, pcArgs, &pS->pMaterials[pS->u32MaterialsCount-1].pfDiffuse[3]); break; case TAGNAME_SHININESS: //--- Retrieve shininess properties if (bParseOnly) break; ExtractParameters(Tag, pcArgs, &pS->pMaterials[pS->u32MaterialsCount-1].fShininess); if (pS->pMaterials[pS->u32MaterialsCount-1].fShininess < 1) pS->pMaterials[pS->u32MaterialsCount-1].fShininess = 1; else if (pS->pMaterials[pS->u32MaterialsCount-1].fShininess > 128) pS->pMaterials[pS->u32MaterialsCount-1].fShininess = 128; break; case TAGNAME_ILLUMINATION: //--- Retrieve lighting properties if (bParseOnly) break; ExtractParameters(Tag, pcArgs, &pS->pMaterials[pS->u32MaterialsCount-1].u32RenderFlags); break; case TAGNAME_AMBIENT: //--- Retrieve ambient properties if (bParseOnly) break; ExtractParameters(Tag, pcArgs, pS->pMaterials[pS->u32MaterialsCount-1].pfAmbient); break; case TAGNAME_DIFFUSE: //--- Retrieve diffuse properties if (bParseOnly) break; ExtractParameters(Tag, pcArgs, pS->pMaterials[pS->u32MaterialsCount-1].pfDiffuse); break; case TAGNAME_SPECULAR: //--- Retrieve specular properties if (bParseOnly) break; ExtractParameters(Tag, pcArgs, pS->pMaterials[pS->u32MaterialsCount-1].pfSpecular); break; case TAGNAME_EMISSION: //--- Retrieve emission properties if (bParseOnly) break; ExtractParameters(Tag, pcArgs, pS->pMaterials[pS->u32MaterialsCount-1].pfEmission); break; case TAGNAME_TEXTURE: //--- Retrieve texture filename if (bParseOnly) break; ExtractParameters(Tag, pcArgs, pS->pMaterials[pS->u32MaterialsCount-1].pcTextureFile); //--- Extract base path strcpy_s(pcPath, sSceneFile); pcPtr = pcPath + strlen(pcPath)-1; while ((pcPtr > pcPath) && (*(pcPtr-1) != '\\') && (*(pcPtr-1) != '/') && (*(pcPtr-1) != ':')) --pcPtr; *pcPtr = 0; strcat_s(pcPath, pS->pMaterials[pS->u32MaterialsCount-1].pcTextureFile); pcPtr = pcPath; while (*pcPtr) { if (*pcPtr == '/') *pcPtr = '\\'; pcPtr++; } //--- Load texture file pS->pMaterials[pS->u32MaterialsCount-1].pDiffuse = ReadTGA(pcPath); break; } } //-- Close library file fclose(pMat); }