Advertisement
Kitomas

wip software renderer

May 19th, 2023 (edited)
948
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.25 KB | Source Code | 0 0
  1. int lineLine(const float a0x,const float a0y, const float a1x,const float a1y,
  2.              const float b0x,const float b0y, const float b1x,const float b1y){
  3.   //get distance to intersection
  4.   const float axd=a1x-a0x, ayd=a1y-a0y;
  5.   const float bxd=b1x-b0x, byd=b1y-b0y;
  6.   const float abxd=a0x-b0x, abyd=a0y-b0y;
  7.   const float divisor=byd*axd - bxd*ayd;
  8.   const float uA=(bxd*abyd - byd*abxd) / divisor;
  9.   const float uB=(axd*abyd - ayd*abxd) / divisor;
  10.   //if true, the two lines are intersecting
  11.   if(uA>=0 && uA<=1  &&  uB>=0 && uB<=1) return 1;
  12.   else return 0;
  13. }
  14. void drawTriangle(KIT_TTM_Canvas3D* canvas, KIT_TTM_Triangle tri, KIT_TTL_Material* umt){
  15.   const int w=canvas->w,h=canvas->h;
  16.   //check if triangle is in any way inside the canvas rectangle, otherwise return early
  17.    //first check if any of the points are inside...
  18.   if(!IN_BOUNDS(tri.a.pos.x,tri.a.pos.y, w,h) &&
  19.      !IN_BOUNDS(tri.b.pos.x,tri.b.pos.y, w,h) &&
  20.      !IN_BOUNDS(tri.c.pos.x,tri.c.pos.y, w,h) ){
  21.     //if not, see if any of the triangle's lines are intersecting the canvas rectangle's lines
  22.     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
  23.     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
  24.     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
  25.     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
  26.  
  27.     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
  28.     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
  29.     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
  30.     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
  31.  
  32.     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
  33.     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
  34.     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
  35.     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
  36.  
  37.     return; collided:; //lol
  38.     //there's gotta be a better way to do that...
  39.   }
  40.   const int rowlen=canvas->pitch/sizeof(KIT_Color);
  41.   SDL_Surface* tex=NULL; KIT_Color* tex_pixels; int tex_w,tex_h,tex_pitch;
  42.   KIT_Color* pixels=canvas->pixels;
  43.   //sort the 3 points of the triangle by top -> bottom, left -> right
  44.   if(tri.a.pos.y > tri.c.pos.y) KIT_TTM_Vertex_Swap(&tri.a,&tri.c);
  45.   if(tri.a.pos.y > tri.b.pos.y) KIT_TTM_Vertex_Swap(&tri.a,&tri.b);
  46.   if(tri.b.pos.y > tri.c.pos.y) KIT_TTM_Vertex_Swap(&tri.b,&tri.c);
  47.   int same_y=0; //possible values are 0 -> 3
  48.   if((int)tri.a.pos.y == (int)tri.c.pos.y){
  49.     if(tri.a.pos.x > tri.c.pos.x) KIT_TTM_Vertex_Swap(&tri.a,&tri.c);
  50.     //same_y|=0b100; //ac same y=1 (redundant; if a=b&b=c, then a=c)
  51.   }
  52.   if((int)tri.a.pos.y == (int)tri.b.pos.y){
  53.     if(tri.a.pos.x > tri.b.pos.x) KIT_TTM_Vertex_Swap(&tri.a,&tri.b);
  54.     same_y|=0b010; //ab same y=1
  55.   }
  56.   if((int)tri.b.pos.y == (int)tri.c.pos.y){
  57.     if(tri.b.pos.x > tri.c.pos.x) KIT_TTM_Vertex_Swap(&tri.b,&tri.c);
  58.     same_y|=0b001; //bc same y=1
  59.   }
  60.   //(d)ifference=second-first
  61.   const KIT_vec3 ab_d=KIT_vec3_SubV(tri.b.pos,tri.a.pos);
  62.   const KIT_vec3 bc_d=KIT_vec3_SubV(tri.c.pos,tri.b.pos);
  63.   const KIT_vec3 ac_d=KIT_vec3_SubV(tri.c.pos,tri.a.pos);
  64.   const SDL_FPoint ab_uv_d={.x=tri.b.uv.x-tri.a.uv.x, .y=tri.b.uv.y-tri.a.uv.y};
  65.   const SDL_FPoint bc_uv_d={.x=tri.c.uv.x-tri.b.uv.x, .y=tri.c.uv.y-tri.b.uv.y};
  66.   const SDL_FPoint ac_uv_d={.x=tri.c.uv.x-tri.a.uv.x, .y=tri.c.uv.y-tri.a.uv.y};
  67.   //(cut down to h if difference is greater than canvas height)
  68.   const uint32_t newlen=(fabs(ac_d.y)<h) ? (uint32_t)(fabs(ac_d.y)+1.0f) : h;
  69.   const uint32_t newsize=newlen*sizeof(KIT_TTM_Vertex);
  70.   if(newsize > canvas->userdata_size){
  71.     //array that stores the start and end vertices for each scanline of triangle
  72.      //(size = max a->c y difference * sizeof(KIT_TTM_Vertex) * 2 sides per scanline)
  73.     canvas->userdata=realloc(canvas->userdata,newsize*2);
  74.     canvas->userdata_len=newlen, canvas->userdata_size=newsize;
  75.   }
  76.  
  77.   //find out which side of line ac point b is (to see if bend abc looks like < or >)
  78.   const SDL_FPoint ab_vector={.x=tri.b.pos.x-tri.a.pos.x, .y=tri.b.pos.y-tri.a.pos.y};
  79.   const SDL_FPoint ac_vector={.x=tri.c.pos.x-tri.a.pos.x, .y=tri.c.pos.y-tri.a.pos.y};
  80.   const int isRightBend=((ab_vector.x*ac_vector.y)-(ab_vector.y*ac_vector.x)) > 0;
  81.   //tx(ty)=x0+(x1-x0)*(ty-x0)/(y1-y0)  ->  tx(ty)=x0+((x1-x0)/(y1-y0))*(ty-y0)
  82.    //(x1-x0)/(y1-y0) is a constant, so it can be pre-calculated
  83.   #define DT_INTERP_X(_ty, _start,_constant) ( _start.x + _constant*(_ty-_start.y) )
  84.   //const float ab_const_divisor=(tri.b.pos.y-tri.a.pos.y) ? tri.b.pos.y-tri.a.pos.y : 1e-7;
  85.   //const float bc_const_divisor=(tri.c.pos.y-tri.b.pos.y) ? tri.c.pos.y-tri.b.pos.y : 1e-7;
  86.   //const float ac_const_divisor=(tri.c.pos.y-tri.a.pos.y) ? tri.c.pos.y-tri.a.pos.y : 1e-7;
  87.   const float ab_const=(tri.b.pos.x-tri.a.pos.x)/(tri.b.pos.y-tri.a.pos.y);//ab_const_divisor;
  88.   const float bc_const=(tri.c.pos.x-tri.b.pos.x)/(tri.c.pos.y-tri.b.pos.y);//bc_const_divisor;
  89.   const float ac_const=(tri.c.pos.x-tri.a.pos.x)/(tri.c.pos.y-tri.a.pos.y);//ac_const_divisor;
  90.  
  91.   KIT_TTM_Vertex currentVert, endVert;
  92.   int scani=0, abi_max=tri.b.pos.y, bci_max=tri.c.pos.y;
  93.   KIT_TTM_Vertex* scanlineStart=canvas->userdata;
  94.   KIT_TTM_Vertex* scanlineEnd  =canvas->userdata+newsize;
  95.   SDL_Point a_int={.x=tri.a.pos.x, .y=tri.a.pos.y};
  96.   SDL_Point b_int={.x=tri.b.pos.x, .y=tri.b.pos.y};
  97.   //interpolate start and end points of each scanline
  98.   switch(same_y){
  99.   case 0b00: //-- -- (all points are on different scanlines)
  100.   case 0b01: //-- bc (bottom side is flat)
  101.     for(int abi=tri.a.pos.y; abi<abi_max; ++abi){
  102.       //a -> b
  103.       if(abi<0 || abi>=h) continue; //continue if y is outside canvas
  104.       currentVert.pos.x=DT_INTERP_X(abi, a_int,ab_const);
  105.       currentVert.pos.y=abi;
  106.       scanlineStart[scani]=currentVert;
  107.       //a -> c
  108.       currentVert.pos.x=DT_INTERP_X(abi, a_int,ac_const);
  109.       scanlineEnd[scani]=currentVert;
  110.       ++scani;
  111.     }
  112.     if(!same_y) goto top_side_flat; //if same_y==0b00, do both abi and bci loops
  113.     else break;
  114.   case 0b10: //ab -- (top side is flat)
  115.     top_side_flat:
  116.     for(int bci=tri.b.pos.y; bci<bci_max; ++bci){
  117.       //b -> c
  118.       if(bci<0 || bci>=h) continue;
  119.       currentVert.pos.x=DT_INTERP_X(bci, b_int,bc_const);
  120.       currentVert.pos.y=bci;
  121.       scanlineStart[scani]=currentVert;
  122.       //a -> c
  123.       currentVert.pos.x=DT_INTERP_X(bci, a_int,ac_const);
  124.       scanlineEnd[scani]=currentVert;
  125.       ++scani;
  126.     }
  127.     break;
  128.   case 0b11: //ab bc (all points are on the same scanline)
  129.     currentVert.pos.x=a_int.x;
  130.     currentVert.pos.y=a_int.y; //y should be same for c too
  131.     scanlineStart[scani]=currentVert;
  132.     currentVert.pos.x=(int)tri.c.pos.x;
  133.     scanlineEnd[scani++]=currentVert;
  134.     break;
  135.   }
  136.  
  137.   //if abc bend is right, then swap start and end of every scanline
  138.   if(isRightBend && same_y!=0b11){ //unless same_y==3 (only 1 scanline)
  139.     scanlineStart=canvas->userdata+newsize;
  140.     scanlineEnd=canvas->userdata;
  141.   }
  142.   //from the wikipedia article for lerp, it says this method doesn't guarantee
  143.    //that the output will be exactly v1 when t=1, but i'm ignoring the last
  144.    //iteration for x and y anyway, so t shouldn't ever actually be 1
  145.   #define DT_INTERP(_t, _start,_difference) ( _start + _t*_difference )
  146.   if(umt){ tex=umt->s_mKd; tex_pixels=tex->pixels; tex_w=tex->w; tex_h=tex->h; tex_pitch=tex->pitch; }
  147.   else { //missing material completely
  148.     for(int sli=0; sli<scani; ++sli){
  149.       currentVert=scanlineStart[sli]; //basically used as 'startVert' here
  150.       endVert=scanlineEnd[sli];
  151.       if(currentVert.pos.x>endVert.pos.x) KIT_TTM_Vertex_Swap(&currentVert,&endVert);
  152.       int x_max=endVert.pos.x, y_pos=currentVert.pos.y*rowlen;
  153.       for(int xi=currentVert.pos.x; xi<x_max; ++xi){
  154.         if(xi<0) continue;
  155.         else if (xi>=w) break;
  156.         pixels[y_pos+xi].value=0xffbf00bf;
  157.       }
  158.     }
  159.     for(int i=0; i<scani; ++i){
  160.       currentVert=scanlineStart[i];
  161.       if(IN_BOUNDS(currentVert.pos.x,currentVert.pos.y, w,h))
  162.         pixels[ARR2D_FLT(currentVert.pos.x,currentVert.pos.y, rowlen)].value=0xffffff00;//0xffff00ff;
  163.       currentVert=scanlineEnd[i];
  164.       if(IN_BOUNDS(currentVert.pos.x,currentVert.pos.y, w,h))
  165.         pixels[ARR2D_FLT(currentVert.pos.x,currentVert.pos.y, rowlen)].value=0xffffff00;//0xff7f007f;
  166.     }
  167.     /*
  168.     if(IN_BOUNDS(tri.a.pos.x,tri.a.pos.y, w,h))
  169.       pixels[ARR2D_FLT(tri.a.pos.x,tri.a.pos.y,w)].value=0xff0000ff;
  170.     if(IN_BOUNDS(tri.b.pos.x,tri.b.pos.y, w,h))
  171.       pixels[ARR2D_FLT(tri.b.pos.x,tri.b.pos.y,w)].value=0xff00ff00;
  172.     if(IN_BOUNDS(tri.c.pos.x,tri.c.pos.y, w,h))
  173.       pixels[ARR2D_FLT(tri.c.pos.x,tri.c.pos.y,w)].value=0xffff0000;*/
  174.   return;}
  175.   if(tex){ //material has diffuse texture
  176.   } else { //material lacks a diffuse texture; use only diffuse color
  177.   }
  178. }
  179. int notAShader3(KIT_TTM_Canvas3D* canvas, KIT_TTM* ttms,int ttms_len, void* data){
  180.   if(!canvas){ return 1; }  if(!ttms){ return 2; } if(!ttms_len){ return 3; }
  181.   float v_w=canvas->v_w, v_h=canvas->v_h; int w=canvas->w, h=canvas->h;
  182.   int w_half=w/2, h_half=h/2;
  183.   KIT_TTM_LockCanvas3D(canvas);
  184.   for(uint32_t ttm_i=0; ttm_i<ttms_len; ++ttm_i){//for every ttm
  185.   uint32_t objects_len=ttms[ttm_i].objects_len;
  186.   for(uint32_t obj_i=0; obj_i<objects_len; ++obj_i){//for every object
  187.     KIT_TTM_Object* object=&ttms[ttm_i].objects[obj_i];
  188.       uint32_t numWorkTris=object->numWorkTris;
  189.       if(numWorkTris==0) continue;
  190.     KIT_TTM_Triangle* render=object->render;
  191.       memcpy(render,object->work,sizeof(KIT_TTM_Triangle)*numWorkTris);
  192.     for(uint32_t tri_i=0; tri_i<numWorkTris; ++tri_i){//for every triangle
  193.       KIT_TTM_Triangle tri=render[tri_i];
  194.       tri=KIT_TTM_ProjectTriangle(tri, w_half,h_half, v_w,v_h);
  195.       drawTriangle(canvas, tri,NULL);//object->umt);
  196.     }
  197.   }}
  198.   if(canvas->autoUnlock) KIT_TTM_UnlockCanvas3D(canvas);
  199.   return 0;
  200. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement