Example #1
0
void Java_co_theengine_loomdemo_LoomVideo_nativeCallback(JNIEnv *env, jobject thiz, jint callbackType, jstring data)
{
    lmLog(gAndroidVideoLogGroup, "LoomVideo Android Callback fired! %d", callbackType);

    const char *dataString = env->GetStringUTFChars(data, 0);
    if (gEventCallback)
    {
        const char *typeString = NULL;
        switch (callbackType)
        {
            case 0:
                gEventCallback("fail", dataString);
                break;

            case 1:
                lmLogError(gAndroidVideoLogGroup, "Video playback complete");
                gEventCallback("complete", dataString);
                break;

            default:
                lmLogError(gAndroidVideoLogGroup, "Got Android Video event of type %d but don't know how to handle it, ignoring...", callbackType);
                break;
        }
    }
    else
    {
        lmLogError(gAndroidVideoLogGroup, "Got Android Video event of type %d but don't know how to handle it, ignoring...", callbackType);
    }
    env->ReleaseStringUTFChars(data, dataString);
}
Example #2
0
int loom_net_initialize()
{
    // Platform-specific init.
#if LOOM_PLATFORM == LOOM_PLATFORM_WIN32
    WSADATA wsaData;
    WORD    wVersionRequested = MAKEWORD(2, 0);
    int     err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        lmLogError(netLogGroup, "Failed WinSock initalization with error %d", err);
        return 0;
    }

    if (((LOBYTE(wsaData.wVersion) != 2) || (HIBYTE(wsaData.wVersion) != 0)) &&
        ((LOBYTE(wsaData.wVersion) != 1) || (HIBYTE(wsaData.wVersion) != 1)))
    {
        lmLogError(netLogGroup, "Failed WinSock initalization due to version mismatch");
        WSACleanup();
        return 0;
    }

    // Sanity checks.
    lmAssert(sizeof(SOCKET) <= sizeof(loom_socketId_t), "Can't pack a SOCKET into loom_socketId_t");

    lmLogDebug(netLogGroup, "Initialized WinSock");
    
    return 1;

#else
    // Ignore sigpipe.
    lmLogDebug(netLogGroup, "Disabling signal SIGPIPE");
    signal(SIGPIPE, SIG_IGN);
    return 1;
#endif
}
Example #3
0
    const BitmapData* BitmapData::fromFramebuffer()
    {
        int w = GFX::Graphics::getWidth();
        int h = GFX::Graphics::getHeight();

        // Sanity check
        if (w == 0 || h == 0) {
            lmLogError(gGFXLogGroup, "Graphics dimensions invalid %d x %d: %s", w, h, SDL_GetError());
            return NULL;
        }

        BitmapData* result = lmNew(NULL) BitmapData(w, h);

        if (result == NULL) {
            lmLogError(gGFXLogGroup, "Unable to allocate memory for screenshot pixel data buffer");
            return NULL;
        }

        GFX::GL_Context* ctx = GFX::Graphics::context();

        utByteArray tmp;
        tmp.resize(result->w * result->h * DATA_BPP);

        ctx->glPixelStorei(GL_PACK_ALIGNMENT, 1);
        ctx->glReadPixels(0, 0, result->w, result->h, GL_RGBA, GL_UNSIGNED_BYTE, tmp.getDataPtr());

        for (int i = result->h - 1; i >= 0; i--)
        {
            memcpy(result->data + (result->h - 1 - i) * result->w * DATA_BPP, (channel_t*)tmp.getDataPtr() + i * result->w * DATA_BPP, result->w * DATA_BPP);
        }

        return result;
    }
