Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First version of Macro#draw rewrite

  • Loading branch information...
commit b85289de90f9cf5dc86ab9be8e8cb6726d9d5d50 1 parent ec218af
@jlnr authored
Showing with 154 additions and 12 deletions.
  1. +122 −12 GosuImpl/Graphics/Macro.hpp
  2. +32 −0 feature_tests/record_draw_as_quad.rb
View
134 GosuImpl/Graphics/Macro.hpp
@@ -13,11 +13,123 @@
class Gosu::Macro : public Gosu::ImageData
{
+ typedef double Float;
+
Graphics& graphics;
VertexArrays vertexArrays;
- int givenWidth, givenHeight;
+ int w, h;
- void realDraw(double x1, double y1, double x2, double y3) const
+ Transform findTransformForTarget(Float x1, Float y1, Float x2, Float y2, Float x3, Float y3, Float x4, Float y4) const
+ {
+ // Transformation logic follows a discussion on the ImageMagick mailing
+ // list (on which ImageMagick's perspective_transform.pl is based).
+
+ // To draw a macro at an arbitrary position, we solve the following system:
+
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
+ // w, 0, 1, 0, 0, 0, -x2w, 0 | x2
+ // 0, 0, 0, w, 0, 1, -y2w, 0 | y2
+ // 0, h, 1, 0, 0, 0, 0, -x3h | x3
+ // 0, 0, 0, 0, h, 1, 0, -y3h | y3
+ // w, h, 1, 0, 0, 0, -x4w, -x4h | x4
+ // 0, 0, 0, w, h, 1, -y4w, -y4h | y4
+
+ // Equivalent:
+
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
+ // w, 0, 0, 0, 0, 0, -x2w, 0 | x2-x1
+ // 0, 0, 0, w, 0, 0, -y2w, 0 | y2-y1
+ // 0, h, 0, 0, 0, 0, 0, -x3h | x3-x1
+ // 0, 0, 0, 0, h, 0, 0, -y3h | y3-y1
+ // 0, 0, 0, 0, 0, 0, (x2-x4)w, (x3-x4)h | x1-x2-x3+x4
+ // 0, 0, 0, 0, 0, 0, (y2-y4)w, (y3-y4)h | y1-y2-y3+y4
+
+ // Since this matrix is relatively sparse, we unroll all three solving paths.
+
+ static const Transform nullTransform = { 0 };
+
+ // Row 7 is useless
+ if (x2 == x4 && x3 == x4)
+ return nullTransform;
+ // Row 8 is useless
+ if (y2 == y3 && y3 == y4)
+ return nullTransform;
+
+ Float c[8];
+
+ // Rows 1, 2
+ c[2] = x1, c[5] = y1;
+
+ // Use row 7 to eliminate the left cell in row 8
+ // Row8 = Row8 - factor78 * Row7
+ assert (x2 != x4);
+ Float factor78 = (y2-y4) / (x2-x4);
+ Float remCell8 = (y3-y4)*h - (x3-x4)*h * factor78;
+ Float rightSide8 = (y1-y2-y3+y4) - (x1-x2-x3+x4) * factor78;
+ assert (remCell8 != 0);
+ c[7] = rightSide8 / remCell8;
+
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
+ // w, 0, 0, 0, 0, 0, -x2w, 0 | x2-x1
+ // 0, 0, 0, w, 0, 0, -y2w, 0 | y2-y1
+ // 0, h, 0, 0, 0, 0, 0, -x3h | x3-x1
+ // 0, 0, 0, 0, h, 0, 0, -y3h | y3-y1
+ // 0, 0, 0, 0, 0, 0, (x2-x4)w, (x3-x4)h | x1-x2-x3+x4
+ // 0, 0, 0, 0, 0, 0, 0, remCell8 | rightSide8
+
+ // Use the remainding value in row 8 to eliminate the right value in row 7.
+ // Row7 = Row7 - factor87 * Row8
+ assert (remCell8 != 0);
+ Float factor87 = (x3-x4)*h / remCell8;
+ Float remCell7 = (x2-x4)*w;
+ Float rightSide7 = (x1-x2-x3+x4) - rightSide8 * factor87;
+ assert (remCell7 != 0);
+ c[6] = rightSide7 / remCell7;
+
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
+ // w, 0, 0, 0, 0, 0, -x2w, 0 | x2-x1
+ // 0, 0, 0, w, 0, 0, -y2w, 0 | y2-y1
+ // 0, h, 0, 0, 0, 0, 0, -x3h | x3-x1
+ // 0, 0, 0, 0, h, 0, 0, -y3h | y3-y1
+ // 0, 0, 0, 0, 0, 0, remCell7, 0 | rightSide7
+ // 0, 0, 0, 0, 0, 0, 0, remCell8 | rightSide8
+
+ // Use the new rows 7 and 8 to calculate c0, c1, c3 & c4.
+ // Row3 = Row3 - factor73 * Row7
+ Float factor73 = -x2*w / remCell7;
+ Float remCell3 = w;
+ Float rightSide3 = (x2-x1) - rightSide7 * factor73;
+ c[0] = rightSide3 / remCell3;
+ // Row4 = Row4 - factor74 * Row7
+ Float factor74 = -y2*w / remCell7;
+ Float remCell4 = w;
+ Float rightSide4 = (y2-y1) - rightSide7 * factor74;
+ c[3] = rightSide4 / remCell4;
+ // Row5 = Row5 - factor85 * Row7
+ Float factor85 = -x3*h / remCell8;
+ Float remCell5 = h;
+ Float rightSide5 = (x3-x1) - rightSide8 * factor85;
+ c[1] = rightSide5 / remCell5;
+ // Row6 = Row6 - factor86 * Row8
+ Float factor86 = -y3*h / remCell8;
+ Float remCell6 = h;
+ Float rightSide6 = (y3-y1) - rightSide8 * factor86;
+ c[4] = rightSide6 / remCell6;
+
+ Transform result = {
+ c[0], c[3], 0, c[6],
+ c[1], c[4], 0, c[7],
+ 0, 0, 1, 0,
+ c[2], c[5], 0, 1
+ };
+ return result;
+ }
+
+ void drawVertexArrays(Float x1, Float y1, Float x2, Float y2, Float x3, Float y3, Float x4, Float y4) const
{
// TODO: Macros should not be split up because they have different transforms! This is insane.
// They should be premultiplied and have the same transform by definition. Then, the transformation
@@ -27,14 +139,14 @@ class Gosu::Macro : public Gosu::ImageData
glEnable(GL_BLEND);
glMatrixMode(GL_MODELVIEW);
+ Transform transform =
+ findTransformForTarget(x1, y1, x2, y2, x3, y3, x4, y4);
+
for (VertexArrays::const_iterator it = vertexArrays.begin(), end = vertexArrays.end(); it != end; ++it)
{
glPushMatrix();
it->renderState.apply();
-
- glTranslated(x1, y1, 0);
- glScaled((x2 - x1) / width(), (y3 - y1) / height(), 1);
-
+ glMultMatrixd(&transform[0]);
glInterleavedArrays(GL_T2F_C4UB_V3F, 0, &it->vertices[0]);
glDrawArrays(GL_QUADS, 0, it->vertices.size());
glPopMatrix();
@@ -44,19 +156,19 @@ class Gosu::Macro : public Gosu::ImageData
public:
Macro(Graphics& graphics, DrawOpQueue& queue, int width, int height)
- : graphics(graphics), givenWidth(width), givenHeight(height)
+ : graphics(graphics), w(width), h(height)
{
queue.compileTo(vertexArrays);
}
int width() const
{
- return givenWidth;
+ return w;
}
int height() const
{
- return givenHeight;
+ return h;
}
void draw(double x1, double y1, Color c1,
@@ -65,11 +177,9 @@ class Gosu::Macro : public Gosu::ImageData
double x4, double y4, Color c4,
ZPos z, AlphaMode mode) const
{
- if (x1 != x3 || x2 != x4 || y1 != y2 || y3 != y4)
- throw std::invalid_argument("Macros cannot be rotated yet");
if (c1 != 0xffffffff || c2 != 0xffffffff || c3 != 0xffffffff || c4 != 0xffffffff)
throw std::invalid_argument("Macros cannot be tinted with colors yet");
- std::tr1::function<void()> f = std::tr1::bind(&Macro::realDraw, this, x1, y1, x2, y3);
+ std::tr1::function<void()> f = std::tr1::bind(&Macro::drawVertexArrays, this, x1, y1, x2, y2, x3, y3, x4, y4);
graphics.scheduleGL(f, z);
}
View
32 feature_tests/record_draw_as_quad.rb
@@ -0,0 +1,32 @@
+$LOAD_PATH << '../lib'
+require 'gosu/preview'
+
+DEST = [[12, 295], [300, 265], [23, 42], [101, 11]]
+
+class FindMatrix < Gosu::Window
+ def initialize
+ super 500, 300
+
+ self.caption = "Macro draw_as_quad - hold <tab> to to see Image draw_as_quad"
+
+ @image = Gosu::Image.new('/Users/jlnr/Pictures/Internetz/sadsadrobot.jpg')
+ @macro = record(@image.width, @image.height) { @image.draw 0, 0, 0 }
+ end
+
+ def draw
+ Gosu::draw_quad\
+ 0, 0, Gosu::Color::WHITE,
+ width, 0, Gosu::Color::WHITE,
+ 0, height, Gosu::Color::WHITE,
+ width, height, Gosu::Color::WHITE, 0
+
+ args = DEST.map { |p| [p[0], p[1], Gosu::Color::WHITE] }.flatten + [0]
+ if button_down? Gosu::KbTab then
+ @image.draw_as_quad *args
+ else
+ @macro.draw_as_quad *args
+ end
+ end
+end
+
+FindMatrix.new.show
Please sign in to comment.
Something went wrong with that request. Please try again.