Example #1
0
void LSLuaState::finalizeAssemblyLoad(Assembly *assembly, utArray<Type *>& types)
{
    for (UTsize j = 0; j < types.size(); j++)
    {
        Type *type = types.at(j);

        if (type->isNative() || type->hasStaticNativeMember())
        {
            // we're native
            NativeInterface::resolveScriptType(type);
        }
    }

    declareLuaTypes(types);
    initializeLuaTypes(types);

    // we avoid runtime validation on mobile, this works but should be unnecessary
    // as issues with be caught on OSX/WINDOWS development platforms
#if LOOM_PLATFORM == LOOM_PLATFORM_OSX || LOOM_PLATFORM == LOOM_PLATFORM_WIN32
    for (UTsize j = 0; j < types.size(); j++)
    {
        Type            *type = types.at(j);
        TypeValidatorRT tv(this, type);
        tv.validate();
    }
#endif

    assembly->bootstrap();
}
Example #2
0
void DLLEXPORT assetAgent_command(const char *cmd)
{
    if (strstr(cmd, ".sendall") != 0)
    {
        postAllFiles();
    }
    else if (strstr(cmd, ".clients") != 0)
    {
        listClients();
    }
    else if (strstr(cmd, ".telemetry") != 0)
    {
        TelemetryServer::isRunning() ? TelemetryServer::stop() : TelemetryServer::start();
        assetAgent_command(TelemetryServer::isRunning() ? "telemetryEnable" : "telemetryDisable");
    }
    else if (cmd[0] != 0)
    {
        loom_mutex_lock(gActiveSocketsMutex);

        if (gActiveHandlers.size() == 0)
        {
            if (strcmp(cmd, "terminate") != 0) sendIgnoredError();
        }

        for (UTsize i = 0; i < gActiveHandlers.size(); i++)
        {
            gActiveHandlers[i]->sendCommand(cmd);
        }

        loom_mutex_unlock(gActiveSocketsMutex);
    }
}
Example #3
0
void loom_asset_pump()
{
   // Currently we only want to do this on the main thread so piggy back on the
   // native delegate sanity check to bail if on secondary thread.
   if(platform_getCurrentThreadId() != LS::NativeDelegate::smMainThreadID && LS::NativeDelegate::smMainThreadID != 0xBAADF00D)
      return;

   loom_mutex_lock(gAssetLock);

   // Talk to the asset server.
   loom_asset_serviceServer();

   // For now just blast all the data from each file into the asset.
   while(gAssetLoadQueue.size())
   {
      loom_asset_t *asset = gAssetLoadQueue.front();

      // Figure out the type from the path.
      utString path = asset->name;
      int type = loom_asset_recognizeAssetTypeFromPath(path);
      
      if(type == 0)
      {
         lmLog(gAssetLogGroup, "Could not infer type of resource '%s', skipping it...", path.c_str());
         asset->state = loom_asset_t::Unloaded;
         gAssetLoadQueue.erase((UTsize)0, true);
         continue;
      }

      // Open the file.
      void *ptr;
      long size;
      if(!platform_mapFile(asset->name.c_str(), &ptr, &size))
      {
         lmAssert(false, "Could not open file '%s'.", asset->name.c_str());
      }

      // Deserialize it.
      LoomAssetCleanupCallback dtor = NULL;
      void *assetBits = loom_asset_deserializeAsset(path, type, size, ptr, &dtor);

      // Close the file.
      platform_unmapFile(ptr);

      // Instate the asset.
      asset->instate(type, assetBits, dtor);

      // Done! Update queue.
      gAssetLoadQueue.erase((UTsize)0, true);
   }

   loom_mutex_unlock(gAssetLock);
}
Example #4
0
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);
}
Example #5
0
void loom_asset_initialize(const char *rootUri)
{
    // Set up the lock for the mutex.
    lmAssert(gAssetLock == NULL, "Double initialization!");
    gAssetLock = loom_mutex_create();

    // Note the CWD.
    char tmpBuff[1024];
    platform_getCurrentWorkingDir(tmpBuff, 1024);
    lmLog(gAssetLogGroup, "Current working directory ='%s'", tmpBuff);

    // And the allocator.
    //gAssetAllocator = loom_allocator_initializeTrackerProxyAllocator(loom_allocator_getGlobalHeap());
    gAssetAllocator = (loom_allocator_getGlobalHeap());

    // Clear, it might have been filled up before (for unit tests)
    gAssetLoadQueue.clear();
    gAssetHash.clear();

    // Asset server connection state.
    gAssetServerSocketLock = loom_mutex_create();

    // And set up some default asset types.
    loom_asset_registerType(LATText, loom_asset_textDeserializer, loom_asset_textRecognizer);
    loom_asset_registerType(LATBinary, loom_asset_binaryDeserializer, loom_asset_binaryRecognizer);

    loom_asset_registerImageAsset();
    loom_asset_registerSoundAsset();
    loom_asset_registerScriptAsset();

    // Listen to log and send it if we have a connection.
    loom_log_addListener(loom_asset_logListener, NULL);
}
Example #6
0
void gkBlenderSceneConverter::applyParents(utArray<Blender::Object*> &children)
{
	UTsize i;
	for (i = 0; i < children.size(); i++)
	{
		Blender::Object* bchild = children.at(i);
		gkGameObject*    gchild = m_gscene->getObject(GKB_IDNAME(bchild));

		if (gchild)
		{
			gkGameObject* gpar = m_gscene->getObject(GKB_IDNAME(bchild->parent));
			if (gpar && !gpar->getProperties().hasBoneParent())
				gchild->setParent(gpar);
		}
	}
}
Example #7
0
void LSLuaState::initializeLuaTypes(const utArray<Type *>& types)
{
    for (UTsize i = 0; i < types.size(); i++)
    {
        types[i]->cache();
    }

    // initialize all classes
    for (UTsize i = 0; i < types.size(); i++)
    {
        initializeClass(types[i]);
    }

    // run static initializers now that all classes have been initialized
    for (UTsize i = 0; i < types.size(); i++)
    {
        lsr_classinitializestatic(VM(), types[i]);
    }
}
Example #8
0
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);
}
Example #9
0
void loom_asset_shutdown()
{
    loom_asset_flushAll();

    // Clear out our queues and maps.
    gAssetDeserializerMap.clear();
    gRecognizerList.clear();

    lmAssert(gAssetLock != NULL, "Shutdown without being initialized!");
    loom_mutex_destroy(gAssetLock);
    gAssetLock = NULL;
}
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;
        }
    }
}
Example #11
0
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);
}
Example #12
0
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);
    }
}
Example #13
0
void LSLuaState::declareLuaTypes(const utArray<Type *>& types)
{
    for (UTsize i = 0; i < types.size(); i++)
    {
        declareClass(types[i]);
    }

    // validate/initialize native types
    for (UTsize i = 0; i < types.size(); i++)
    {
        Type *type = types.at(i);

        if (type->isNative() || type->hasStaticNativeMember())
        {
            NativeTypeBase *ntb = NativeInterface::getNativeType(type);

            if (!ntb)
            {
                LSError("Unable to get NativeTypeBase for type %s", type->getFullName().c_str());
            }

            if (type->isNativeManaged() != ntb->isManaged())
            {
                if (type->isNativeManaged())
                {
                    LSError("Managed mismatch for type %s, script declaration specifies native while native bindings are unmanaged", type->getFullName().c_str());
                }
                else
                {
                    LSError("Managed mismatch for type %s, script declaration specifies unmanaged while native bindings are managed", type->getFullName().c_str());
                }
            }

            ntb->validate(type);
            type->setCTypeName(ntb->getCTypeName());
        }
    }
}
Example #14
0
// Dump connected clients to the console; useful for telling who is connected to the console!
static void listClients()
{
    loom_mutex_lock(gActiveSocketsMutex);

    // Blast it out to all clients.
    lmLog(gAssetAgentLogGroup, "Clients");

    for (UTsize i = 0; i < gActiveHandlers.size(); i++)
    {
        lmLog(gAssetAgentLogGroup, "   #%d - %s", gActiveHandlers[i]->getId(), gActiveHandlers[i]->description().c_str());
    }

    loom_mutex_unlock(gActiveSocketsMutex);
}
Example #15
0
// Helper to recognize an asset's type from its path/name.
static int loom_asset_recognizeAssetTypeFromPath(utString& path)
{
    // Easy out - empty strings are no good!
    if (path.length() == 0)
    {
        return 0;
    }

    // Walk backwards to first dot.
    size_t firstDotPos = path.size() - 1;
    for (size_t pos = path.size() - 1; pos > 0; pos--)
    {
        if (path.at(pos) != '.')
        {
            continue;
        }

        firstDotPos = pos;
        break;
    }

    // Split out the extension.
    utString pathExt = path.substr(firstDotPos + 1);

    // See if we can get a type out of any of the recognizers.
    int type = 0;
    for (UTsize i = 0; i < gRecognizerList.size(); i++)
    {
        type = gRecognizerList[i](pathExt.c_str());
        if (type)
        {
            break;
        }
    }

    // No match, so let's use text.
    if (type == 0)
    {
        lmLogInfo(gAssetLogGroup, "Couldn't recognize '%s', defaulting to LATText...", path.c_str());
        type = LATText;
    }

    return type;
}
Example #16
0
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);
}
void akMeshLoaderUtils_getSmoothFaces(Blender::Mesh* bmesh, utArray<utArray<UTuint32> >& faces)
{
    faces.resize(bmesh->totvert);
    for (int i = 0; i< bmesh->totvert; i++)
    {
        for (int j = 0; j< bmesh->totface; j++)
        {
            const Blender::MFace& bface = bmesh->mface[j];
            if( (bface.flag & ME_SMOOTH) &&
                    (bface.v1 == i ||
                     bface.v2 == i ||
                     bface.v3 == i ||
                     bface.v4 == i ))
            {
                faces[i].push_back(j);
            }
        }
    }
}
Example #18
0
/**
 * 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_getShapeKeysNormals(Blender::Mesh* bmesh, UTuint32 numshape, utArray<btAlignedObjectArray<akVector3> >& shapenormals)
{
    Blender::Key* bk = bmesh->key;
    if(bk)
    {

        shapenormals.resize(numshape);
        Blender::KeyBlock* bkb = (Blender::KeyBlock*)bk->block.first;

        // skip first shape key (basis)
        UTuint32 shape=0;
        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)
                {
                    float* pos = (float*)bkb->data;
                    shapenormals[shape].resize(bmesh->totface);
                    for(int i=0; i<bmesh->totface; i++)
                    {
                        const Blender::MFace& bface = bmesh->mface[i];
                        akVector3 normal = akMeshLoaderUtils_calcMorphNormal(bface, pos);
                        shapenormals[shape][i]=normal;
                    }
                    shape++;
                }
            }
            bkb = bkb->next;
        }
    }
}
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;
        }
    }
}
Example #21
0
// 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;
}
Example #22
0
int loom_asset_queryPendingLoads()
{
    return gAssetLoadQueue.size() > 0 ? 1 : 0;
}
 ~akSubMeshPair()
 {
     idxmap.clear();
 }
Example #24
0
void LSLuaState::cacheAssemblyTypes(Assembly *assembly, utArray<Type *>& types)
{
    // setup assembly type lookup field
    lua_rawgeti(L, LUA_GLOBALSINDEX, LSASSEMBLYLOOKUP);
    lua_pushlightuserdata(L, assembly);
    lua_setfield(L, -2, assembly->getName().c_str());
    lua_pop(L, 1);

    assembly->ordinalTypes = new Type *[types.size() + 1];

    for (UTsize j = 0; j < types.size(); j++)
    {
        Type *type = types.at(j);

        assembly->types.insert(type->getName(), type);

        lmAssert(type->getTypeID() > 0 && type->getTypeID() <= (LSTYPEID)types.size(), "LSLuaState::cacheAssemblyTypes TypeID out of range");

        assembly->ordinalTypes[type->getTypeID()] = type;

        const char *typeName = type->getFullName().c_str();

        // fast access cache
        if (!strcmp(typeName, "system.Object"))
        {
            objectType = type;
        }
        else if (!strcmp(typeName, "system.Null"))
        {
            nullType = type;
        }
        else if (!strcmp(typeName, "system.Boolean"))
        {
            booleanType = type;
        }
        else if (!strcmp(typeName, "system.Number"))
        {
            numberType = type;
        }
        else if (!strcmp(typeName, "system.String"))
        {
            stringType = type;
        }
        else if (!strcmp(typeName, "system.Function"))
        {
            functionType = type;
        }
        else if (!strcmp(typeName, "system.Vector"))
        {
            vectorType = type;
        }

        lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXMEMBERINFONAME);
        lua_pushlightuserdata(L, type);
        lua_gettable(L, -2);

        // cache all members for fast lookup of memberinfo -> pre-interned
        // lua string (interning strings is the devil's work)
        if (lua_isnil(L, -1))
        {
            lua_pop(L, 1);

            utArray<MemberInfo *> members;
            MemberTypes           types;
            types.method   = true;
            types.field    = true;
            types.property = true;
            type->findMembers(types, members, false);

            // cache the type to member info table
            lua_pushlightuserdata(L, type);
            lua_pushstring(L, type->getName());
            lua_settable(L, -3);

            for (UTsize i = 0; i < members.size(); i++)
            {
                MemberInfo *mi = members.at(i);

                lua_pushlightuserdata(L, mi);
                lua_pushstring(L, mi->getName());
                lua_settable(L, -3);
            }
        }
        else
        {
            lua_pop(L, 1);
        }

        lua_pop(L, 1);

        // if we weren't cached during assembly load, cache now
        if (!typeCache.get(type->getFullName()))
        {
            typeCache.insert(type->getFullName(), type);
        }
    }

    lmAssert(nullType, "LSLuaState::cacheAssemblyTypes - system.Null not found");
    lmAssert(booleanType, "LSLuaState::cacheAssemblyTypes - system.Boolean not found");
    lmAssert(numberType, "LSLuaState::cacheAssemblyTypes - system.Number not found");
    lmAssert(stringType, "LSLuaState::cacheAssemblyTypes - system.String not found");
    lmAssert(functionType, "LSLuaState::cacheAssemblyTypes - system.Function not found");
    lmAssert(vectorType, "LSLuaState::cacheAssemblyTypes - system.Vector not found");
}
Example #25
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;
            }
        }
    }
Example #27
0
void NativeDelegate::executeDeferredCalls(lua_State *L)
{
    ensureQueueInit();
    loom_mutex_lock(gCallNoteMutex);

    // Try to resolve the delegate pointer.
    utArray<NativeDelegate *> *delegates = NULL;
    if (sActiveNativeDelegates.find(L) != UT_NPOS)
    {
        delegates = *(sActiveNativeDelegates.get(L));
    }
    else
    {
        // No delegate list, can't do it.
        loom_mutex_unlock(gCallNoteMutex);
        return;
    }

    for(unsigned int i=0; i<gNDCallNoteQueue.size(); i++)
    {
        NativeDelegateCallNote *ndcn = gNDCallNoteQueue[i];

        bool found = false;
        for(unsigned int i=0; i<delegates->size(); i++)
        {
            // Look for our delegate.
            if((*delegates)[i] != ndcn->delegate)
                continue;

            // If key mismatches, warn and bail.
            if((*delegates)[i]->_key != ndcn->delegateKey)
            {
                lmLogError(gNativeDelegateGroup, "Found delegate call note with key mismatch (delegate=%x actualKey=%x expectedKey=%x), ignoring...", (*delegates)[i], (*delegates)[i]->_key, ndcn->delegateKey);
                break;
            }

            // Match!
            found = true;
            break;
        }

        // Bail if no match.
        if(!found)
            continue;

        // Otherwise, let's call it.
        const NativeDelegate *theDelegate = ndcn->delegate;
        for(;;)
        {
            unsigned char actionType = ndcn->readByte();
            bool done = false;
            char *str = NULL;
            utByteArray *bytes;
            switch(actionType)
            {
                case MSG_Nop:
                    lmLogError(gNativeDelegateGroup, "Got a nop in delegate data stream.");
                break;

                case MSG_PushString:
                    str = ndcn->readString();
                    theDelegate->pushArgument(str);
                    free(str);
                    break;

                case MSG_PushByteArray:
                    bytes = ndcn->readByteArray();
                    theDelegate->pushArgument(bytes);
                    free(bytes);
                    break;

                case MSG_PushDouble:
                    theDelegate->pushArgument(ndcn->readDouble());
                    break;

                case MSG_PushFloat:
                    theDelegate->pushArgument(ndcn->readFloat());
                    break;
                
                case MSG_PushInt:
                    theDelegate->pushArgument((int)ndcn->readInt());
                    break;
                
                case MSG_PushBool:
                    theDelegate->pushArgument(ndcn->readBool());
                    break;

                case MSG_Invoke:
                    theDelegate->invoke();
                    done = true;
                    break;
            }

            if(done)
                break;
        }

    }

    // Purge queue.
    gNDCallNoteQueue.clear();

    loom_mutex_unlock(gCallNoteMutex);
}
void gkBlenderSceneConverter::convertGroups(utArray<Blender::Object*> &groups)
{
	gkGroupManager* mgr = gkGroupManager::getSingletonPtr();

	// This is a complete list of groups & containing objects.
	// The gkGameObjectGroup is a containter, the gkGameObjectGroupInstance
	// is where the object should be added / removed from the scene.
	
	//	for (Blender::Group* bgrp = (Blender::Group*)m_file->_getInternalFile()->m_group.first; bgrp != 0; 
	//	bgrp = (Blender::Group*)bgrp->id.next)

	gkBlendListIterator iter = m_file->_getInternalFile()->getGroupList();
	while (iter.hasMoreElements())
	{
		Blender::Group* bgrp = (Blender::Group*)iter.getNext();


		const gkResourceName groupName(GKB_IDNAME(bgrp), m_groupName);

		if (mgr->exists(groupName))
		{
			// Can most likely assert here
			continue;
		}

		gkGameObjectGroup* group = (gkGameObjectGroup*)mgr->create(groupName);


		for (Blender::GroupObject* bgobj = (Blender::GroupObject*)bgrp->gobject.first; bgobj; bgobj = bgobj->next)
		{
			if (bgobj->ob)
			{
				Blender::Object* bobj = bgobj->ob;

				if (!validObject(bobj))
					continue;

				gkGameObject* gobj = m_gscene->getObject(GKB_IDNAME(bobj));

				// add it to the list
				if (gobj)
					group->addObject(gobj);
			}
		}

		// Destroy if empty
		if (group->isEmpty())
			mgr->destroy(group);
		else
			mgr->attachGroupToScene(m_gscene, group);

	}

	// Process user created groups.
	utArray<Blender::Object*>::Iterator it = groups.iterator();
	while (it.hasMoreElements())
	{
		Blender::Object* bobj = it.getNext();


		// Should not fail
		GK_ASSERT((bobj->transflag& OB_DUPLIGROUP && bobj->dup_group != 0));


		// Owning group
		Blender::Group* bgobj = bobj->dup_group;
		const gkResourceName groupName(GKB_IDNAME(bgobj), m_groupName);


		if (mgr->exists(groupName))
		{
			gkGameObjectGroup* ggobj = (gkGameObjectGroup*)mgr->getByName(groupName);


			gkGameObjectInstance* inst = ggobj->createGroupInstance(m_gscene, gkResourceName(GKB_IDNAME(bobj), m_groupName));
			if (inst)
				convertObject(bobj, inst->getRoot());
		}
	}
}
Example #29
0
namespace LS {
utHashTable<utPointerHashKey, utArray<NativeDelegate *> *> NativeDelegate::sActiveNativeDelegates;
static const int scmBadThreadID = 0xBAADF00D;
int              NativeDelegate::smMainThreadID = scmBadThreadID;

/**
 * Responsible for storing and recalling serialized NativeDelegate calls.
 *
 * Used internally by NativeDelegate for "async" delegate calls.
 */