Example #4
0
void *loom_asset_lock(const char *name, unsigned int type, int block)
{
    const char *namePtr = stringtable_insert(name);

    loom_mutex_lock(gAssetLock);

    // Look it up.
    loom_asset_t *asset = loom_asset_getAssetByName(namePtr, 1);
    lmAssert(asset != NULL, "Didn't get asset even though we should have!");

    // If not loaded, and we aren't ready to block, return NULL.
    if ((block == 0) && (asset->state != loom_asset_t::Loaded))
    {
        lmLogDebug(gAssetLogGroup, "Not blocking and not loaded yet; lock of '%s' failed.", namePtr);
        loom_mutex_unlock(gAssetLock);
        return NULL;
    }

    // Otherwise, let's force it to load now.
    if (asset->state != loom_asset_t::Loaded)
    {
        lmLogDebug(gAssetLogGroup, "Blocking so forcing load of '%s'.", namePtr);

        loom_asset_preload(namePtr);

        lmAssert(loom_asset_isOnTrackToLoad(asset), "Preloaded but wasn't on track to load!");

        while (loom_asset_checkLoadedPercentage(namePtr) != 1.f && loom_asset_isOnTrackToLoad(asset))
        {
            lmLogDebug(gAssetLogGroup, "Pumping load of '%s'...", namePtr);
            loom_asset_pump();
        }

        if (asset->state != loom_asset_t::Loaded)
        {
            lmLogError(gAssetLogGroup, "Unable to load asset '%s'!", name);
            loom_mutex_unlock(gAssetLock);
            return NULL;
        }
    }

    // Check type.
    if (asset->type != type)
    {
        lmLogError(gAssetLogGroup, "Tried to lock asset '%s' with wrong type, assetType=%x, requestedType=%x", name, asset->type, type);
        loom_mutex_unlock(gAssetLock);
        return NULL;
    }

    // Inc count.
    asset->blob->incRef();

    loom_mutex_unlock(gAssetLock);

    lmLogDebug(gAssetLogGroup, "Locked asset '%s'...", namePtr);

    // Return ptr.
    return asset->blob->bits;
}
Example #5
0
static void LoomProfilerEntryDumpRecurse(LoomProfilerEntry *data, char *buffer, U32 bufferLen, F64 totalTime, float threshold)
{
    float tm = (float)(data->mRoot == NULL ? 100.0 : 100.0 * data->mTotalTime / totalTime);

    if (tm < threshold)
    {
        suppressedEntries++;
    }
    else
    {
        // dump out this one:
        lmLogError(gProfilerLogGroup, "%8.3f %8.3f %8.3f %8.3f %8.3f %8d %s%s",
                   data->mRoot == NULL ? 100.0 : 100.0 * data->mTotalTime / totalTime,
                   data->mRoot == NULL ? 100.0 : 100.0 * (data->mTotalTime - data->mSubTime) / totalTime,
                   data->mTotalTime / (1000.0 * 1000.0 * (data->mInvokeCount > 0 ? data->mInvokeCount : 1)),
                   data->mMaxTime / (1000.0 * 1000.0),
                   data->mMinTime / (1000.0 * 1000.0),
                   data->mInvokeCount,
                   buffer,
                   data->mRoot ? data->mRoot->mName : "ROOT");
    }

    data->mTotalTime = 0;
    data->mSubTime = 0;
    data->mMaxTime = 0;
    data->mMinTime = INFINITY;
    data->mInvokeCount = 0;

    buffer[bufferLen]     = ' ';
    buffer[bufferLen + 1] = ' ';
    buffer[bufferLen + 2] = 0;

    // sort data's children...
    LoomProfilerEntry *list = NULL;

    while (data->mFirstChild)
    {
        LoomProfilerEntry *ins = data->mFirstChild;
        data->mFirstChild = ins->mNextSibling;
        LoomProfilerEntry **walk = &list;
        while (*walk && (*walk)->mTotalTime > ins->mTotalTime)
        {
            walk = &(*walk)->mNextSibling;
        }
        ins->mNextSibling = *walk;
        *walk             = ins;
    }

    data->mFirstChild = list;

    while (list)
    {
        if (list->mInvokeCount)
        {
            LoomProfilerEntryDumpRecurse(list, buffer, bufferLen + 2, totalTime, threshold);
        }
        list = list->mNextSibling;
    }
    buffer[bufferLen] = 0;
}
Example #6
0
    BitmapData* BitmapData::diff(const BitmapData* a, const BitmapData* b)
    {
        if (a->w != b->w || a->h != b->h)
            return NULL;

        BitmapData* result = lmNew(NULL) BitmapData(
            (size_t)a->w,
            (size_t)a->h
        );

        if (result == NULL) {
            lmLogError(gGFXLogGroup, "Unable to allocate memory for BitmapData diff result");
            return NULL;
        }

        rgba_t* pixelptr_a = reinterpret_cast<rgba_t*>(a->data);
        rgba_t* pixelptr_b = reinterpret_cast<rgba_t*>(b->data);
        rgba_t* resultptr = reinterpret_cast<rgba_t*>(result->data);

        for (size_t i = 0; i < a->w * a->h; i++)
        {
            Color ap(convertHostToBEndian(pixelptr_a[i]));
            Color bp(convertHostToBEndian(pixelptr_b[i]));
            Color rp(fabsf(ap.r - bp.r), fabsf(ap.g - bp.g), fabsf(ap.b - bp.b), 1.0f);
            rgba_t a = rp.getHex();
            resultptr[i] = convertBEndianToHost(a);
        }

        return result;
    }
