mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-27 13:42:02 +00:00
TWINE: added missing clip functionality
see https://bugs.scummvm.org/ticket/12074 but this doesn't yet fix the holomap clipping bug
This commit is contained in:
parent
d5331c3c2c
commit
db4eb789e7
@ -20,13 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "twine/renderer/renderer.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/util.h"
|
||||
#include "twine/menu/interface.h"
|
||||
#include "twine/menu/menu.h"
|
||||
#include "twine/parser/body.h"
|
||||
#include "twine/renderer/redraw.h"
|
||||
#include "twine/renderer/shadeangletab.h"
|
||||
#include "twine/resources/resources.h"
|
||||
@ -383,55 +377,375 @@ static FORCEINLINE int16 clamp(int16 x, int16 a, int16 b) {
|
||||
return x < a ? a : (x > b ? b : x);
|
||||
}
|
||||
|
||||
bool Renderer::computePolygons(int16 polyRenderType, const Vertex *vertices, int32 numVertices) { // ComputePolyMinMax
|
||||
uint8 vertexParam1 = vertices[numVertices - 1].colorIndex;
|
||||
int16 currentVertexX = vertices[numVertices - 1].x;
|
||||
int16 currentVertexY = vertices[numVertices - 1].y;
|
||||
int16 Renderer::leftClip(int16 polyRenderType, Vertex** offTabPoly, int32 numVertices) {
|
||||
const Common::Rect &clip = _engine->_interface->_clip;
|
||||
Vertex *pTabPolyClip = offTabPoly[1];
|
||||
Vertex *pTabPoly = offTabPoly[0];
|
||||
int16 newNbPoints = 0;
|
||||
|
||||
// invert the pointers to continue on the clipped vertices in the next method
|
||||
offTabPoly[0] = pTabPolyClip;
|
||||
offTabPoly[1] = pTabPoly;
|
||||
|
||||
for (; numVertices > 0; --numVertices, pTabPoly++) {
|
||||
const Vertex *p0 = pTabPoly;
|
||||
const Vertex *p1 = p0 + 1;
|
||||
|
||||
// clipFlag :
|
||||
// 0x00 : none clipped
|
||||
// 0x01 : point 0 clipped
|
||||
// 0x02 : point 1 clipped
|
||||
// 0x03 : both clipped
|
||||
uint8 clipFlag = (p1->x < clip.left) ? 2 : 0;
|
||||
|
||||
if (p0->x < clip.left) {
|
||||
if (clipFlag) {
|
||||
continue; // both clipped, skip point 0
|
||||
}
|
||||
clipFlag |= 1;
|
||||
} else {
|
||||
// point 0 not clipped, store it
|
||||
*pTabPolyClip++ = *pTabPoly;
|
||||
++newNbPoints;
|
||||
}
|
||||
|
||||
if (clipFlag) {
|
||||
// point 0 or 1 is clipped, apply clipping
|
||||
if (p1->x >= p0->x) {
|
||||
p0 = p1;
|
||||
p1 = pTabPoly;
|
||||
}
|
||||
|
||||
const int32 dx = p1->x - p0->x;
|
||||
const int32 dy = p1->y - p0->y;
|
||||
const int32 dxClip = clip.left - p0->x;
|
||||
|
||||
pTabPolyClip->y = (int16)(p0->y + ((dxClip * dy) / dx));
|
||||
pTabPolyClip->x = (int16)clip.left;
|
||||
|
||||
if (polyRenderType >= POLYGONTYPE_GOURAUD) {
|
||||
pTabPolyClip->colorIndex = (int16)(p0->colorIndex + (((p1->colorIndex - p0->colorIndex) * dxClip) / dx));
|
||||
}
|
||||
|
||||
++pTabPolyClip;
|
||||
++newNbPoints;
|
||||
}
|
||||
}
|
||||
|
||||
// copy first vertex to the end
|
||||
*pTabPolyClip = *offTabPoly[0];
|
||||
return newNbPoints;
|
||||
}
|
||||
|
||||
int16 Renderer::rightClip(int16 polyRenderType, Vertex** offTabPoly, int32 numVertices) {
|
||||
const Common::Rect &clip = _engine->_interface->_clip;
|
||||
Vertex *pTabPolyClip = offTabPoly[1];
|
||||
Vertex *pTabPoly = offTabPoly[0];
|
||||
int16 newNbPoints = 0;
|
||||
|
||||
// invert the pointers to continue on the clipped vertices in the next method
|
||||
offTabPoly[0] = pTabPolyClip;
|
||||
offTabPoly[1] = pTabPoly;
|
||||
|
||||
for (; numVertices > 0; --numVertices, pTabPoly++) {
|
||||
const Vertex *p0 = pTabPoly;
|
||||
const Vertex *p1 = p0 + 1;
|
||||
|
||||
// clipFlag :
|
||||
// 0x00 : none clipped
|
||||
// 0x01 : point 0 clipped
|
||||
// 0x02 : point 1 clipped
|
||||
// 0x03 : both clipped
|
||||
uint8 clipFlag = (p1->x > clip.right) ? 2 : 0;
|
||||
|
||||
if (p0->x > clip.right) {
|
||||
if (clipFlag) {
|
||||
continue; // both clipped, skip point 0
|
||||
}
|
||||
clipFlag |= 1;
|
||||
} else {
|
||||
// point 0 not clipped, store it
|
||||
*pTabPolyClip++ = *pTabPoly;
|
||||
++newNbPoints;
|
||||
}
|
||||
|
||||
if (clipFlag) {
|
||||
// point 0 or 1 is clipped, apply clipping
|
||||
if (p1->x >= p0->x) {
|
||||
p0 = p1;
|
||||
p1 = pTabPoly;
|
||||
}
|
||||
|
||||
const int32 dx = p1->x - p0->x;
|
||||
const int32 dy = p1->y - p0->y;
|
||||
const int32 dxClip = clip.right - p0->x;
|
||||
|
||||
pTabPolyClip->y = (int16)(p0->y + ((dxClip * dy) / dx));
|
||||
pTabPolyClip->x = (int16)clip.right;
|
||||
|
||||
if (polyRenderType >= POLYGONTYPE_GOURAUD) {
|
||||
pTabPolyClip->colorIndex = (int16)(p0->colorIndex + (((p1->colorIndex - p0->colorIndex) * dxClip) / dx));
|
||||
}
|
||||
|
||||
++pTabPolyClip;
|
||||
++newNbPoints;
|
||||
}
|
||||
}
|
||||
|
||||
// copy first vertex to the end
|
||||
*pTabPolyClip = *offTabPoly[0];
|
||||
return newNbPoints;
|
||||
}
|
||||
|
||||
int16 Renderer::topClip(int16 polyRenderType, Vertex** offTabPoly, int32 numVertices) {
|
||||
const Common::Rect &clip = _engine->_interface->_clip;
|
||||
Vertex *pTabPolyClip = offTabPoly[1];
|
||||
Vertex *pTabPoly = offTabPoly[0];
|
||||
int16 newNbPoints = 0;
|
||||
|
||||
// invert the pointers to continue on the clipped vertices in the next method
|
||||
offTabPoly[0] = pTabPolyClip;
|
||||
offTabPoly[1] = pTabPoly;
|
||||
|
||||
for (; numVertices > 0; --numVertices, pTabPoly++) {
|
||||
const Vertex *p0 = pTabPoly;
|
||||
const Vertex *p1 = p0 + 1;
|
||||
|
||||
// clipFlag :
|
||||
// 0x00 : none clipped
|
||||
// 0x01 : point 0 clipped
|
||||
// 0x02 : point 1 clipped
|
||||
// 0x03 : both clipped
|
||||
uint8 clipFlag = (p1->y < clip.top) ? 2 : 0;
|
||||
|
||||
if (p0->y < clip.top) {
|
||||
if (clipFlag) {
|
||||
continue; // both clipped, skip point 0
|
||||
}
|
||||
clipFlag |= 1;
|
||||
} else {
|
||||
// point 0 not clipped, store it
|
||||
*pTabPolyClip++ = *pTabPoly;
|
||||
++newNbPoints;
|
||||
}
|
||||
|
||||
if (clipFlag) {
|
||||
// point 0 or 1 is clipped, apply clipping
|
||||
if (p1->y >= p0->y) {
|
||||
p0 = p1;
|
||||
p1 = pTabPoly;
|
||||
}
|
||||
|
||||
const int32 dx = p1->x - p0->x;
|
||||
const int32 dy = p1->y - p0->y;
|
||||
const int32 dyClip = clip.top - p0->y;
|
||||
|
||||
pTabPolyClip->x = (int16)(p0->x + ((dyClip * dx) / dy));
|
||||
pTabPolyClip->y = (int16)clip.top;
|
||||
|
||||
if (polyRenderType >= POLYGONTYPE_GOURAUD) {
|
||||
pTabPolyClip->colorIndex = (int16)(p0->colorIndex + (((p1->colorIndex - p0->colorIndex) * dyClip) / dy));
|
||||
}
|
||||
|
||||
++pTabPolyClip;
|
||||
++newNbPoints;
|
||||
}
|
||||
}
|
||||
|
||||
// copy first vertex to the end
|
||||
*pTabPolyClip = *offTabPoly[0];
|
||||
return newNbPoints;
|
||||
}
|
||||
|
||||
int16 Renderer::bottomClip(int16 polyRenderType, Vertex** offTabPoly, int32 numVertices) {
|
||||
const Common::Rect &clip = _engine->_interface->_clip;
|
||||
Vertex *pTabPolyClip = offTabPoly[1];
|
||||
Vertex *pTabPoly = offTabPoly[0];
|
||||
int16 newNbPoints = 0;
|
||||
|
||||
// invert the pointers to continue on the clipped vertices in the next method
|
||||
offTabPoly[0] = pTabPolyClip;
|
||||
offTabPoly[1] = pTabPoly;
|
||||
|
||||
for (; numVertices > 0; --numVertices, pTabPoly++) {
|
||||
const Vertex *p0 = pTabPoly;
|
||||
const Vertex *p1 = p0 + 1;
|
||||
|
||||
// clipFlag :
|
||||
// 0x00 : none clipped
|
||||
// 0x01 : point 0 clipped
|
||||
// 0x02 : point 1 clipped
|
||||
// 0x03 : both clipped
|
||||
uint8 clipFlag = (p1->y > clip.bottom) ? 2 : 0;
|
||||
|
||||
if (p0->y > clip.bottom) {
|
||||
if (clipFlag) {
|
||||
continue; // both clipped, skip point 0
|
||||
}
|
||||
clipFlag |= 1;
|
||||
} else {
|
||||
// point 0 not clipped, store it
|
||||
*pTabPolyClip++ = *pTabPoly;
|
||||
++newNbPoints;
|
||||
}
|
||||
|
||||
if (clipFlag) {
|
||||
// point 0 or 1 is clipped, apply clipping
|
||||
if (p1->y >= p0->y) {
|
||||
p0 = p1;
|
||||
p1 = pTabPoly;
|
||||
}
|
||||
|
||||
const int32 dx = p1->x - p0->x;
|
||||
const int32 dy = p1->y - p0->y;
|
||||
const int32 dyClip = clip.bottom - p0->y;
|
||||
|
||||
pTabPolyClip->x = (int16)(p0->x + ((dyClip * dx) / dy));
|
||||
pTabPolyClip->y = (int16)clip.bottom;
|
||||
|
||||
if (polyRenderType >= POLYGONTYPE_GOURAUD) {
|
||||
pTabPolyClip->colorIndex = (int16)(p0->colorIndex + (((p1->colorIndex - p0->colorIndex) * dyClip) / dy));
|
||||
}
|
||||
|
||||
++pTabPolyClip;
|
||||
++newNbPoints;
|
||||
}
|
||||
}
|
||||
|
||||
// copy first vertex to the end
|
||||
*pTabPolyClip = *offTabPoly[0];
|
||||
return newNbPoints;
|
||||
}
|
||||
|
||||
int32 Renderer::computePolyMinMax(int16 polyRenderType, Vertex **offTabPoly, int32 numVertices) {
|
||||
const Common::Rect &clip = _engine->_interface->_clip;
|
||||
if (clip.isEmpty()) {
|
||||
return numVertices;
|
||||
}
|
||||
|
||||
int32 minsx = SCENE_SIZE_MAX;
|
||||
int32 maxsx = SCENE_SIZE_MIN;
|
||||
int32 minsy = SCENE_SIZE_MAX;
|
||||
int32 maxsy = SCENE_SIZE_MIN;
|
||||
|
||||
Vertex* pTabPoly = offTabPoly[0];
|
||||
for (int32 i = 0; i < numVertices; i++) {
|
||||
if (pTabPoly[i].x < minsx) {
|
||||
minsx = pTabPoly[i].x;
|
||||
}
|
||||
if (pTabPoly[i].x > maxsx) {
|
||||
maxsx = pTabPoly[i].x;
|
||||
}
|
||||
if (pTabPoly[i].y < minsy) {
|
||||
minsy = pTabPoly[i].y;
|
||||
}
|
||||
if (pTabPoly[i].y > maxsy) {
|
||||
maxsy = pTabPoly[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
// no vertices
|
||||
if (minsy > maxsy || maxsx < clip.left || minsx > clip.right || maxsy < clip.top || minsy > clip.bottom) {
|
||||
debug(10, "Clipped %i:%i:%i:%i, clip rect(%i:%i:%i:%i)", minsx, minsy, maxsx, maxsy, clip.left, clip.top, clip.right, clip.bottom);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pTabPoly[numVertices] = *offTabPoly[0];
|
||||
|
||||
bool hasBeenClipped = false;
|
||||
|
||||
int32 clippedNumVertices = numVertices;
|
||||
if (minsx < clip.left) {
|
||||
clippedNumVertices = leftClip(polyRenderType, offTabPoly, clippedNumVertices);
|
||||
if (!clippedNumVertices) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hasBeenClipped = true;
|
||||
}
|
||||
|
||||
if (maxsx > clip.right) {
|
||||
clippedNumVertices = rightClip(polyRenderType, offTabPoly, clippedNumVertices);
|
||||
if (!clippedNumVertices) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hasBeenClipped = true;
|
||||
}
|
||||
|
||||
if (minsy < clip.top) {
|
||||
clippedNumVertices = topClip(polyRenderType, offTabPoly, clippedNumVertices);
|
||||
if (!clippedNumVertices) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hasBeenClipped = true;
|
||||
}
|
||||
|
||||
if (maxsy > clip.bottom) {
|
||||
clippedNumVertices = bottomClip(polyRenderType, offTabPoly, clippedNumVertices);
|
||||
if (!clippedNumVertices) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hasBeenClipped = true;
|
||||
}
|
||||
|
||||
if (hasBeenClipped) {
|
||||
minsy = 32767;
|
||||
maxsy = -32768;
|
||||
|
||||
for (int32 i = 0; i < clippedNumVertices; i++) {
|
||||
if (offTabPoly[0][i].y < minsy) {
|
||||
minsy = offTabPoly[0][i].y;
|
||||
}
|
||||
|
||||
if (offTabPoly[0][i].y > maxsy) {
|
||||
maxsy = offTabPoly[0][i].y;
|
||||
}
|
||||
}
|
||||
|
||||
if (minsy >= maxsy) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return clippedNumVertices;
|
||||
}
|
||||
|
||||
bool Renderer::computePoly(int16 polyRenderType, const Vertex *vertices, int32 numVertices) {
|
||||
const int16 *polyTabBegin = _polyTab;
|
||||
const int16 *polyTabEnd = &_polyTab[_polyTabSize - 1];
|
||||
const int16 *colProgressBufStart = _colorProgressionBuffer;
|
||||
const int16 *colProgressBufEnd = &_colorProgressionBuffer[_polyTabSize - 1];
|
||||
const int screenHeight = _engine->height();
|
||||
|
||||
const Common::Rect &clip = _engine->_interface->_clip;
|
||||
if (!clip.isEmpty()) {
|
||||
int32 vleft;
|
||||
int32 vright;
|
||||
int32 vtop;
|
||||
int32 vbottom;
|
||||
|
||||
vleft = vtop = SCENE_SIZE_MAX;
|
||||
vright = vbottom = SCENE_SIZE_MIN;
|
||||
|
||||
for (int32 i = 0; i < numVertices; i++) {
|
||||
if (vertices[i].x < vleft)
|
||||
vleft = vertices[i].x;
|
||||
if (vertices[i].x > vright)
|
||||
vright = vertices[i].x;
|
||||
if (vertices[i].y < vtop)
|
||||
vtop = vertices[i].y;
|
||||
if (vertices[i].y > vbottom)
|
||||
vbottom = vertices[i].y;
|
||||
}
|
||||
// no vertices
|
||||
if (vtop > vbottom) {
|
||||
return false;
|
||||
}
|
||||
if (vright <= clip.left || vleft >= clip.right || vbottom <= clip.top || vtop >= clip.bottom) {
|
||||
debug(10, "Clipped %i:%i:%i:%i, clip rect(%i:%i:%i:%i)", vleft, vtop, vright, vbottom, clip.left, clip.top, clip.right, clip.bottom);
|
||||
return false;
|
||||
}
|
||||
assert(numVertices < ARRAYSIZE(_clippedPolygonVertices1));
|
||||
for (int i = 0; i < numVertices; ++i) {
|
||||
_clippedPolygonVertices1[i] = vertices[i];
|
||||
}
|
||||
|
||||
Vertex *offTabPoly[] = {_clippedPolygonVertices1, _clippedPolygonVertices2};
|
||||
|
||||
numVertices = computePolyMinMax(polyRenderType, offTabPoly, numVertices);
|
||||
if (numVertices == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Vertex *clippedVertices = offTabPoly[0];
|
||||
uint8 vertexParam1 = clippedVertices[numVertices - 1].colorIndex;
|
||||
int16 currentVertexX = clippedVertices[numVertices - 1].x;
|
||||
int16 currentVertexY = clippedVertices[numVertices - 1].y;
|
||||
|
||||
for (int32 nVertex = 0; nVertex < numVertices; nVertex++) {
|
||||
const int16 oldVertexY = currentVertexY;
|
||||
const int16 oldVertexX = currentVertexX;
|
||||
const uint8 oldVertexParam = vertexParam1;
|
||||
|
||||
vertexParam1 = vertices[nVertex].colorIndex;
|
||||
vertexParam1 = clippedVertices[nVertex].colorIndex;
|
||||
const uint8 vertexParam2 = vertexParam1;
|
||||
currentVertexX = vertices[nVertex].x;
|
||||
currentVertexY = vertices[nVertex].y;
|
||||
currentVertexX = clippedVertices[nVertex].x;
|
||||
currentVertexY = clippedVertices[nVertex].y;
|
||||
|
||||
// drawLine(oldVertexX,oldVertexY,currentVertexX,currentVertexY,255);
|
||||
|
||||
@ -985,7 +1299,7 @@ void Renderer::renderPolygonsSimplified(int vtop, int32 vsize, uint16 color) con
|
||||
}
|
||||
|
||||
void Renderer::renderPolygons(const CmdRenderPolygon &polygon, Vertex *vertices, int vtop, int vbottom) {
|
||||
if (computePolygons(polygon.renderType, vertices, polygon.numVertices)) {
|
||||
if (computePoly(polygon.renderType, vertices, polygon.numVertices)) {
|
||||
const int32 vsize = vbottom - vtop + 1;
|
||||
fillVertices(vtop, vsize, polygon.renderType, polygon.colorIndex);
|
||||
}
|
||||
|
@ -182,6 +182,8 @@ private:
|
||||
* that is needed to render the primitive.
|
||||
*/
|
||||
uint8 _renderCoordinatesBuffer[10000]{0};
|
||||
Vertex _clippedPolygonVertices1[128];
|
||||
Vertex _clippedPolygonVertices2[128];
|
||||
|
||||
int32 _polyTabSize = 0;
|
||||
int16 *_polyTab = nullptr;
|
||||
@ -205,7 +207,7 @@ private:
|
||||
void renderPolygonsDither(int vtop, int32 vsize) const;
|
||||
void renderPolygonsMarble(int vtop, int32 vsize, uint16 color) const;
|
||||
void renderPolygonsSimplified(int vtop, int32 vsize, uint16 color) const;
|
||||
bool computePolygons(int16 polyRenderType, const Vertex *vertices, int32 numVertices);
|
||||
bool computePoly(int16 polyRenderType, const Vertex *vertices, int32 numVertices);
|
||||
|
||||
const RenderCommand *depthSortRenderCommands(int32 numOfPrimitives);
|
||||
uint8 *preparePolygons(const Common::Array<BodyPolygon>& polygons, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData);
|
||||
@ -218,6 +220,11 @@ private:
|
||||
void computeHolomapPolygon(int32 y1, int32 x1, int32 y2, int32 x2, int16 *polygonTabPtr);
|
||||
void fillHolomapPolygons(const Vertex &vertex1, const Vertex &vertex2, const Vertex &texCoord1, const Vertex &texCoord2, int32 &top, int32 &bottom);
|
||||
|
||||
int16 leftClip(int16 polyRenderType, Vertex** offTabPoly, int32 numVertices);
|
||||
int16 rightClip(int16 polyRenderType, Vertex** offTabPoly, int32 numVertices);
|
||||
int16 topClip(int16 polyRenderType, Vertex** offTabPoly, int32 numVertices);
|
||||
int16 bottomClip(int16 polyRenderType, Vertex** offTabPoly, int32 numVertices);
|
||||
int32 computePolyMinMax(int16 polyRenderType, Vertex **offTabPoly, int32 numVertices);
|
||||
public:
|
||||
Renderer(TwinEEngine *engine);
|
||||
~Renderer();
|
||||
|
Loading…
x
Reference in New Issue
Block a user