找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5925|回复: 3

【算法】在文曲星平台上,用gvmaker实现3D场景渲染!(附:文曲星GVMaker开发环境下载,GVMaker模拟器下载,源码下载)

[复制链接]
发表于 2017-3-17 12:14:42 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
注:本文所指的“文曲星”是“文曲星A2008”机型。。

wqx.png
QQ图片20170316224846.png

    文曲星不支持浮点数运算,而且运行也十分缓慢——其实不是文曲星慢,而是它上面运行的gvmaker虚拟机太慢了。所以我使用定点数来代替浮点数进行运算。

    所谓定点数,就是小数点位置被固定到指定位置的一种数据类型,比如我存储1.0,对于定点数,我把小数点固定在第10位,那么我实际存储的数值就是0x400(十进制1024)。这样的话,我的定点数的精度,最低也是1/1024。

    定点数的加减法和整数无异,直接+ - 就好。但乘除法的话,如果你用一个定点数去乘一个定点数,并且你直接用的是整数的乘法的处理方式的话,你需要把得到的积再除以定点数表示的1.0,你才能得到正确的结果。比如你的定点数1.0用整数方式存储是1024的话,为了得到2.0 * 2.0 = 4.0的效果,你实际做的整数乘法是2048 * 2048,得到的是4194304,你需要再除以1024(也就是你的定点数的1.0),你才能得到4096。同理除法也需要经过这样的处理,只不过除法是先让被除数乘上定点数1.0,再除以除数。比如1.0 / 2.0 = 0.5,用定点数做运算的话,就是1024 * 1024 / 2048 = 512。

    和浮点数做对比,定点数运算比较快,并且它的精度是可控的——因为浮点数的小数点位置是浮动的,它的精度与数值的大小有密切的关系,所以用定点数能保证精度的统一,而浮点数则不能。

    但定点数的缺点在于做乘除法的时候,会严重地损失精度,尤其是圆周率,32位浮点数能存储3.1415927,而定点数假设小数点在第10位,那么它只能用 3216 来表示圆周率(3216 = π×1024 取整)。而如果我把小数点放在第16位的位置上(1.0用65536表示)的话,我虽然能精确到1/65536,但我能存储的最大的数值也从之前的4294966272变成了65536,而且我每次做乘除法的时候,我都要用一个64位的整数来存储中间值,这会严重降低运算的效率(然而x86平台还好)。

    有关3D渲染的算法,其实就是很简单的矩阵变换和投影,其它并没有什么玄妙。顺带一提,很多人以为用了DirectX或者OpenGL才能算真3D,但其实3D渲染的“真伪”只取决于你用的算法,和你使用的媒介无关。事实上就算你用的是正交投影,某种程度上也算是“真3D”的。我之前就写过一篇帖子,讲如何用VB自带的Line进行3D画面的绘制的。

    文曲星运行用户程序,用的是一款叫“gvmaker”的开发环境,和它的启动器。这里放出下载:
gvmaker开发环境: GVmaker2.4开发环境_20071011_113832.rar (6.08 MB, 下载次数: 24)
文曲星端的gvmaker启动器: GVM2008.prg (69.67 KB, 下载次数: 11)

源码:(320x240,64K色)
#define FIXED 1024
#define FIXED_SHIFT 10
#define MSTACK_SIZE 16 // 矩阵栈的大小

#define VP_WIDTH 320
#define VP_HEIGHT 240

#define VP_CENTERX 160
#define VP_CENTERY 120

#define VP_RIGHT 319
#define VP_BOTTOM 239

// 触屏判断
struct point
{
    int x;
    int y;
};
struct point pt;
struct point pt_old;

//向量
struct vec3
{
    long x,y,z;
};

struct vec4
{
    long x,y,z,w;
};

// 矩阵
struct mat4
{
    struct vec4 x,y,z,w;
};

// 矩阵栈
struct mat4 m_stack[MSTACK_SIZE];
int m_stacktop; // 栈顶
struct mat4 m; // 临时矩阵(gvmaker不能把结构体变量作为局部变量定义)
struct mat4 m_modelview; // 模型矩阵
struct mat4 m_projection; // 投影矩阵

struct vec3 eye_pos; // 眼睛位置
long eye_yaw, eye_pitch; // 眼睛角度
struct vec3 eye_xaxis; // 眼睛右方向
struct vec3 eye_yaxis; // 眼睛上方向
struct vec3 eye_zaxis; // 眼睛前方向

long time_global; // 全局时间
long time_delta; // 帧时间

void mat_init();
void mat_push();
void mat_pop();
void mat_mult();
void mat_transpose();
void mat_load_identity();
void mat_load_RotXAxis(long deg);
void mat_load_RotYAxis(long deg);
void mat_load_RotZAxis(long deg);
void mat_load_RotAxis(long ax, long ay, long az, long deg);
void mat_load_EulerRotation(long yaw, long pitch, long roll);
void mat_load_view_lh(long x, long y, long z, long yaw, long pitch, long roll);
void mat_load_perspective_lh(long fovy, long aspect, long zn, long zf);
void mat_load_modelview();
void mat_load_projection();
void mat_set_modelview();
void mat_set_projection();
void mat_print(int x, int y);

long tan(long deg)
{
    return (sin(deg) << FIXED_SHIFT) / cos(deg);
}

long cot(long deg)
{
    return (cos(deg) << FIXED_SHIFT) / sin(deg);
}

// 初始化矩阵栈
void mat_init()
{
    m_stacktop = 0;
    mat_load_identity();
}

