/** * Translates a raw image resource into a graphics surface. The caller is then responsible * for managing and destroying the surface when done with it * * @imgData Raw image resource * @size Size of the resource */ GfxSurface surfaceFromRes(const byte *imgData) { Rect r(0, 0, READ_LE_UINT16(imgData), READ_LE_UINT16(imgData + 2)); GfxSurface s; s.create(r.width(), r.height()); s._centroid.x = READ_LE_UINT16(imgData + 4); s._centroid.y = READ_LE_UINT16(imgData + 6); s._transColor = *(imgData + 8); bool rleEncoded = (imgData[9] & 2) != 0; const byte *srcP = imgData + 10; Graphics::Surface destSurface = s.lockSurface(); byte *destP = (byte *)destSurface.getBasePtr(0, 0); if (!rleEncoded) { Common::copy(srcP, srcP + (r.width() * r.height()), destP); } else { Common::set_to(destP, destP + (r.width() * r.height()), s._transColor); for (int yp = 0; yp < r.height(); ++yp) { int width = r.width(); destP = (byte *)destSurface.getBasePtr(0, yp); while (width > 0) { uint8 controlVal = *srcP++; if ((controlVal & 0x80) == 0) { // Copy specified number of bytes Common::copy(srcP, srcP + controlVal, destP); width -= controlVal; srcP += controlVal; destP += controlVal; } else if ((controlVal & 0x40) == 0) { // Skip a specified number of output pixels destP += controlVal & 0x3f; width -= controlVal & 0x3f; } else { // Copy a specified pixel a given number of times controlVal &= 0x3f; int pixel = *srcP++; Common::set_to(destP, destP + controlVal, pixel); destP += controlVal; width -= controlVal; } } assert(width == 0); } } s.unlockSurface(); return s; }
/** * Scales a passed surface, creating a new surface with the result * @param srcImage Source image to scale * @param NewWidth New width for scaled image * @param NewHeight New height for scaled image * @remarks Caller is responsible for freeing the returned surface */ static GfxSurface ResizeSurface(GfxSurface &src, int xSize, int ySize, int transIndex) { GfxSurface s; s.create(xSize, ySize); Graphics::Surface srcImage = src.lockSurface(); Graphics::Surface destImage = s.lockSurface(); int *horizUsage = scaleLine(xSize, srcImage.w); int *vertUsage = scaleLine(ySize, srcImage.h); // Loop to create scaled version for (int yp = 0; yp < ySize; ++yp) { byte *destP = (byte *)destImage.getBasePtr(0, yp); if (vertUsage[yp] == -1) { Common::set_to(destP, destP + xSize, transIndex); } else { const byte *srcP = (const byte *)srcImage.getBasePtr(0, vertUsage[yp]); for (int xp = 0; xp < xSize; ++xp) { if (horizUsage[xp] != -1) { const byte *tempSrcP = srcP + horizUsage[xp]; *destP++ = *tempSrcP++; } else { // Pixel overrun at the end of the line *destP++ = transIndex; } } } } // Unlock surfaces src.unlockSurface(); s.unlockSurface(); // Delete arrays and return surface delete[] horizUsage; delete[] vertUsage; return s; }
void EventsClass::pushCursor(CursorType cursorType) { const byte *cursor; bool delFlag = true; uint size; switch (cursorType) { case CURSOR_NONE: // No cursor cursor = _resourceManager->getSubResource(4, 1, 6, &size); break; case CURSOR_LOOK: // Look cursor cursor = _resourceManager->getSubResource(4, 1, 5, &size); break; case CURSOR_USE: // Use cursor cursor = _resourceManager->getSubResource(4, 1, 4, &size); break; case CURSOR_TALK: // Talk cursor cursor = _resourceManager->getSubResource(4, 1, 3, &size); break; case CURSOR_ARROW: // Arrow cursor cursor = CURSOR_ARROW_DATA; delFlag = false; break; case CURSOR_WALK: default: // Walk cursor cursor = CURSOR_WALK_DATA; delFlag = false; break; } // Decode the cursor GfxSurface s = surfaceFromRes(cursor); Graphics::Surface surface = s.lockSurface(); const byte *cursorData = (const byte *)surface.getBasePtr(0, 0); CursorMan.pushCursor(cursorData, surface.w, surface.h, s._centroid.x, s._centroid.y, s._transColor); s.unlockSurface(); if (delFlag) DEALLOCATE(cursor); }
/** * Copys an area from one GfxSurface to another */ void GfxSurface::copyFrom(GfxSurface &src, Rect srcBounds, Rect destBounds, Region *priorityRegion) { GfxSurface srcImage; if (srcBounds.isEmpty()) return; if (srcBounds == src.getBounds()) srcImage = src; else { // Set the source image to be the subset specified by the source bounds Graphics::Surface srcSurface = src.lockSurface(); srcImage.create(srcBounds.width(), srcBounds.height()); Graphics::Surface destSurface = srcImage.lockSurface(); const byte *srcP = (const byte *)srcSurface.getBasePtr(srcBounds.left, srcBounds.top); byte *destP = (byte *)destSurface.pixels; for (int yp = srcBounds.top; yp < srcBounds.bottom; ++yp, srcP += srcSurface.pitch, destP += destSurface.pitch) { Common::copy(srcP, srcP + srcBounds.width(), destP); } srcImage.unlockSurface(); src.unlockSurface(); } if ((destBounds.width() != srcBounds.width()) || (destBounds.height() != srcBounds.height())) srcImage = ResizeSurface(srcImage, destBounds.width(), destBounds.height(), src._transColor); Graphics::Surface srcSurface = srcImage.lockSurface(); Graphics::Surface destSurface = lockSurface(); // Adjust bounds to ensure destination will be on-screen int srcX = 0, srcY = 0; if (destBounds.left < 0) { srcX = -destBounds.left; destBounds.left = 0; } if (destBounds.top < 0) { srcY = -destBounds.top; destBounds.top = 0; } if (destBounds.right > destSurface.w) destBounds.right = destSurface.w; if (destBounds.bottom > destSurface.h) destBounds.bottom = destSurface.h; if (destBounds.isValidRect()) { const byte *pSrc = (const byte *)srcSurface.getBasePtr(srcX, srcY); byte *pDest = (byte *)destSurface.getBasePtr(destBounds.left, destBounds.top); for (int y = 0; y < destBounds.height(); ++y, pSrc += srcSurface.pitch, pDest += destSurface.pitch) { if (!priorityRegion && (src._transColor == -1)) Common::copy(pSrc, pSrc + destBounds.width(), pDest); else { const byte *tempSrc = pSrc; byte *tempDest = pDest; int xp = destBounds.left; while (tempSrc < (pSrc + destBounds.width())) { if (!priorityRegion || !priorityRegion->contains(Common::Point( xp + _globals->_sceneManager._scene->_sceneBounds.left, destBounds.top + y + _globals->_sceneManager._scene->_sceneBounds.top))) { if (*tempSrc != src._transColor) *tempDest = *tempSrc; } ++tempSrc; ++tempDest; ++xp; } } } } unlockSurface(); srcImage.unlockSurface(); }
/** * Sets the specified cursor * * @cursorType Specified cursor number */ void EventsClass::setCursor(CursorType cursorType) { if (cursorType == _lastCursor) return; _lastCursor = cursorType; _globals->clearFlag(122); CursorMan.showMouse(true); const byte *cursor; bool delFlag = true; uint size; switch (cursorType) { case CURSOR_NONE: // No cursor _globals->setFlag(122); if (_vm->getFeatures() & GF_DEMO) { CursorMan.showMouse(false); return; } cursor = _resourceManager->getSubResource(4, 1, 6, &size); break; case CURSOR_LOOK: // Look cursor cursor = _resourceManager->getSubResource(4, 1, 5, &size); _currentCursor = CURSOR_LOOK; break; case CURSOR_USE: // Use cursor cursor = _resourceManager->getSubResource(4, 1, 4, &size); _currentCursor = CURSOR_USE; break; case CURSOR_TALK: // Talk cursor cursor = _resourceManager->getSubResource(4, 1, 3, &size); _currentCursor = CURSOR_TALK; break; case CURSOR_ARROW: // Arrow cursor cursor = CURSOR_ARROW_DATA; delFlag = false; break; case CURSOR_WALK: default: // Walk cursor cursor = CURSOR_WALK_DATA; _currentCursor = CURSOR_WALK; delFlag = false; break; } // Decode the cursor GfxSurface s = surfaceFromRes(cursor); Graphics::Surface surface = s.lockSurface(); const byte *cursorData = (const byte *)surface.getBasePtr(0, 0); CursorMan.replaceCursor(cursorData, surface.w, surface.h, s._centroid.x, s._centroid.y, s._transColor); s.unlockSurface(); if (delFlag) DEALLOCATE(cursor); }
/** * Sets the specified cursor * * @cursorType Specified cursor number */ void EventsClass::setCursor(CursorType cursorType) { if (cursorType == _lastCursor) return; _lastCursor = cursorType; g_globals->clearFlag(122); CursorMan.showMouse(true); const byte *cursor; bool delFlag = true; uint size; bool questionEnabled = false; switch (cursorType) { case CURSOR_NONE: // No cursor g_globals->setFlag(122); if ((g_vm->getGameID() != GType_Ringworld) || ((g_vm->getGameID() == GType_Ringworld) && (g_vm->getFeatures() & GF_DEMO))) { CursorMan.showMouse(false); return; } cursor = g_resourceManager->getSubResource(4, 1, 6, &size); break; case CURSOR_LOOK: // Look cursor if (g_vm->getGameID() == GType_BlueForce) { cursor = g_resourceManager->getSubResource(1, 5, 3, &size); } else if (g_vm->getGameID() == GType_Ringworld2) { cursor = g_resourceManager->getSubResource(5, 1, 5, &size); } else { cursor = g_resourceManager->getSubResource(4, 1, 5, &size); } _currentCursor = CURSOR_LOOK; break; case CURSOR_USE: // Use cursor if (g_vm->getGameID() == GType_BlueForce) { cursor = g_resourceManager->getSubResource(1, 5, 2, &size); } else if (g_vm->getGameID() == GType_Ringworld2) { cursor = g_resourceManager->getSubResource(5, 1, 4, &size); } else { cursor = g_resourceManager->getSubResource(4, 1, 4, &size); } _currentCursor = CURSOR_USE; break; case CURSOR_TALK: // Talk cursor if (g_vm->getGameID() == GType_BlueForce) { cursor = g_resourceManager->getSubResource(1, 5, 4, &size); } else if (g_vm->getGameID() == GType_Ringworld2) { cursor = g_resourceManager->getSubResource(5, 1, 6, &size); } else { cursor = g_resourceManager->getSubResource(4, 1, 3, &size); } _currentCursor = CURSOR_TALK; break; case CURSOR_EXIT: // Exit cursor (Blue Force) assert(g_vm->getGameID() == GType_BlueForce); cursor = g_resourceManager->getSubResource(1, 5, 7, &size); _currentCursor = CURSOR_EXIT; break; case CURSOR_PRINTER: // Printer cursor (Blue Force) assert(g_vm->getGameID() == GType_BlueForce); cursor = g_resourceManager->getSubResource(1, 7, 6, &size); _currentCursor = CURSOR_PRINTER; break; case CURSOR_ARROW: // Arrow cursor cursor = CURSOR_ARROW_DATA; delFlag = false; break; case CURSOR_WALK: default: switch (g_vm->getGameID()) { case GType_BlueForce: if (cursorType == CURSOR_WALK) { cursor = g_resourceManager->getSubResource(1, 5, 1, &size); } else { // Inventory icon cursor = g_resourceManager->getSubResource(10, ((int)cursorType - 1) / 20 + 1, ((int)cursorType - 1) % 20 + 1, &size); questionEnabled = true; } _currentCursor = cursorType; break; case GType_Ringworld2: if (cursorType == CURSOR_WALK) { cursor = CURSOR_WALK_DATA; delFlag = false; } else { // Inventory icon InvObject *invObject = g_globals->_inventory->getItem((int)cursorType); cursor = g_resourceManager->getSubResource(6, invObject->_strip, invObject->_frame, &size); questionEnabled = true; } _currentCursor = cursorType; break; default: // For Ringworld, always treat as the walk cursor cursor = CURSOR_WALK_DATA; _currentCursor = CURSOR_WALK; delFlag = false; break; } break; // Ringworld 2 specific cursors case EXITCURSOR_N: case EXITCURSOR_S: case EXITCURSOR_W: case EXITCURSOR_E: case EXITCURSOR_LEFT_HAND: case CURSOR_INVALID: case EXITCURSOR_NE: case EXITCURSOR_SE: case EXITCURSOR_SW: case EXITCURSOR_NW: case SHADECURSOR_UP: case SHADECURSOR_DOWN: case SHADECURSOR_HAND: _currentCursor = cursorType; cursor = g_resourceManager->getSubResource(5, 1, cursorType - R2CURSORS_START, &size); break; case R2_CURSOR_ROPE: _currentCursor = cursorType; cursor = g_resourceManager->getSubResource(5, 4, 1, &size); break; } // Decode the cursor GfxSurface s = surfaceFromRes(cursor); Graphics::Surface surface = s.lockSurface(); const byte *cursorData = (const byte *)surface.getPixels(); CursorMan.replaceCursor(cursorData, surface.w, surface.h, s._centroid.x, s._centroid.y, s._transColor); s.unlockSurface(); if (delFlag) DEALLOCATE(cursor); // For Blue Force and Return to Ringworld, enable the question button when an inventory icon is selected if (g_vm->getGameID() != GType_Ringworld) T2_GLOBALS._uiElements._question.setEnabled(questionEnabled); }