Example #7
0
void *loom_asset_imageDeserializer( void *buffer, size_t bufferLen, LoomAssetCleanupCallback *dtor )
{
   loom_asset_image_t *img;

   lmAssert(buffer != NULL, "buffer should not be null");

   img = (loom_asset_image_t*)lmAlloc(gAssetAllocator, sizeof(loom_asset_image_t));

    // parse any orientation info from exif format
   img->orientation = exifinfo_parse_orientation(buffer, (unsigned int)bufferLen);

   img->bits = stbi_load_from_memory((const stbi_uc *)buffer, (int)bufferLen, &img->width, &img->height, &img->bpp, 4);
   
   *dtor = loom_asset_imageDtor;
   
   if(!img->bits)
   {
      lmLogError(gImageAssetGroup, "Image load failed due to this cryptic reason: %s", stbi_failure_reason());
      lmFree(gAssetAllocator, img);
      return 0;
   }
   
   lmLogDebug(gImageAssetGroup, "Allocated %d bytes for an image!", img->width * img->height * 4);
   
   return img;
}
Example #8
0
void VectorTextFormat::ensureFontId() {
	if (fontId == VectorTextFormat::FONT_UNDEFINED) {
		int id = nvgFindFont(nvg, font.c_str());
		fontId = id >= 0 ? id : VectorTextFormat::FONT_NOTFOUND;
	}

	if (fontId == VectorTextFormat::FONT_NOTFOUND) {
		if (defaultFontId == VectorTextFormat::FONT_UNDEFINED) loadDefaultFontFace();
		fontId = defaultFontId;
	}

	if (fontId < 0) {
		if (defaultFontId != VectorTextFormat::FONT_REPORTEDERROR) {
			const char *msg;
			switch (defaultFontId) {
				case VectorTextFormat::FONT_DEFAULTMISSING: msg = "Missing default system font face (load error or unsupported platform)"; break;
				case VectorTextFormat::FONT_DEFAULTMEMORY:  msg = "Unable to create default font face memory"; break;
				default:                                    msg = "Unknown error"; break;
			}
			lmLogError(gGFXVectorRendererLogGroup, "TextFormat font error: %s", msg);
			defaultFontId = VectorTextFormat::FONT_REPORTEDERROR;
		}
		return;
	}
}
Example #9
0
// Helper to deserialize an asset, routing to the right function by type.
static void *loom_asset_deserializeAsset(const utString &path, int type, int size, void *ptr, LoomAssetCleanupCallback *dtor)
{
    lmAssert(gAssetDeserializerMap.find(type) != UT_NPOS, "Can't deserialize asset, no deserializer was set for type %x!", type);
    LoomAssetDeserializeCallback ladc = *gAssetDeserializerMap.get(type);

    if (ladc == NULL)
    {
        lmLogError(gAssetLogGroup, "Failed deserialize asset '%s', deserializer was not found for type '%x'!", path.c_str(), type);
        return NULL;
    }

   void *assetBits = ladc(ptr, size, dtor);

    if (assetBits == NULL)
    {
        lmLogError(gAssetLogGroup, "Failed to deserialize asset '%s', deserializer returned NULL for type '%x'!", path.c_str(), type);
        return NULL;
    }

    return assetBits;
}
Example #10
0
void loom_net_enableSocketKeepalive(loom_socketId_t s)
{
    int       optVal = 1;
    socklen_t optLen = sizeof(optVal);

    if (loom_net_isSocketDead(s))
    {
        lmLogError(netLogGroup, "Tried to set keepalive on dead socket.");
        return;
    }

    //lmLog(netLogGroup, "Setting keepalive with %d %d", optVal, optLen);

    if (setsockopt((int)s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optVal, optLen) < 0)
    {
        // This failure when due to EINVAL (22 on darwin) on a freshly created
        // socket is often because the sockethas been shutdown asynchronously by the OS.
        lmLogError(netLogGroup, "Could not set SO_KEEPALIVE on socket %x due to %d", s, errno);
        return;
    }
}
Example #11
0
loom_socketId_t loom_net_listenTCPSocket(unsigned short port)
{
    struct sockaddr_in listenName;
    int                status;

    // Create the socket.
    SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);

    lmAssert(listenSocket != -1, "Failed to allocate TCP socket to listen on!");

    // Bind to a port.
    listenName.sin_family      = AF_INET;
    listenName.sin_addr.s_addr = INADDR_ANY;
    listenName.sin_port        = htons(port);

    // Reuse addy. This avoids issues where socket lingers in TIME_WAIT and we cannot
    // reacquire it.
    loom_net_setSocketReuseAddress((loom_socketId_t)listenSocket, 1);

    status = bind(listenSocket, (struct sockaddr *)&listenName, sizeof(listenName));
    if (status == -1)
    {
        lmLogError(netLogGroup, "Could not bind TCP socket");
        return (loom_socketId_t)-1;
    }

    // Start listening.
    status = listen(listenSocket, 5);
    if (status == -1)
    {
        lmLogError(netLogGroup, "Could not listen on TCP socket");
        return (loom_socketId_t)-1;
    }

    // And set it nonblocking so we can poll accept.
    loom_net_setSocketBlocking((loom_socketId_t)listenSocket, 0);


    return (loom_socketId_t)listenSocket;
}
Example #12
0
    void BitmapData::save(const char* path) const
    {
        const char* ext = strrchr(path, '.');
        if (ext == NULL)
        {
            lmLogError(gGFXLogGroup, "No extension in path %s. Unable to detect file format.", path);
            return;
        }

        if (stricmp(ext, ".bmp") == 0)
        {
            if (stbi_write_bmp(path, w, h, DATA_BPP, data) != 1)
            {
                lmLogError(gGFXLogGroup, "Unable to write image %s", path);
            }
            return;
        }

        if (stricmp(ext, ".png") == 0)
        {
            if (stbi_write_png(path, w, h, DATA_BPP, data, w * DATA_BPP) != 1)
            {
                lmLogError(gGFXLogGroup, "Unable to write image %s", path);
            }
            return;
        }

        if (stricmp(ext, ".tga") == 0)
        {
            if (stbi_write_tga(path, w, h, DATA_BPP, data) != 1)
            {
                lmLogError(gGFXLogGroup, "Unable to write image %s", path);
            }
            return;
        }

        lmLogError(gGFXLogGroup, "Unsupported image extension in path %s.", path);
    }