struct NativeDelegateCallNote
{
    // Keep a reference to the delegate we're working with. This is used as a key
    // and verified against the global list of valid nativedelegates before being
    // dereferenced. The delegateKey is used to disambiguate new allocations at 
    // the same memory location.
    const NativeDelegate *delegate;
    int delegateKey;

    // Storage for serialized parameters.
    unsigned char *data;
    unsigned int ndata;

    // Current offset in data for read or write.
    unsigned int offset;

    NativeDelegateCallNote(const NativeDelegate *target)
    {
        // Note our target delegate.
        delegate = target;
        delegateKey = target->_key;

        // Start with enough buffer space we won't need to realloc in most cases.
        ndata = 512; 
        data = (unsigned char*)lmAlloc(NULL, ndata);
        offset = 0;
    }

    ~NativeDelegateCallNote()
    {
        delegate = NULL;
        delegateKey = -1;
        
        if(data)
        {        
            free(data);
            data = NULL;
        }
        ndata = -1;
        
        offset = -1;
    }

    // Make sure we have enough room to write freeBytes, and grow the buffer
    // if we don't.
    void ensureBuffer(unsigned int freeBytes)
    {
        // Nop if enough free space.
        if(offset+freeBytes<ndata)
            return;

        ndata = offset + freeBytes; // Resize to requested size
        ndata += ndata / 2; // Allocate 0.5x more
        if (ndata < 4096) ndata = 4096;

        data = (unsigned char*)lmRealloc(NULL, data, ndata);

    }