// 压入新矩阵
void mat_push()
{
    m_stacktop = (m_stacktop + 1) % MSTACK_SIZE;
}

// 压入栈顶
void mat_pushtop()
{
    int prev;
    prev = m_stacktop;
    m_stacktop = (m_stacktop + 1) % MSTACK_SIZE;
    memcpy(&m_stack[m_stacktop].x.x, &m_stack[prev].x.x, 64);
}

// 弹出矩阵
void mat_pop()
{
    m_stacktop = m_stacktop - 1;
    if(m_stacktop < 0)
        m_stacktop = m_stacktop + MSTACK_SIZE;
}

// 将栈顶两个矩阵做矩阵乘法
void mat_mult()
{
    long ptr2;
    ptr2 = m_stacktop;
    mat_pop();

    m.x.x = (m_stack[m_stacktop].x.x * m_stack[ptr2].x.x >> FIXED_SHIFT) + (m_stack[m_stacktop].x.y * m_stack[ptr2].y.x >> FIXED_SHIFT) + (m_stack[m_stacktop].x.z * m_stack[ptr2].z.x >> FIXED_SHIFT) + (m_stack[m_stacktop].x.w * m_stack[ptr2].w.x >> FIXED_SHIFT);
    m.x.y = (m_stack[m_stacktop].x.x * m_stack[ptr2].x.y >> FIXED_SHIFT) + (m_stack[m_stacktop].x.y * m_stack[ptr2].y.y >> FIXED_SHIFT) + (m_stack[m_stacktop].x.z * m_stack[ptr2].z.y >> FIXED_SHIFT) + (m_stack[m_stacktop].x.w * m_stack[ptr2].w.y >> FIXED_SHIFT);
    m.x.z = (m_stack[m_stacktop].x.x * m_stack[ptr2].x.z >> FIXED_SHIFT) + (m_stack[m_stacktop].x.y * m_stack[ptr2].y.z >> FIXED_SHIFT) + (m_stack[m_stacktop].x.z * m_stack[ptr2].z.z >> FIXED_SHIFT) + (m_stack[m_stacktop].x.w * m_stack[ptr2].w.z >> FIXED_SHIFT);
    m.x.w = (m_stack[m_stacktop].x.x * m_stack[ptr2].x.w >> FIXED_SHIFT) + (m_stack[m_stacktop].x.y * m_stack[ptr2].y.w >> FIXED_SHIFT) + (m_stack[m_stacktop].x.z * m_stack[ptr2].z.w >> FIXED_SHIFT) + (m_stack[m_stacktop].x.w * m_stack[ptr2].w.w >> FIXED_SHIFT);

    m.y.x = (m_stack[m_stacktop].y.x * m_stack[ptr2].x.x >> FIXED_SHIFT) + (m_stack[m_stacktop].y.y * m_stack[ptr2].y.x >> FIXED_SHIFT) + (m_stack[m_stacktop].y.z * m_stack[ptr2].z.x >> FIXED_SHIFT) + (m_stack[m_stacktop].y.w * m_stack[ptr2].w.x >> FIXED_SHIFT);
    m.y.y = (m_stack[m_stacktop].y.x * m_stack[ptr2].x.y >> FIXED_SHIFT) + (m_stack[m_stacktop].y.y * m_stack[ptr2].y.y >> FIXED_SHIFT) + (m_stack[m_stacktop].y.z * m_stack[ptr2].z.y >> FIXED_SHIFT) + (m_stack[m_stacktop].y.w * m_stack[ptr2].w.y >> FIXED_SHIFT);
    m.y.z = (m_stack[m_stacktop].y.x * m_stack[ptr2].x.z >> FIXED_SHIFT) + (m_stack[m_stacktop].y.y * m_stack[ptr2].y.z >> FIXED_SHIFT) + (m_stack[m_stacktop].y.z * m_stack[ptr2].z.z >> FIXED_SHIFT) + (m_stack[m_stacktop].y.w * m_stack[ptr2].w.z >> FIXED_SHIFT);
    m.y.w = (m_stack[m_stacktop].y.x * m_stack[ptr2].x.w >> FIXED_SHIFT) + (m_stack[m_stacktop].y.y * m_stack[ptr2].y.w >> FIXED_SHIFT) + (m_stack[m_stacktop].y.z * m_stack[ptr2].z.w >> FIXED_SHIFT) + (m_stack[m_stacktop].y.w * m_stack[ptr2].w.w >> FIXED_SHIFT);

    m.z.x = (m_stack[m_stacktop].z.x * m_stack[ptr2].x.x >> FIXED_SHIFT) + (m_stack[m_stacktop].z.y * m_stack[ptr2].y.x >> FIXED_SHIFT) + (m_stack[m_stacktop].z.z * m_stack[ptr2].z.x >> FIXED_SHIFT) + (m_stack[m_stacktop].z.w * m_stack[ptr2].w.x >> FIXED_SHIFT);
    m.z.y = (m_stack[m_stacktop].z.x * m_stack[ptr2].x.y >> FIXED_SHIFT) + (m_stack[m_stacktop].z.y * m_stack[ptr2].y.y >> FIXED_SHIFT) + (m_stack[m_stacktop].z.z * m_stack[ptr2].z.y >> FIXED_SHIFT) + (m_stack[m_stacktop].z.w * m_stack[ptr2].w.y >> FIXED_SHIFT);
    m.z.z = (m_stack[m_stacktop].z.x * m_stack[ptr2].x.z >> FIXED_SHIFT) + (m_stack[m_stacktop].z.y * m_stack[ptr2].y.z >> FIXED_SHIFT) + (m_stack[m_stacktop].z.z * m_stack[ptr2].z.z >> FIXED_SHIFT) + (m_stack[m_stacktop].z.w * m_stack[ptr2].w.z >> FIXED_SHIFT);
    m.z.w = (m_stack[m_stacktop].z.x * m_stack[ptr2].x.w >> FIXED_SHIFT) + (m_stack[m_stacktop].z.y * m_stack[ptr2].y.w >> FIXED_SHIFT) + (m_stack[m_stacktop].z.z * m_stack[ptr2].z.w >> FIXED_SHIFT) + (m_stack[m_stacktop].z.w * m_stack[ptr2].w.w >> FIXED_SHIFT);

    m.w.x = (m_stack[m_stacktop].w.x * m_stack[ptr2].x.x >> FIXED_SHIFT) + (m_stack[m_stacktop].w.y * m_stack[ptr2].y.x >> FIXED_SHIFT) + (m_stack[m_stacktop].w.z * m_stack[ptr2].z.x >> FIXED_SHIFT) + (m_stack[m_stacktop].w.w * m_stack[ptr2].w.x >> FIXED_SHIFT);
    m.w.y = (m_stack[m_stacktop].w.x * m_stack[ptr2].x.y >> FIXED_SHIFT) + (m_stack[m_stacktop].w.y * m_stack[ptr2].y.y >> FIXED_SHIFT) + (m_stack[m_stacktop].w.z * m_stack[ptr2].z.y >> FIXED_SHIFT) + (m_stack[m_stacktop].w.w * m_stack[ptr2].w.y >> FIXED_SHIFT);
    m.w.z = (m_stack[m_stacktop].w.x * m_stack[ptr2].x.z >> FIXED_SHIFT) + (m_stack[m_stacktop].w.y * m_stack[ptr2].y.z >> FIXED_SHIFT) + (m_stack[m_stacktop].w.z * m_stack[ptr2].z.z >> FIXED_SHIFT) + (m_stack[m_stacktop].w.w * m_stack[ptr2].w.z >> FIXED_SHIFT);
    m.w.w = (m_stack[m_stacktop].w.x * m_stack[ptr2].x.w >> FIXED_SHIFT) + (m_stack[m_stacktop].w.y * m_stack[ptr2].y.w >> FIXED_SHIFT) + (m_stack[m_stacktop].w.z * m_stack[ptr2].z.w >> FIXED_SHIFT) + (m_stack[m_stacktop].w.w * m_stack[ptr2].w.w >> FIXED_SHIFT);

    memcpy(&m_stack[m_stacktop].x.x, &m.x.x, 64);
}

