Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- int lineLine(const float a0x,const float a0y, const float a1x,const float a1y,
- const float b0x,const float b0y, const float b1x,const float b1y){
- //get distance to intersection
- const float axd=a1x-a0x, ayd=a1y-a0y;
- const float bxd=b1x-b0x, byd=b1y-b0y;
- const float abxd=a0x-b0x, abyd=a0y-b0y;
- const float divisor=byd*axd - bxd*ayd;
- const float uA=(bxd*abyd - byd*abxd) / divisor;
- const float uB=(axd*abyd - ayd*abxd) / divisor;
- //if true, the two lines are intersecting
- if(uA>=0 && uA<=1 && uB>=0 && uB<=1) return 1;
- else return 0;
- }
- void drawTriangle(KIT_TTM_Canvas3D* canvas, KIT_TTM_Triangle tri, KIT_TTL_Material* umt){
- const int w=canvas->w,h=canvas->h;
- //check if triangle is in any way inside the canvas rectangle, otherwise return early
- //first check if any of the points are inside...
- if(!IN_BOUNDS(tri.a.pos.x,tri.a.pos.y, w,h) &&
- !IN_BOUNDS(tri.b.pos.x,tri.b.pos.y, w,h) &&
- !IN_BOUNDS(tri.c.pos.x,tri.c.pos.y, w,h) ){
- //if not, see if any of the triangle's lines are intersecting the canvas rectangle's lines
- if(lineLine(tri.a.pos.x,tri.a.pos.y, tri.b.pos.x,tri.b.pos.y, 0,0, w,0)) goto collided; //ab & top
- if(lineLine(tri.a.pos.x,tri.a.pos.y, tri.b.pos.x,tri.b.pos.y, w,0, w,h)) goto collided; //ab & right
- if(lineLine(tri.a.pos.x,tri.a.pos.y, tri.b.pos.x,tri.b.pos.y, 0,h, w,h)) goto collided; //ab & bottom
- if(lineLine(tri.a.pos.x,tri.a.pos.y, tri.b.pos.x,tri.b.pos.y, 0,0, 0,h)) goto collided; //ab & left
- if(lineLine(tri.b.pos.x,tri.b.pos.y, tri.c.pos.x,tri.c.pos.y, 0,0, w,0)) goto collided; //bc & top
- if(lineLine(tri.b.pos.x,tri.b.pos.y, tri.c.pos.x,tri.c.pos.y, w,0, w,h)) goto collided; //bc & right
- if(lineLine(tri.b.pos.x,tri.b.pos.y, tri.c.pos.x,tri.c.pos.y, 0,h, w,h)) goto collided; //bc & bottom
- if(lineLine(tri.b.pos.x,tri.b.pos.y, tri.c.pos.x,tri.c.pos.y, 0,0, 0,h)) goto collided; //bc & left
- if(lineLine(tri.c.pos.x,tri.c.pos.y, tri.a.pos.x,tri.a.pos.y, 0,0, w,0)) goto collided; //ca & top
- if(lineLine(tri.c.pos.x,tri.c.pos.y, tri.a.pos.x,tri.a.pos.y, w,0, w,h)) goto collided; //ca & right
- if(lineLine(tri.c.pos.x,tri.c.pos.y, tri.a.pos.x,tri.a.pos.y, 0,h, w,h)) goto collided; //ca & bottom
- if(lineLine(tri.c.pos.x,tri.c.pos.y, tri.a.pos.x,tri.a.pos.y, 0,0, 0,h)) goto collided; //ca & left
- return; collided:; //lol
- //there's gotta be a better way to do that...
- }
- const int rowlen=canvas->pitch/sizeof(KIT_Color);
- SDL_Surface* tex=NULL; KIT_Color* tex_pixels; int tex_w,tex_h,tex_pitch;
- KIT_Color* pixels=canvas->pixels;
- //sort the 3 points of the triangle by top -> bottom, left -> right
- if(tri.a.pos.y > tri.c.pos.y) KIT_TTM_Vertex_Swap(&tri.a,&tri.c);
- if(tri.a.pos.y > tri.b.pos.y) KIT_TTM_Vertex_Swap(&tri.a,&tri.b);
- if(tri.b.pos.y > tri.c.pos.y) KIT_TTM_Vertex_Swap(&tri.b,&tri.c);
- int same_y=0; //possible values are 0 -> 3
- if((int)tri.a.pos.y == (int)tri.c.pos.y){
- if(tri.a.pos.x > tri.c.pos.x) KIT_TTM_Vertex_Swap(&tri.a,&tri.c);
- //same_y|=0b100; //ac same y=1 (redundant; if a=b&b=c, then a=c)
- }
- if((int)tri.a.pos.y == (int)tri.b.pos.y){
- if(tri.a.pos.x > tri.b.pos.x) KIT_TTM_Vertex_Swap(&tri.a,&tri.b);
- same_y|=0b010; //ab same y=1
- }
- if((int)tri.b.pos.y == (int)tri.c.pos.y){
- if(tri.b.pos.x > tri.c.pos.x) KIT_TTM_Vertex_Swap(&tri.b,&tri.c);
- same_y|=0b001; //bc same y=1
- }
- //(d)ifference=second-first
- const KIT_vec3 ab_d=KIT_vec3_SubV(tri.b.pos,tri.a.pos);
- const KIT_vec3 bc_d=KIT_vec3_SubV(tri.c.pos,tri.b.pos);
- const KIT_vec3 ac_d=KIT_vec3_SubV(tri.c.pos,tri.a.pos);
- const SDL_FPoint ab_uv_d={.x=tri.b.uv.x-tri.a.uv.x, .y=tri.b.uv.y-tri.a.uv.y};
- const SDL_FPoint bc_uv_d={.x=tri.c.uv.x-tri.b.uv.x, .y=tri.c.uv.y-tri.b.uv.y};
- const SDL_FPoint ac_uv_d={.x=tri.c.uv.x-tri.a.uv.x, .y=tri.c.uv.y-tri.a.uv.y};
- //(cut down to h if difference is greater than canvas height)
- const uint32_t newlen=(fabs(ac_d.y)<h) ? (uint32_t)(fabs(ac_d.y)+1.0f) : h;
- const uint32_t newsize=newlen*sizeof(KIT_TTM_Vertex);
- if(newsize > canvas->userdata_size){
- //array that stores the start and end vertices for each scanline of triangle
- //(size = max a->c y difference * sizeof(KIT_TTM_Vertex) * 2 sides per scanline)
- canvas->userdata=realloc(canvas->userdata,newsize*2);
- canvas->userdata_len=newlen, canvas->userdata_size=newsize;
- }
- //find out which side of line ac point b is (to see if bend abc looks like < or >)
- const SDL_FPoint ab_vector={.x=tri.b.pos.x-tri.a.pos.x, .y=tri.b.pos.y-tri.a.pos.y};
- const SDL_FPoint ac_vector={.x=tri.c.pos.x-tri.a.pos.x, .y=tri.c.pos.y-tri.a.pos.y};
- const int isRightBend=((ab_vector.x*ac_vector.y)-(ab_vector.y*ac_vector.x)) > 0;
- //tx(ty)=x0+(x1-x0)*(ty-x0)/(y1-y0) -> tx(ty)=x0+((x1-x0)/(y1-y0))*(ty-y0)
- //(x1-x0)/(y1-y0) is a constant, so it can be pre-calculated
- #define DT_INTERP_X(_ty, _start,_constant) ( _start.x + _constant*(_ty-_start.y) )
- //const float ab_const_divisor=(tri.b.pos.y-tri.a.pos.y) ? tri.b.pos.y-tri.a.pos.y : 1e-7;
- //const float bc_const_divisor=(tri.c.pos.y-tri.b.pos.y) ? tri.c.pos.y-tri.b.pos.y : 1e-7;
- //const float ac_const_divisor=(tri.c.pos.y-tri.a.pos.y) ? tri.c.pos.y-tri.a.pos.y : 1e-7;
- const float ab_const=(tri.b.pos.x-tri.a.pos.x)/(tri.b.pos.y-tri.a.pos.y);//ab_const_divisor;
- const float bc_const=(tri.c.pos.x-tri.b.pos.x)/(tri.c.pos.y-tri.b.pos.y);//bc_const_divisor;
- const float ac_const=(tri.c.pos.x-tri.a.pos.x)/(tri.c.pos.y-tri.a.pos.y);//ac_const_divisor;
- KIT_TTM_Vertex currentVert, endVert;
- int scani=0, abi_max=tri.b.pos.y, bci_max=tri.c.pos.y;
- KIT_TTM_Vertex* scanlineStart=canvas->userdata;
- KIT_TTM_Vertex* scanlineEnd =canvas->userdata+newsize;
- SDL_Point a_int={.x=tri.a.pos.x, .y=tri.a.pos.y};
- SDL_Point b_int={.x=tri.b.pos.x, .y=tri.b.pos.y};
- //interpolate start and end points of each scanline
- switch(same_y){
- case 0b00: //-- -- (all points are on different scanlines)
- case 0b01: //-- bc (bottom side is flat)
- for(int abi=tri.a.pos.y; abi<abi_max; ++abi){
- //a -> b
- if(abi<0 || abi>=h) continue; //continue if y is outside canvas
- currentVert.pos.x=DT_INTERP_X(abi, a_int,ab_const);
- currentVert.pos.y=abi;
- scanlineStart[scani]=currentVert;
- //a -> c
- currentVert.pos.x=DT_INTERP_X(abi, a_int,ac_const);
- scanlineEnd[scani]=currentVert;
- ++scani;
- }
- if(!same_y) goto top_side_flat; //if same_y==0b00, do both abi and bci loops
- else break;
- case 0b10: //ab -- (top side is flat)
- top_side_flat:
- for(int bci=tri.b.pos.y; bci<bci_max; ++bci){
- //b -> c
- if(bci<0 || bci>=h) continue;
- currentVert.pos.x=DT_INTERP_X(bci, b_int,bc_const);
- currentVert.pos.y=bci;
- scanlineStart[scani]=currentVert;
- //a -> c
- currentVert.pos.x=DT_INTERP_X(bci, a_int,ac_const);
- scanlineEnd[scani]=currentVert;
- ++scani;
- }
- break;
- case 0b11: //ab bc (all points are on the same scanline)
- currentVert.pos.x=a_int.x;
- currentVert.pos.y=a_int.y; //y should be same for c too
- scanlineStart[scani]=currentVert;
- currentVert.pos.x=(int)tri.c.pos.x;
- scanlineEnd[scani++]=currentVert;
- break;
- }
- //if abc bend is right, then swap start and end of every scanline
- if(isRightBend && same_y!=0b11){ //unless same_y==3 (only 1 scanline)
- scanlineStart=canvas->userdata+newsize;
- scanlineEnd=canvas->userdata;
- }
- //from the wikipedia article for lerp, it says this method doesn't guarantee
- //that the output will be exactly v1 when t=1, but i'm ignoring the last
- //iteration for x and y anyway, so t shouldn't ever actually be 1
- #define DT_INTERP(_t, _start,_difference) ( _start + _t*_difference )
- if(umt){ tex=umt->s_mKd; tex_pixels=tex->pixels; tex_w=tex->w; tex_h=tex->h; tex_pitch=tex->pitch; }
- else { //missing material completely
- for(int sli=0; sli<scani; ++sli){
- currentVert=scanlineStart[sli]; //basically used as 'startVert' here
- endVert=scanlineEnd[sli];
- if(currentVert.pos.x>endVert.pos.x) KIT_TTM_Vertex_Swap(¤tVert,&endVert);
- int x_max=endVert.pos.x, y_pos=currentVert.pos.y*rowlen;
- for(int xi=currentVert.pos.x; xi<x_max; ++xi){
- if(xi<0) continue;
- else if (xi>=w) break;
- pixels[y_pos+xi].value=0xffbf00bf;
- }
- }
- for(int i=0; i<scani; ++i){
- currentVert=scanlineStart[i];
- if(IN_BOUNDS(currentVert.pos.x,currentVert.pos.y, w,h))
- pixels[ARR2D_FLT(currentVert.pos.x,currentVert.pos.y, rowlen)].value=0xffffff00;//0xffff00ff;
- currentVert=scanlineEnd[i];
- if(IN_BOUNDS(currentVert.pos.x,currentVert.pos.y, w,h))
- pixels[ARR2D_FLT(currentVert.pos.x,currentVert.pos.y, rowlen)].value=0xffffff00;//0xff7f007f;
- }
- /*
- if(IN_BOUNDS(tri.a.pos.x,tri.a.pos.y, w,h))
- pixels[ARR2D_FLT(tri.a.pos.x,tri.a.pos.y,w)].value=0xff0000ff;
- if(IN_BOUNDS(tri.b.pos.x,tri.b.pos.y, w,h))
- pixels[ARR2D_FLT(tri.b.pos.x,tri.b.pos.y,w)].value=0xff00ff00;
- if(IN_BOUNDS(tri.c.pos.x,tri.c.pos.y, w,h))
- pixels[ARR2D_FLT(tri.c.pos.x,tri.c.pos.y,w)].value=0xffff0000;*/
- return;}
- if(tex){ //material has diffuse texture
- } else { //material lacks a diffuse texture; use only diffuse color
- }
- }
- int notAShader3(KIT_TTM_Canvas3D* canvas, KIT_TTM* ttms,int ttms_len, void* data){
- if(!canvas){ return 1; } if(!ttms){ return 2; } if(!ttms_len){ return 3; }
- float v_w=canvas->v_w, v_h=canvas->v_h; int w=canvas->w, h=canvas->h;
- int w_half=w/2, h_half=h/2;
- KIT_TTM_LockCanvas3D(canvas);
- for(uint32_t ttm_i=0; ttm_i<ttms_len; ++ttm_i){//for every ttm
- uint32_t objects_len=ttms[ttm_i].objects_len;
- for(uint32_t obj_i=0; obj_i<objects_len; ++obj_i){//for every object
- KIT_TTM_Object* object=&ttms[ttm_i].objects[obj_i];
- uint32_t numWorkTris=object->numWorkTris;
- if(numWorkTris==0) continue;
- KIT_TTM_Triangle* render=object->render;
- memcpy(render,object->work,sizeof(KIT_TTM_Triangle)*numWorkTris);
- for(uint32_t tri_i=0; tri_i<numWorkTris; ++tri_i){//for every triangle
- KIT_TTM_Triangle tri=render[tri_i];
- tri=KIT_TTM_ProjectTriangle(tri, w_half,h_half, v_w,v_h);
- drawTriangle(canvas, tri,NULL);//object->umt);
- }
- }}
- if(canvas->autoUnlock) KIT_TTM_UnlockCanvas3D(canvas);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement