Files
scummvm-cursorfix/engines/hpl1/engine/resources/FrameBitmap.cpp
2026-02-02 04:50:13 +01:00

267 lines
8.0 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Copyright (C) 2006-2010 - Frictional Games
*
* This file is part of HPL1 Engine.
*/
#include "hpl1/engine/resources/FrameBitmap.h"
#include "hpl1/engine/graphics/Texture.h"
#include "hpl1/engine/graphics/bitmap2D.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/resources/FrameTexture.h"
#include "hpl1/engine/resources/ResourceImage.h"
#include "hpl1/engine/system/low_level_system.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cFrameBitmap::cFrameBitmap(Bitmap2D *apBitmap, cFrameTexture *apFrmTex, int alHandle) : iFrameBase() {
mpBitmap = apBitmap;
mpFrameTexture = apFrmTex;
mpBitmap->fillRect(cRect2l(0, 0, 0, 0), cColor(1, 1));
mlMinHole = 6;
mlHandle = alHandle;
mbIsFull = false;
mbIsLocked = false;
// Root node in rect tree
mRects.Insert(cFBitmapRect(0, 0, mpBitmap->getWidth(), mpBitmap->getHeight(), -1));
}
cFrameBitmap::~cFrameBitmap() {
hplDelete(mpBitmap);
mpBitmap = NULL;
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
#define DEBUG_BTREE (false)
cResourceImage *cFrameBitmap::AddBitmap(Bitmap2D *apSrc) {
cResourceImage *pImage = NULL;
// source size
//+2 because we are gonna have a border to get rid if some antialiasing problems
int lSW = apSrc->getWidth() + 2;
int lSH = apSrc->getHeight() + 2;
// destination size
// int lDW = mpBitmap->getWidth();
// int lDH = mpBitmap->getHeight();
cVector2l vPos;
bool bFoundEmptyNode = false;
bool bFoundNode = false;
// Debug
int node = 0;
if (DEBUG_BTREE)
Log("**** Image %d *****\n", mlPicCount);
// Get the leaves of the tree and search it for a good pos.
tRectTreeNodeList lstNodes = mRects.GetLeafList();
tRectTreeNodeListIt it;
for (it = lstNodes.begin(); it != lstNodes.end(); ++it) {
if (DEBUG_BTREE)
Log("Checking node %d:\n", node++);
tRectTreeNode *TopNode = *it;
cFBitmapRect *pData = TopNode->GetData();
// Check if the space is free
if (pData->mlHandle < 0) {
if (DEBUG_BTREE)
Log("Found free node\n");
bFoundEmptyNode = true; // An empty node was found.. bitmap not full yet.
// Check if the Image fits in the rect
cRect2l NewRect = cRect2l(pData->mRect.x, pData->mRect.y, lSW, lSH);
if (DEBUG_BTREE)
Log("Fit: [%d:%d:%d:%d] in [%d:%d:%d:%d]\n",
NewRect.x, NewRect.y, NewRect.w, NewRect.h,
pData->mRect.x, pData->mRect.y, pData->mRect.w, pData->mRect.h);
if (cMath::BoxFit(NewRect, pData->mRect)) {
if (DEBUG_BTREE)
Log("The node fits!\n");
bFoundNode = true;
// If the bitmap fits perfectly add the node without splitting
if (MinimumFit(NewRect, pData->mRect)) {
if (DEBUG_BTREE)
Log("Minimum fit!\n");
pData->mRect = NewRect;
pData->mlHandle = 1;
}
// If there is still space left, make new nodes.
else {
if (DEBUG_BTREE)
Log("Normal fit!\n");
// Insert 2 children for the top node (lower and upper part.
tRectTreeNode *UpperNode;
// Upper
UpperNode = mRects.InsertAt(cFBitmapRect(NewRect.x, NewRect.y,
pData->mRect.w, NewRect.h, -2),
TopNode,
eBinTreeNode_Left);
// Lower
mRects.InsertAt(cFBitmapRect(NewRect.x, NewRect.y + NewRect.h,
pData->mRect.w, pData->mRect.h - NewRect.h, -3),
TopNode,
eBinTreeNode_Right);
// Split the Upper Node into 2 nodes.
pData = UpperNode->GetData(); // Get the data for the upper node.
// Upper split, this is the new bitmap
mRects.InsertAt(cFBitmapRect(NewRect.x, NewRect.y,
NewRect.w, NewRect.h, 2),
UpperNode,
eBinTreeNode_Left);
// Lower split, this is empty
mRects.InsertAt(cFBitmapRect(NewRect.x + NewRect.w, NewRect.y,
pData->mRect.w - NewRect.w, NewRect.h, -4),
UpperNode,
eBinTreeNode_Right);
}
vPos = cVector2l(NewRect.x + 1, NewRect.y + 1); //+1 for the right pos
// Draw 4 times so we get a nice extra border
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++) {
apSrc->drawToBitmap(*mpBitmap, cVector2l(NewRect.x + i * 2, NewRect.y + j * 2));
}
// Fix the border a little more:
for (int i = -1; i < 2; i++)
for (int j = -1; j < 2; j++)
if ((i == 0 || j == 0) && (i != j)) {
apSrc->drawToBitmap(*mpBitmap, cVector2l(NewRect.x + 1 + i, NewRect.y + 1 + j));
}
// Draw the final
apSrc->drawToBitmap(*mpBitmap, cVector2l(NewRect.x + 1, NewRect.y + 1));
mlPicCount++;
mpFrameTexture->SetPicCount(mlPicCount);
break;
}
}
}
if (bFoundNode) {
// Create the image resource
pImage = hplNew(cResourceImage, (apSrc->getFileName(), mpFrameTexture, this,
cRect2l(vPos, cVector2l(lSW - 2, lSH - 2)), //-2 to get the correct size.
cVector2l(mpBitmap->getWidth(), mpBitmap->getHeight()),
mlHandle));
if (!bFoundEmptyNode) {
mbIsFull = true;
}
mbIsUpdated = true;
}
/// LAST DEBUG ///
if (DEBUG_BTREE) {
Log("Current Tree begin:\n");
tRectTreeNodeList lstNodes2 = mRects.GetNodeList();
tRectTreeNodeListIt it2;
int node2 = 0;
for (it2 = lstNodes2.begin(); it2 != lstNodes2.end(); ++it) {
cRect2l Rect = (*it2)->GetData()->mRect;
int h = (*it)->GetData()->mlHandle;
Log(" %d: [%d:%d:%d:%d]:%d\n", node2, Rect.x, Rect.y, Rect.w, Rect.h, h);
node2++;
}
Log("Current Tree end:\n");
Log("-----------------\n");
Log("Current Leaves begin:\n");
lstNodes2 = mRects.GetLeafList();
node2 = 0;
for (it2 = lstNodes2.begin(); it2 != lstNodes2.end(); ++it) {
cRect2l Rect = (*it2)->GetData()->mRect;
int h = (*it2)->GetData()->mlHandle;
Log(" %d: [%d:%d:%d:%d]: %d\n", node2, Rect.x, Rect.y, Rect.w, Rect.h, h);
node2++;
}
Log("Current Tree end:\n");
Log("-----------------\n");
}
return pImage;
}
//-----------------------------------------------------------------------
bool cFrameBitmap::MinimumFit(cRect2l aSrc, cRect2l aDest) {
if (aDest.w - aSrc.w < mlMinHole && aDest.h - aSrc.h < mlMinHole)
return true;
return false;
}
//-----------------------------------------------------------------------
bool cFrameBitmap::IsUpdated() {
return mbIsUpdated;
}
//-----------------------------------------------------------------------
bool cFrameBitmap::IsFull() {
return mbIsFull;
}
//-----------------------------------------------------------------------
bool cFrameBitmap::FlushToTexture() {
if (mbIsUpdated) {
mpFrameTexture->GetTexture()->CreateFromBitmap(mpBitmap);
mpFrameTexture->GetTexture()->SetWrapS(eTextureWrap_ClampToEdge);
mpFrameTexture->GetTexture()->SetWrapT(eTextureWrap_ClampToEdge);
// mpFrameTexture->SetPicCount(mlPicCount);
mbIsUpdated = false;
return true;
} else {
return false;
}
}
//-----------------------------------------------------------------------
} // namespace hpl