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

423 lines
14 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/graphics/GraphicsDrawer.h"
#include "hpl1/engine/graphics/GfxObject.h"
#include "hpl1/engine/graphics/LowLevelGraphics.h"
#include "hpl1/engine/graphics/Material.h"
#include "hpl1/engine/graphics/MaterialHandler.h"
#include "hpl1/engine/resources/FrameBitmap.h"
#include "hpl1/engine/resources/ResourceImage.h"
#include "hpl1/engine/resources/TextureManager.h"
#include "hpl1/engine/system/low_level_system.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/resources/ImageManager.h"
#include "hpl1/engine/resources/Resources.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cGraphicsDrawer::cGraphicsDrawer(iLowLevelGraphics *apLowLevelGraphics, cMaterialHandler *apMaterialHandler,
cResources *apResources) {
mpLowLevelGraphics = apLowLevelGraphics;
mpMaterialHandler = apMaterialHandler;
mpResources = apResources;
}
//-----------------------------------------------------------------------
cGraphicsDrawer::~cGraphicsDrawer() {
ClearBackgrounds();
STLDeleteAll(mlstGfxObjects);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iMaterial *cGfxBufferObject::GetMaterial() const {
return mpObject->GetMaterial();
}
//-----------------------------------------------------------------------
bool cGfxBufferCompare::operator()(const cGfxBufferObject &aObjectA, const cGfxBufferObject &aObjectB) const {
if (aObjectA.GetZ() != aObjectB.GetZ()) {
return aObjectA.GetZ() < aObjectB.GetZ();
} else if (aObjectA.GetMaterial()->GetTexture(eMaterialTexture_Diffuse) !=
aObjectB.GetMaterial()->GetTexture(eMaterialTexture_Diffuse)) {
return aObjectA.GetMaterial()->GetTexture(eMaterialTexture_Diffuse) >
aObjectB.GetMaterial()->GetTexture(eMaterialTexture_Diffuse);
} else if (aObjectA.GetMaterial()->GetType(eMaterialRenderType_Diffuse) !=
aObjectB.GetMaterial()->GetType(eMaterialRenderType_Diffuse)) {
return aObjectA.GetMaterial()->GetType(eMaterialRenderType_Diffuse) >
aObjectB.GetMaterial()->GetType(eMaterialRenderType_Diffuse);
} else {
}
return false;
}
//-----------------------------------------------------------------------
static void FlushImage(cGfxObject *apObject) {
if (apObject->IsImage()) {
cResourceImage *pImage = apObject->GetMaterial()->GetImage(eMaterialTexture_Diffuse);
pImage->GetFrameBitmap()->FlushToTexture();
}
}
void cGraphicsDrawer::DrawGfxObject(cGfxObject *apObject, const cVector3f &avPos,
const cVector2f &avSize, const cColor &aColor,
bool abFlipH, bool abFlipV, float afAngle) {
FlushImage(apObject);
cGfxBufferObject BuffObj;
BuffObj.mpObject = apObject;
BuffObj.mvTransform = avPos;
BuffObj.mvSize = avSize;
BuffObj.mColor = aColor;
BuffObj.mbFlipH = abFlipH;
BuffObj.mbFlipV = abFlipV;
BuffObj.mfAngle = afAngle;
BuffObj.mbIsColorAndSize = true;
m_setGfxBuffer.insert(BuffObj);
}
//-----------------------------------------------------------------------
void cGraphicsDrawer::DrawGfxObject(cGfxObject *apObject, const cVector3f &avPos) {
FlushImage(apObject);
cGfxBufferObject BuffObj;
BuffObj.mpObject = apObject;
BuffObj.mvTransform = avPos;
BuffObj.mbIsColorAndSize = false;
m_setGfxBuffer.insert(BuffObj);
}
//-----------------------------------------------------------------------
void cGraphicsDrawer::DrawAll() {
// Set all states
mpLowLevelGraphics->SetDepthTestActive(false);
mpLowLevelGraphics->SetIdentityMatrix(eMatrix_ModelView);
mpLowLevelGraphics->SetOrthoProjection(mpLowLevelGraphics->GetVirtualSize(), -1000, 1000);
int lIdxAdd = 0;
iMaterial *pPrevMat = NULL;
iMaterial *pMat = NULL;
const cGfxBufferObject *pObj = NULL;
tGfxBufferSetIt ObjectIt = m_setGfxBuffer.begin();
if (ObjectIt != m_setGfxBuffer.end())
pMat = ObjectIt->GetMaterial();
while (ObjectIt != m_setGfxBuffer.end()) {
if (pMat->StartRendering(eMaterialRenderType_Diffuse, NULL, NULL) == false) {
ObjectIt++;
if (ObjectIt != m_setGfxBuffer.end())
pMat = ObjectIt->GetMaterial();
continue;
}
do {
pObj = &(*ObjectIt);
if (pObj->mbIsColorAndSize) {
cVector3f vPos[4];
float fW = pObj->mvSize.x * 0.5f;
float fH = pObj->mvSize.y * 0.5f;
cMatrixf mtxTrans = cMath::MatrixTranslate(pObj->mvTransform + cVector3f(fW, fH, 0));
vPos[0] = cVector3f(-fW, -fH, 0);
vPos[1] = cVector3f(fW, -fH, 0);
vPos[2] = cVector3f(fW, fH, 0);
vPos[3] = cVector3f(-fW, fH, 0);
if (pObj->mfAngle != 0) {
cMatrixf mtxRot = cMath::MatrixRotateZ(pObj->mfAngle);
vPos[0] = cMath::MatrixMul(mtxRot, vPos[0]);
vPos[1] = cMath::MatrixMul(mtxRot, vPos[1]);
vPos[2] = cMath::MatrixMul(mtxRot, vPos[2]);
vPos[3] = cMath::MatrixMul(mtxRot, vPos[3]);
}
vPos[0] = cMath::MatrixMul(mtxTrans, vPos[0]);
vPos[1] = cMath::MatrixMul(mtxTrans, vPos[1]);
vPos[2] = cMath::MatrixMul(mtxTrans, vPos[2]);
vPos[3] = cMath::MatrixMul(mtxTrans, vPos[3]);
if (pObj->mbFlipH) {
mpLowLevelGraphics->AddVertexToBatch_Size2D(pObj->mpObject->GetVtxPtr(0),
&vPos[0],
&pObj->mColor,
0, 0);
mpLowLevelGraphics->AddVertexToBatch_Size2D(pObj->mpObject->GetVtxPtr(1),
&vPos[1],
&pObj->mColor,
0, 0);
mpLowLevelGraphics->AddVertexToBatch_Size2D(pObj->mpObject->GetVtxPtr(2),
&vPos[2],
&pObj->mColor,
0, 0);
mpLowLevelGraphics->AddVertexToBatch_Size2D(pObj->mpObject->GetVtxPtr(3),
&vPos[3],
&pObj->mColor,
pObj->mvSize.x, pObj->mvSize.y);
} else {
mpLowLevelGraphics->AddVertexToBatch_Size2D(pObj->mpObject->GetVtxPtr(0),
&vPos[0],
&pObj->mColor,
0, 0);
mpLowLevelGraphics->AddVertexToBatch_Size2D(pObj->mpObject->GetVtxPtr(1),
&vPos[1],
&pObj->mColor,
0, 0);
mpLowLevelGraphics->AddVertexToBatch_Size2D(pObj->mpObject->GetVtxPtr(2),
&vPos[2],
&pObj->mColor,
0, 0);
mpLowLevelGraphics->AddVertexToBatch_Size2D(pObj->mpObject->GetVtxPtr(3),
&vPos[3],
&pObj->mColor,
0, 0);
}
for (int i = 0; i < 4; i++)
mpLowLevelGraphics->AddIndexToBatch(lIdxAdd + i);
} else {
for (int i = 0; i < (int)pObj->mpObject->GetVertexVec()->size(); i++) {
mpLowLevelGraphics->AddVertexToBatch(pObj->mpObject->GetVtxPtr(i),
&pObj->mvTransform);
mpLowLevelGraphics->AddIndexToBatch(lIdxAdd + i);
}
}
lIdxAdd += (int)pObj->mpObject->GetVertexVec()->size();
pPrevMat = pMat;
ObjectIt++;
if (ObjectIt == m_setGfxBuffer.end()) {
pMat = NULL;
break;
} else {
pMat = ObjectIt->GetMaterial();
}
} while (pMat->GetType(eMaterialRenderType_Diffuse) ==
pPrevMat->GetType(eMaterialRenderType_Diffuse) &&
pMat->GetTexture(eMaterialTexture_Diffuse) ==
pPrevMat->GetTexture(eMaterialTexture_Diffuse));
lIdxAdd = 0;
do {
mpLowLevelGraphics->FlushQuadBatch(pPrevMat->GetBatchFlags(eMaterialRenderType_Diffuse), false);
} while (pPrevMat->NextPass(eMaterialRenderType_Diffuse));
mpLowLevelGraphics->ClearBatch();
pPrevMat->EndRendering(eMaterialRenderType_Diffuse);
}
// Clear the buffer of objects.
m_setGfxBuffer.clear();
// Reset all states
mpLowLevelGraphics->SetDepthTestActive(true);
}
//-----------------------------------------------------------------------
cGfxObject *cGraphicsDrawer::CreateGfxObject(const tString &asFileName, const tString &asMaterialName,
bool abAddToList) {
cResourceImage *pImage = mpResources->GetImageManager()->CreateImage(asFileName);
if (pImage == NULL) {
error("Couldn't load image '%s'", asFileName.c_str());
return NULL;
}
iMaterial *pMat = mpMaterialHandler->Create(asMaterialName, eMaterialPicture_Image);
if (pMat == NULL) {
error("Couldn't create material '%s'", asMaterialName.c_str());
return NULL;
}
// mpResources->GetImageManager()->FlushAll();
pMat->SetImage(pImage, eMaterialTexture_Diffuse);
cGfxObject *pObject = hplNew(cGfxObject, (pMat, asFileName, true));
if (abAddToList)
mlstGfxObjects.push_back(pObject);
return pObject;
}
//-----------------------------------------------------------------------
cGfxObject *cGraphicsDrawer::CreateGfxObject(Bitmap2D *apBmp, const tString &asMaterialName,
bool abAddToList) {
cResourceImage *pImage = mpResources->GetImageManager()->CreateFromBitmap("", apBmp);
if (pImage == NULL) {
error("Couldn't create image");
return NULL;
}
iMaterial *pMat = mpMaterialHandler->Create(asMaterialName, eMaterialPicture_Image);
if (pMat == NULL) {
error("Couldn't create material '%s'", asMaterialName.c_str());
return NULL;
}
// mpResources->GetImageManager()->FlushAll();
pMat->SetImage(pImage, eMaterialTexture_Diffuse);
cGfxObject *pObject = hplNew(cGfxObject, (pMat, "", true));
if (abAddToList)
mlstGfxObjects.push_back(pObject);
return pObject;
}
//-----------------------------------------------------------------------
cGfxObject *cGraphicsDrawer::CreateGfxObjectFromTexture(const tString &asFileName, const tString &asMaterialName,
bool abAddToList) {
iTexture *pTex = mpResources->GetTextureManager()->Create2D(asFileName, false);
if (pTex == NULL) {
error("Couldn't create texture '%s'", asFileName.c_str());
return NULL;
}
iMaterial *pMat = mpMaterialHandler->Create(asMaterialName, eMaterialPicture_Texture);
if (pMat == NULL) {
error("Couldn't create material '%s'", asMaterialName.c_str());
return NULL;
}
// mpResources->GetImageManager()->FlushAll();
pMat->SetTexture(pTex, eMaterialTexture_Diffuse);
cGfxObject *pObject = hplNew(cGfxObject, (pMat, asFileName, false));
if (abAddToList)
mlstGfxObjects.push_back(pObject);
return pObject;
}
//-----------------------------------------------------------------------
void cGraphicsDrawer::DestroyGfxObject(cGfxObject *apObject) {
STLFindAndDelete(mlstGfxObjects, apObject);
}
//-----------------------------------------------------------------------
cBackgroundImage *cGraphicsDrawer::AddBackgroundImage(const tString &asFileName,
const tString &asMaterialName,
const cVector3f &avPos,
bool abTile, const cVector2f &avSize, const cVector2f &avPosPercent, const cVector2f &avVel) {
cResourceImage *pImage = mpResources->GetImageManager()->CreateImage(asFileName);
if (pImage == NULL) {
error("Couldn't load image '%s'", asFileName.c_str());
return NULL;
}
iMaterial *pMat = mpMaterialHandler->Create(asMaterialName, eMaterialPicture_Image);
if (pMat == NULL) {
error("Couldn't create material '%s'", asMaterialName.c_str());
return NULL;
}
// mpResources->GetImageManager()->FlushAll();
pMat->SetImage(pImage, eMaterialTexture_Diffuse);
cBackgroundImage *pBG = hplNew(cBackgroundImage, (pMat, avPos, abTile, avSize, avPosPercent, avVel));
m_mapBackgroundImages.insert(tBackgroundImageMap::value_type(avPos.z, pBG));
return pBG;
}
//-----------------------------------------------------------------------
void cGraphicsDrawer::UpdateBackgrounds() {
tBackgroundImageMapIt it = m_mapBackgroundImages.begin();
for (; it != m_mapBackgroundImages.end(); it++) {
it->second->Update();
}
}
//-----------------------------------------------------------------------
void cGraphicsDrawer::DrawBackgrounds(const cRect2f &aCollideRect) {
mpLowLevelGraphics->SetIdentityMatrix(eMatrix_ModelView);
mpLowLevelGraphics->SetDepthTestActive(true);
mpLowLevelGraphics->SetDepthWriteActive(false);
mpLowLevelGraphics->SetAlphaTestFunc(eAlphaTestFunc_Greater, 0.1f);
mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_LessOrEqual);
tBackgroundImageMapIt it = m_mapBackgroundImages.begin();
for (; it != m_mapBackgroundImages.end(); it++) {
it->second->Draw(aCollideRect, mpLowLevelGraphics);
}
mpLowLevelGraphics->SetAlphaTestFunc(eAlphaTestFunc_Greater, 0.05f);
mpLowLevelGraphics->SetDepthWriteActive(true);
}
//-----------------------------------------------------------------------
void cGraphicsDrawer::ClearBackgrounds() {
tBackgroundImageMapIt it = m_mapBackgroundImages.begin();
for (; it != m_mapBackgroundImages.end(); it++) {
hplDelete(it->second);
}
m_mapBackgroundImages.clear();
}
//-----------------------------------------------------------------------
} // namespace hpl