#include <easyx.h>
#include <math.h>
#include <conio.h>
#include <stdio.h>
#include <algorithm>
// π
#define PI 3.1415926535
// 点信息结构体
struct dPOINT
{
double x;
double y;
};
// 3D 点和颜色信息
struct dCPOINT3D
{
double x, y, z;
COLORREF c;
bool operator< (dCPOINT3D p)
{
return z < p.z;
}
bool operator<= (dCPOINT3D p)
{
return z <= p.z;
}
bool operator> (dCPOINT3D p)
{
return z > p.z;
}
bool operator>= (dCPOINT3D p)
{
return z >= p.z;
}
};
// 3D 点信息结构体
struct dPOINT3D
{
dPOINT3D()
{
}
dPOINT3D(dCPOINT3D p) : x(p.x), y(p.y), z(p.z)
{
}
double x;
double y;
double z;
};
void Equal(dCPOINT3D& pc, const dPOINT3D& p)
{
pc = { p.x, p.y, p.z, pc.c };
}
// 物体
class Object
{
public:
Object()
{
}
Object(int num)
{
New(num);
}
void New(int num)
{
p = new dCPOINT3D[num];
capacity = num;
}
void Free()
{
delete[] p;
p = NULL;
capacity = 0;
n = 0;
}
void Copy(Object obj)
{
New(obj.n);
memcpy(p, obj.p, obj.n * sizeof(dCPOINT3D));
n = obj.n;
}
dCPOINT3D* p = NULL;
int capacity = 0;
int n = 0;
};
dCPOINT3D rotate3D(dCPOINT3D p, double Z, double Y, double X)
{
return {
p.x * (cos(Y) * cos(Z)) +
p.y * (-(cos(X) * sin(Z)) + (sin(X) * sin(Y) * cos(Z))) +
p.z * ((sin(X) * sin(Z)) + (cos(X) * sin(Y) * cos(Z))),
p.x * (cos(Y) * sin(Z)) +
p.y * ((cos(X) * cos(Z)) + (sin(X) * sin(Y) * sin(Z))) +
p.z * ((-sin(X) * cos(Z)) + (cos(X) * sin(Y) * sin(Z))),
p.x * (-sin(Y)) +
p.y * (sin(X) * cos(Y)) +
p.z * (cos(X) * cos(Y)),
p.c
};
}
void AddPointFromImage(Object& obj, COLORREF c)
{
for (int i = 0; i < getwidth(); i++)
{
for (int j = 0; j < getheight(); j++)
{
if (getpixel(i, j) != BLACK)
{
obj.p[obj.n++] = { (double)i, (double)j, 0, c };
}
}
}
}
void RotateObj(Object obj, double x, double y, double z)
{
for (int i = 0; i < obj.n; i++)
{
obj.p[i] = rotate3D(obj.p[i], z, y, x);
}
}
void Render(Object obj)
{
Object obj_sort;
obj_sort.Copy(obj);
std::sort(obj_sort.p, obj_sort.p + obj_sort.n);
for (int i = obj_sort.n - 1; i >= 0; i--)
{
putpixel((int)obj_sort.p[i].x + 320, (int)obj_sort.p[i].y + 240, obj_sort.p[i].c);
}
obj_sort.Free();
}
Object GetObj()
{
int w = 50, h = 50, depth = 70;
IMAGE img(w, h);
Object obj(w * h * depth);
SetWorkingImage(&img);
solidcircle(25, 25, 24);
AddPointFromImage(obj, GREEN);
int len = obj.n;
Object obj2(w * h);
cleardevice();
circle(25, 25, 24);
AddPointFromImage(obj2, GREEN);
int len2 = obj2.n;
for (int k = 0; k < depth - 1; k++)
{
for (int m = 0; m < len2; m++)
{
obj.p[obj.n] = obj2.p[m];
obj.p[obj.n].c = RGB(123, 223, 213);
obj.p[obj.n].z = k;
obj.n++;
}
}
for (int m = 0; m < len; m++)
{
obj.p[obj.n] = obj.p[m];
obj.p[obj.n].c = RED;
obj.p[obj.n].z = depth - 1;
obj.n++;
}
SetWorkingImage();
return obj;
}
class Drag
{
private:
ExMessage old, msg;
int dx, dy;
bool lbtn = false, mbtn = false, rbtn = false;
bool newmsg = false;
bool UpdateDragInfo(bool& btn, int msgid_down, int msgid_up)
{
if (newmsg)
{
if (btn)
{
if (msg.message == msgid_up)
{
btn = false;
}
dx = msg.x - old.x;
dy = msg.y - old.y;
old = msg;
return true;
}
else
{
if (msg.message == msgid_down)
{
btn = true;
old = msg;
}
return false;
}
newmsg = false;
}
else
{
return false;
}
}
public:
void UpdateMessage(ExMessage m)
{
msg = m;
newmsg = true;
}
bool isLeftDrag()
{
return UpdateDragInfo(lbtn, WM_LBUTTONDOWN, WM_LBUTTONUP);
}
bool isMiddleDrag()
{
return UpdateDragInfo(mbtn, WM_MBUTTONDOWN, WM_MBUTTONUP);
}
bool isRightDrag()
{
return UpdateDragInfo(rbtn, WM_RBUTTONDOWN, WM_RBUTTONUP);
}
int GetDragX() { return dx; };
int GetDragY() { return dy; };
};
int main()
{
// 图形界面初始化
initgraph(640, 480, EX_SHOWCONSOLE);
BeginBatchDraw();
setbkcolor(BLUE);
cleardevice();
Object obj = GetObj();
RotateObj(obj, 0, 0, 0);
double x = 0, y = 0;
Drag drag;
for (double i = 0;; i += 0.05)
{
cleardevice();
Object obj2;
obj2.Copy(obj);
RotateObj(obj2, x, y, 0);
Render(obj2);
obj2.Free();
FlushBatchDraw();
if (i >= 2 * PI)
{
i = 0;
}
ExMessage msg;
while (peekmessage(&msg, EX_MOUSE))
{
drag.UpdateMessage(msg);
if (drag.isLeftDrag())
{
y += drag.GetDragX() / 10.0;
x += drag.GetDragY() / 10.0;
}
}
}
// 关闭窗口
EndBatchDraw();
closegraph();
return 0;
}