// 矩阵转置
void mat_transpose()
{
    long t;

    t = m_stack[m_stacktop].x.y;
    m_stack[m_stacktop].x.y = m_stack[m_stacktop].y.x;
    m_stack[m_stacktop].y.x = t;

    t = m_stack[m_stacktop].x.z;
    m_stack[m_stacktop].x.z = m_stack[m_stacktop].z.x;
    m_stack[m_stacktop].z.x = t;

    t = m_stack[m_stacktop].x.w;
    m_stack[m_stacktop].x.w = m_stack[m_stacktop].w.x;
    m_stack[m_stacktop].w.x = t;

    t = m_stack[m_stacktop].y.z;
    m_stack[m_stacktop].y.z = m_stack[m_stacktop].z.y;
    m_stack[m_stacktop].z.y = t;

    t = m_stack[m_stacktop].y.w;
    m_stack[m_stacktop].y.w = m_stack[m_stacktop].w.y;
    m_stack[m_stacktop].w.y = t;

    t = m_stack[m_stacktop].z.w;
    m_stack[m_stacktop].z.w = m_stack[m_stacktop].w.z;
    m_stack[m_stacktop].w.z = t;
}

// 载入单位矩阵
void mat_load_identity()
{
    m_stack[m_stacktop].x.x=FIXED;m_stack[m_stacktop].x.y=0;m_stack[m_stacktop].x.z=0;m_stack[m_stacktop].x.w=0;
    m_stack[m_stacktop].y.y=FIXED;m_stack[m_stacktop].y.x=0;m_stack[m_stacktop].y.z=0;m_stack[m_stacktop].y.w=0;
    m_stack[m_stacktop].z.z=FIXED;m_stack[m_stacktop].z.x=0;m_stack[m_stacktop].z.y=0;m_stack[m_stacktop].z.w=0;
    m_stack[m_stacktop].w.w=FIXED;m_stack[m_stacktop].w.x=0;m_stack[m_stacktop].w.y=0;m_stack[m_stacktop].w.z=0;
}

// 载入平移矩阵
void mat_load_translate(long x, long y, long z)
{
    m_stack[m_stacktop].x.x=FIXED;m_stack[m_stacktop].x.y=0;m_stack[m_stacktop].x.z=0;m_stack[m_stacktop].x.w=0;
    m_stack[m_stacktop].y.y=FIXED;m_stack[m_stacktop].y.x=0;m_stack[m_stacktop].y.z=0;m_stack[m_stacktop].y.w=0;
    m_stack[m_stacktop].z.z=FIXED;m_stack[m_stacktop].z.x=0;m_stack[m_stacktop].z.y=0;m_stack[m_stacktop].z.w=0;
    m_stack[m_stacktop].w.w=FIXED;m_stack[m_stacktop].w.x=x;m_stack[m_stacktop].w.y=y;m_stack[m_stacktop].w.z=z;
}