    void writeByte(unsigned char value)
    {
        ensureBuffer(1);
        data[offset] = value;
        offset++;
    }

    void writeBytes(const char* value, UTsize size)
    {
        ensureBuffer(size);
        memcpy(data + sizeof(unsigned char)*offset, value, size);
        offset += size;
    }

    void writeInt(unsigned int value)
    {
        ensureBuffer(4);
        memcpy(&data[offset], &value, sizeof(unsigned int));
        offset += 4;
    }

    void writeFloat(float value)
    {
        ensureBuffer(4);
        memcpy(&data[offset], &value, sizeof(float));
        offset += 4;
    }

    void writeDouble(double value)
    {
        ensureBuffer(8);
        memcpy(&data[offset], &value, sizeof(double));
        offset += 8;
    }

    void writeString(const char *value)
    {
        size_t size = strlen(value);
        writeInt(size);
        writeBytes(value, size);
    }

    void writeByteArray(utByteArray *value)
    {
        UTsize size = value->getSize();
        writeInt(size);
        writeBytes((const char*) value->getDataPtr(), size);
    }

    void writeBool(bool value)
    {
        if(value)
            writeByte(1);
        else
            writeByte(0);
    }

    void rewind()
    {
        offset = 0;
    }

    unsigned char readByte()
    {
        //assert(offset + 1 < ndata);
        unsigned char v = data[offset];
        offset++;
        return v;
    }
    