Example #13
0
int loom_net_isSocketDead(loom_socketId_t s)
{
    // According to http://stackoverflow.com/questions/4142012/how-to-find-the-socket-connection-state-in-c
    // If there is a non-zero error code it is dead.
    int       error = 0, retval = 0;
    socklen_t len   = sizeof(error);

    retval = getsockopt((int)s, SOL_SOCKET, SO_ERROR, (char *)&error, &len);
    if (retval == -1)
    {
        lmLogError(netLogGroup, "Could not read error on socket %x due to %d, must be dead.", s, errno);
        return 1;
    }

    return error != 0;
}
Example #14
0
// Convert a path into its canonical form.
static int makeAssetPathCanonical(const char *pathIn, char pathOut[MAXPATHLEN])
{
    // First thing, safe pathOut.
    pathOut[0] = 0;

    char cwd[MAXPATHLEN];
    char* cwdres = getcwd(cwd, MAXPATHLEN);

    char* resolvedPathPtr = NULL;
    // Note, man page suggests that realpath won't work right for
    // non-existant folders/files.
    if (cwdres != NULL)
    {
        resolvedPathPtr = platform_realpath(pathIn, NULL);
    }

    if (resolvedPathPtr == NULL)
    {
        lmLogError(gAssetAgentLogGroup, "Failed to resolve path %s via realpath due to %s", pathIn, strerror(errno));
        return 0;
    }

    // Now slurp off the prefix if possible.
    lmLogDebug(gAssetAgentLogGroup, "Checking for prefix '%s' '%s' '%s'", resolvedPathPtr, cwd, pathIn);

    lmAssert(resolvedPathPtr, "No resolved path!");
    lmAssert(cwd, "Could not get working dir?");

    const char *prefixOffset = strstr(resolvedPathPtr, cwd);
    if (prefixOffset != NULL)
    {
        // Great, it's known to us.
        strncpy(pathOut, prefixOffset + strlen(cwd) + 1, MAXPATHLEN);
        // free(resolvedPathPtr);
        return 1;
    }
    else
    {
        // Nope, unknown.
        // free(resolvedPathPtr);
        return 0;
    }
}
Example #15
0
int platform_error(const char *out, ...)
{
    // TODO: Does this need to be smarter, or stripped in release builds?
    char    buff[4096];
    va_list args;

    va_start(args, out);
    vsnprintf(buff, 4094, out, args);
    va_end(args);

    // Try to output/log error with re-entrancy guard.
    static int pesafety = 0;
    if (pesafety == 0)
    {
        pesafety = 1;
        lmLogError(gPlatformErrorLogGroup, "%s", buff);
        pesafety = 0;
    }

    return 0;
}
Example #16
0
    const BitmapData* BitmapData::fromAsset(const char* name)
    {
        loom_asset_image_t* img = static_cast<loom_asset_image_t*>(loom_asset_lock(name, LATImage, 1));
        loom_asset_unlock(name);

        if (img == NULL)
            return NULL;

        BitmapData* result = lmNew(NULL) BitmapData(
            (size_t)img->width,
            (size_t)img->height
        );

        if (result == NULL) {
            lmLogError(gGFXLogGroup, "Unable to allocate memory for BitmapData asset data");
            return NULL;
        }

        memcpy(result->data, img->bits, img->width * img->height * DATA_BPP);

        return result;
    }
