Files
2026-02-02 04:50:13 +01:00

414 lines
11 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/scene/ImageEntity.h"
#include "hpl1/engine/graphics/Graphics.h"
#include "hpl1/engine/graphics/GraphicsTypes.h"
#include "hpl1/engine/graphics/ImageEntityData.h"
#include "hpl1/engine/graphics/RenderObject2D.h"
#include "hpl1/engine/graphics/Renderer2D.h"
#include "hpl1/engine/impl/tinyXML/tinyxml.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/resources/ImageEntityManager.h"
#include "hpl1/engine/resources/Resources.h"
#include "hpl1/engine/system/String.h"
#include "hpl1/engine/system/low_level_system.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cImageEntity::cImageEntity(tString asName, cResources *apResources, cGraphics *apGraphics,
bool abAutoDeleteData)
: iEntity2D(asName) {
mvSize = cVector2f(-1, -1);
mbFlipH = false;
mbFlipV = false;
mpAnimation = NULL;
mfFrameNum = 0;
mfAnimSpeed = 0.5f;
mlFrame = 0;
mlLastFrame = -1;
mbFlashing = false;
mfAlpha = 1.0f;
mpEntityData = NULL;
mpResources = apResources;
mpGraphics = apGraphics;
UpdateBoundingBox();
msTempString = "Default";
mbAnimationPaused = false;
mbRotationHasChanged = true;
mbAutoDeleteData = abAutoDeleteData;
mbLoopAnimation = true;
}
//-----------------------------------------------------------------------
cImageEntity::~cImageEntity() {
if (mbAutoDeleteData) {
if (mpEntityData)
mpResources->GetImageEntityManager()->Destroy(mpEntityData);
}
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
int cImageEntity::GetMaxFrameNum() {
if (mpAnimation == NULL)
return 0;
// One for the -1, one for the frame jump, and one because we start with 0.
return (int)mpAnimation->mvFrameNums.size() - 3;
}
//-----------------------------------------------------------------------
bool cImageEntity::SetAnimation(const tString &asName, bool abLoop) {
mbLoopAnimation = abLoop;
if (mpAnimation->msName == asName)
return true;
cImageAnimation *pAnim = mpEntityData->GetAnimationByName(asName);
if (pAnim == NULL)
return false;
mpAnimation = pAnim;
mfFrameNum = 0;
return true;
}
//-----------------------------------------------------------------------
const tString &cImageEntity::GetCurrentAnimation() const {
if (mpAnimation == NULL) {
return msTempString;
}
return mpAnimation->msName;
}
//-----------------------------------------------------------------------
void cImageEntity::StopAnimation() {
for (int i = 0; i < (int)mpAnimation->mvFrameNums.size(); i++) {
if (mpAnimation->mvFrameNums[i] == -1) {
mlFrame = i;
mlLastFrame = i;
mfFrameNum = (float)i;
break;
}
}
if (mbLoopAnimation)
mbLoopAnimation = false;
}
//-----------------------------------------------------------------------
void cImageEntity::SetSize(const cVector2f &avSize) {
if (avSize.x == mvSize.x && avSize.y == mvSize.y)
return;
mvSize.x = avSize.x == 0 ? 0.001f : avSize.x;
mvSize.y = avSize.y == 0 ? 0.001f : avSize.y;
mbSizeHasChanged = true;
mbRotationHasChanged = true;
}
//-----------------------------------------------------------------------
void cImageEntity::SetFlipH(bool abX) {
if (mbFlipH == abX)
return;
mbFlipH = abX;
mbRotationHasChanged = true;
}
//-----------------------------------------------------------------------
void cImageEntity::SetFlipV(bool abX) {
if (mbFlipV == abX)
return;
mbFlipV = abX;
mbRotationHasChanged = true;
}
//-----------------------------------------------------------------------
void cImageEntity::UpdateLogic(float afTimeStep) {
if (mbFlashing) {
float fAlpha = GetAlpha();
if (mfFlashAdd < 0) {
fAlpha += mfFlashAdd * 7;
if (fAlpha < 0) {
fAlpha = 0;
mfFlashAdd = -mfFlashAdd;
}
SetAlpha(fAlpha);
} else {
fAlpha += mfFlashAdd;
if (fAlpha > 1) {
fAlpha = 1;
mbFlashing = false;
}
SetAlpha(fAlpha);
}
}
if (mpAnimation && !mbAnimationPaused) {
if (mpAnimation->mvFrameNums[(int)mfFrameNum] != -1) {
mfFrameNum += mfAnimSpeed * mpAnimation->mfSpeed;
int lFrameNum = (int)mfFrameNum;
if (mpAnimation->mvFrameNums[lFrameNum] == -1) {
if (mbLoopAnimation) {
float fTemp = (float)mpAnimation->mvFrameNums[lFrameNum + 1];
mfFrameNum = fTemp + cMath::GetFraction(mfFrameNum);
}
}
}
}
}
//-----------------------------------------------------------------------
bool cImageEntity::AnimationIsPlaying() {
int lFrameNum = (int)mfFrameNum;
return mpAnimation->mvFrameNums[lFrameNum] != -1;
}
//-----------------------------------------------------------------------
void cImageEntity::Render() {
if (!mbIsActive)
return;
/*Update frame stuff if needed here*/
mvTransform = GetWorldPosition();
/// Get the frame to be used //////////////
if (mpEntityData->GetFrameNum() == 1) {
mlFrame = 0;
mlLastFrame = 0;
} else {
mlLastFrame = mlFrame;
mlFrame = mpAnimation->mvFrameNums[(int)mfFrameNum];
if (mlFrame == -1)
mlFrame = mpAnimation->mvFrameNums[((int)mfFrameNum) - 1];
/// If Frame has changed update vertexes
if (mlLastFrame != mlFrame) {
tVertexVec *pVtx = &mpEntityData->GetImageFrame(mlFrame)->mvVtx;
for (int i = 0; i < (int)pVtx->size(); i++) {
mvVtx[i].tex.x = (*pVtx)[i].tex.x;
mvVtx[i].tex.y = (*pVtx)[i].tex.y;
mvVtx[i].tex.z = (*pVtx)[i].tex.z;
}
}
}
if (mbSizeHasChanged) {
for (int i = 0; i < (int)mvBaseVtx.size(); i++) {
// Slow as hell!! Change this perhaps?
// This also only works on square meshes...
mvBaseVtx[i].pos.x = ABS(mvBaseVtx[i].pos.x) / mvBaseVtx[i].pos.x;
mvBaseVtx[i].pos.y = ABS(mvBaseVtx[i].pos.y) / mvBaseVtx[i].pos.y;
mvBaseVtx[i].pos.x *= mvSize.x / 2;
mvBaseVtx[i].pos.y *= mvSize.y / 2;
mvBaseVtx[i].pos.z = 0;
}
}
/// If rotation or frame has changed, update the vertexes
if (mbRotationHasChanged || mfCurrentAngle != GetWorldRotation().z) {
mbRotationHasChanged = false;
mfCurrentAngle = GetWorldRotation().z;
float fSin = sin(mfCurrentAngle);
float fCos = cos(mfCurrentAngle);
float fNormZ = 3;
if (mbFlipV)
fNormZ = 1;
if (mbFlipH)
fNormZ *= -1;
for (int i = 0; i < (int)mvVtx.size(); i++) {
mvVtx[i].pos.x = mvBaseVtx[i].pos.x * fCos - mvBaseVtx[i].pos.y * fSin;
mvVtx[i].pos.y = mvBaseVtx[i].pos.x * fSin + mvBaseVtx[i].pos.y * fCos;
if (mbFlipH)
mvVtx[i].pos.x = -mvVtx[i].pos.x;
if (mbFlipV)
mvVtx[i].pos.y = -mvVtx[i].pos.y;
mvVtx[i].norm.x = fCos;
mvVtx[i].norm.y = fSin;
mvVtx[i].norm.z = fNormZ;
}
}
cRenderObject2D _obj = cRenderObject2D(
mpEntityData->GetImageFrame(mlFrame)->mpMaterial,
&mvVtx, &mvIdxVec,
ePrimitiveType_Quad, GetWorldPosition().z,
mBoundingBox, NULL, &mvTransform);
// Add the render object.
mpGraphics->GetRenderer2D()->AddObject(_obj);
}
//-----------------------------------------------------------------------
bool cImageEntity::LoadData(TiXmlElement *apRootElem) {
tString sDataName = cString::ToString(apRootElem->Attribute("DataName"), "");
mbFlipH = cString::ToBool(apRootElem->Attribute("FlipH"), false);
mbFlipV = cString::ToBool(apRootElem->Attribute("FlipV"), false);
mvRotation.z = cMath::ToRad(cString::ToFloat(apRootElem->Attribute("Angle"), 0));
mvSize.x = cString::ToFloat(apRootElem->Attribute("Width"), 2);
mvSize.y = cString::ToFloat(apRootElem->Attribute("Height"), 2);
int lAnimNum = cString::ToInt(apRootElem->Attribute("AnimNum"), 0);
return LoadEntityData(sDataName, lAnimNum);
}
//-----------------------------------------------------------------------
bool cImageEntity::LoadEntityData(tString asDataName, int alAnimNum) {
cImageEntityData *pImageData = mpResources->GetImageEntityManager()->CreateData(asDataName);
if (pImageData == NULL) {
error("Couldn't load Data '%s' for entity '%s'", asDataName.c_str(), msName.c_str());
return false;
}
return LoadEntityData(pImageData, alAnimNum);
}
//-----------------------------------------------------------------------
bool cImageEntity::LoadEntityData(cImageEntityData *apData, int alAnimNum) {
mpEntityData = apData;
if (mpEntityData->GetFrameNum() > 1) {
mpAnimation = mpEntityData->GetAnimationByHandle(alAnimNum);
mlFrame = mpAnimation->mvFrameNums[0];
mlLastFrame = -1;
} else {
mlFrame = 0;
}
mvBaseVtx = mpEntityData->GetImageFrame(mlFrame)->mvVtx;
if (mvSize.x < 0 && mvSize.y < 0) {
mvSize = mpEntityData->GetImageSize();
}
mvVtx = mvBaseVtx;
mvIdxVec = *mpEntityData->GetIndexVec();
mbRotationHasChanged = true;
mbSizeHasChanged = true;
mfCurrentAngle = 0;
return true;
}
//-----------------------------------------------------------------------
const cRect2f &cImageEntity::GetBoundingBox() {
return mBoundingBox;
}
//-----------------------------------------------------------------------
bool cImageEntity::UpdateBoundingBox() {
cVector2f vSize;
if (mvRotation.z != 0) {
// Only Temp...
float fMaxSize = sqrt(mvSize.x * mvSize.x + mvSize.y * mvSize.y);
vSize.x = fMaxSize;
vSize.y = fMaxSize;
} else {
vSize = mvSize;
}
mBoundingBox = cRect2f(cVector2f(GetWorldPosition().x - vSize.x / 2,
GetWorldPosition().y - vSize.y / 2),
vSize);
return true;
}
//-----------------------------------------------------------------------
void cImageEntity::SetAlpha(float afX) {
if (mfAlpha != afX) {
mfAlpha = afX;
for (int i = 0; i < (int)mvVtx.size(); i++) {
mvVtx[i].col.a = mfAlpha;
}
}
}
//-----------------------------------------------------------------------
void cImageEntity::Flash(float afAdd) {
mbFlashing = true;
mfFlashAdd = -ABS(afAdd);
}
//-----------------------------------------------------------------------
} // namespace hpl