// 载入绕X轴旋转矩阵
void mat_load_RotXAxis(long deg)
{
    m_stack[m_stacktop].x.x = FIXED;
    m_stack[m_stacktop].x.y = 0;
    m_stack[m_stacktop].x.z = 0;
    m_stack[m_stacktop].x.w = 0;

    m_stack[m_stacktop].y.x = 0;
    m_stack[m_stacktop].y.y = cos(deg);
    m_stack[m_stacktop].y.z =-sin(deg);
    m_stack[m_stacktop].y.w = 0;

    m_stack[m_stacktop].z.x = 0;
    m_stack[m_stacktop].z.y = sin(deg);
    m_stack[m_stacktop].z.z = cos(deg);
    m_stack[m_stacktop].z.w = 0;

    m_stack[m_stacktop].w.x = 0;
    m_stack[m_stacktop].w.y = 0;
    m_stack[m_stacktop].w.z = 0;
    m_stack[m_stacktop].w.w = FIXED;
}

// 载入绕Y轴旋转矩阵
void mat_load_RotYAxis(long deg)
{
    m_stack[m_stacktop].x.x = cos(deg);
    m_stack[m_stacktop].x.y = 0;
    m_stack[m_stacktop].x.z = sin(deg);
    m_stack[m_stacktop].x.w = 0;

    m_stack[m_stacktop].y.x = 0;
    m_stack[m_stacktop].y.y = FIXED;
    m_stack[m_stacktop].y.z = 0;
    m_stack[m_stacktop].y.w = 0;

    m_stack[m_stacktop].z.x =-sin(deg);
    m_stack[m_stacktop].z.y = 0;
    m_stack[m_stacktop].z.z = cos(deg);
    m_stack[m_stacktop].z.w = 0;

    m_stack[m_stacktop].w.x = 0;
    m_stack[m_stacktop].w.y = 0;
    m_stack[m_stacktop].w.z = 0;
    m_stack[m_stacktop].w.w = FIXED;
}

// 载入绕Z轴旋转矩阵
void mat_load_RotZAxis(long deg)
{
    m_stack[m_stacktop].x.x = cos(deg);
    m_stack[m_stacktop].x.y = sin(deg);
    m_stack[m_stacktop].x.z = 0;
    m_stack[m_stacktop].x.w = 0;

    m_stack[m_stacktop].y.x =-sin(deg);
    m_stack[m_stacktop].y.y = cos(deg);
    m_stack[m_stacktop].y.z = 0;
    m_stack[m_stacktop].y.w = 0;

    m_stack[m_stacktop].z.x = 0;
    m_stack[m_stacktop].z.y = 0;
    m_stack[m_stacktop].z.z = FIXED;
    m_stack[m_stacktop].z.w = 0;

    m_stack[m_stacktop].w.x = 0;
    m_stack[m_stacktop].w.y = 0;
    m_stack[m_stacktop].w.z = 0;
    m_stack[m_stacktop].w.w = FIXED;
}

// 载入绕轴旋转矩阵
void mat_load_RotAxis(long ax, long ay, long az, long deg)
{
    m_stack[m_stacktop].x.x = (((FIXED - cos(deg)) * ax >> FIXED_SHIFT) * ax >> FIXED_SHIFT) + cos(deg);
    m_stack[m_stacktop].x.y = (((FIXED - cos(deg)) * ax >> FIXED_SHIFT) * ay >> FIXED_SHIFT) - sin(deg) * az >> FIXED_SHIFT;
    m_stack[m_stacktop].x.z = (((FIXED - cos(deg)) * ax >> FIXED_SHIFT) * az >> FIXED_SHIFT) + sin(deg) * ay >> FIXED_SHIFT;
    m_stack[m_stacktop].x.w = 0;

    m_stack[m_stacktop].y.x = (((FIXED - cos(deg)) * ay >> FIXED_SHIFT) * ax >> FIXED_SHIFT) + sin(deg) * az >> FIXED_SHIFT;
    m_stack[m_stacktop].y.y = (((FIXED - cos(deg)) * ay >> FIXED_SHIFT) * ay >> FIXED_SHIFT) + cos(deg);
    m_stack[m_stacktop].y.z = (((FIXED - cos(deg)) * ay >> FIXED_SHIFT) * az >> FIXED_SHIFT) - sin(deg) * ax >> FIXED_SHIFT;
    m_stack[m_stacktop].y.w = 0;

    m_stack[m_stacktop].z.x = (((FIXED - cos(deg)) * az >> FIXED_SHIFT) * ax >> FIXED_SHIFT) - sin(deg) * ay >> FIXED_SHIFT;
    m_stack[m_stacktop].z.y = (((FIXED - cos(deg)) * az >> FIXED_SHIFT) * ay >> FIXED_SHIFT) + sin(deg) * ax >> FIXED_SHIFT;
    m_stack[m_stacktop].z.z = (((FIXED - cos(deg)) * az >> FIXED_SHIFT) * az >> FIXED_SHIFT) + cos(deg);
    m_stack[m_stacktop].z.w = 0;

    m_stack[m_stacktop].w.x = 0;
    m_stack[m_stacktop].w.y = 0;
    m_stack[m_stacktop].w.z = 0;
    m_stack[m_stacktop].w.w = FIXED;
}