    void readBytes(const char* value, UTsize size)
    {
        memcpy((void*) value, data + sizeof(unsigned char)*offset, size);
        offset += size;
    }

    unsigned int readInt()
    {
        //assert(offset + 4 < ndata);
        int v = 0;
        memcpy(&v, &data[offset], sizeof(unsigned int));
        offset += 4;
        return v;
    }

    float readFloat()
    {
        //assert(offset + 4 < ndata);
        float v = 0.f;
        memcpy(&v, &data[offset], sizeof(float));
        offset += 4;
        return v;
    }

    double readDouble()
    {
        //assert(offset + 8 < ndata);
        double v = 0.0;
        memcpy(&v, &data[offset], sizeof(double));
        offset += 8;
        return v;
    }

    // Don't forget to free()
    char *readString()
    {
        unsigned int strLen = readInt();
        char *str = (char*)malloc(strLen + 1);
        readBytes(str, strLen);
        str[strLen] = 0;
        return str;
    }

    // Don't forget to free()
    utByteArray *readByteArray()
    {
        UTsize size = readInt();
        utByteArray *bytes = new utByteArray();
        bytes->reserve(size);
        readBytes((const char*) bytes->getDataPtr(), size);
        return bytes;
    }

    bool readBool()
    {
        return readByte() == 0 ? false : true;
    }
};

