diff --git a/graphics/tinygl/zrect.cpp b/graphics/tinygl/zrect.cpp index 845d7dcbaf7..a7f695d7139 100644 --- a/graphics/tinygl/zrect.cpp +++ b/graphics/tinygl/zrect.cpp @@ -1,5 +1,6 @@ #include "graphics/tinygl/zrect.h" #include "graphics/tinygl/zgl.h" +#include "graphics/tinygl/gl.h" void tglPresentBuffer() { TinyGL::GLContext *c = TinyGL::gl_get_context(); @@ -18,11 +19,169 @@ DrawCall::DrawCall(DrawCallType type) : _type(type) { } RasterizationDrawCall::RasterizationDrawCall() : DrawCall(DrawCall_Rasterization) { - + TinyGL::GLContext *c = TinyGL::gl_get_context(); + _vertexCount = c->vertex_cnt; + _vertex = new TinyGL::GLVertex[_vertexCount]; + _drawTriangleFront = c->draw_triangle_front; + _drawTriangleBack = c->draw_triangle_back; + memcpy(_vertex, c->vertex, sizeof(TinyGL::GLVertex) * _vertexCount); + _state = loadState(); } void RasterizationDrawCall::execute() const { + TinyGL::GLContext *c = TinyGL::gl_get_context(); + TinyGL::GLVertex *prevVertex = c->vertex; + int prevVertexCount = c->vertex_cnt; + + RasterizationDrawCall::RasterizationState backupState = loadState(); + applyState(_state); + + 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, cnt; + + n = c->vertex_n; + cnt = c->vertex_cnt; + switch (c->begin_type) { + case TGL_POINTS: + gl_draw_point(c, &c->vertex[0]); + n = 0; + break; + case TGL_LINES: + if (n == 2) { + gl_draw_line(c, &c->vertex[0], &c->vertex[1]); + n = 0; + } + break; + case TGL_LINE_STRIP: + case TGL_LINE_LOOP: + if (n == 1) { + c->vertex[2] = c->vertex[0]; + } else if (n == 2) { + gl_draw_line(c, &c->vertex[0], &c->vertex[1]); + c->vertex[0] = c->vertex[1]; + n = 1; + } else if (c->vertex_cnt >= 3) { + gl_draw_line(c, &c->vertex[0], &c->vertex[2]); + } + break; + case TGL_TRIANGLES: + if (n == 3) { + gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]); + n = 0; + } + break; + case TGL_TRIANGLE_STRIP: + if (cnt >= 3) { + if (n == 3) + n = 0; + // 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; + } + } + break; + case TGL_TRIANGLE_FAN: + if (n == 3) { + gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]); + c->vertex[1] = c->vertex[2]; + n = 2; + } + break; + case TGL_QUADS: + if (n == 4) { + c->vertex[2].edge_flag = 0; + gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]); + c->vertex[2].edge_flag = 1; + c->vertex[0].edge_flag = 0; + gl_draw_triangle(c, &c->vertex[0], &c->vertex[2], &c->vertex[3]); + n = 0; + } + break; + case TGL_QUAD_STRIP: + if (n == 4) { + 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]; + n = 2; + } + break; + case TGL_POLYGON: { + int i = c->vertex_cnt; + while (i >= 3) { + i--; + gl_draw_triangle(c, &c->vertex[i], &c->vertex[0], &c->vertex[i - 1]); + } + break; + } + default: + error("glBegin: type %x not handled", c->begin_type); + } + + c->vertex = prevVertex; + c->vertex_cnt = prevVertexCount; + applyState(backupState); +} + +RasterizationDrawCall::RasterizationState RasterizationDrawCall::loadState() const { + RasterizationState state; + TinyGL::GLContext *c = TinyGL::gl_get_context(); + state.alphaTest = c->fb->isAplhaTestEnabled(); + 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; + + 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->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; +} + +RasterizationDrawCall::~RasterizationDrawCall() { + delete [] _vertex; } void RasterizationDrawCall::execute( const Common::Rect &clippingRectangle ) const { diff --git a/graphics/tinygl/zrect.h b/graphics/tinygl/zrect.h index c9549a26e7c..3204f7412e1 100644 --- a/graphics/tinygl/zrect.h +++ b/graphics/tinygl/zrect.h @@ -25,9 +25,12 @@ #include "common/rect.h" #include "graphics/tinygl/zblit.h" +#include "common/array.h" namespace TinyGL { struct GLContext; + struct GLVertex; + struct GLTexture; } namespace Graphics { @@ -53,8 +56,39 @@ private: class RasterizationDrawCall : public DrawCall { public: RasterizationDrawCall(); + ~RasterizationDrawCall(); virtual void execute() const; virtual void execute(const Common::Rect &clippingRectangle) const; + +private: + typedef void (*gl_draw_triangle_func_ptr)(TinyGL::GLContext *c, TinyGL::GLVertex *p0, TinyGL::GLVertex *p1, TinyGL::GLVertex *p2); + int _vertexCount; + TinyGL::GLVertex *_vertex; + gl_draw_triangle_func_ptr _drawTriangleFront, _drawTriangleBack; + + struct RasterizationState { + int beginType; + int currentFrontFace; + int cullFaceEnabled; + int colorMask; + int depthTest; + int shadowMode; + int texture2DEnabled; + int currentShadeModel; + int polygonModeBack; + int polygonModeFront; + bool enableBlending; + int sfactor, dfactor; + bool alphaTest; + int alphaFunc, alphaRefValue; + TinyGL::GLTexture *texture; + unsigned char *shadowMaskBuf; + }; + + RasterizationState _state; + + RasterizationState loadState() const; + void applyState(const RasterizationState &state) const; }; class BlittingDrawCall : public DrawCall {