// 载入欧拉角旋转矩阵
void mat_load_EulerRotation(long yaw, long pitch, long roll)
{
    mat_load_RotZAxis(roll);

    mat_push();
    mat_load_RotXAxis(pitch);

    mat_mult();

    mat_push();
    mat_load_RotYAxis(yaw);

    mat_mult();
}

// 载入左手坐标系观察矩阵
void mat_load_view_lh(long x, long y, long z, long yaw, long pitch, long roll)
{
    long t;
    mat_load_EulerRotation(yaw, pitch, roll);

    eye_xaxis.x = m_stack[m_stacktop].x.x;
    eye_xaxis.y = m_stack[m_stacktop].x.y;
    eye_xaxis.z = m_stack[m_stacktop].x.z;
    eye_yaxis.x = m_stack[m_stacktop].y.x;
    eye_yaxis.y = m_stack[m_stacktop].y.y;
    eye_yaxis.z = m_stack[m_stacktop].y.z;
    eye_zaxis.x = m_stack[m_stacktop].z.x;
    eye_zaxis.y = m_stack[m_stacktop].z.y;
    eye_zaxis.z = m_stack[m_stacktop].z.z;

    m_stack[m_stacktop].w.x = -((eye_xaxis.x * x >> FIXED_SHIFT) + (eye_xaxis.y * y >> FIXED_SHIFT) + (eye_xaxis.z * z >> FIXED_SHIFT));
    m_stack[m_stacktop].w.y = -((eye_yaxis.x * x >> FIXED_SHIFT) + (eye_yaxis.y * y >> FIXED_SHIFT) + (eye_yaxis.z * z >> FIXED_SHIFT));
    m_stack[m_stacktop].w.z = -((eye_zaxis.x * x >> FIXED_SHIFT) + (eye_zaxis.y * y >> FIXED_SHIFT) + (eye_zaxis.z * z >> FIXED_SHIFT));
    m_stack[m_stacktop].w.w = FIXED;

    t = m_stack[m_stacktop].x.y;
    m_stack[m_stacktop].x.y = m_stack[m_stacktop].y.x;
    m_stack[m_stacktop].y.x = t;

    t = m_stack[m_stacktop].x.z;
    m_stack[m_stacktop].x.z = m_stack[m_stacktop].z.x;
    m_stack[m_stacktop].z.x = t;

    t = m_stack[m_stacktop].y.z;
    m_stack[m_stacktop].y.z = m_stack[m_stacktop].z.y;
    m_stack[m_stacktop].z.y = t;

    m_stack[m_stacktop].x.w = 0;
    m_stack[m_stacktop].y.w = 0;
    m_stack[m_stacktop].z.w = 0;
}

// 载入左手坐标系投影矩阵
void mat_load_perspective_lh(long fovy, long aspect, long zn, long zf)
{
    long xscale,yscale;
    long zdiff;
    zdiff = zf-zn;
    yscale = cot(fovy / 2);
    xscale = (yscale << FIXED_SHIFT) / aspect;
    m_stack[m_stacktop].x.x = xscale; m_stack[m_stacktop].x.y = 0; m_stack[m_stacktop].x.z = 0; m_stack[m_stacktop].x.w = 0;
    m_stack[m_stacktop].y.x = 0; m_stack[m_stacktop].y.y = yscale; m_stack[m_stacktop].y.z = 0; m_stack[m_stacktop].y.w = 0;
    m_stack[m_stacktop].z.x = 0; m_stack[m_stacktop].z.y = 0; m_stack[m_stacktop].z.z = (zf<<FIXED_SHIFT)/zdiff; m_stack[m_stacktop].z.w = FIXED;
    m_stack[m_stacktop].w.x = 0; m_stack[m_stacktop].w.y = 0; m_stack[m_stacktop].w.z = -zn*zf/zdiff; m_stack[m_stacktop].w.w = 0;
}

// 将模型矩阵复制到栈顶
void mat_load_modelview()
{
    memcpy(&m_stack[m_stacktop].x.x, &m_modelview.x.x, 64);
}

// 将投影矩阵复制到栈顶
void mat_load_projection()
{
    memcpy(&m_stack[m_stacktop].x.x, &m_projection.x.x, 64);
}

// 将栈顶的矩阵复制到模型矩阵
void mat_set_modelview()
{
    memcpy(&m_modelview.x.x, &m_stack[m_stacktop].x.x, 64);
}

// 将栈顶的矩阵复制到投影矩阵
void mat_set_projection()
{
    memcpy(&m_projection.x.x, &m_stack[m_stacktop].x.x, 64);
}

// 打印矩阵的值到屏幕上
void mat_print(int x, int y)
{
    char buf[256];
    sprintf(buf, "%d:",m_stacktop);
    TextOut(x,y,buf);y=y+GetFontSize();
    sprintf(buf, "%d,%d,%d,%d", m_stack[m_stacktop].x.x,m_stack[m_stacktop].x.y,m_stack[m_stacktop].x.z,m_stack[m_stacktop].x.w);
    TextOut(x,y,buf);y=y+GetFontSize();
    sprintf(buf, "%d,%d,%d,%d", m_stack[m_stacktop].y.x,m_stack[m_stacktop].y.y,m_stack[m_stacktop].y.z,m_stack[m_stacktop].y.w);
    TextOut(x,y,buf);y=y+GetFontSize();
    sprintf(buf, "%d,%d,%d,%d", m_stack[m_stacktop].z.x,m_stack[m_stacktop].z.y,m_stack[m_stacktop].z.z,m_stack[m_stacktop].z.w);
    TextOut(x,y,buf);y=y+GetFontSize();
    sprintf(buf, "%d,%d,%d,%d", m_stack[m_stacktop].w.x,m_stack[m_stacktop].w.y,m_stack[m_stacktop].w.z,m_stack[m_stacktop].w.w);
    TextOut(x,y,buf);
}

