承接上次的EGE光栅化三角形,这次实现了纹理映射
#include <graphics.h> #include <algorithm> #include <cmath> #include <stdio.h> #include <map> using namespace std; //判断点v是否在[a,b]中 //C#与JAVa的后遗症,EGEAPP namespace EA { using namespace std; #define ct color_t //几个全局变量 //屏幕buffer color_t* wBuffer=nullptr; //纹理buffer PIMAGE img; color_t* tBuffer=nullptr; //屏幕长宽 int W=0; int H=0; //纹理宽 int tW=0; int tH=0; inline float F2I(float f) { return floor(f); } //把浮点数位数强定为3位(担心爆精度 inline float F2F3(float f) { return floor(f*1000.0f)/1000.0f; } template<class T> inline bool IsCovered(T a,T b,T v) { if(a>b) swap(a,b); return (a<=v&&v<=b); } //数据类型 class Vertex2D { public: float x; float y; ct c; inline Vertex2D() { x=y=0.0f; c=0; } inline Vertex2D(float _x,float _y,ct _c) { x=_x,y=_y,c=_c; } inline void Format() { x=EA::F2I(x); y=EA::F2I(y); } inline VECTOR3D ToVec3D() { return VECTOR3D(x,y,0); } }; typedef struct Vertex2D Ver2D; class Point2D{ public: Vertex2D xy;//位置 Vertex2D uv;//纹理坐标 Point2D(float x,float y,float u,float v){ xy.x=x;xy.y=y; uv.x=u;uv.y=v; } Point2D(){ } }; //函数 //初始化绘图环境 void InitGraph(int w,int h,string image) { initgraph(w,h,0); ege_enable_aa(1); W=getwidth(),H=getheight(); img=newimage(); getimage(img,image.c_str()); ege_enable_aa(1,img); tW=getwidth(img); tH=getheight(img); wBuffer=getbuffer(NULL); tBuffer=getbuffer(img); } //向量插值,0<=v<=1 inline Point2D VerLerp(Point2D c1,Point2D c2,float v); //高速画点 inline void PutPixel_f(Point2D v); //高速画水平线 //这个会渐变 inline void DrawLine_f(float x1,float x2,float y,float u1,float u2,float v); //绘制简单三角,要求至少两个点y一样 inline void DrawSimpleTrangle(Point2D v1,Point2D v2,Point2D v3); //绘制复杂三角 inline void DrawTrangle(Point2D v1,Point2D v2,Point2D v3); #undef ct } using EA::Point2D; #define ct color_t //程序入口 int main() { EA::InitGraph(1000,800,"此文件涉嫌违规问题.gif"); //setbkcolor(RED); EA::DrawTrangle(Point2D(0,0,0,0),Point2D(0,EA::H,0,EA::tH),Point2D(EA::W,0,EA::tW,0)); delay_fps(60); getch(); closegraph(); return 0; } Point2D EA::VerLerp(Point2D c1,Point2D c2,float v) { return Point2D((c1.xy.x-c2.xy.x)*v+c2.xy.x,(c1.xy.y-c2.xy.y)*v+c2.xy.y,(c1.uv.x-c2.uv.x)*v+c2.uv.x,(c1.uv.y-c2.uv.y)*v+c2.uv.y); } void EA::PutPixel_f(Point2D v) { if(EA::IsCovered(0,W,int(v.xy.x))&&EA::IsCovered(0,H,int(v.xy.y))) { //☆☆☆这一点很坑,如果写成wBuffer坐标一样的话会出大乱子...引以为戒☆☆☆ wBuffer[int(v.xy.x+v.xy.y*W)]=tBuffer[int(v.uv.x)+int(v.uv.y)*tW]; } } void EA::DrawLine_f(float x1,float x2,float y,float u1,float u2,float v) { if(x1>x2) swap(x1,x2); Point2D pt; float k=(u1-u2)/(x1-x2); for(float i=x1; i<=x2; ++i) { PutPixel_f(Point2D(i,y,k*(i-x1)+u1,v)); } } //v1.y==v2.y void EA::DrawSimpleTrangle(Point2D v1,Point2D v2,Point2D v3) { //Format if(v2.xy.y==v3.xy.y&&v1.xy.y!=v2.xy.y) { swap(v1,v2); swap(v2,v3); } else if(v1.xy.y==v3.xy.y&&v1.xy.y!=v2.xy.y) { swap(v2,v3); } if(v1.xy.x>v2.xy.x) { swap(v1,v2); } //解一次方程 float h=v3.xy.y-v1.xy.y; float kL=(v3.xy.x-v1.xy.x)/h; float kR=(v3.xy.x-v2.xy.x)/h; float xL=0; float xR=0; xL=v1.xy.x; xR=v2.xy.x; Point2D p1,p2; if(h>0) { for(float i=v1.xy.y; i<=v3.xy.y; ++i) { float percent=1.0f-(i-v1.xy.y)/(v3.xy.y-v1.xy.y); p1=EA::VerLerp(v1,v3,percent); p2=EA::VerLerp(v2,v3,percent); EA::DrawLine_f(xL,xR,i,p1.uv.x,p2.uv.x,p1.uv.y); xL+=kL; xR+=kR; } } else { for(float i=v1.xy.y; i>=v3.xy.y; --i) { float percent=(i-v3.xy.y)/(v1.xy.y-v3.xy.y); p1=EA::VerLerp(v1,v3,percent); p2=EA::VerLerp(v2,v3,percent); EA::DrawLine_f(xL,xR,i,p1.uv.x,p2.uv.x,p1.uv.y); xL-=kL; xR-=kR; } } } void EA::DrawTrangle(Point2D v1,Point2D v2,Point2D v3) { if(v1.xy.y==v2.xy.y||v1.xy.y==v3.xy.y||v2.xy.y==v3.xy.y) { EA::DrawSimpleTrangle(v1,v2,v3); } else { //找出y中间的顶点,并放在v3的位置 if(v2.xy.y<v1.xy.y&&v1.xy.y<v3.xy.y) { swap(v1,v3); } else if(v1.xy.y<v2.xy.y&&v2.xy.y<v3.xy.y) { swap(v2,v3); } //切成两半 float h=v1.xy.y-v2.xy.y; float w=v1.xy.x-v2.xy.x; Point2D pt=EA::VerLerp(v2,v1,(v3.xy.y-v2.xy.y)/h); Point2D vm((w/h)*(v3.xy.y-v2.xy.y)+v2.xy.x,v3.xy.y,pt.uv.x,pt.uv.y); //画他 DrawSimpleTrangle(v1,vm,v3); DrawSimpleTrangle(v2,vm,v3); } } #undef ct
项目:EGE纹理映射