// Constants used to encode NativeDelegate parameters in a NativeDelegateCallNote.
enum
{
    MSG_Nop = 0,
    MSG_PushInt,
    MSG_PushFloat,
    MSG_PushDouble,
    MSG_PushString,
    MSG_PushByteArray,
    MSG_PushBool,
    MSG_Invoke,
};

// Thread-safe queue of NativeDelegateCallNotes for execution on main thread.
static MutexHandle gCallNoteMutex = NULL;
static utArray<NativeDelegateCallNote*> gNDCallNoteQueue;

static void ensureQueueInit()
{
    if(gCallNoteMutex)
        return;

    gCallNoteMutex = loom_mutex_create();
}

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 NativeDelegate::executeDeferredCalls(lua_State *L)
{
    ensureQueueInit();
    loom_mutex_lock(gCallNoteMutex);

    // Try to resolve the delegate pointer.
    utArray<NativeDelegate *> *delegates = NULL;
    if (sActiveNativeDelegates.find(L) != UT_NPOS)
    {
        delegates = *(sActiveNativeDelegates.get(L));
    }
    else
    {
        // No delegate list, can't do it.
        loom_mutex_unlock(gCallNoteMutex);
        return;
    }

    for(unsigned int i=0; i<gNDCallNoteQueue.size(); i++)
    {
        NativeDelegateCallNote *ndcn = gNDCallNoteQueue[i];

        bool found = false;
        for(unsigned int i=0; i<delegates->size(); i++)
        {
            // Look for our delegate.
            if((*delegates)[i] != ndcn->delegate)
                continue;

            // If key mismatches, warn and bail.
            if((*delegates)[i]->_key != ndcn->delegateKey)
            {
                lmLogError(gNativeDelegateGroup, "Found delegate call note with key mismatch (delegate=%x actualKey=%x expectedKey=%x), ignoring...", (*delegates)[i], (*delegates)[i]->_key, ndcn->delegateKey);
                break;
            }

            // Match!
            found = true;
            break;
        }

        // Bail if no match.
        if(!found)
            continue;

        // Otherwise, let's call it.
        const NativeDelegate *theDelegate = ndcn->delegate;
        for(;;)
        {
            unsigned char actionType = ndcn->readByte();
            bool done = false;
            char *str = NULL;
            utByteArray *bytes;
            switch(actionType)
            {
                case MSG_Nop:
                    lmLogError(gNativeDelegateGroup, "Got a nop in delegate data stream.");
                break;

                case MSG_PushString:
                    str = ndcn->readString();
                    theDelegate->pushArgument(str);
                    free(str);
                    break;

                case MSG_PushByteArray:
                    bytes = ndcn->readByteArray();
                    theDelegate->pushArgument(bytes);
                    free(bytes);
                    break;

                case MSG_PushDouble:
                    theDelegate->pushArgument(ndcn->readDouble());
                    break;

                case MSG_PushFloat:
                    theDelegate->pushArgument(ndcn->readFloat());
                    break;
                
                case MSG_PushInt:
                    theDelegate->pushArgument((int)ndcn->readInt());
                    break;
                
                case MSG_PushBool:
                    theDelegate->pushArgument(ndcn->readBool());
                    break;

                case MSG_Invoke:
                    theDelegate->invoke();
                    done = true;
                    break;
            }

            if(done)
                break;
        }

    }

    // Purge queue.
    gNDCallNoteQueue.clear();

    loom_mutex_unlock(gCallNoteMutex);
}

