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); }
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 }
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; }
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; }
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; }
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; }
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; }
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; } }
// 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; }
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; } }
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; }
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); }
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; }
// 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; } }
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; }
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; }
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; }
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; }
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); }
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; }
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; }
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; }
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); }
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; }