// 线性插值
long m_lerp(long v1, long v2, long s)
{
    return v1 + ((v2 - v1) * s >> FIXED_SHIFT);
}

// 画线
void g_draw_line(long x1, long y1, long x2, long y2)
{
    // gvmaker原版的画线函数不能处理坐标超出屏幕外的情况
    // 所以要做一个插值处理
    if(x1 < 0)
    {
        if(x2 < 0)
            return; // 防止除零异常
        y1 = y1 + (y2 - y1) *-x1 / (x2 - x1);
        x1 = 0;
    }
    if(y1 < 0)
    {
        if(y2 < 0)
            return;
        x1 = x1 + (x2 - x1) *-y1 / (y2 - y1);
        y1 = 0;
    }
    if(x2 < 0)
    {
        if(x1 <= 0)
            return;
        y2 = y2 + (y1 - y2) *-x2 / (x1 - x2);
        x2 = 0;
    }
    if(y2 < 0)
    {
        if(y1 <= 0)
            return;
        x2 = x2 + (x1 - x2) *-y2 / (y1 - y2);
        y2 = 0;
    }
    if(x1 > VP_RIGHT)
    {
        if(x2 > VP_RIGHT)
            return;
        y1 = y1 + (y2 - y1) * (x1 - VP_RIGHT) / (x1 - x2);
        x1 = VP_RIGHT;
    }
    if(y1 > VP_BOTTOM)
    {
        if(y2 > VP_BOTTOM)
            return;
        x1 = x1 + (x2 - x1) * (y1 - VP_BOTTOM) / (y1 - y2);
        y1 = VP_BOTTOM;
    }
    if(x2 > VP_RIGHT)
    {
        if(x1 >= VP_RIGHT)
            return;
        y2 = y2 + (y1 - y2) * (x2 - VP_RIGHT) / (x2 - x1);
        x2 = VP_RIGHT;
    }
    if(y2 > VP_BOTTOM)
    {
        if(y1 >= VP_BOTTOM)
            return;
        x2 = x2 + (x1 - x2) * (y2 - VP_BOTTOM) / (y2 - y1);
        y2 = VP_BOTTOM;
    }
    if(x1 == x2)
        VLine(x1, y1, y2);
    else if(y1 == y2)
        HLine(x1, x2, y1);
    else
        Line(x1,y1,x2,y2);
}