// To disambiguate NativeDelegates at the address of old NDs, we have a key.
// in order to collide you have to allocate and free 4 billion NDs and get the same address
// on the 4 billionth ND as you did on the first. If you get a crash due to this coincidence,
// I'll buy you something nice.
static int gNativeDelegateKeyGenerator = 1000;

NativeDelegate::NativeDelegate()
    : L(NULL), _callbackCount(0), _allowAsync(true), _argumentCount(0), _activeNote(NULL), _key(gNativeDelegateKeyGenerator++)
{
}

void NativeDelegate::disallowAsync()
{
    lmLogDebug(gNativeDelegateGroup, "SETTING ASYNC OFF %x", this);
    _allowAsync = false;
}

void NativeDelegate::createCallbacks()
{
    //lmAssert(gNativeDelegateMainThread == platform_getCurrentThreadId(), "Working with a NativeDelegate outside of the main thread!");

    if (!L)
    {
        LSError("NativeDelegate attempting to create callbacks table without valid VM");
    }

    // we must create a lua table to hold our script callbacks
    // these cannot be held in the context of the script binding
    // as they may change/be stripped via mechanisms of pure native
    // handling
    int top = lua_gettop(L);

    lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXNATIVEDELEGATES);
    lua_pushlightuserdata(L, this);
    lua_newtable(L);
    lua_newtable(L);
    lua_rawseti(L, -2, LSINDEXNATIVEDELEGATECALLBACKS);
    lua_settable(L, -3);
    lua_settop(L, top);
}


void NativeDelegate::registerDelegate(lua_State *L, NativeDelegate *delegate)
{
    assertMainThread();

    utArray<NativeDelegate *> *delegates = NULL;

    if (sActiveNativeDelegates.find(L) != UT_NPOS)
    {
        delegates = *(sActiveNativeDelegates.get(L));
    }

    if (!delegates)
    {
        delegates = new utArray<NativeDelegate *>;
        sActiveNativeDelegates.insert(L, delegates);
    }

    delegates->push_back(delegate);
}


void NativeDelegate::setVM(lua_State *vm, bool newCallbacks)
{
    if (L)
    {
        if (newCallbacks)
        {
            createCallbacks();
        }
        return;
    }

    L = vm;

    registerDelegate(vm, this);

    // first time we're setting VM, so make sure callbacks table exists
    createCallbacks();
}


void NativeDelegate::getCallbacks(lua_State *L) const
{
    lua_pushnil(L);
    int top = lua_gettop(L);

    lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXNATIVEDELEGATES);
    lua_pushlightuserdata(L, (void *)this);
    lua_gettable(L, -2);
    lua_rawgeti(L, -1, LSINDEXNATIVEDELEGATECALLBACKS);
    lua_replace(L, top);
    lua_settop(L, top);
}


NativeDelegateCallNote *NativeDelegate::prepCallbackNote() const
{
    lmLogDebug(gNativeDelegateGroup, "Considering async callback %x", this);
    
    // Are noting currently? Just work with that.
    if(_activeNote)
    {
        lmLogDebug(gNativeDelegateGroup, " OUT due to activeNote already present");
        return _activeNote;
    }

    // See if we should try to go async.
    if(_allowAsync == false)
    {
        lmLogDebug(gNativeDelegateGroup, " OUT due to async being disallowed");
        return NULL;
    }

    if(smMainThreadID == platform_getCurrentThreadId())
        return NULL;

    // Only do this for async delegates off main thread.
    lmLogDebug(gNativeDelegateGroup, "Prepping async callback!");
    _activeNote = lmNew(NULL) NativeDelegateCallNote(this);
    return _activeNote;
}


void NativeDelegate::pushArgument(const char *value) const
{
    if (NativeDelegateCallNote *ndcn = prepCallbackNote())
    {
        ndcn->writeByte(MSG_PushString);
        ndcn->writeString(value);
        return;
    }

    if (!L)
        return;

    lua_pushstring(L, value);
    _argumentCount++;
}

