scummvm/graphics/tinygl/zdirtyrect.cpp
Vincent Pelletier 5cbdabb69d TINYGL: Continue comparing past first divergence
It is common that the same number of calls are done in the same order, so
do not stop comparing after the first divergence. This saves a significant
number of dirty rectangle in crowded scenes, like sets cn and bi where a few
calls may differ in the middle of call sequence, but later calls would stay
the same.
As a consequence, move current-frame-has-fewer-calls handling to its own
loop.
Also, factorise and extend code appending dirty rectangles.
Also, skip conseutive identical rectangles.
2017-04-23 10:35:04 +00:00

736 lines
24 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/*
* This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
* which is licensed under the zlib-license (see LICENSE).
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
*/
#include "graphics/tinygl/zdirtyrect.h"
#include "graphics/tinygl/zgl.h"
#include "graphics/tinygl/gl.h"
#include "common/debug.h"
#include "common/math.h"
namespace TinyGL {
void tglIssueDrawCall(Graphics::DrawCall *drawCall) {
TinyGL::GLContext *c = TinyGL::gl_get_context();
c->_drawCallsQueue.push_back(drawCall);
}
void tglDrawRectangle(Common::Rect rect, int r, int g, int b) {
TinyGL::GLContext *c = TinyGL::gl_get_context();
if (rect.left < 0)
rect.left = 0;
if (rect.right >= c->fb->xsize)
rect.right = c->fb->xsize - 1;
if (rect.top < 0)
rect.top = 0;
if (rect.bottom >= c->fb->ysize)
rect.bottom = c->fb->ysize - 1;
for(int x = rect.left; x < rect.right; x++) {
c->fb->writePixel(rect.top * c->fb->xsize + x, 255, r, g, b);
c->fb->writePixel(rect.bottom * c->fb->xsize + x, 255, r, g, b);
}
for(int y = rect.top; y < rect.bottom; y++) {
c->fb->writePixel(y * c->fb->xsize + rect.left, 255, r, g, b);
c->fb->writePixel(y * c->fb->xsize + rect.right, 255, r, g, b);
}
}
struct DirtyRectangle {
Common::Rect rectangle;
int r, g, b;
DirtyRectangle() { }
DirtyRectangle(Common::Rect rect, int red, int green, int blue) {
this->rectangle = rect;
this->r = red;
this->g = green;
this->b = blue;
}
};
void tglDisposeResources(TinyGL::GLContext *c) {
// Dispose textures and resources.
bool allDisposed = true;
do {
allDisposed = true;
for (int i = 0; i < TEXTURE_HASH_TABLE_SIZE; i++) {
TinyGL::GLTexture *t = c->shared_state.texture_hash_table[i];
while (t) {
if (t->disposed) {
TinyGL::free_texture(c, t);
allDisposed = false;
break;
}
t = t->next;
}
}
} while (allDisposed == false);
Graphics::Internal::tglCleanupImages();
}
void tglDisposeDrawCallLists(TinyGL::GLContext *c) {
typedef Common::List<Graphics::DrawCall *>::const_iterator DrawCallIterator;
for (DrawCallIterator it = c->_previousFrameDrawCallsQueue.begin(); it != c->_previousFrameDrawCallsQueue.end(); ++it) {
delete *it;
}
c->_previousFrameDrawCallsQueue.clear();
for (DrawCallIterator it = c->_drawCallsQueue.begin(); it != c->_drawCallsQueue.end(); ++it) {
delete *it;
}
c->_drawCallsQueue.clear();
}
inline void _appendDirtyRectangle(const Graphics::DrawCall &call, Common::List<DirtyRectangle> &rectangles, int r, int g, int b) {
Common::Rect dirty_region = call.getDirtyRegion();
if (rectangles.empty() || dirty_region != (*rectangles.end()).rectangle)
rectangles.push_back(DirtyRectangle(dirty_region, r, g, b));
}
void tglPresentBufferDirtyRects(TinyGL::GLContext *c) {
typedef Common::List<Graphics::DrawCall *>::const_iterator DrawCallIterator;
typedef Common::List<TinyGL::DirtyRectangle>::iterator RectangleIterator;
Common::List<DirtyRectangle> rectangles;
DrawCallIterator itFrame = c->_drawCallsQueue.begin();
DrawCallIterator endFrame = c->_drawCallsQueue.end();
DrawCallIterator itPrevFrame = c->_previousFrameDrawCallsQueue.begin();
DrawCallIterator endPrevFrame = c->_previousFrameDrawCallsQueue.end();
// Compare draw calls.
if (c->_drawCallsQueue.size() > 0) {
for ( ; itPrevFrame != endPrevFrame && itFrame != endFrame;
++itPrevFrame, ++itFrame) {
const Graphics::DrawCall &currentCall = **itFrame;
const Graphics::DrawCall &previousCall = **itPrevFrame;
if (previousCall != currentCall) {
_appendDirtyRectangle(previousCall, rectangles, 255, 255, 255);
_appendDirtyRectangle(currentCall, rectangles, 255, 0, 0);
}
}
}
for ( ; itPrevFrame != endPrevFrame; ++itPrevFrame) {
_appendDirtyRectangle(**itPrevFrame, rectangles, 255, 255, 255);
}
for ( ; itFrame != endFrame; ++itFrame) {
_appendDirtyRectangle(**itFrame, rectangles, 255, 0, 0);
}
// This loop increases outer rectangle coordinates to favor merging of adjacent rectangles.
for (RectangleIterator it = rectangles.begin(); it != rectangles.end(); ++it) {
(*it).rectangle.right++;
(*it).rectangle.bottom++;
}
// Merge coalesce dirty rects.
bool restartMerge;
do {
restartMerge = false;
for (RectangleIterator it1 = rectangles.begin(); it1 != rectangles.end(); ++it1) {
for (RectangleIterator it2 = rectangles.begin(); it2 != rectangles.end();) {
if (it1 != it2) {
if ((*it1).rectangle.intersects((*it2).rectangle)) {
(*it1).rectangle.extend((*it2).rectangle);
it2 = rectangles.erase(it2);
restartMerge = true;
} else {
++it2;
}
} else {
++it2;
}
}
}
} while(restartMerge);
Common::Rect renderRect(0, 0, c->fb->xsize - 1, c->fb->ysize - 1);
for (RectangleIterator it1 = rectangles.begin(); it1 != rectangles.end(); ++it1) {
RectangleIterator it2 = it1;
it2++;
while (it2 != rectangles.end()) {
if ((*it1).rectangle.contains((*it2).rectangle)) {
it2 = rectangles.erase(it2);
} else {
++it2;
}
}
(*it1).rectangle.clip(renderRect);
}
// Execute draw calls.
for (DrawCallIterator it = c->_drawCallsQueue.begin(); it != c->_drawCallsQueue.end(); ++it) {
Common::Rect drawCallRegion = (*it)->getDirtyRegion();
for (RectangleIterator itRect = rectangles.begin(); itRect != rectangles.end(); ++itRect) {
Common::Rect dirtyRegion = (*itRect).rectangle;
if (dirtyRegion.intersects(drawCallRegion) || drawCallRegion.contains(dirtyRegion)) {
(*it)->execute(dirtyRegion, true);
}
}
}
// Dispose not necessary draw calls.
for (DrawCallIterator it = c->_previousFrameDrawCallsQueue.begin(); it != c->_previousFrameDrawCallsQueue.end(); ++it) {
delete *it;
}
c->_previousFrameDrawCallsQueue = c->_drawCallsQueue;
c->_drawCallsQueue.clear();
#if TGL_DIRTY_RECT_SHOW
// Draw debug rectangles.
// Note: white rectangles are rectangle that contained other rectangles
// blue rectangles are rectangle merged from other rectangles
// red rectangles are original dirty rects
bool blendingEnabled = c->fb->isBlendingEnabled();
bool alphaTestEnabled = c->fb->isAlphaTestEnabled();
c->fb->enableBlending(false);
c->fb->enableAlphaTest(false);
for (RectangleIterator it = rectangles.begin(); it != rectangles.end(); ++it) {
tglDrawRectangle((*it).rectangle, (*it).r, (*it).g, (*it).b);
}
c->fb->enableBlending(blendingEnabled);
c->fb->enableAlphaTest(alphaTestEnabled);
#endif
tglDisposeResources(c);
c->_currentAllocatorIndex++;
if (c->_currentAllocatorIndex == 2) {
c->_currentAllocatorIndex = 0;
c->_drawCallAllocator[0].reset();
c->_drawCallAllocator[1].reset();
}
}
void tglPresentBufferSimple(TinyGL::GLContext *c) {
typedef Common::List<Graphics::DrawCall *>::const_iterator DrawCallIterator;
for (DrawCallIterator it = c->_drawCallsQueue.begin(); it != c->_drawCallsQueue.end(); ++it) {
(*it)->execute(true);
delete *it;
}
c->_drawCallsQueue.clear();
tglDisposeResources(c);
c->_drawCallAllocator[c->_currentAllocatorIndex].reset();
}
void tglPresentBuffer() {
TinyGL::GLContext *c = TinyGL::gl_get_context();
if (c->_enableDirtyRectangles) {
tglPresentBufferDirtyRects(c);
} else {
tglPresentBufferSimple(c);
}
}
} // end of namespace TinyGL
namespace Graphics {
bool DrawCall::operator==(const DrawCall &other) const {
if (_type == other._type) {
switch (_type) {
case DrawCall_Rasterization:
return *(const RasterizationDrawCall *)this == (const RasterizationDrawCall &)other;
break;
case DrawCall_Blitting:
return *(const BlittingDrawCall *)this == (const BlittingDrawCall &)other;
break;
case DrawCall_Clear:
return *(const ClearBufferDrawCall *)this == (const ClearBufferDrawCall &)other;
break;
default:
return false;
}
} else {
return false;
}
}
RasterizationDrawCall::RasterizationDrawCall() : DrawCall(DrawCall_Rasterization) {
TinyGL::GLContext *c = TinyGL::gl_get_context();
_vertexCount = c->vertex_cnt;
_vertex = (TinyGL::GLVertex *) ::Internal::allocateFrame(_vertexCount * sizeof(TinyGL::GLVertex));
_drawTriangleFront = c->draw_triangle_front;
_drawTriangleBack = c->draw_triangle_back;
memcpy(_vertex, c->vertex, sizeof(TinyGL::GLVertex) * _vertexCount);
_state = captureState();
if (c->_enableDirtyRectangles) {
computeDirtyRegion();
}
}
void RasterizationDrawCall::computeDirtyRegion() {
TinyGL::GLContext *c = TinyGL::gl_get_context();
int width = c->fb->xsize;
int height = c->fb->ysize;
int left = width, right = 0, top = height, bottom = 0;
bool pointInsideVolume = false;
for (int i = 0; i < _vertexCount; i++) {
TinyGL::GLVertex *v = &_vertex[i];
float winv;
// coordinates
winv = (float)(1.0 / v->pc.W);
float pcX = v->pc.X * winv;
float pcY = v->pc.Y * winv;
int screenCoordsX = (int)(pcX * c->viewport.scale.X + c->viewport.trans.X);
int screenCoordsY = (int)(pcY * c->viewport.scale.Y + c->viewport.trans.Y);
left = MIN(left, screenCoordsX);
right = MAX(right, screenCoordsX);
top = MIN(top, screenCoordsY);
bottom = MAX(bottom, screenCoordsY);
if (!pointInsideVolume) {
if (pcX >= -2 && pcX <= 2 && pcY >= -2 && pcY <= 2) { // Normalized cube clipping.
pointInsideVolume = true;
}
}
}
// Clipping out of screen cases.
// Reason: other "out of screen cases are actually full screen quads"
if (pointInsideVolume == false) {
left = right = top = bottom = 0;
}
// Those nested ifs cover the case where the triangle is slightly offscreen
// but it should still be rendered.
if (left < 0) {
left = 0;
if (right < left) {
left = 0;
right = width - 1;
}
}
if (right >= width) {
right = width - 1;
if (left > right) {
left = 0;
right = width - 1;
}
}
if (top < 0) {
top = 0;
if (bottom < top) {
top = 0;
bottom = height - 1;
}
}
if (bottom >= height) {
bottom = height - 1;
if (top > bottom) {
top = 0;
bottom = height - 1;
}
}
_dirtyRegion = Common::Rect(left, top, right, bottom);
// This takes into account precision issues that occur during rasterization.
_dirtyRegion.left -= 2;
_dirtyRegion.top -= 2;
_dirtyRegion.right += 2;
_dirtyRegion.bottom += 2;
}
void RasterizationDrawCall::execute(bool restoreState) const {
TinyGL::GLContext *c = TinyGL::gl_get_context();
RasterizationDrawCall::RasterizationState backupState;
if (restoreState) {
backupState = captureState();
}
applyState(_state);
TinyGL::GLVertex *prevVertex = c->vertex;
int prevVertexCount = c->vertex_cnt;
c->vertex = _vertex;
c->vertex_cnt = _vertexCount;
c->draw_triangle_front = (TinyGL::gl_draw_triangle_func)_drawTriangleFront;
c->draw_triangle_back = (TinyGL::gl_draw_triangle_func)_drawTriangleBack;
int n = c->vertex_n;
int cnt = c->vertex_cnt;
switch (c->begin_type) {
case TGL_POINTS:
for(int i = 0; i < cnt; i++) {
gl_draw_point(c, &c->vertex[i]);
}
break;
case TGL_LINES:
for(int i = 0; i < cnt / 2; i++) {
gl_draw_line(c, &c->vertex[i * 2], &c->vertex[i * 2 + 1]);
}
break;
case TGL_LINE_STRIP:
case TGL_LINE_LOOP:
for(int i = 0; i < cnt - 1; i++) {
gl_draw_line(c, &c->vertex[i], &c->vertex[i + 1]);
}
gl_draw_line(c, &c->vertex[cnt - 1], &c->vertex[0]);
break;
case TGL_TRIANGLES:
for(int i = 0; i < cnt; i += 3) {
gl_draw_triangle(c, &c->vertex[i], &c->vertex[i + 1], &c->vertex[i + 2]);
}
break;
case TGL_TRIANGLE_STRIP:
while (cnt >= 3) {
// needed to respect triangle orientation
switch (cnt & 1) {
case 0:
gl_draw_triangle(c, &c->vertex[2], &c->vertex[1], &c->vertex[0]);
break;
case 1:
gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]);
break;
}
cnt--;
c->vertex++;
}
break;
case TGL_TRIANGLE_FAN:
for(int i = 1; i < cnt; i += 2) {
gl_draw_triangle(c, &c->vertex[0], &c->vertex[i], &c->vertex[i + 1]);
}
break;
case TGL_QUADS:
for(int i = 0; i < cnt; i += 4) {
c->vertex[i + 2].edge_flag = 0;
gl_draw_triangle(c, &c->vertex[i], &c->vertex[i + 1], &c->vertex[i + 2]);
c->vertex[i + 2].edge_flag = 1;
c->vertex[i + 0].edge_flag = 0;
gl_draw_triangle(c, &c->vertex[i], &c->vertex[i + 2], &c->vertex[i + 3]);
}
break;
case TGL_QUAD_STRIP:
for( ; n >= 4; n -= 2) {
gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]);
gl_draw_triangle(c, &c->vertex[1], &c->vertex[3], &c->vertex[2]);
for (int i = 0; i < 2; i++) {
c->vertex[i] = c->vertex[i + 2];
}
}
break;
case TGL_POLYGON: {
for (int i = c->vertex_cnt; i >= 3; i--) {
gl_draw_triangle(c, &c->vertex[i - 1], &c->vertex[0], &c->vertex[i - 2]);
}
break;
}
default:
error("glBegin: type %x not handled", c->begin_type);
}
c->vertex = prevVertex;
c->vertex_cnt = prevVertexCount;
if (restoreState) {
applyState(backupState);
}
}
RasterizationDrawCall::RasterizationState RasterizationDrawCall::captureState() const {
RasterizationState state;
TinyGL::GLContext *c = TinyGL::gl_get_context();
state.alphaTest = c->fb->isAlphaTestEnabled();
c->fb->getBlendingFactors(state.sfactor, state.dfactor);
state.enableBlending = c->fb->isBlendingEnabled();
state.alphaFunc = c->fb->getAlphaTestFunc();
state.alphaRefValue = c->fb->getAlphaTestRefVal();
state.cullFaceEnabled = c->cull_face_enabled;
state.beginType = c->begin_type;
state.colorMask = c->color_mask;
state.currentFrontFace = c->current_front_face;
state.currentShadeModel = c->current_shade_model;
state.depthTest = c->depth_test;
state.polygonModeBack = c->polygon_mode_back;
state.polygonModeFront = c->polygon_mode_front;
state.shadowMode = c->shadow_mode;
state.texture2DEnabled = c->texture_2d_enabled;
state.texture = c->current_texture;
state.shadowMaskBuf = c->fb->shadow_mask_buf;
state.depthFunction = c->fb->getDepthFunc();
state.depthWrite = c->fb->getDepthWrite();
state.lightingEnabled = c->lighting_enabled;
state.depthTestEnabled = c->fb->getDepthTestEnabled();
if (c->current_texture != nullptr)
state.textureVersion = c->current_texture->versionNumber;
memcpy(state.viewportScaling, c->viewport.scale._v, sizeof(c->viewport.scale._v));
memcpy(state.viewportTranslation, c->viewport.trans._v, sizeof(c->viewport.trans._v));
memcpy(state.currentColor, c->longcurrent_color, sizeof(c->longcurrent_color));
return state;
}
void RasterizationDrawCall::applyState(const RasterizationDrawCall::RasterizationState &state) const {
TinyGL::GLContext *c = TinyGL::gl_get_context();
c->fb->setBlendingFactors(state.sfactor, state.dfactor);
c->fb->enableBlending(state.enableBlending);
c->fb->enableAlphaTest(state.alphaTest);
c->fb->setAlphaTestFunc(state.alphaFunc, state.alphaRefValue);
c->fb->setDepthFunc(state.depthFunction);
c->fb->enableDepthWrite(state.depthWrite);
c->fb->enableDepthTest(state.depthTestEnabled);
c->lighting_enabled = state.lightingEnabled;
c->cull_face_enabled = state.cullFaceEnabled;
c->begin_type = state.beginType;
c->color_mask = state.colorMask;
c->current_front_face = state.currentFrontFace;
c->current_shade_model = state.currentShadeModel;
c->depth_test = state.depthTest;
c->polygon_mode_back = state.polygonModeBack;
c->polygon_mode_front = state.polygonModeFront;
c->shadow_mode = state.shadowMode;
c->texture_2d_enabled = state.texture2DEnabled;
c->current_texture = state.texture;
c->fb->shadow_mask_buf = state.shadowMaskBuf;
memcpy(c->viewport.scale._v, state.viewportScaling, sizeof(c->viewport.scale._v));
memcpy(c->viewport.trans._v, state.viewportTranslation, sizeof(c->viewport.trans._v));
memcpy(c->longcurrent_color, state.currentColor, sizeof(c->longcurrent_color));
}
void RasterizationDrawCall::execute(const Common::Rect &clippingRectangle, bool restoreState) const {
TinyGL::GLContext *c = TinyGL::gl_get_context();
c->fb->setScissorRectangle(clippingRectangle.left, clippingRectangle.right, clippingRectangle.top, clippingRectangle.bottom);
execute(restoreState);
c->fb->setScissorRectangle(0, c->fb->xsize, 0, c->fb->ysize);
}
const Common::Rect RasterizationDrawCall::getDirtyRegion() const {
return _dirtyRegion;
}
bool RasterizationDrawCall::operator==(const RasterizationDrawCall &other) const {
if (_vertexCount == other._vertexCount &&
_drawTriangleFront == other._drawTriangleFront &&
_drawTriangleBack == other._drawTriangleBack &&
_state == other._state) {
for (int i = 0; i < _vertexCount; i++) {
if ((_vertex[i] != other._vertex[i])) {
return false;
}
}
return true;
}
return false;
}
BlittingDrawCall::BlittingDrawCall(Graphics::BlitImage *image, const BlitTransform &transform, BlittingMode blittingMode) : DrawCall(DrawCall_Blitting), _transform(transform), _mode(blittingMode), _image(image) {
tglIncBlitImageRef(image);
_blitState = captureState();
_imageVersion = tglGetBlitImageVersion(image);
}
BlittingDrawCall::~BlittingDrawCall() {
tglDeleteBlitImage(_image);
}
void BlittingDrawCall::execute(bool restoreState) const {
BlittingState backupState;
if (restoreState) {
backupState = captureState();
}
applyState(_blitState);
switch (_mode) {
case Graphics::BlittingDrawCall::BlitMode_Regular:
Graphics::Internal::tglBlit(_image, _transform);
break;
case Graphics::BlittingDrawCall::BlitMode_NoBlend:
Graphics::Internal::tglBlitNoBlend(_image, _transform);
break;
case Graphics::BlittingDrawCall::BlitMode_Fast:
Graphics::Internal::tglBlitFast(_image, _transform._destinationRectangle.left, _transform._destinationRectangle.top);
break;
case Graphics::BlittingDrawCall::BlitMode_ZBuffer:
Graphics::Internal::tglBlitZBuffer(_image, _transform._destinationRectangle.left, _transform._destinationRectangle.top);
break;
default:
break;
}
if (restoreState) {
applyState(backupState);
}
}
void BlittingDrawCall::execute(const Common::Rect &clippingRectangle, bool restoreState) const {
Graphics::Internal::tglBlitSetScissorRect(clippingRectangle.left, clippingRectangle.top, clippingRectangle.right, clippingRectangle.bottom);
execute(restoreState);
Graphics::Internal::tglBlitSetScissorRect(0, 0, 0, 0);
}
BlittingDrawCall::BlittingState BlittingDrawCall::captureState() const {
BlittingState state;
TinyGL::GLContext *c = TinyGL::gl_get_context();
state.alphaTest = c->fb->isAlphaTestEnabled();
c->fb->getBlendingFactors(state.sfactor, state.dfactor);
state.enableBlending = c->fb->isBlendingEnabled();
state.alphaFunc = c->fb->getAlphaTestFunc();
state.alphaRefValue = c->fb->getAlphaTestRefVal();
state.depthTestEnabled = c->fb->getDepthTestEnabled();
return state;
}
void BlittingDrawCall::applyState(const BlittingState &state) const {
TinyGL::GLContext *c = TinyGL::gl_get_context();
c->fb->setBlendingFactors(state.sfactor, state.dfactor);
c->fb->enableBlending(state.enableBlending);
c->fb->enableAlphaTest(state.alphaTest);
c->fb->setAlphaTestFunc(state.alphaFunc, state.alphaRefValue);
c->fb->enableDepthTest(state.depthTestEnabled);
}
const Common::Rect BlittingDrawCall::getDirtyRegion() const {
int blitWidth = _transform._destinationRectangle.width();
int blitHeight = _transform._destinationRectangle.height();
if (blitWidth == 0) {
if (_transform._sourceRectangle.width() != 0) {
blitWidth = _transform._sourceRectangle.width();
} else {
tglGetBlitImageSize(_image, blitWidth, blitHeight);
}
}
if (blitHeight == 0) {
if (_transform._sourceRectangle.height() != 0) {
blitHeight = _transform._sourceRectangle.height();
} else {
tglGetBlitImageSize(_image, blitWidth, blitHeight);
}
}
return Common::Rect(_transform._destinationRectangle.left, _transform._destinationRectangle.top, _transform._destinationRectangle.left + blitWidth, _transform._destinationRectangle.top + blitHeight);
}
bool BlittingDrawCall::operator==(const BlittingDrawCall &other) const {
return _mode == other._mode &&
_image == other._image &&
_transform == other._transform &&
_blitState == other._blitState &&
_imageVersion == tglGetBlitImageVersion(other._image);
}
ClearBufferDrawCall::ClearBufferDrawCall(bool clearZBuffer, int zValue, bool clearColorBuffer, int rValue, int gValue, int bValue)
: _clearZBuffer(clearZBuffer), _clearColorBuffer(clearColorBuffer), _zValue(zValue), _rValue(rValue), _gValue(gValue), _bValue(bValue), DrawCall(DrawCall_Clear) {
}
void ClearBufferDrawCall::execute(bool restoreState) const {
TinyGL::GLContext *c = TinyGL::gl_get_context();
c->fb->clear(_clearZBuffer, _zValue, _clearColorBuffer, _rValue, _gValue, _bValue);
}
void ClearBufferDrawCall::execute(const Common::Rect &clippingRectangle, bool restoreState) const {
TinyGL::GLContext *c = TinyGL::gl_get_context();
Common::Rect clearRect = clippingRectangle.findIntersectingRect(_dirtyRegion);
c->fb->clearRegion(clearRect.left, clearRect.top, clearRect.width(), clearRect.height(), _clearZBuffer, _zValue, _clearColorBuffer, _rValue, _gValue, _bValue);
}
const Common::Rect ClearBufferDrawCall::getDirtyRegion() const {
TinyGL::GLContext *c = TinyGL::gl_get_context();
return Common::Rect(0, 0, c->fb->xsize, c->fb->ysize);
}
bool ClearBufferDrawCall::operator==(const ClearBufferDrawCall &other) const {
return _clearZBuffer == other._clearZBuffer &&
_clearColorBuffer == other._clearColorBuffer &&
_rValue == other._rValue &&
_gValue == other._gValue &&
_bValue == other._bValue &&
_zValue == other._zValue;
}
bool RasterizationDrawCall::RasterizationState::operator==(const RasterizationState &other) const {
return beginType == other.beginType &&
currentFrontFace == other.currentFrontFace &&
cullFaceEnabled == other.cullFaceEnabled &&
colorMask == other.colorMask &&
depthTest == other.depthTest &&
depthFunction == other.depthFunction &&
depthWrite == other.depthWrite &&
shadowMode == other.shadowMode &&
texture2DEnabled == other.texture2DEnabled &&
currentShadeModel == other.currentShadeModel &&
polygonModeBack == other.polygonModeBack &&
polygonModeFront == other.polygonModeFront &&
lightingEnabled == other.lightingEnabled &&
enableBlending == other.enableBlending &&
sfactor == other.sfactor &&
dfactor == other.dfactor &&
alphaTest == other.alphaTest &&
alphaFunc == other.alphaFunc &&
alphaRefValue == other.alphaRefValue &&
texture == other.texture &&
shadowMaskBuf == other.shadowMaskBuf &&
currentColor[0] == other.currentColor[0] &&
currentColor[1] == other.currentColor[1] &&
currentColor[2] == other.currentColor[2] &&
currentColor[3] == other.currentColor[3] &&
viewportTranslation[0] == other.viewportTranslation[0] &&
viewportTranslation[1] == other.viewportTranslation[1] &&
viewportTranslation[2] == other.viewportTranslation[2] &&
viewportScaling[0] == other.viewportScaling[0] &&
viewportScaling[1] == other.viewportScaling[1] &&
viewportScaling[2] == other.viewportScaling[2] &&
depthTestEnabled == other.depthTestEnabled &&
textureVersion == texture->versionNumber;
}
} // end of namespace Graphics
void *Internal::allocateFrame(int size) {
TinyGL::GLContext *c = TinyGL::gl_get_context();
return c->_drawCallAllocator[c->_currentAllocatorIndex].allocate(size);
}