// 画3D线,坐标将经过矩阵变换和投影处理。
void g_draw_3d_line(long x1, long y1, long z1, long x2, long y2, long z2)
{
    long pxt, pyt, pzt, pwt; // 临时坐标
    long px1, py1, pz1, pw1; // 坐标1
    long px2, py2, pz2, pw2; // 坐标2
    long ls;

    pxt = (x1 * m_modelview.x.x >> FIXED_SHIFT) + (y1 * m_modelview.y.x >> FIXED_SHIFT) + (z1 * m_modelview.z.x >> FIXED_SHIFT) + m_modelview.w.x;
    pyt = (x1 * m_modelview.x.y >> FIXED_SHIFT) + (y1 * m_modelview.y.y >> FIXED_SHIFT) + (z1 * m_modelview.z.y >> FIXED_SHIFT) + m_modelview.w.y;
    pzt = (x1 * m_modelview.x.z >> FIXED_SHIFT) + (y1 * m_modelview.y.z >> FIXED_SHIFT) + (z1 * m_modelview.z.z >> FIXED_SHIFT) + m_modelview.w.z;
    pwt = (x1 * m_modelview.x.w >> FIXED_SHIFT) + (y1 * m_modelview.y.w >> FIXED_SHIFT) + (z1 * m_modelview.z.w >> FIXED_SHIFT) + m_modelview.w.w;

    px1 = (pxt * m_projection.x.x >> FIXED_SHIFT) + (pyt * m_projection.y.x >> FIXED_SHIFT) + (pzt * m_projection.z.x >> FIXED_SHIFT) + (pwt * m_projection.w.x >> FIXED_SHIFT);
    py1 = (pxt * m_projection.x.y >> FIXED_SHIFT) + (pyt * m_projection.y.y >> FIXED_SHIFT) + (pzt * m_projection.z.y >> FIXED_SHIFT) + (pwt * m_projection.w.y >> FIXED_SHIFT);
    pz1 = (pxt * m_projection.x.z >> FIXED_SHIFT) + (pyt * m_projection.y.z >> FIXED_SHIFT) + (pzt * m_projection.z.z >> FIXED_SHIFT) + (pwt * m_projection.w.z >> FIXED_SHIFT);
    pw1 = (pxt * m_projection.x.w >> FIXED_SHIFT) + (pyt * m_projection.y.w >> FIXED_SHIFT) + (pzt * m_projection.z.w >> FIXED_SHIFT) + (pwt * m_projection.w.w >> FIXED_SHIFT);

    pxt = (x2 * m_modelview.x.x >> FIXED_SHIFT) + (y2 * m_modelview.y.x >> FIXED_SHIFT) + (z2 * m_modelview.z.x >> FIXED_SHIFT) + m_modelview.w.x;
    pyt = (x2 * m_modelview.x.y >> FIXED_SHIFT) + (y2 * m_modelview.y.y >> FIXED_SHIFT) + (z2 * m_modelview.z.y >> FIXED_SHIFT) + m_modelview.w.y;
    pzt = (x2 * m_modelview.x.z >> FIXED_SHIFT) + (y2 * m_modelview.y.z >> FIXED_SHIFT) + (z2 * m_modelview.z.z >> FIXED_SHIFT) + m_modelview.w.z;
    pwt = (x2 * m_modelview.x.w >> FIXED_SHIFT) + (y2 * m_modelview.y.w >> FIXED_SHIFT) + (z2 * m_modelview.z.w >> FIXED_SHIFT) + m_modelview.w.w;

    px2 = (pxt * m_projection.x.x >> FIXED_SHIFT) + (pyt * m_projection.y.x >> FIXED_SHIFT) + (pzt * m_projection.z.x >> FIXED_SHIFT) + (pwt * m_projection.w.x >> FIXED_SHIFT);
    py2 = (pxt * m_projection.x.y >> FIXED_SHIFT) + (pyt * m_projection.y.y >> FIXED_SHIFT) + (pzt * m_projection.z.y >> FIXED_SHIFT) + (pwt * m_projection.w.y >> FIXED_SHIFT);
    pz2 = (pxt * m_projection.x.z >> FIXED_SHIFT) + (pyt * m_projection.y.z >> FIXED_SHIFT) + (pzt * m_projection.z.z >> FIXED_SHIFT) + (pwt * m_projection.w.z >> FIXED_SHIFT);
    pw2 = (pxt * m_projection.x.w >> FIXED_SHIFT) + (pyt * m_projection.y.w >> FIXED_SHIFT) + (pzt * m_projection.z.w >> FIXED_SHIFT) + (pwt * m_projection.w.w >> FIXED_SHIFT);

    // 处理近视距剪切
    if(pz1 < FIXED)
    {
        if(pz2 < FIXED)
            return;

        if(pz1 == pz2)
            return;

        ls = ((pz2 - FIXED) << FIXED_SHIFT) / (pz2 - pz1);

        px1 = m_lerp(px2, px1, ls);
        py1 = m_lerp(py2, py1, ls);
        pz1 = m_lerp(pz2, pz1, ls);
        pw1 = m_lerp(pw2, pw1, ls);
    }

    if(pz2 < FIXED)
    {
        if(pz1 < FIXED)
            return;

        if(pz1 == pz2)
            return;

        ls = ((pz1 - FIXED) << FIXED_SHIFT) / (pz1 - pz2);

        px2 = m_lerp(px1, px2, ls);
        py2 = m_lerp(py1, py2, ls);
        pz2 = m_lerp(pz1, pz2, ls);
        pw2 = m_lerp(pw1, pw2, ls);
    }

    // 投影
    px1 = px1 * VP_CENTERX / pw1 + VP_CENTERX;
    py1 = VP_CENTERY - py1 * VP_CENTERY / pw1;
    px2 = px2 * VP_CENTERX / pw2 + VP_CENTERX;
    py2 = VP_CENTERY - py2 * VP_CENTERY / pw2;
    g_draw_line(px1,py1,px2,py2);
}

// 用线条画长方体
void g_draw_cube(long dx, long dy, long dz)
{
    // Up
    g_draw_3d_line(-dx, dy, dz, dx, dy, dz);
    g_draw_3d_line( dx, dy, dz, dx, dy,-dz);
    g_draw_3d_line( dx, dy,-dz,-dx, dy,-dz);
    g_draw_3d_line(-dx, dy,-dz,-dx, dy, dz);

    // Down
    g_draw_3d_line(-dx,-dy, dz, dx,-dy, dz);
    g_draw_3d_line( dx,-dy, dz, dx,-dy,-dz);
    g_draw_3d_line( dx,-dy,-dz,-dx,-dy,-dz);
    g_draw_3d_line(-dx,-dy,-dz,-dx,-dy, dz);

    // Pillars
    g_draw_3d_line(-dx, dy, dz,-dx,-dy, dz);
    g_draw_3d_line( dx, dy, dz, dx,-dy, dz);
    g_draw_3d_line( dx, dy,-dz, dx,-dy,-dz);
    g_draw_3d_line(-dx, dy,-dz,-dx,-dy,-dz);
}

// 输出16进制数
void XDigitOut(int x, int y, long digit)
{
    int ch;
    int w;
    int shifts;

    w = GetFontSize() / 2;

    if(!digit)
    {
        TextOut(x, y, "00000000");
        return;
    }

    x=x+w*7;
    shifts=32;
    while(shifts)
    {
        ch=digit&0xF;
        if(ch>=10)
            CharOut(x, y, ch-10+'A');
        else
            CharOut(x, y, ch+'0');
        x=x-w;
        digit=digit>>4;
        shifts=shifts-4;
    }
}