void NativeDelegate::pushArgument(utByteArray *value) const
{
    if(NativeDelegateCallNote *ndcn = prepCallbackNote())
    {
        ndcn->writeByte(MSG_PushByteArray);
        ndcn->writeByteArray(value);
        return;
    }

    if (!L)
        return;

    lualoom_pushnative<utByteArray>(L, value);
    _argumentCount++;
}


void NativeDelegate::pushArgument(int value) const
{
    if(NativeDelegateCallNote *ndcn = prepCallbackNote())
    {
        ndcn->writeByte(MSG_PushInt);
        ndcn->writeInt(value);
        return;
    }

    if (!L)
        return;

    lua_pushinteger(L, value);
    _argumentCount++;
}


void NativeDelegate::pushArgument(float value) const
{
    if(NativeDelegateCallNote *ndcn = prepCallbackNote())
    {
        ndcn->writeByte(MSG_PushFloat);
        ndcn->writeFloat(value);
        return;
    }

    if (!L)
        return;

    lua_pushnumber(L, value);
    _argumentCount++;
}


void NativeDelegate::pushArgument(double value) const
{
    if(NativeDelegateCallNote *ndcn = prepCallbackNote())
    {
        ndcn->writeByte(MSG_PushDouble);
        ndcn->writeDouble(value);
        return;
    }

    if (!L)
        return;

    lua_pushnumber(L, value);
    _argumentCount++;
}


void NativeDelegate::pushArgument(bool value) const
{
    if(NativeDelegateCallNote *ndcn = prepCallbackNote())
    {
        ndcn->writeByte(MSG_PushBool);
        ndcn->writeBool(value);
        return;
    }

    if (!L)
        return;

    lua_pushboolean(L, value);
    _argumentCount++;
}


int NativeDelegate::getCount() const
{
    return _callbackCount;
}


// We don't currently support return values as this makes it the responsibility
// of the caller to clean up the stack, this can be changed if we automate
void NativeDelegate::invoke () const
{
    if(NativeDelegateCallNote *ndcn = prepCallbackNote())
    {
        ndcn->writeByte(MSG_Invoke);

        // Submit it and clear state.
        postNativeDelegateCallNote(ndcn);
        _activeNote = NULL;
        return;
    }

    // Don't do this from non-main thread.
    assertMainThread();

    // if we have no callbacks defined, the VM state will be NULL
    if (!L)
    {
        // Even if we don't do anything, need to reset arg count.
        _argumentCount = 0;
        return;
    }

    int top = lua_gettop(L);

    int numArgs = _argumentCount;

    // Reset argument count, so recursion is properly handled
    _argumentCount = 0;

    getCallbacks(L);

    int tidx = lua_gettop(L);

    if (!lua_istable(L, tidx))
    {
        LSError("Error getting native delegate callback table");
    }

    for (int i = 0; i < _callbackCount; i++)
    {
        lua_pushnumber(L, (double)i);
        lua_gettable(L, tidx);

        int t = lua_gettop(L);

        for (int i = top - numArgs; i < top; i++)
        {
            lua_pushvalue(L, i + 1);
        }

        lua_call(L, numArgs, 1);

        lua_settop(L, t);

        /* removes last lua_function called */
        lua_pop(L, 1);
    }

    lua_settop(L, top);

    // clean up arguments off stack
    lua_pop(L, numArgs);
}


int NativeDelegate::__op_assignment(lua_State *L)
{
    NativeDelegate *delegate = (NativeDelegate *)lualoom_getnativepointer(L, 1,
                                                                          true, "system.NativeDelegate");

    if (!delegate)
    {
        LSError("Unable to get native delegate on += operator");
    }

    // set the VM, and recreate callbacks table
    delegate->setVM(L, true);

    delegate->getCallbacks(L);

    if (!lua_istable(L, -1))
    {
        LSError("Bad native delegates table");
    }

    // clear current callbacks
    for (int i = 0; i < delegate->_callbackCount; i++)
    {
        lua_pushnumber(L, (double)i);
        lua_pushnil(L);
        lua_settable(L, -3);
    }

    // reset
    delegate->_callbackCount = 0;

    if (lua_isnil(L, 2))
    {
        return 0;
    }

    if (!lua_isfunction(L, 2) && !lua_iscfunction(L, 2))
    {
        LSError("Unknown type on NativeDelegate assignment operator");
    }

    // add the lua function or cfunction to our delegate's callback table
    lua_pushnumber(L, (double)0);
    lua_pushvalue(L, 2);
    lua_settable(L, -3);
    lua_pop(L, 1);
    // pop __lscallbacks

    delegate->_callbackCount++;

    return 0;
}