Example #17
0
bool load_wav(const uint8_t* inData,
              const int32_t inDataLen,
              uint8_t* outData,
              wav_info* outInfo)
{
    if (inData == NULL)
    {
        lmLogError(gSoundAssetGroup, "No input data passed to wav loader");
        return false;
    }
    
    const uint8_t* cursor = inData;
    
    riff_header* riff = (riff_header*)cursor;
    if (riff->header.chunkId[0] != 'R' ||
        riff->header.chunkId[1] != 'I' ||
        riff->header.chunkId[2] != 'F' ||
        riff->header.chunkId[3] != 'F')
    {
        lmLogError(gSoundAssetGroup, "Bad wav file format");
        return false;
    }
    
    if (riff->riffType[0] != 'W' ||
        riff->riffType[1] != 'A' ||
        riff->riffType[2] != 'V' ||
        riff->riffType[3] != 'E')
    {
        lmLogError(gSoundAssetGroup, "Bad wav file format");
        return false;
    }
    
    riff->header.chunkDataSize = convertLEndianToHost(riff->header.chunkDataSize);
    
    if (inDataLen < static_cast<int32_t>(sizeof(chunk_header) + riff->header.chunkDataSize))
    {
        lmLogError(gSoundAssetGroup, "Not enough data in wav buffer");
        return false;
    }
    
    cursor += sizeof(riff_header);
    
    while (cursor < inData + inDataLen)
    {
        chunk_header* curChunkHeader = (chunk_header*)cursor;
        curChunkHeader->chunkDataSize = convertLEndianToHost(curChunkHeader->chunkDataSize);
        
        if (curChunkHeader->chunkId[0] == 'f' &&
            curChunkHeader->chunkId[1] == 'm' &&
            curChunkHeader->chunkId[2] == 't' &&
            curChunkHeader->chunkId[3] == ' ')
        {
            fmt_chunk* fmt = (fmt_chunk*)(cursor + sizeof(chunk_header));
            fmt->compressionType = convertLEndianToHost(fmt->compressionType);
            if (fmt->compressionType != 0x01)
            {
                // This loader only supports simple PCM (8-bit or 16-bit, which should be the most common)
                lmLogError(gSoundAssetGroup, "Unsupported wav format: 0x%2x. Recommend 8 or 16-bit PCM",
                           fmt->compressionType);
                return false;
            }
            
            if (outInfo)
            {
                outInfo->numChannels = convertLEndianToHost(fmt->numChannels);
                outInfo->samplesPerSecond = convertLEndianToHost(fmt->sampleRate);
                outInfo->sampleSize = convertLEndianToHost(fmt->bitsPerSample);
            }
        }
        else if (curChunkHeader->chunkId[0] == 'd' &&
                 curChunkHeader->chunkId[1] == 'a' &&
                 curChunkHeader->chunkId[2] == 't' &&
                 curChunkHeader->chunkId[3] == 'a')
        {
            if (outInfo)
            {
                outInfo->sampleDataSize = curChunkHeader->chunkDataSize;
            }
            
            if (outData != NULL)
            {
                memcpy(outData, cursor + sizeof(chunk_header), curChunkHeader->chunkDataSize);
            }
        }
        
        cursor += sizeof(chunk_header) + curChunkHeader->chunkDataSize;
    }
    
    return true;
}
Example #18
0
void *loom_asset_soundDeserializer( void *buffer, size_t bufferLen, LoomAssetCleanupCallback *dtor )
{
    loom_asset_sound_t *sound = (loom_asset_sound_t*)lmAlloc(gAssetAllocator, sizeof(loom_asset_sound_t));
    memset(sound, 0, sizeof(loom_asset_sound_t));
    unsigned char *charBuff = (unsigned char *)buffer;

    // Look for magic header in buffer.
    if(charBuff[0] == 0x4f 
        && charBuff[1] == 0x67
        && charBuff[2] == 0x67
        && charBuff[3] == 0x53)
    {
        // It's an Ogg, assume vorbis and throw it to stb_vorbis.
        int channels = 0;
        short *outputBuffer = NULL;
        int sampleCount = stb_vorbis_decode_memory(charBuff, (int)bufferLen, &channels, &outputBuffer);
        if(sampleCount < 0)
        {
            lmLogError(gSoundAssetGroup, "Failed to decode Ogg Vorbis");
            loom_asset_soundDtor(&sound);
            return NULL;
        }

        sound->channels = channels;
        sound->bytesPerSample = 2;
        sound->sampleCount = sampleCount;
        sound->bufferSize = sampleCount * channels * 2;
        sound->sampleRate = 44100; // TODO: This should be variable

        // We can skip this if we get clever about allocations in stbv.
        sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize);
        memcpy(sound->buffer, outputBuffer, sound->bufferSize);

        free(outputBuffer);
    }
    else if((charBuff[0] == 0x49 // ID3
        &&   charBuff[1] == 0x44
        &&   charBuff[2] == 0x33)
        ||  (charBuff[0] == 0xff // Missing ID3 Tag
        &&   charBuff[1] == 0xfb))
    {
        // It's an MP3, y'all!
        short *outBuffer = (short*)lmAlloc(gAssetAllocator, MP3_MAX_SAMPLES_PER_FRAME * 2);
        mp3_info_t mp3Info;

        // Decode once to get total size.
        size_t totalBytes = 0;
        size_t bytesRead = 0, bytesLeft = bufferLen;

        mp3_decoder_t decmp3 = mp3_create();
        for(;;)
        {
            int bytesDecoded = mp3_decode(decmp3, charBuff + bytesRead, (int)bytesLeft, outBuffer, &mp3Info);
            bytesRead += bytesDecoded;
            bytesLeft -= bytesDecoded;
            totalBytes += mp3Info.audio_bytes;
            if(bytesDecoded > 0)
                continue;

            // Clean up.
            mp3_done(decmp3);
            break;
        }

        // Great, set up the sound asset.
        // TODO: Warn about non 44.1khz mp3s.
        sound->channels = mp3Info.channels;
        sound->bytesPerSample = 2;
        sound->sampleCount = (int)totalBytes / sound->bytesPerSample;
        sound->bufferSize = sound->channels * sound->bytesPerSample * sound->sampleCount;
        sound->sampleRate = 44100; // TODO: This should be variable
        sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize);

        // Decode again to get real samples.        
        decmp3 = mp3_create();
        bytesRead = 0; bytesLeft = bufferLen;
        int curBufferOffset = 0;
        for(;;)
        {
            int bytesDecoded = mp3_decode(decmp3, charBuff + bytesRead, (int)bytesLeft, outBuffer, &mp3Info);
            bytesRead += bytesDecoded;
            bytesLeft -= bytesDecoded;

            memcpy(((unsigned char*)sound->buffer) + curBufferOffset, outBuffer, mp3Info.audio_bytes);
            curBufferOffset += mp3Info.audio_bytes;

            if(bytesDecoded > 0)
                continue;

            // Clean up.
            mp3_done(decmp3);
            break;
        }

        // Awesome, all set!
        lmFree(gAssetAllocator, outBuffer);
    }
    else if(charBuff[0] == 0x52 // 'RIFF'
         && charBuff[1] == 0x49
         && charBuff[2] == 0x46
         && charBuff[3] == 0x46)
    {
        // We've got a wav file
        wav_info wav;
        bool wavLoadSuccess = load_wav(charBuff, bufferLen, NULL, &wav);
        if (!wavLoadSuccess)
        {
            lmLogError(gSoundAssetGroup, "Failed to load wav format info");
            loom_asset_soundDtor(sound);
            return 0;
        }
        
        sound->channels = wav.numChannels;
        sound->bytesPerSample = wav.sampleSize / 8; // wav sample size is in bits
        if (sound->bytesPerSample != 1 && sound->bytesPerSample != 2)
        {
            lmLogError(gSoundAssetGroup, "Unsupported wav format. Currently only 8-bit or 16-bit PCM are supported");
            loom_asset_soundDtor(sound);
            return 0;
        }
        sound->bufferSize = wav.sampleDataSize;
        sound->sampleCount = sound->bufferSize / sound->bytesPerSample;
        sound->sampleRate = wav.samplesPerSecond;
        
        sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize);
        bool dataCopySuccess = load_wav(charBuff, bufferLen, (uint8_t*)sound->buffer, NULL);
        if (!dataCopySuccess)
        {
            lmLogError(gSoundAssetGroup, "Failed to copy wav data");
            loom_asset_soundDtor(sound);
            return 0;
        }
    }
    else
    {
        lmLogError(gSoundAssetGroup, "Failed to identify sound buffer by magic number!");
        loom_asset_soundDtor(sound);
        return 0;
    }

   *dtor = loom_asset_soundDtor;
   if(!sound->buffer)
   {
      lmLogError(gSoundAssetGroup, "Sound load failed due to this cryptic reason: %s", "(unknown)");
      lmFree(gAssetAllocator, sound);
      return 0;
   }

    lmLogDebug(gSoundAssetGroup, "Sound allocation: %d bytes", sound->bufferSize);
    return sound;
}
Example #19
0
void loom_net_readTCPSocket(loom_socketId_t s, void *buffer, int *bytesToRead, int peek /*= 0*/)
{
    int errorCode;

    int waiting;

    int tmp = *bytesToRead;

    int bytesLeft;

    if (loom_net_isSocketDead(s))
    {
        *bytesToRead = 0;
        return;
    }

    if (peek) {
        *bytesToRead = recv((SOCKET)s, buffer, tmp, MSG_PEEK);
        return;
    }

    bytesLeft = *bytesToRead;

    while (bytesLeft > 0)
    {
        int received = recv((SOCKET)s, buffer, bytesLeft, 0);
        if (received == -1) {
            waiting = 0;
#if LOOM_PLATFORM == LOOM_PLATFORM_WIN32
            errorCode = WSAGetLastError();
            if (errorCode == WSAEWOULDBLOCK)
            {
                waiting = 1;
            }
#else
            errorCode = errno;
            if (errorCode == EAGAIN)
            {
                waiting = 1;
            }
#endif
            if (waiting)
            {
                // TODO figure out a better way to do this?
                //lmLogDebug(netLogGroup, "Waiting for receive buffer %d / %d", *bytesToRead - bytesLeft, *bytesToRead);
                loom_thread_sleep(5);
                continue;
            }
            else
            {
                lmLogError(netLogGroup, "Read socket error (%d)", errorCode);
                *bytesToRead = -1;
                return;
            }
        }
        bytesLeft -= received;
        buffer = (char*)buffer + received;
    }

    lmAssert(bytesLeft == 0, "Internal recv error, read too much data? %d", bytesLeft);
}
Example #20
0
void LoomProfiler::dump()
{
    bool enableSave = mEnabled;

    mEnabled = false;
    mStackDepth++;

    // may have some profiled calls... gotta turn em off.

    utArray<LoomProfilerRoot *> rootVector;
    F64 totalTime = 0.0;
    for (LoomProfilerRoot *walk = LoomProfilerRoot::sRootList; walk; walk = walk->mNextRoot)
    {
        if (walk->mTotalInvokeCount == 0)
        {
            continue;
        }

        totalTime += walk->mTotalTime - walk->mSubTime;
        lmAssert(totalTime == totalTime, "Got a bad LoomProfilerRoot!"); // NaN is always inequal to itself.
        rootVector.push_back(walk);
    }

    qsort((void *)&rootVector[0], rootVector.size(), sizeof(LoomProfilerRoot *), rootDataCompare);

    lmLogError(gProfilerLogGroup, "Profiler Data Dump:");
    lmLogError(gProfilerLogGroup, "Ordered by non-sub total time -");
    lmLogError(gProfilerLogGroup, "%%NSTime  %% Time  Invoke #  Name");

    suppressedEntries = 0;

    float threshold = 0.1f;

    for (U32 i = 0; i < rootVector.size(); i++)
    {
        LoomProfilerRoot *root = rootVector[i];
        float tm = (float)(100.0 * (root->mTotalTime - root->mSubTime) / totalTime);
        if (tm >= threshold)
        {
            lmLogError(gProfilerLogGroup, "%7.3f %7.3f %8.3f %8.3f %8.3f %8d %s",
                       100.0 * (root->mTotalTime - root->mSubTime) / totalTime,
                       100.0 * root->mTotalTime / totalTime,
                       root->mTotalTime / (1000.0 * 1000.0 * (root->mTotalInvokeCount > 0 ? root->mTotalInvokeCount : 1)),
                       root->mMaxTime / (1000.0 * 1000.0),
                       root->mMinTime / (1000.0 * 1000.0),
                       root->mTotalInvokeCount,
                       root->mName);
        }
        else
        {
            suppressedEntries++;
        }

        root->mTotalInvokeCount = 0;
        root->mTotalTime = 0;
        root->mSubTime = 0;
        root->mMaxTime = 0;
        root->mMinTime = INFINITY;
    }
    lmLogError(gProfilerLogGroup, "Suppressed %i items with < %.1f%% of measured time.", suppressedEntries, threshold);
    lmLogError(gProfilerLogGroup, "");
    lmLogError(gProfilerLogGroup, "Ordered by stack trace total time -");
    lmLogError(gProfilerLogGroup, "%% Time  %% NSTime AvgTime  MaxTime  MinTime  Invoke #  Name");

    mCurrentLoomProfilerEntry->mTotalTime = endHighResolutionTimer(mCurrentLoomProfilerEntry->mStartTime);

    char depthBuffer[MaxStackDepth * 2 + 1];
    depthBuffer[0]    = 0;
    suppressedEntries = 0;
    LoomProfilerEntryDumpRecurse(mCurrentLoomProfilerEntry, depthBuffer, 0, totalTime, threshold);
    lmLogError(gProfilerLogGroup, "Suppressed %i items with < %.1f%% of measured time.", suppressedEntries, threshold);

    mEnabled = enableSave;
    mStackDepth--;

    mDumpToConsole = false;
}
Example #21
0
    virtual bool handleMessage(int fourcc, AssetProtocolHandler *handler, NetworkBuffer& buffer)
    {
        switch (fourcc)
        {
        case LOOM_FOURCC('F', 'I', 'L', 'E'):
           {
               // How many pending files?
               gPendingFiles = buffer.readInt();
               loom_asset_notifyPendingCountChange();

               // Read the filename.
               char *path;
               int  fileStringLength;
               buffer.readString(&path, &fileStringLength);

               // And the file length.
               int bitsLength = buffer.readInt();

               // Checkpoint at end!
               buffer.readCheckpoint(0xDEADBEE3);

               // Prepare the buffer!
               if (pendingFile != NULL)
               {
                   lmLogError(gAssetLogGroup, "Got a new FILE '%s' while still processing existing file '%s'!", path, pendingFilePath.c_str());
                   wipePendingData();
               }

               // Update the pending file state.
               pendingFilePath = path;
               lmFree(NULL, path);
               path = NULL;

               pendingFileLength = bitsLength;
               pendingFile       = (const char *)lmAlloc(gAssetAllocator, pendingFileLength);

               // Log it.
               lmLogDebug(gAssetLogGroup, "FILE '%s' %d bytes incoming.", pendingFilePath.c_str(), bitsLength);

               // Awesome, sit back and wait for chunks to come in.
               return true;
           }

        case LOOM_FOURCC('F', 'C', 'H', 'K'):
           {
               // How many pending files?
               gPendingFiles = buffer.readInt();
               loom_asset_notifyPendingCountChange();

               // Get the offset.
               int chunkOffset = buffer.readInt();

               // Read bits into the buffer.
               char *fileBits;
               int  fileBitsLength;
               buffer.readString(&fileBits, &fileBitsLength);
               memcpy((void *)(pendingFile + chunkOffset), (void *)fileBits, fileBitsLength);
               lmFree(NULL, fileBits);

               // Checkpoint at end!
               buffer.readCheckpoint(0xDEADBEE2);

               int lastByteOffset = chunkOffset + fileBitsLength;

               // Log it.
               lmLogDebug(gAssetLogGroup, "FILE '%s' %d of %d bytes!", pendingFilePath.c_str(), lastByteOffset, pendingFileLength);

               // If it's the last one, instate it and wipe our buffer.
               if (lastByteOffset == pendingFileLength)
               {
                   // And this resolves a file so decrement the pending count. This way
                   // we will get to zero.
                   gPendingFiles--;
                   loom_asset_notifyPendingCountChange();

                   // Instate the new asset data.
                   loom_asset_t *asset    = loom_asset_getAssetByName(pendingFilePath.c_str(), 1);
                   int          assetType = loom_asset_recognizeAssetTypeFromPath(pendingFilePath);
                   if (assetType == 0)
                   {
                       lmLogDebug(gAssetLogGroup, "Couldn't infer file type for '%s', ignoring.", pendingFilePath.c_str());
                       wipePendingData();
                       return true;
                   }

                   lmLogWarn(gAssetLogGroup, "Applying new version of '%s', %d bytes.", pendingFilePath.c_str(), pendingFileLength);
                   LoomAssetCleanupCallback dtor = NULL;
                   void *assetBits = loom_asset_deserializeAsset(pendingFilePath.c_str(), assetType, pendingFileLength, (void *)pendingFile, &dtor);
                   asset->instate(assetType, assetBits, dtor);

                   // And wipe the pending date.
                   wipePendingData();
               }
         }

         return true;
      }

    return false;
    }
