// This is the entry point for the file watcher thread. It scans local files // for changes and processes the diffs with processFileEntryDeltas. static int fileWatcherThread(void *payload) { // Start with a sane state so we don't stream everything. utArray<FileEntry> *oldState = generateFileState("."); // Loop forever looking for changes. for ( ; ; ) { int startTime = platform_getMilliseconds(); utArray<FileEntry> *newState = generateFileState("."); utArray<FileEntryDelta> *deltas = compareFileEntries(oldState, newState); int endTime = platform_getMilliseconds(); if (endTime - startTime > 250) { lmLogWarn(gAssetAgentLogGroup, "Scanning files took %dms, consider removing unused files", endTime - startTime); } processFileEntryDeltas(deltas); lmDelete(NULL, deltas); // Make the new state the old state and clean up the old state. lmDelete(NULL, oldState); oldState = newState; // Wait a bit so we don't saturate disk or CPU. loom_thread_sleep(gFileCheckInterval); } }
// Clears the asset name cache that is built up // through loom_asset_lock and others static void loom_asset_clear() { utHashTableIterator<utHashTable<utHashedString, loom_asset_t *> > assetIterator(gAssetHash); while (assetIterator.hasMoreElements()) { utHashedString key = assetIterator.peekNextKey(); lmDelete(NULL, assetIterator.peekNextValue()); assetIterator.next(); } gAssetHash.clear(); }
bool decRef() { refCount--; if(refCount == 0) { if(dtor) dtor(bits); else lmFree(gAssetAllocator, bits); refCount = 0xBAADF00D; length = -1; bits = NULL; lmDelete(gAssetAllocator, this); return true; } return false; }
static void loom_asset_binaryDtor(void *bytes) { lmDelete(NULL, (utByteArray*)bytes); }
void DLLEXPORT assetAgent_run(IdleCallback idleCb, LogCallback logCb, FileChangeCallback changeCb) { loom_log_initialize(); platform_timeInitialize(); stringtable_initialize(); loom_net_initialize(); // Put best effort towards closing our listen socket when we shut down, to // avoid bugs on OSX where the OS won't release it for a while. #if LOOM_PLATFORM == LOOM_PLATFORM_OSX || LOOM_PLATFORM == LOOM_PLATFORM_LINUX atexit(shutdownListenSocket); signal(SIGINT, shutdownListenSocketSignalHandler); #endif // Set up mutexes. gActiveSocketsMutex = loom_mutex_create(); gFileScannerLock = loom_mutex_create(); gCallbackLock = loom_mutex_create(); // Note callbacks. gLogCallback = logCb; gFileChangeCallback = changeCb; utString *sdkPath = optionGet("sdk"); if (sdkPath != NULL) TelemetryServer::setClientRootFromSDK(sdkPath->c_str()); const char *ltcPath = getenv("LoomTelemetry"); if (ltcPath != NULL) TelemetryServer::setClientRoot(ltcPath); if (optionEquals("telemetry", "true")) TelemetryServer::start(); // Set up the log callback. loom_log_addListener(fileWatcherLogListener, NULL); lmLogDebug(gAssetAgentLogGroup, "Starting file watcher thread..."); gFileWatcherThread = loom_thread_start((ThreadFunction)fileWatcherThread, NULL); lmLogDebug(gAssetAgentLogGroup, " o OK!"); lmLogDebug(gAssetAgentLogGroup, "Starting socket listener thread..."); gSocketListenerThread = loom_thread_start((ThreadFunction)socketListeningThread, NULL); lmLogDebug(gAssetAgentLogGroup, " o OK!"); // Loop till it's time to quit. while (!gQuitFlag) { // Serve the idle callback. if (idleCb) { idleCb(); } // And anything in the queue. while (CallbackQueueNote *cqn = dequeueCallback()) { if (!cqn) { break; } // Issue the call. if (cqn->type == QNT_Change) { gFileChangeCallback(cqn->text.c_str()); } else if (cqn->type == QNT_Log) { gLogCallback(cqn->text.c_str()); } else { lmAssert(false, "Unknown callback queue note type."); } // Clean it up. //free((void *)cqn->text); lmDelete(NULL, cqn); } // Pump any remaining socket writes loom_net_pump(); // Poll at about 60hz. loom_thread_sleep(16); } // Clean up the socket. shutdownListenSocket(); }
// 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; }
void DisplayObject::render(lua_State *L) { // Disable reentrancy for this function (read: don't cache to texture while caching to a texture) if (cacheAsBitmapInProgress) return; // Clear and free the cached image if the conditions apply if ((!cacheAsBitmap || !cacheAsBitmapValid) && cachedImage != NULL) { Quad* quad = static_cast<Quad*>(cachedImage); lmAssert(quad != NULL, "Cached image is invalid"); GFX::Texture::dispose(quad->getNativeTextureID()); quad->setNativeTextureID(-1); lmDelete(NULL, quad); cachedImage = NULL; cacheAsBitmapValid = false; } // Cache the contents into an image if the conditions apply if (cacheAsBitmap && !cacheAsBitmapValid && cachedImage == NULL) { cacheAsBitmapInProgress = true; // Used for displaying the texture Quad* quad = lmNew(NULL) Quad(); // Setup for getmember lualoom_pushnative<DisplayObject>(L, this); // Push function and arguments lualoom_getmember(L, -1, "getBounds"); lualoom_pushnative<DisplayObject>(L, this); lua_pushnil(L); // Call getBounds lua_call(L, 2, 1); // Returned result Loom2D::Rectangle *bounds = (Loom2D::Rectangle*) lualoom_getnativepointer(L, -1); cacheAsBitmapOffsetX = bounds->x; cacheAsBitmapOffsetY = bounds->y; lmscalar fracWidth = bounds->width; lmscalar fracHeight = bounds->height; // pop bounds Rectangle and the DisplayObject at the top lua_pop(L, 1+1); if (cacheApplyScale) { fracWidth *= scaleX; fracHeight *= scaleY; } // Convert to integers for the following math int texWidthI = static_cast<int>(ceil(fracWidth)); int texHeightI = static_cast<int>(ceil(fracHeight)); // Calculate power of 2 sizes if (cacheUseTexturesPot) { _UT_UTHASHTABLE_POW2(texWidthI); _UT_UTHASHTABLE_POW2(texHeightI); } // Calculate the resulting scale (as a consequence of pow2 sizes) // Used for 'trans' matrix lmscalar calcScaleX = texWidthI / bounds->width; lmscalar calcScaleY = texHeightI / bounds->height; // Setup texture TextureInfo *tinfo = Texture::initEmptyTexture(texWidthI, texHeightI); Texture::clear(tinfo->id, 0x000000, 0); tinfo->smoothing = TEXTUREINFO_SMOOTHING_BILINEAR; tinfo->wrapU = TEXTUREINFO_WRAP_CLAMP; tinfo->wrapV = TEXTUREINFO_WRAP_CLAMP; TextureID id = tinfo->id; // Setup quad for rendering the texture quad->setNativeTextureID(id); VertexPosColorTex* qv; qv = &quad->quadVertices[0]; qv->x = 0; qv->y = 0; qv->z = 0; qv->abgr = 0xFFFFFFFF; qv->u = 0; qv->v = 0; qv = &quad->quadVertices[1]; qv->x = (float)bounds->width; qv->y = 0; qv->z = 0; qv->abgr = 0xFFFFFFFF; qv->u = 1; qv->v = 0; qv = &quad->quadVertices[2]; qv->x = 0; qv->y = (float)bounds->height; qv->z = 0; qv->abgr = 0xFFFFFFFF; qv->u = 0; qv->v = 1; qv = &quad->quadVertices[3]; qv->x = (float)bounds->width; qv->y = (float)bounds->height; qv->z = 0; qv->abgr = 0xFFFFFFFF; qv->u = 1; qv->v = 1; quad->setNativeVertexDataInvalid(false); lmAssert(Texture::getRenderTarget() == -1, "Unsupported render target state: %d", Texture::getRenderTarget()); // Set render target to texture Texture::setRenderTarget(id); // Shift the contents down and to the right so that the elements extending // past the left and top edges don't get cut off, ignore other existing transforms Matrix trans; trans.translate(-cacheAsBitmapOffsetX, -cacheAsBitmapOffsetY); trans.scale(calcScaleX, calcScaleY); // Setup for Graphics::render lualoom_pushnative<DisplayObject>(L, this); lualoom_pushnative<Matrix>(L, &trans); lua_pushnumber(L, 1); // Render the contents into the texture Graphics::render(L); // Pop previous arguments lua_pop(L, 3); // Restore render target Texture::setRenderTarget(-1); // Set valid cached state cachedImage = quad; cacheAsBitmapValid = true; cacheAsBitmapInProgress = false; } }