int NativeDelegate::__op_minusassignment(lua_State *L)
{
    NativeDelegate *delegate = (NativeDelegate *)lualoom_getnativepointer(L, 1,
                                                                          "system.NativeDelegate");

    if (!delegate)
    {
        LSError("Unable to get native delegate on += operator");
    }

    if (!delegate->_callbackCount)
    {
        return 0;
    }

    delegate->setVM(L);

    delegate->getCallbacks(L);

    int tidx = lua_gettop(L);

    if (!lua_istable(L, tidx))
    {
        LSError("Bad native delegates table");
    }

    if (lua_isfunction(L, 2) || lua_iscfunction(L, 2))
    {
        int idx = -1;
        for (int i = 0; i < delegate->_callbackCount; i++)
        {
            lua_rawgeti(L, tidx, i);
            if (lua_equal(L, 2, -1))
            {
                idx = i;
                lua_pop(L, 1);
                break;
            }
            lua_pop(L, 1);
        }


        // this function was never added in the first place
        if (idx == -1)
        {
            return 0;
        }

        // shift the other delegates down
        lua_pushnumber(L, (double)idx);
        lua_pushnil(L);
        lua_settable(L, tidx);

        int ntable = 0;
        if (delegate->_callbackCount > 1)
        {
            // temp table
            lua_newtable(L);
            ntable = lua_gettop(L);

            int c = 0;
            for (int nidx = 0; nidx < delegate->_callbackCount; nidx++)
            {
                lua_pushnumber(L, (double)nidx);
                lua_gettable(L, tidx);
                if (lua_isnil(L, -1))
                {
                    lua_pop(L, 1);
                    continue;
                }

                lua_pushnumber(L, (double)c);
                lua_pushvalue(L, -2);
                lua_settable(L, ntable);
                // pop lua_function
                lua_pop(L, 1);
                c++;
            }
        }

        // clear it
        delegate->_callbackCount--;

        // and copy from new temp table
        for (int nidx = 0; nidx < delegate->_callbackCount; nidx++)
        {
            lua_pushnumber(L, (double)nidx);
            lua_pushnumber(L, (double)nidx);
            lua_gettable(L, ntable);
            lua_settable(L, tidx);
        }
    }
    else
    {
        LSError("Unknown type on NativeDelegate -= operator");
    }

    return 0;
}


int NativeDelegate::__op_plusassignment(lua_State *L)
{
    NativeDelegate *delegate = (NativeDelegate *)lualoom_getnativepointer(L, 1,
                                                                          "system.NativeDelegate");

    if (!delegate)
    {
        LSError("Unable to get native delegate on += operator");
    }

    delegate->setVM(L);

    delegate->getCallbacks(L);

    int tidx = lua_gettop(L);

    if (!lua_istable(L, -1))
    {
        LSError("Bad native delegates table");
    }

    if (lua_isfunction(L, 2) || lua_iscfunction(L, 2))
    {
        // check if we already added this callback
        for (int i = 0; i < delegate->_callbackCount; i++)
        {
            lua_rawgeti(L, tidx, i);
            if (lua_equal(L, 2, -1))
            {
                lua_pop(L, 1);
                return 0; // already added
            }
            lua_pop(L, 1);
        }

        // add the lua function or cfunction to our delegate's callback table
        lua_pushnumber(L, (double)delegate->_callbackCount++);
        lua_pushvalue(L, 2);
        lua_settable(L, -3);
        lua_pop(L, 1);
        // pop __lscallbacks
    }
    else
    {
        LSError("Unknown type on NativeDelegate += operator");
    }

    return 0;
}


void NativeDelegate::invalidate()
{
    _callbackCount = 0;

    if (L)
    {
        lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXNATIVEDELEGATES);
        lua_pushlightuserdata(L, this);
        lua_pushnil(L);
        lua_settable(L, -3);
        lua_pop(L, 1);
    }

    L = NULL;
}


void NativeDelegate::invalidateLuaStateDelegates(lua_State *L)
{
    utArray<NativeDelegate *> *delegates = NULL;

    if (sActiveNativeDelegates.find(L) != UT_NPOS)
    {
        delegates = *(sActiveNativeDelegates.get(L));
    }

    if (delegates)
    {
        for (UTsize i = 0; i < delegates->size(); i++)
        {
            NativeDelegate *delegate = delegates->at(i);
            delegate->invalidate();
        }

        sActiveNativeDelegates.erase(L);
        delete delegates;
    }
}


NativeDelegate::~NativeDelegate()
{
    // If we are in the native delegate list, remove ourselves.
    utArray<NativeDelegate *> *delegates = NULL;
    if (sActiveNativeDelegates.find(L) != UT_NPOS)
    {
        delegates = *(sActiveNativeDelegates.get(L));
    }

    if (delegates)
    {
        UTsize idx = delegates->find(this);
        if(idx != UT_NPOS)
            delegates->erase(idx);
    }

    // And clean up our Lua VM state.
    invalidate();
}


void NativeDelegate::markMainThread()
{
    smMainThreadID = platform_getCurrentThreadId();
}


void NativeDelegate::assertMainThread()
{
    if(smMainThreadID == scmBadThreadID)
    {
        lmLogWarn(gNativeDelegateGroup,
                 "Tried to touch a NativeDelegate before the main thread was marked. "
                 "Probably need to add a markMainThread call?");
    }

    if( smMainThreadID != platform_getCurrentThreadId())
    {
        lmLogWarn(gNativeDelegateGroup,
                 "Trying to fire a NativeDelegate from thread %x that is not the main "
                 "thread %x. This will result in memory corruption and race conditions!",
                platform_getCurrentThreadId(), smMainThreadID);
    }
}
}
Example #30
0
void loom_asset_registerType(unsigned int type, LoomAssetDeserializeCallback deserializer, LoomAssetRecognizerCallback recognizer)
{
    gAssetDeserializerMap.insert(type, deserializer);
    gRecognizerList.push_back(recognizer);
}