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

274 lines
8.4 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/Mesh2d.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/system/MemoryManager.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cMesh2D::cMesh2D() {
}
//-----------------------------------------------------------------------
cMesh2D::~cMesh2D() {
mvPos.clear();
mvTexCoord.clear();
mvColor.clear();
mvIndex.clear();
for (int i = 0; i < eTileRotation_LastEnum; i++)
mvVtx[i].clear();
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cMesh2D::AddVertex(cVector2f avPos, cVector2f avTexCoord, cColor aCol) {
mvPos.push_back(avPos);
mvTexCoord.push_back(avTexCoord);
mvColor.push_back(aCol);
}
//-----------------------------------------------------------------------
void cMesh2D::AddIndex(unsigned int alIndex) {
mvIndex.push_back(alIndex);
}
//-----------------------------------------------------------------------
void cMesh2D::AddEdgeIndex(unsigned int alIndex) {
mvEdgeIndex.push_back(alIndex);
}
//-----------------------------------------------------------------------
void cMesh2D::CreateVertexVec() {
for (int i = 0; i < (int)mvPos.size(); i++) {
mvVtx[0].push_back(cVertex(cVector3f(mvPos[i].x, mvPos[i].y, 0), mvTexCoord[i], mvColor[i]));
}
CalculateEdges(eTileRotation_0, mvVtx[0], mvEdgeIndex);
}
//-----------------------------------------------------------------------
void cMesh2D::CreateTileVertexVec() {
int i;
CreateVertexVec();
for (i = 1; i < eTileRotation_LastEnum; i++) {
mvVtx[i] = mvVtx[0];
}
//--- Create the angles;---
for (int angle = 1; angle < 4; angle++) {
for (i = 0; i < (int)mvVtx[0].size(); i++) {
float fAngle = ((float)angle) * kPi2f;
mvVtx[angle][i].pos.x = cos(fAngle) * mvVtx[0][i].pos.x -
sin(fAngle) * mvVtx[0][i].pos.y;
mvVtx[angle][i].pos.y = sin(fAngle) * mvVtx[0][i].pos.x +
cos(fAngle) * mvVtx[0][i].pos.y;
}
// Can use same edge index here since order has not changed.
CalculateEdges((eTileRotation)angle, mvVtx[angle], mvEdgeIndex);
}
// SKIP THESE FOR NOW
// The edges are not calculated correctly..and I din't think they are that needed.
/*//--- Flip horizontally ---
for(i=0;i<(int)mvVtx[0].size();i++)
mvVtx[4][i].pos.x = -mvVtx[0][i].pos.x;
CalculateEdges(eTileRotation_FlipH, mvVtx[4], mvEdgeIndex);
//--- Flip vertically ---
for(i=0;i<(int)mvVtx[0].size();i++)
mvVtx[5][i].pos.y = -mvVtx[0][i].pos.y;
CalculateEdges(eTileRotation_FlipV,mvVtx[5],InvEdgeIndex);
//--- Flip vertically and horizontal---
for(i=0;i<(int)mvVtx[0].size();i++)
{
mvVtx[6][i].pos.y = -mvVtx[0][i].pos.y;
mvVtx[6][i].pos.x = -mvVtx[0][i].pos.x;
}
//The two flips make it right again. No need to reverse
CalculateEdges(eTileRotation_FlipHV,mvVtx[6],mvEdgeIndex);*/
}
//-----------------------------------------------------------------------
tVertexVec *cMesh2D::GetVertexVec(const cRect2f &aImageRect, cVector2f avSize, eTileRotation aRotation) {
cVector3f vImageStart(aImageRect.x, aImageRect.y, 0);
cVector3f vImageSize(aImageRect.w, aImageRect.h, 0);
/*Log("ImageStart: %s\n",vImageStart.ToString().c_str());
Log("ImageSize: %s\n",vImageSize.ToString().c_str());*/
for (int j = 0; j < (int)mvVtx[aRotation].size(); j++) {
// we want the same texture coords for all angles. therefor 0
cVector3f vPos = (mvVtx[0][j].pos + avSize / 2) / avSize;
mvVtx[aRotation][j].col = 1;
mvVtx[aRotation][j].tex = vImageStart + (vPos * vImageSize);
switch (aRotation) {
case eTileRotation_0:
mvVtx[aRotation][j].norm = cVector3f(1, 0, 3);
break;
case eTileRotation_90:
mvVtx[aRotation][j].norm = cVector3f(0, 1, 3);
break;
case eTileRotation_180:
mvVtx[aRotation][j].norm = cVector3f(-1, 0, 3);
break;
case eTileRotation_270:
mvVtx[aRotation][j].norm = cVector3f(0, -1, 3);
break;
default:
break;
}
}
return &mvVtx[aRotation];
}
//-----------------------------------------------------------------------
tUIntVec *cMesh2D::GetIndexVec() {
return &mvIndex;
}
//-----------------------------------------------------------------------
tMesh2DEdgeVec *cMesh2D::GetEdgeVec(eTileRotation aRotation) {
return &mvEdge[aRotation];
}
//-----------------------------------------------------------------------
bool cMesh2D::PointIsInside(const cVector2f &avPoint, const cVector2f &avMeshPos, eTileRotation aRotation) {
cVector2f vLocalPoint;
cVector2f vNormal;
for (int i = 0; i < (int)mvEdge[aRotation].size(); i++) {
vLocalPoint = avPoint - avMeshPos - mvEdge[aRotation][i].mvMidPos;
vNormal = mvEdge[aRotation][i].mvNormal;
if ((vLocalPoint.x * vNormal.x + vLocalPoint.y * vNormal.y) >= 0)
return false;
}
return true;
}
//-----------------------------------------------------------------------
cCollisionMesh2D *cMesh2D::CreateCollisonMesh(const cVector2f &avPos, const cVector2f &avSizeMul, eTileRotation aRotation) {
cCollisionMesh2D *pCollMesh = hplNew(cCollisionMesh2D, ());
for (int i = 0; i < (int)mvEdgeIndex.size(); i++) {
cVector3f vPos = mvVtx[aRotation][mvEdgeIndex[i]].pos;
pCollMesh->mvPos.push_back(cVector2f(vPos.x, vPos.y) * (avSizeMul / 2) + avPos);
}
for (int i = 0; i < (int)mvEdge[aRotation].size(); i++) {
pCollMesh->mvNormal.push_back(mvEdge[aRotation][i].mvNormal);
}
return pCollMesh;
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PRIAVTE METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
/**
* Walks through the positions using the indexes in an Clockwise order and calculates the
* normal for every edge (startpos -> endpos).
*/
void cMesh2D::CalculateEdges(eTileRotation aRotation, tVertexVec &aVtx, tUIntVec &aIdx) {
cVector2f vLargest = -100000;
cVector2f vSmallest = 1000000;
for (int i = 0; i < (int)aIdx.size(); i++) {
// Do some checks for the BB creation:
// X:
if (aVtx[aIdx[i]].pos.x > vLargest.x)
vLargest.x = aVtx[aIdx[i]].pos.x;
else if (aVtx[aIdx[i]].pos.x < vSmallest.x)
vSmallest.x = aVtx[aIdx[i]].pos.x;
// Y:
if (aVtx[aIdx[i]].pos.y > vLargest.y)
vLargest.y = aVtx[aIdx[i]].pos.y;
else if (aVtx[aIdx[i]].pos.y < vSmallest.y)
vSmallest.y = aVtx[aIdx[i]].pos.y;
int start = i;
int end = i + 1 >= (int)aIdx.size() ? 0 : i + 1;
cVector2f vNormal;
vNormal.x = -(aVtx[aIdx[start]].pos.y - aVtx[aIdx[end]].pos.y);
vNormal.y = aVtx[aIdx[start]].pos.x - aVtx[aIdx[end]].pos.x;
vNormal.Normalise();
cVector2f vMidPos;
vMidPos.x = (aVtx[aIdx[start]].pos.x + aVtx[aIdx[end]].pos.x) / 2;
vMidPos.y = (aVtx[aIdx[start]].pos.y + aVtx[aIdx[end]].pos.y) / 2;
mvEdge[aRotation].push_back(cMesh2DEdge(vNormal, vMidPos, mvEdgeIndex[start], mvEdgeIndex[end]));
}
// Create the bounding box.
mvBoundingBox[aRotation].x = vSmallest.x;
mvBoundingBox[aRotation].y = vSmallest.y;
mvBoundingBox[aRotation].w = vLargest.x - vSmallest.x;
mvBoundingBox[aRotation].h = vLargest.y - vSmallest.y;
}
//-----------------------------------------------------------------------
} // namespace hpl