Example #22
0
void *loom_asset_soundDeserializer( void *buffer, size_t bufferLen, LoomAssetCleanupCallback *dtor )
{
   loom_asset_sound_t *sound = (loom_asset_sound_t*)lmAlloc(gAssetAllocator, sizeof(loom_asset_sound_t));
   unsigned char *charBuff = (unsigned char *)buffer;

    // Look for magic header in buffer.
    if(charBuff[0] == 0x4f 
        && charBuff[1] == 0x67
        && charBuff[2] == 0x67
        && charBuff[3] == 0x53)
    {
        // It's an Ogg, assume vorbis and throw it to stb_vorbis.
        int channels = 0;
        short *outputBuffer = NULL;
        int sampleCount = stb_vorbis_decode_memory(charBuff, bufferLen, &channels, &outputBuffer);
        if(sampleCount < 0)
        {
            lmLogError(gSoundAssetGroup, "Failed to decode Ogg Vorbis!");
            return NULL;
        }

        sound->channels = channels;
        sound->bytesPerSample = 2;
        sound->sampleCount = sampleCount;
        sound->bufferSize = sampleCount * channels * 2;

        // We can skip this if we get clever about allocations in stbv.
        sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize);
        memcpy(sound->buffer, outputBuffer, sound->bufferSize);

        free(outputBuffer);
    }
    else if((charBuff[0] == 0x49 // ID3
        &&   charBuff[1] == 0x44
        &&   charBuff[2] == 0x33)
        ||  (charBuff[0] == 0xff // Missing ID3 Tag
        &&   charBuff[1] == 0xfb))
    {
        // It's an MP3, y'all!
        short *outBuffer = (short*)lmAlloc(gAssetAllocator, MP3_MAX_SAMPLES_PER_FRAME * 2);
        mp3_info_t mp3Info;

        // Decode once to get total size.
        int totalBytes = 0;
        int bytesRead = 0, bytesLeft = bufferLen;

        mp3_decoder_t decmp3 = mp3_create();
        for(;;)
        {
            int bytesDecoded = mp3_decode(decmp3, charBuff + bytesRead, bytesLeft, outBuffer, &mp3Info);
            bytesRead += bytesDecoded;
            bytesLeft -= bytesDecoded;
            totalBytes += mp3Info.audio_bytes;
            if(bytesDecoded > 0)
                continue;

            // Clean up.
            mp3_done(decmp3);
            break;
        }

        // Great, set up the sound asset.
        // TODO: Warn about non 44.1khz mp3s.
        sound->channels = mp3Info.channels;
        sound->bytesPerSample = 2;
        sound->sampleCount = totalBytes / sound->bytesPerSample;
        sound->bufferSize = sound->channels * sound->bytesPerSample * sound->sampleCount;
        sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize);

        // Decode again to get real samples.        
        decmp3 = mp3_create();
        bytesRead = 0; bytesLeft = bufferLen;
        int curBufferOffset = 0;
        for(;;)
        {
            int bytesDecoded = mp3_decode(decmp3, charBuff + bytesRead, bytesLeft, outBuffer, &mp3Info);
            bytesRead += bytesDecoded;
            bytesLeft -= bytesDecoded;

            memcpy(((unsigned char*)sound->buffer) + curBufferOffset, outBuffer, mp3Info.audio_bytes);
            curBufferOffset += mp3Info.audio_bytes;

            if(bytesDecoded > 0)
                continue;

            // Clean up.
            mp3_done(decmp3);
            break;
        }

        // Awesome, all set!
        lmFree(gAssetAllocator, outBuffer);
    }
    else
    {
        lmLogError(gSoundAssetGroup, "Failed to identify sound buffer by magic number!");
        return 0;
    }

   *dtor = loom_asset_soundDtor;
   if(!sound->buffer)
   {
      lmLogError(gSoundAssetGroup, "Sound load failed due to this cryptic reason: %s", "(unknown)");
      lmFree(gAssetAllocator, sound);
      return 0;
   }

   lmLogError(gSoundAssetGroup, "Allocated %d bytes for a sound!", sound->bufferSize);
   return sound;
}
Example #23
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);
}
Example #24
0
loom_socketId_t loom_net_openTCPSocket(const char *host, unsigned short port, int blocking)
{
    SOCKET s;
    int     status, res;
    struct addrinfo hints;
    struct addrinfo *hostInfo;
    char portString[16];

    //set up he hints
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    //copy the port over to a string
    sprintf(portString, "%ld", port);

    // Resolve the host.
    res = getaddrinfo(host, portString, &hints, &hostInfo);
    if (res != 0)
    {
        lmLogError(netLogGroup, "Failed to resolve host '%s' via getaddrinfo: %s", host, gai_strerror(res));
        return NULL;
    }

    // Create the socket.
    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s == -1)
    {
        lmLogError(netLogGroup, "Failed to open TCP socket - socket() failed.");
        freeaddrinfo(hostInfo);
        return NULL;
    }

    // Block if user wants it.
    loom_net_setSocketBlocking((loom_socketId_t)s, blocking);

    // Disable SIGPIPE, we handle that in another way.
#ifdef SO_NOSIGPIPE
    int set = 1;
    setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
#endif

    // Do the connect.
    status = connect(s, hostInfo->ai_addr, (int)hostInfo->ai_addrlen);
    if (status != 0)
    {
        // Get the real error code, might be WOULDBLOCK.
#if LOOM_PLATFORM == LOOM_PLATFORM_WIN32
        int res = WSAGetLastError();
#else
        int res = errno;
#endif

        if (res != EINPROGRESS

            // Assorted platform specific checks/exceptions.
#if LOOM_PLATFORM == LOOM_PLATFORM_WIN32
            && res != 0 &&
            res != WSAEWOULDBLOCK
#endif
            )
        {
            // Failure due to some grody reason.
            lmLogError(netLogGroup, "Failed to connect() TCP socket due to error code %d.", res);
            closesocket(s);
            freeaddrinfo(hostInfo);
            return NULL;
        }
    }

    freeaddrinfo(hostInfo);
    return (loom_socketId_t)s;
}