const AnimData* AnimResManager::loadAnimData(const char *aniFileName) { assert(aniFileName != NULL && *aniFileName != 0); vector< Pair >::iterator node = find(m_AnimData.begin(), m_AnimData.end(), aniFileName); if (node != m_AnimData.end()) { return node->pAnimData; } char *s2 = strdup(aniFileName); if (!s2) return 0; vector<const char *> pathTokens; for (const char *pathToken = strtok(s2, "/\\"); pathToken; pathToken = strtok(0, "/\\")) { pathTokens.push_back(pathToken); } const char *cdot = strrchr(pathTokens.back(), '.'); bool bXmlFile = false; if (cdot && 0 == strcmp(cdot, ".xml")) bXmlFile = true; free(s2); if (bXmlFile) { AnimData *pAnimData = new AnimData; if (pAnimData) { if (!pAnimData->loadFromXml(aniFileName)) { delete pAnimData; pAnimData = 0; } } return pAnimData; } else { iByteStream *byteStream = iSystem::GetInstance()->loadStream(aniFileName); if (!byteStream) return 0; AnimData *pAnimData = new AnimData; if (pAnimData) { if (!pAnimData->loadFromByteStream(byteStream)) { delete pAnimData; pAnimData = 0; } } iSystem::GetInstance()->release(byteStream); return pAnimData; } }
Animation::Animation(const AnimData& anim_data) : anim_data_(anim_data), timeline_(0), fps_(anim_data.fps()), total_frames_(anim_data_.total_frames()), current_frame_(0), playing_(false), hidden_(false), looping_(true) { sprite_.SetImage(anim_data.texture()); update_sprite_to_frame(); }
/** * Draw one overlay * @param it Overlay info */ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { int idx, len, width; ObjectStruct *obj; AnimData *sprite; byte *mask; switch (it->type) { // color sprite case 0: if (g_cine->_objectTable[it->objIdx].frame < 0) { return; } sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; memcpy(mask, sprite->mask(), len); remaskSprite(mask, it); drawMaskedSprite(g_cine->_objectTable[it->objIdx], mask); delete[] mask; break; // game message case 2: if (it->objIdx >= g_cine->_messageTable.size()) { return; } _messageLen += g_cine->_messageTable[it->objIdx].size(); drawMessage(g_cine->_messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color); waitForPlayerClick = 1; break; // action failure message case 3: idx = it->objIdx * 4 + g_cine->_rnd.getRandomNumber(3); len = strlen(failureMessages[idx]); _messageLen += len; width = 6 * len + 20; width = width > 300 ? 300 : width; drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, 4); waitForPlayerClick = 1; break; // bitmap case 4: assert(it->objIdx < NUM_MAX_OBJECT); obj = &g_cine->_objectTable[it->objIdx]; if (obj->frame < 0) { return; } if (!g_cine->_animDataTable[obj->frame].data()) { return; } fillSprite(*obj); break; } }
/** * Draw one overlay * @param it Overlay info * @todo Add handling of type 22 overlays */ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { int len, idx, width, height; ObjectStruct *obj; AnimData *sprite; byte *mask; byte color; switch (it->type) { // color sprite case 0: if (g_cine->_objectTable[it->objIdx].frame < 0) { break; } sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; generateMask(sprite->data(), mask, len, g_cine->_objectTable[it->objIdx].part); remaskSprite(mask, it); drawMaskedSprite(g_cine->_objectTable[it->objIdx], mask); delete[] mask; break; // game message case 2: if (it->objIdx >= g_cine->_messageTable.size()) { return; } _messageLen += g_cine->_messageTable[it->objIdx].size(); drawMessage(g_cine->_messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color); if (it->color >= 0) { // This test isn't in Future Wars's implementation waitForPlayerClick = 1; } break; // action failure message case 3: idx = it->objIdx * 4 + g_cine->_rnd.getRandomNumber(3); len = strlen(failureMessages[idx]); _messageLen += len; width = 6 * len + 20; width = width > 300 ? 300 : width; // The used color here differs from Future Wars drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, _messageBg); waitForPlayerClick = 1; break; // bitmap case 4: if (g_cine->_objectTable[it->objIdx].frame >= 0) { FWRenderer::renderOverlay(it); } break; // masked background case 20: assert(it->objIdx < NUM_MAX_OBJECT); var5 = it->x; // A global variable updated here! obj = &g_cine->_objectTable[it->objIdx]; sprite = &g_cine->_animDataTable[obj->frame]; if (obj->frame < 0 || it->x < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) { break; } maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y); break; // FIXME: Implement correct drawing of type 21 overlays. // Type 21 overlays aren't just filled rectangles, I found their drawing routine // from Operation Stealth's drawSprite routine. So they're likely some kind of sprites // and it's just a coincidence that the oxygen meter during the first arcade sequence // works even somehow currently. I tried the original under DOSBox and the oxygen gauge // is a long red bar that gets shorter as the air runs out. case 21: // A filled rectangle: case 22: // TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing). assert(it->objIdx < NUM_MAX_OBJECT); obj = &g_cine->_objectTable[it->objIdx]; color = obj->part & 0x0F; width = obj->frame; height = obj->costume; drawPlainBox(obj->x, obj->y, width, height, color); debug(5, "renderOverlay: type=%d, x=%d, y=%d, width=%d, height=%d, color=%d", it->type, obj->x, obj->y, width, height, color); break; // something else default: FWRenderer::renderOverlay(it); break; } }
/** * Draw one overlay * @param it Overlay info * @todo Add handling of type 22 overlays */ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { int len, idx, width, height; ObjectStruct *obj; AnimData *sprite; byte color; switch (it->type) { // color sprite case 0: if (g_cine->_objectTable[it->objIdx].frame < 0) { break; } sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; drawSprite(&(*it), sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, g_cine->_objectTable[it->objIdx].x, g_cine->_objectTable[it->objIdx].y, g_cine->_objectTable[it->objIdx].part, sprite->_bpp); break; // game message case 2: if (it->objIdx >= g_cine->_messageTable.size()) { return; } _messageLen += g_cine->_messageTable[it->objIdx].size(); drawMessage(g_cine->_messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color); if (it->color >= 0) { // This test isn't in Future Wars's implementation waitForPlayerClick = 1; } break; // action failure message case 3: idx = it->objIdx * 4 + g_cine->_rnd.getRandomNumber(3); len = strlen(failureMessages[idx]); _messageLen += len; width = 6 * len + 20; width = width > 300 ? 300 : width; // The used color here differs from Future Wars drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, _messageBg); waitForPlayerClick = 1; break; // bitmap case 4: if (g_cine->_objectTable[it->objIdx].frame >= 0) { FWRenderer::renderOverlay(it); } break; // masked background case 20: assert(it->objIdx < NUM_MAX_OBJECT); var5 = it->x; // A global variable updated here! obj = &g_cine->_objectTable[it->objIdx]; sprite = &g_cine->_animDataTable[obj->frame]; if (obj->frame < 0 || it->x < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) { break; } maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y); break; case 22: // TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing). assert(it->objIdx < NUM_MAX_OBJECT); obj = &g_cine->_objectTable[it->objIdx]; color = obj->part & 0x0F; width = obj->frame; height = obj->costume; drawPlainBox(obj->x, obj->y, width, height, color); debug(5, "renderOverlay: type=%d, x=%d, y=%d, width=%d, height=%d, color=%d", it->type, obj->x, obj->y, width, height, color); break; // something else default: FWRenderer::renderOverlay(it); break; } }