void GLWidget::project_quad_texture() { const int sx = width(), sy = height(); Point pt[4]; static Vec3f corners[] = { Vec3f(0, 0, 0), Vec3f(sx-1, 0, 0), Vec3f(0, sy-1, 0), Vec3f(sx-1, sy-1, 0) }; for (int i = 0; i < 4; i++) { pt[i] = project(Vec3f(corners[i].x - sx/2, corners[i].y - sy/2, 0)); pt[i].x += sx/2; pt[i].y += sy/2; } Vec3f normal1(0, 0, 1); Vec3f normal2; { Vec3f foo[3]; for (int i = 0; i < 3; i++) foo[i] = project2(corners[i]); normal2 = normal(foo[0], foo[1], foo[2]); } double dir = normal1.x * normal2.x + normal1.y * normal2.y + normal1.z * normal2.z; QImage& tex = dir < 0 ? back : front; int ow = tex.width(), oh = tex.height(); Vec2f p2[4]; for (int i = 0; i < 4; i++) p2[i] = Vec2f(pt[i].x, pt[i].y); QImage texture(QSize(sx, sy), QImage::Format_RGB888); texture.fill(Qt::black); const Vec2f projected[2][3] = { { p2[0], p2[1], p2[2] }, { p2[3], p2[1], p2[2] } }; const Vec2f origs[2][3] = { { Vec2f(0, 0), Vec2f(ow-1, 0), Vec2f(0, oh-1) }, { Vec2f(ow-1, oh-1), Vec2f(ow-1, 0), Vec2f(0, oh-1) } }; const Triangle triangles[2] = { Triangle(projected[0][0], projected[0][1], projected[0][2]), Triangle(projected[1][0], projected[1][1], projected[1][2]) }; int orig_pitch = tex.bytesPerLine(); int dest_pitch = texture.bytesPerLine(); const unsigned char* orig = tex.bits(); unsigned char* dest = texture.bits(); int orig_depth = tex.depth() / 8; int dest_depth = texture.depth() / 8; /* image breakage? */ if (orig_depth < 3) return; for (int y = 0; y < sy; y++) for (int x = 0; x < sx; x++) { Vec2f pos; pos.x = x; pos.y = y; for (int i = 0; i < 2; i++) { Vec2f coords; if (triangles[i].barycentric_coords(pos, coords)) { double qx = origs[i][0].x + coords.x * (origs[i][2].x - origs[i][0].x) + coords.y * (origs[i][1].x - origs[i][0].x); double qy = origs[i][0].y + coords.x * (origs[i][2].y - origs[i][0].y) + coords.y * (origs[i][1].y - origs[i][0].y); int qx1 = std::min<int>(ow - 1, std::max<int>(0, qx - 0.5)); int qy1 = std::min<int>(oh - 1, std::max<int>(0, qy - 0.5)); int qx2 = std::min<int>(ow - 1, std::max<int>(0, qx + 0.5)); int qy2 = std::min<int>(oh - 1, std::max<int>(0, qy + 0.5)); double dx1 = qx1 - qx; double dy1 = qy1 - qy; double dx2 = qx2 - qx; double dy2 = qy2 - qy; double d1 = 2 - (dx1 * dx1 + dy1 * dy1); double d2 = 2 - (dx2 * dx2 + dy2 * dy2); double d3 = 2 - (dx2 * dx2 + dy1 * dy1); double d4 = 2 - (dx1 * dx1 + dy2 * dy2); double inv_norm = 1. / (d1 + d2 + d3 + d4); d1 *= inv_norm; d2 *= inv_norm; d3 *= inv_norm; d4 *= inv_norm; double r = d1 * (double) orig[qy1 * orig_pitch + qx1 * orig_depth + 2] + d2 * (double) orig[qy2 * orig_pitch + qx2 * orig_depth + 2] + d3 * (double) orig[qy1 * orig_pitch + qx2 * orig_depth + 2] + d4 * (double) orig[qy2 * orig_pitch + qx1 * orig_depth + 2]; double g = d1 * (double) orig[qy1 * orig_pitch + qx1 * orig_depth + 1] + d2 * (double) orig[qy2 * orig_pitch + qx2 * orig_depth + 1] + d3 * (double) orig[qy1 * orig_pitch + qx2 * orig_depth + 1] + d4 * (double) orig[qy2 * orig_pitch + qx1 * orig_depth + 1]; double b = d1 * (double) orig[qy1 * orig_pitch + qx1 * orig_depth + 0] + d2 * (double) orig[qy2 * orig_pitch + qx2 * orig_depth + 0] + d3 * (double) orig[qy1 * orig_pitch + qx2 * orig_depth + 0] + d4 * (double) orig[qy2 * orig_pitch + qx1 * orig_depth + 0]; dest[y * dest_pitch + x * dest_depth + 0] = std::max<int>(0, std::min<int>(255, r)); dest[y * dest_pitch + x * dest_depth + 1] = std::max<int>(0, std::min<int>(255, g)); dest[y * dest_pitch + x * dest_depth + 2] = std::max<int>(0, std::min<int>(255, b)); break; } } } pixmap = QPixmap::fromImage(texture); }
void GLWidget::project_quad_texture() { const int sx = width(), sy = height(); Point pt[4]; static Vec3f corners[] = { Vec3f(0, 0, 0), Vec3f(sx-1, 0, 0), Vec3f(0, sy-1, 0), Vec3f(sx-1, sy-1, 0) }; for (int i = 0; i < 4; i++) { pt[i] = project(Vec3f(corners[i].x - sx/2, corners[i].y - sy/2, 0)); pt[i].x += sx/2; pt[i].y += sy/2; } Vec3f normal1(0, 0, 1); Vec3f normal2; { Vec3f foo[3]; for (int i = 0; i < 3; i++) foo[i] = project2(corners[i]); normal2 = normal(foo[0], foo[1], foo[2]); } double dir = normal1.x * normal2.x + normal1.y * normal2.y + normal1.z * normal2.z; QImage& tex = dir < 0 ? back : front; int ow = tex.width(), oh = tex.height(); Vec2f p2[4]; for (int i = 0; i < 4; i++) p2[i] = Vec2f(pt[i].x, pt[i].y); QImage texture(QSize(sx, sy), QImage::Format_RGB888); QColor bgColor = palette().color(QPalette::Current, QPalette::Window); texture.fill(bgColor); const Vec2f projected[2][3] = { { p2[0], p2[1], p2[2] }, { p2[3], p2[1], p2[2] } }; const Vec2f origs[2][3] = { { Vec2f(0, 0), Vec2f(ow-1, 0), Vec2f(0, oh-1) }, { Vec2f(ow-1, oh-1), Vec2f(ow-1, 0), Vec2f(0, oh-1) } }; const Triangle triangles[2] = { Triangle(projected[0][0], projected[0][1], projected[0][2]), Triangle(projected[1][0], projected[1][1], projected[1][2]) }; int orig_pitch = tex.bytesPerLine(); int dest_pitch = texture.bytesPerLine(); const unsigned char* orig = tex.bits(); unsigned char* dest = texture.bits(); int orig_depth = tex.depth() / 8; int dest_depth = texture.depth() / 8; /* image breakage? */ if (orig_depth < 3) return; for (int y = 0; y < sy; y++) for (int x = 0; x < sx; x++) { Vec2f pos; pos.x = x; pos.y = y; for (int i = 0; i < 2; i++) { Vec2f coords; if (triangles[i].barycentric_coords(pos, coords)) { int px = origs[i][0].x + coords.x * (origs[i][2].x - origs[i][0].x) + coords.y * (origs[i][1].x - origs[i][0].x); int py = origs[i][0].y + coords.x * (origs[i][2].y - origs[i][0].y) + coords.y * (origs[i][1].y - origs[i][0].y); int r = orig[py * orig_pitch + px * orig_depth + 2]; int g = orig[py * orig_pitch + px * orig_depth + 1]; int b = orig[py * orig_pitch + px * orig_depth + 0]; dest[y * dest_pitch + x * dest_depth + 0] = r; dest[y * dest_pitch + x * dest_depth + 1] = g; dest[y * dest_pitch + x * dest_depth + 2] = b; break; } } } this->texture = texture; }
void tests() { cout << "Running tests..." << endl; TEST("1", 1); TEST("1 + 2", 3); TEST("1 - 2", -1); TEST("2 * 3", 6); TEST("10 / 5", 2); TEST("2 == 2", 1); TEST("2 == 3", 0); TEST("2 != 3", 1); TEST("2 != 2", 0); TEST("1 < 2", 1); TEST("2 < 1", 0); TEST("3 > 1", 1); TEST("3 > 10", 0); TEST("c(1,2)", 1, 2); TEST("c(1, 2, 3)", 1, 2, 3); TEST("c(1, 2) + c(3, 4)", 4, 6); TEST("c(1, 2) - c(2, 1)", -1, 1); TEST("c(2, 3) * c(3, 4)", 6, 12); TEST("c(10, 9) / c(2, 3)", 5, 3); TEST("c(1,2) == c(3, 4)", 0, 0); TEST("c(1,2) == c(1, 4)", 1, 0); TEST("c(1,2) == c(3, 2)", 0, 1); TEST("c(1,2) == c(1, 2)", 1, 1); TEST("c(1,2) != c(3, 4)", 1, 1); TEST("c(1,2) != c(1, 4)", 0, 1); TEST("c(1,2) != c(3, 2)", 1, 0); TEST("c(1,2) != c(1, 2)", 0, 0); TEST("c(1,2) < c(3,4)", 1, 1); TEST("c(1,2) < c(2, 1)", 1, 0); TEST("c(3,4) > c(5, 6)", 0, 0); TEST("c(1,2,3) < 2", 1, 0, 0); TEST("c(1,2,3) + c(1,2)", 2, 4, 4); TEST("\"a\"", "a"); TEST("\"foo\" + \"bar\"", "foobar"); TEST("\"aba\" == \"aca\"", 1, 0, 1); TEST("\"aba\" == c(1,2)", 0); TEST("\"aba\" != c(1,2)", 1); TEST("a = 1 a", 1); TEST("a = 1 a = a + 2 a", 3); TEST("a = 1 a = a - a a", 0); TEST("a = 2 a = a * 3 a", 6); TEST("a = 20 a / 4", 5); TEST("a = 1 b = 2 a < b", 1); TEST("a = 1 a = c(a, a)", 1, 1); TEST("type(1)", "double"); TEST("type(\"a\")", "character"); TEST("type(function() { 1 })", "function"); TEST("length(1)", 1); TEST("length(\"aba\")", 3); TEST("length(\"\")", 0); TEST("a = 1 if (a) { 1 } else { 2 }", 1); TEST("a = 1 b = 1 if (a) { b = 2 } b", 2); TEST("a = 0 b = 1 if (a) { b = 2 } b", 1); TEST("a = 10 b = 0 while (a > 0) { b = b + 1 a = a - 1 } c(a, b)", 0, 10); TEST("f = function() { 1 } f()", 1); TEST("f = function(a, b) { a + b } f(1, 2)", 3); TEST("f = function() { a + b } a = 1 b = 2 f()", 3); TEST("f = function() { a = 1 a } a = 2 c(f(), a)", 1, 2); TEST("a = c(1, 2, 3) a[1]", 2); TEST("a = \"aba\" a[c(0,2)]", "aa"); TEST("a = c(1,2,3) a[c(0,1)] = 56 a", 56, 56, 3); project2(); project3(); project4(); project5(); project6(); }