void loom_asset_registerType(unsigned int type, LoomAssetDeserializeCallback deserializer, LoomAssetRecognizerCallback recognizer) { lmAssert(gAssetDeserializerMap.find(type) == UT_NPOS, "Asset type already registered!"); gAssetDeserializerMap.insert(type, deserializer); gRecognizerList.push_back(recognizer); }
void loom_asset_reload(const char *name) { loom_mutex_lock(gAssetLock); loom_asset_t *asset = loom_asset_getAssetByName(name, 1); // Put it in the queue, this will trigger a new blob to be loaded. gAssetLoadQueue.push_back(asset); loom_mutex_unlock(gAssetLock); }
void akMeshLoaderUtils_getVertexGroups(Blender::Mesh* bmesh, Blender::Object* bobj, utArray<utString>& vgroups) { if(bmesh->dvert) { Blender::bDeformGroup* dg = (Blender::bDeformGroup*)bobj->defbase.first; while(dg) { vgroups.push_back(dg->name); dg = dg->next; } } }
void NativeDelegate::postNativeDelegateCallNote(NativeDelegateCallNote *ndcn) { ensureQueueInit(); loom_mutex_lock(gCallNoteMutex); // Prep for reading. ndcn->rewind(); // Store for later access. gNDCallNoteQueue.push_back(ndcn); loom_mutex_unlock(gCallNoteMutex); }
void Type::findMembers(const MemberTypes& memberTypes, utArray<MemberInfo *>& membersOut, bool includeBases, bool includePropertyGetterSetters) { if (!includeBases) { membersOut.clear(); } for (size_t i = 0; i < members.size(); i++) { MemberInfo *m = members.at((int)i); if (m->isConstructor() && memberTypes.constructor) { membersOut.push_back(m); } if (m->isMethod() && memberTypes.method) { membersOut.push_back(m); } if (m->isField() && memberTypes.field) { membersOut.push_back(m); } if (m->isProperty() && memberTypes.property) { membersOut.push_back(m); if (includePropertyGetterSetters) { PropertyInfo *p = (PropertyInfo *)m; if (p->getter && (p->getter->getDeclaringType() == p->getDeclaringType())) { membersOut.push_back(p->getter); } if (p->setter && (p->setter->getDeclaringType() == p->getDeclaringType())) { membersOut.push_back(p->setter); } } } } if (baseType && includeBases) { baseType->findMembers(memberTypes, membersOut, true, includePropertyGetterSetters); } }
void loom_asset_preload(const char *name) { loom_mutex_lock(gAssetLock); // Look 'er up. loom_asset_t *asset = loom_asset_getAssetByName(name, 1); // If it's not pending load, then stick it in the queue. if (loom_asset_isOnTrackToLoad(asset)) { loom_mutex_unlock(gAssetLock); return; } asset->state = loom_asset_t::QueuedForDownload; gAssetLoadQueue.push_back(asset); loom_mutex_unlock(gAssetLock); }
/** * Post all known files to all clients, or if specified, a single client. * * Useful for fully synching client with the current asset state. * * TODO: Optimize to use hashes to only transmit modified data, based on * client's starting assets. */ static void postAllFiles(int clientId = -1) { lmLog(gAssetAgentLogGroup, "Queueing all files for client %d.", clientId); loom_mutex_lock(gFileScannerLock); // Walk all the files. utArray<FileEntry> *list = lmNew(NULL) utArray<FileEntry>(); platform_walkFiles(".", handleFileStateWalkCallback, list); // Queue them all to be sent. for (UTsize i = 0; i < list->size(); i++) { FileModificationNote note; note.path = stringtable_insert((*list)[i].path.c_str()); note.lastSeenTime = 0; note.onlyForClient = clientId; gPendingModifications.push_back(note); } loom_mutex_unlock(gFileScannerLock); }
void akMeshLoaderUtils_getShapeKeys(Blender::Mesh* bmesh, utArray<utString>& shapes) { Blender::Key* bk = bmesh->key; if(bk) { Blender::KeyBlock* bkb = (Blender::KeyBlock*)bk->block.first; // skip first shape key (basis) if(bkb) bkb = bkb->next; while(bkb) { if(bkb->type == KEY_RELATIVE) { Blender::KeyBlock* basis = (Blender::KeyBlock*)bk->block.first; for(int i=0; basis && i<bkb->relative; i++) basis = basis->next; if(basis) shapes.push_back(bkb->name); } bkb = bkb->next; } } }
// Entry point for the socket thread. Listen for connections and incoming data, // and route it to the protocol handlers. static int socketListeningThread(void *payload) { // Listen for incoming connections. int listenPort = 12340; gListenSocket = (loom_socketId_t)-1; for ( ; ; ) { gListenSocket = loom_net_listenTCPSocket(listenPort); if (gListenSocket != (loom_socketId_t)-1) { break; } lmLogWarn(gAssetAgentLogGroup, " - Failed to acquire port %d, trying port %d", listenPort, listenPort + 1); listenPort++; } lmLog(gAssetAgentLogGroup, "Listening on port %d", listenPort); while (loom_socketId_t acceptedSocket = loom_net_acceptTCPSocket(gListenSocket)) { // Check to see if we got anybody... if (!acceptedSocket || ((int)(long)acceptedSocket == -1)) { // Process the connections. loom_mutex_lock(gActiveSocketsMutex); for (UTsize i = 0; i < gActiveHandlers.size(); i++) { AssetProtocolHandler* aph = gActiveHandlers[i]; aph->process(); // Check for ping timeout int msSincePing = loom_readTimer(aph->lastActiveTime); if (msSincePing > socketPingTimeoutMs) { gActiveHandlers.erase(i); i--; lmLog(gAssetAgentLogGroup, "Client timed out (%x)", aph->socket); loom_net_closeTCPSocket(aph->socket); lmDelete(NULL, aph); } } loom_mutex_unlock(gActiveSocketsMutex); loom_thread_sleep(10); continue; } lmLog(gAssetAgentLogGroup, "Client connected (%x)", acceptedSocket); loom_mutex_lock(gActiveSocketsMutex); gActiveHandlers.push_back(lmNew(NULL) AssetProtocolHandler(acceptedSocket)); AssetProtocolHandler *handler = gActiveHandlers.back(); handler->registerListener(lmNew(NULL) TelemetryListener()); if (TelemetryServer::isRunning()) handler->sendCommand("telemetryEnable"); // Send it all of our files. // postAllFiles(gActiveHandlers[gActiveHandlers.size()-1]->getId()); loom_mutex_unlock(gActiveSocketsMutex); } return 0; }
// Take a difference report from compareFileEntries and issue appropriate // file modification notes, and check whether they have settled. If so, // transmit updates to clients. static void processFileEntryDeltas(utArray<FileEntryDelta> *deltas) { int curTime = platform_getMilliseconds(); loom_mutex_lock(gFileScannerLock); // Update the pending list with all the stuff we've seen. for (UTsize i = 0; i < deltas->size(); i++) { // Get the delta. const FileEntryDelta& fed = deltas->at(i); // If it's removal, we don't currently send a notification. if (fed.action == FileEntryDelta::Removed) { continue; } // If it's not whitelisted, ignore it. if (!checkInWhitelist(fed.path)) { continue; } // Note it in the pending modification list. bool sawInList = false; for (UTsize i = 0; i < gPendingModifications.size(); i++) { FileModificationNote& fmn = gPendingModifications.at(i); if (strcmp(fmn.path, fed.path.c_str())) { continue; } // Match - update time. lmLogDebug(gAssetAgentLogGroup, "FILE CHANGING - '%s'", fed.path.c_str()); fmn.lastSeenTime = curTime; sawInList = true; } if (!sawInList) { FileModificationNote fmn; fmn.path = stringtable_insert(fed.path.c_str()); fmn.lastSeenTime = curTime; gPendingModifications.push_back(fmn); lmLogDebug(gAssetAgentLogGroup, "FILE CHANGED - '%s'", fed.path.c_str()); } } // Now, walk the pending list and send everyone who hasn't been touched for the settling period. // See how many files we're sending and note that state. const int settleTimeMs = 750; int transferStartTime = platform_getMilliseconds(); int totalPendingTransfers = 0; for (UTsize i = 0; i < gPendingModifications.size(); i++) { // Only consider pending items that have aged out. FileModificationNote& fmn = gPendingModifications.at(i); if (curTime - fmn.lastSeenTime < settleTimeMs) { continue; } totalPendingTransfers++; } bool didWeNotifyUserAboutPending = false; for (UTsize i = 0; i < gPendingModifications.size(); i++) { // Only consider pending items that have aged out. FileModificationNote& fmn = gPendingModifications.at(i); if (curTime - fmn.lastSeenTime < settleTimeMs) { continue; } // Make the path canonical. utString filename = fmn.path; char canonicalFile[MAXPATHLEN]; makeAssetPathCanonical(filename.c_str(), canonicalFile); // Note: we don't deal with deleted files properly (by uploading new state) because realpath // only works right when the file exists. So we just skip doing anything about it. // Note we are using gActiveHandlers.size() outside of a lock, but this is ok as it's a word. if ((strstr(canonicalFile, ".loom") || strstr(canonicalFile, ".ls")) && (gActiveHandlers.size() > 0)) { lmLog(gAssetAgentLogGroup, "Changed '%s'", canonicalFile); } if (canonicalFile[0] == 0) { lmLog(gAssetAgentLogGroup, " o Ignoring file missing from the asset folder!"); // Remove from the pending list. gPendingModifications.erase(i); i--; continue; } // Queue the callback. enqueueFileChangeCallback(canonicalFile); // Map the file. void *fileBits = NULL; long fileBitsLength = 0; if (!platform_mapFile(canonicalFile, &fileBits, &fileBitsLength)) { lmLog(gAssetAgentLogGroup, " o Skipping due to file failing to map."); continue; } // Loop over the active sockets. loom_mutex_lock(gActiveSocketsMutex); // Blast it out to all clients. for (UTsize j = 0; j < gActiveHandlers.size(); j++) { // If it's for a specific client then only send to that client. if ((fmn.onlyForClient != -1) && (fmn.onlyForClient != gActiveHandlers[j]->getId())) { continue; } gActiveHandlers[j]->sendFile(canonicalFile, fileBits, fileBitsLength, totalPendingTransfers); // If it has been more than a second, note that we are still working. const int remainingTransferCount = (totalPendingTransfers * gActiveHandlers.size()) - j; if (((platform_getMilliseconds() - transferStartTime) > 2000) && (remainingTransferCount > 1)) { transferStartTime = platform_getMilliseconds(); lmLog(gAssetAgentLogGroup, "Still transferring files. %d to go!", remainingTransferCount - 1); didWeNotifyUserAboutPending = true; } } loom_mutex_unlock(gActiveSocketsMutex); totalPendingTransfers--; // Unmap the file. platform_unmapFile(fileBits); // Remove from the pending list. gPendingModifications.erase(i); i--; } loom_mutex_unlock(gFileScannerLock); if (didWeNotifyUserAboutPending) { lmLog(gAssetAgentLogGroup, "Done transferring files!"); } }
void addVertex(unsigned int fi, unsigned int bindex, const akMeshLoader::TempVert& ref) { utArray<float> uvs; for(int j=0; j<AK_UV_MAX; j++) { uvs.push_back(ref.uv[j][0]); uvs.push_back(ref.uv[j][1]); } UTuint32 id = item->addVertex(ref.co, ref.no, ref.vcol, uvs); idxmap.push_back(bindex); // vgroups if(m_bmesh->dvert) { Blender::MDeformVert& dv = m_bmesh->dvert[bindex]; for(int j=0; j<dv.totweight; j++) { UTuint32 vgi = dv.dw[j].def_nr; if( vgi < item->getNumVertexGroups() ) { akVertexGroup* vg = item->getVertexGroup(vgi); vg->add(id, dv.dw[j].weight); } } } // morphtargets if(m_bmesh->key) { Blender::KeyBlock* bkb = (Blender::KeyBlock*)m_bmesh->key->block.first; // skip first shape key (basis) int mti=0; if(bkb) bkb = bkb->next; while(bkb) { if(bkb->type == KEY_RELATIVE) { Blender::KeyBlock* basis = (Blender::KeyBlock*)m_bmesh->key->block.first; for(int i=0; basis && i<bkb->relative; i++) basis = basis->next; if(basis) { //akMorphTarget* mt = item->getMorphTarget(bkb->name); akMorphTarget* mt = item->getMorphTarget(mti); float* kpos = (float*)bkb->data; float* bpos = (float*)basis->data; akVector3 k(kpos[3*bindex+0], kpos[3*bindex+1], kpos[3*bindex+2]); akVector3 b(bpos[3*bindex+0], bpos[3*bindex+1], bpos[3*bindex+2]); k = k-b; btAlignedObjectArray<akVector3>& norms = shapekeysnormals->at(mti); akVector3 normal(0,0,0); const Blender::MFace& bface = m_bmesh->mface[fi]; if(bface.flag & ME_SMOOTH) { utArray<UTuint32>& smoothfaces = smoothfacesarray->at(bindex); for (int j = 0; j< smoothfaces.size(); j++) { UTuint32 bface2id = smoothfaces[j]; normal += norms.at(bface2id); } normal = normalize(normal); } else { normal = norms.at(fi); } normal = normal - ref.no; if(!akFuzzyT(lengthSqr(k), 1e-10f) || !akFuzzyT(lengthSqr(normal), 1e-10f)) mt->add(id, k, normal); mti++; } } bkb = bkb->next; } } }
void loom_asset_registerType(unsigned int type, LoomAssetDeserializeCallback deserializer, LoomAssetRecognizerCallback recognizer) { gAssetDeserializerMap.insert(type, deserializer); gRecognizerList.push_back(recognizer); }