void main()
{
    long i;
    int x,y;

    SetFontSize(12);
    SetLCDMode(0);

    eye_pos.x=0;
    eye_pos.y=3 << FIXED_SHIFT;
    eye_pos.z=-10 << FIXED_SHIFT;

    mat_init();

    time_global = GetTickCount();

    for(;;)
    {
        // 帧时间处理
        i = GetTickCount();
        time_delta = i - time_global;
        time_global = i;

        ClearScreen();

        // 设置投影矩阵
        mat_load_perspective_lh(60, (VP_WIDTH << FIXED_SHIFT) / VP_HEIGHT, FIXED, 1000 << FIXED_SHIFT);
        mat_set_projection();

        // 设置旋转立方体的矩阵
        mat_load_RotYAxis(time_global * 60 / 1000);
        mat_push();
        mat_load_translate(0,FIXED,0);
        mat_mult();
        mat_push();
        mat_load_view_lh(eye_pos.x, eye_pos.y, eye_pos.z, eye_yaw, eye_pitch, 0);
        mat_mult();
        mat_set_modelview();

        // 画立方体
        g_draw_cube(FIXED, FIXED, FIXED);

        // 设置地面的矩阵
        mat_load_view_lh(eye_pos.x, eye_pos.y, eye_pos.z, eye_yaw, eye_pitch, 0);
        mat_set_modelview();

        // 画地面
        for(x = -10; x <= 10; x++)
        {
            g_draw_3d_line( x << FIXED_SHIFT, 0, 10 << FIXED_SHIFT, x << FIXED_SHIFT, 0, -10 << FIXED_SHIFT);
        }
        for(y = -10; y <= 10; y++)
        {
            g_draw_3d_line( 10 << FIXED_SHIFT, 0, y << FIXED_SHIFT,-10 << FIXED_SHIFT, 0, y << FIXED_SHIFT);
        }

        // 根据触屏操作来转动镜头
        if(GetMousePos(pt) == 2)
        {
            eye_yaw = eye_yaw + pt_old.x - pt.x;
            eye_pitch = eye_pitch + pt_old.y - pt.y;
            if(eye_yaw < 0)
                eye_yaw = eye_yaw + 360;
            if(eye_yaw > 360)
                eye_yaw = eye_yaw - 360;
            if(eye_pitch < 0)
                eye_pitch = eye_pitch + 360;
            if(eye_pitch > 360)
                eye_pitch = eye_pitch - 360;
        }
        pt_old.x = pt.x;
        pt_old.y = pt.y;

        // 键盘移动操作
        if(CheckKey(KEY_LEFT))
        {
            eye_pos.x = eye_pos.x - eye_xaxis.x * time_delta * 10 / 1000;
            eye_pos.y = eye_pos.y - eye_xaxis.y * time_delta * 10 / 1000;
            eye_pos.z = eye_pos.z - eye_xaxis.z * time_delta * 10 / 1000;
        }
        if(CheckKey(KEY_RIGHT))
        {
            eye_pos.x = eye_pos.x + eye_xaxis.x * time_delta * 10 / 1000;
            eye_pos.y = eye_pos.y + eye_xaxis.y * time_delta * 10 / 1000;
            eye_pos.z = eye_pos.z + eye_xaxis.z * time_delta * 10 / 1000;
        }
        if(CheckKey(KEY_UP))
        {
            eye_pos.x = eye_pos.x + eye_zaxis.x * time_delta * 10 / 1000;
            eye_pos.y = eye_pos.y + eye_zaxis.y * time_delta * 10 / 1000;
            eye_pos.z = eye_pos.z + eye_zaxis.z * time_delta * 10 / 1000;
        }
        if(CheckKey(KEY_DOWN))
        {
            eye_pos.x = eye_pos.x - eye_zaxis.x * time_delta * 10 / 1000;
            eye_pos.y = eye_pos.y - eye_zaxis.y * time_delta * 10 / 1000;
            eye_pos.z = eye_pos.z - eye_zaxis.z * time_delta * 10 / 1000;
        }

        Refresh();
    }
}
Src: main.txt (23.31 KB, 下载次数: 8)
Bin: main.gvm (8.82 KB, 下载次数: 6)

回复

使用道具 举报

发表于 2017-3-17 18:07:24 | 显示全部楼层
本帖最后由 Ayala 于 2017-3-17 18:28 编辑
    但定点数的缺点在于做乘除法的时候,会严重地损失精度,尤其是圆周率,32位浮点数能存储3.1415927,而定点数假设小数点在第10位,那么它只能用 3216 来表示圆周率(3216 = π×1024 取整)。而如果我把小数点放在第16位的位置上(1.0用65536表示)的话,我虽然能精确到1/65536,但我能存储的最大的数值也从之前的4294966272变成了65536,而且我每次做乘除法的时候,我都要用一个64位的整数来存储中间值,这会严重降低运算的效率(然而x86平台还好)

这个问题其实可以用1024* PI*2**8 (定点数 π×1024 * 256 =0xC90FE)来解决 当然也可以用 1024*PI*2**15更高数值
另外PI*1024 取整也应该是3216.990877≈3217 而不是 3216
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2017-3-17 20:06:54 | 显示全部楼层
Ayala 发表于 2017-3-17 18:07
这个问题其实可以用1024* PI*2**8 (定点数 π×1024 * 256 =0xC90FE)来解决 当然也可以用 1024*PI*2**15更 ...

其实是说错,不是取整,而是“商”,所以是没有四舍五入的
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2017-9-15 17:52:06 | 显示全部楼层
另外因为文曲星的解释器特征,优化方面侧重于多调用它的函数进行绘图,少进行自己的绘图方式。比如它的画线函数,其实虽然明明可以自己写一个不使用乘除法的画线函数,但依然还是推荐使用它自己的画线函数(VLine、HLine、Line)。因为自己写的画线函数在运行的时候需要GVMaker虚拟机对其进行指令层面的判断和模拟执行的操作,而它自己的画线函数则是用文曲星本机的处理器指令执行的。
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2026-2-3 07:23 , Processed in 0.038067 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表