int main() { int exit = 0; MAP* map = load_map("zaza.wad"); init(); clock_t last_clock = clock(); while(!exit) { clock_t now = clock(); float dt = (float)(now - last_clock) / CLOCKS_PER_SEC; last_clock = now; VEC2F view_dir = vec2f(cos(ang), sin(ang)); VEC2F view_dir_norm = vec2f(-view_dir.y, view_dir.x); if(key[KEY_ESC]) exit = 1; if(key[KEY_S]) vp = vec2f_sum(vp, vec2f_uscale(view_dir, -move_speed * dt)); if(key[KEY_W]) vp = vec2f_sum(vp, vec2f_uscale(view_dir, move_speed * dt)); if(key[KEY_A]) vp = vec2f_sum(vp, vec2f_uscale(view_dir_norm, -move_speed * dt)); if(key[KEY_D]) vp = vec2f_sum(vp, vec2f_uscale(view_dir_norm, move_speed * dt)); if(key[KEY_LEFT]) ang -= rot_speed * dt; if(key[KEY_RIGHT]) ang += rot_speed * dt; clear_to_color(buffer, makecol(64, 64, 64)); SECTOR* s = find_sector(map, map->node_num - 1, vp); float h = s->floor_height + 45; int i = 0; for(i = 0; i < H_RES; ++i) { float t = i - H_RES / 2; float u = FOCAL_DIST; VEC2F ray_dir = vec2f_sum(vec2f_uscale(view_dir, u), vec2f_uscale(view_dir_norm, t)); //vec2f(view_dir.x * FOCAL_DIST + view_dir_norm.x * t, view_dir.y * FOCAL_DIST + view_dir_norm.y * t); float ray_len = sqrt(ray_dir.x * ray_dir.x + ray_dir.y * ray_dir.y); ray_dir.x /= ray_len; ray_dir.y /= ray_len; int minh = 0; int maxh = SCREEN_H; render_col(buffer, map, map->node_num - 1, vp, -h, ray_dir, i, &minh, &maxh); printf("\n"); //line(buffer, SCREEN_W / 2, SCREEN_H / 2, SCREEN_W / 2 + ray_dir.x * 200, SCREEN_H / 2 + ray_dir.y * 200, makecol(255, 255, 255)); } draw_sprite(buffer, mouse_sprite, mouse_x, mouse_y); blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); } destroy_map(map); deinit(); return 0; }END_OF_MAIN()
/* ** Triangles passed to this function have already been clipped by ** the clip box. */ static void render_triangle_1(WILLUSBITMAP *bmap,TRIANGLE2D *srctri, RENDER_COLOR *rcolor, RENDER_COLOR *bgcolor,int render_type) { TRIANGLE2D *tri,_tri; int row,bottom_row,top_row; /* { int i; printf("@render_triangle_1\n"); for (i=0;i<4;i++) printf("%6.4f %6.4f\n",srctri->p[i%3].x*bmap->width,srctri->p[i%3].y*bmap->height); printf("//nc\n"); } */ if (render_type==RENDER_TYPE_SET) { render_triangle_2(bmap,srctri,rcolor); return; } tri=&_tri; if (tri2d_zero_area(srctri)) return; (*tri)=(*srctri); tri2d_sort_ypoints(tri); bottom_row = render_row(bmap,tri->p[0].y); top_row = render_row(bmap,tri->p[2].y); for (row=bottom_row;row<=top_row;row++) { int nx,i,j,k,col,left_col,right_col; double y0,y1; static double x[9]; // printf("row=%d\n",row); y0 = (double)row/bmap->height; y1 = (double)(row+1)/bmap->height; i=0; /* Create array of possible extreme x-coords */ /* Triangle vertices */ for (j=0;j<3;j++) if (y0<=tri->p[j].y && y1>=tri->p[j].y) x[i++] = tri->p[j].x; /* Segments intercepting y0 */ for (j=0;j<2;j++) for (k=j+1;k<3;k++) if (tri->p[j].y < y0 && tri->p[k].y > y0) x[i++] = p2d_x_intercept(y0,tri->p[j],tri->p[k]); /* Segments intercepting y1 */ for (j=0;j<2;j++) for (k=j+1;k<3;k++) if (tri->p[j].y < y1 && tri->p[k].y > y1) x[i++] = p2d_x_intercept(y1,tri->p[j],tri->p[k]); nx=i; left_col = render_col(bmap,array_min(x,nx)); right_col = render_col(bmap,array_max(x,nx)); // printf(" %d to %d\n",left_col,right_col); for (col=left_col;col<=right_col;col++) { if (render_type==RENDER_TYPE_ANTIALIASED) render_pixelset(bmap,col,row,rcolor, render_type,bgcolor, tri2d_intersection_area(bmap,tri,row,col)); else if (render_pixel_contained(bmap,tri,row,col)) render_pixelset(bmap,col,row,rcolor, render_type,bgcolor,1.); } } }
void render_col(BITMAP* buffer, MAP* map, short idx, VEC2F vp, float cam_h, VEC2F ray_dir, int col) { if(idx & SHORT_SIGN_FLAG) { //printf("ASDF = %d %d\n", (short)(idx & ~SHORT_SIGN_FLAG), idx); SSECTOR* ssector = &map->ssectors[(short)(idx & ~SHORT_SIGN_FLAG)]; int i; for(i = 0; i < ssector->seg_num; ++i) { SEG* seg = &map->segs[ssector->first_seg_idx + i]; VEC2F v1 = get_vertex(map, seg->v1_idx); VEC2F v2 = get_vertex(map, seg->v2_idx); RAY_VS_SEGMENT_RESULT res = ray_vs_segment(v1, v2, vp, ray_dir); VEC2F n = vec2f(v1.y - v2.y, v2.x - v1.x); LINEDEF* linedef = &map->linedefs[seg->linedef_idx]; SIDEDEF *sidedef1, *sidedef2; SECTOR *sector1, *sector2; if(seg->dir) { sidedef1 = &map->sidedefs[linedef->neg_sidedef_idx]; sector1 = &map->sectors[sidedef1->sector_idx]; sidedef2 = linedef->pos_sidedef_idx == -1 ? NULL : &map->sidedefs[linedef->pos_sidedef_idx]; sector2 = linedef->pos_sidedef_idx == -1 ? NULL : &map->sectors[sidedef2->sector_idx]; } else { sidedef1 = &map->sidedefs[linedef->pos_sidedef_idx]; sector1 = &map->sectors[sidedef1->sector_idx]; sidedef2 = linedef->neg_sidedef_idx == -1 ? NULL : &map->sidedefs[linedef->neg_sidedef_idx]; sector2 = linedef->neg_sidedef_idx == -1 ? NULL : &map->sectors[sidedef2->sector_idx]; } //printf("%c%c%c%c%c%c%c%c\n", sidedef->mid_tex_name[0], sidedef->mid_tex_name[1], //sidedef->mid_tex_name[2], sidedef->mid_tex_name[3], sidedef->mid_tex_name[4], sidedef->mid_tex_name[5], //sidedef->mid_tex_name[6], sidedef->mid_tex_name[7]); if(res.t > 10 && res.k >= 0 && res.k <= 1.0 && vec2f_dot(n, vec2f_diff(vp, v1)) < 0) { VEC2F d = vec2f_diff(v2, v1); VEC2F wall_normal = vec2f(-d.y, d.x); float wall_len = sqrt(d.x * d.x + d.y * d.y); wall_normal.x /= wall_len; wall_normal.y /= wall_len; int r = clamp255((int)(fabs(wall_normal.x) * 4000 / sqrt(res.t))); int g = clamp255((int)(fabs(wall_normal.y) * 4000 / sqrt(res.t))); int color = makecol(r, g, 0); if(sidedef1 && !sidedef2) render_col_helper(col, sector1->ceil_height + cam_h, sector1->floor_height + cam_h, res.t, color); else { render_col_helper(col, sector2->ceil_height + cam_h, sector1->ceil_height + cam_h, res.t, color); render_col_helper(col, sector2->floor_height + cam_h, sector1->floor_height + cam_h, res.t, color); if(sidedef1->mid_tex_name[0] != '-') render_col_helper(col, sector1->floor_height + cam_h, sector1->ceil_height + cam_h, res.t, color); } } } // render subsector... } else { NODE* node = &map->nodes[idx]; VEC2F n = vec2f(-node->y2, node->x2); if(vec2f_dot(n, vec2f(vp.x - node->x1, vp.y - node->y1)) >= 0) { render_col(buffer, map, node->left_child_idx, vp, cam_h, ray_dir, col); render_col(buffer, map, node->right_child_idx, vp, cam_h, ray_dir, col); } else { render_col(buffer, map, node->right_child_idx, vp, cam_h, ray_dir, col); render_col(buffer, map, node->left_child_idx, vp, cam_h, ray_dir, col); } } }
int main() { int exit = 0; MAP* map = load_map("e1m1.wad"); VEC2F vp = vec2f(0.f, 0.f); float ang, move_speed = 200.f, rot_speed = 2.5f; init(); //VEC2F vn = vec2f(-v.y, v.x); //VEC2F ray_dir = vec2f(); //short s = -1; //s &= ~(1 << 15); //printf("ZOMG = %d\n", s); clock_t last_clock = clock(); while(!exit) { clock_t now = clock(); float dt = (float)(now - last_clock) / CLOCKS_PER_SEC; last_clock = now; VEC2F view_dir = vec2f(cos(ang), sin(ang)); VEC2F view_dir_norm = vec2f(-view_dir.y, view_dir.x); if(key[KEY_ESC]) exit = 1; if(key[KEY_S]) vp = vec2f_sum(vp, vec2f_uscale(view_dir, -move_speed * dt)); if(key[KEY_W]) vp = vec2f_sum(vp, vec2f_uscale(view_dir, move_speed * dt)); if(key[KEY_A]) vp = vec2f_sum(vp, vec2f_uscale(view_dir_norm, -move_speed * dt)); if(key[KEY_D]) vp = vec2f_sum(vp, vec2f_uscale(view_dir_norm, move_speed * dt)); if(key[KEY_LEFT]) ang -= rot_speed * dt; if(key[KEY_RIGHT]) ang += rot_speed * dt; clear_to_color(buffer, 0); SECTOR* s = find_sector(map, map->node_num - 1, vp); float h = s->floor_height + 45; int i; for(i = 0; i < H_RES; ++i) { float t = i - H_RES / 2; float u = FOCAL_DIST; VEC2F ray_dir = vec2f_sum(vec2f_uscale(view_dir, u), vec2f_uscale(view_dir_norm, t)); //vec2f(view_dir.x * FOCAL_DIST + view_dir_norm.x * t, view_dir.y * FOCAL_DIST + view_dir_norm.y * t); float ray_len = sqrt(ray_dir.x * ray_dir.x + ray_dir.y * ray_dir.y); ray_dir.x /= ray_len; ray_dir.y /= ray_len; render_col(buffer, map, map->node_num - 1, vp, -h, ray_dir, i); //line(buffer, SCREEN_W / 2, SCREEN_H / 2, SCREEN_W / 2 + ray_dir.x * 200, SCREEN_H / 2 + ray_dir.y * 200, makecol(255, 255, 255)); } if(key[KEY_TAB]) for(i = 0; i < map->seg_num; ++i) { VERTEX v1t = map->vertexes[map->segs[i].v1_idx]; VERTEX v2t = map->vertexes[map->segs[i].v2_idx]; VEC2F v1 = vec2f(v1t.x, v1t.y); VEC2F v2 = vec2f(v2t.x, v2t.y); VEC2F mid = vec2f((v1.x + v2.x) / 2, (v1.y + v2.y) / 2); VEC2F n = normalized_normal(vec2f_diff(v2, v1)); float scl = 1.f / 2.f; line(buffer, v1.x*scl + SCREEN_W / 2, v1.y*scl + SCREEN_H / 2, v2.x*scl + SCREEN_W / 2, v2.y*scl + SCREEN_H / 2, makecol(255, 255, 255)); circlefill(buffer, (int)vp.x*scl + SCREEN_W/2, (int)vp.y*scl +SCREEN_H/2, 3, makecol(255, 255, 255)); line(buffer, SCREEN_W/2+ mid.x*scl, SCREEN_H/2 + mid.y*scl, SCREEN_W/2+ (mid.x + n.x * 10)*scl, SCREEN_H/2+ (mid.y + n.y * 10)*scl, makecol(255, 255, 255)); line(buffer, SCREEN_W/2+vp.x*scl, SCREEN_H/2+vp.y*scl, SCREEN_W/2+(vp.x+view_dir.x*100)*scl, SCREEN_H/2+(vp.y+view_dir.y*100)*scl, makecol(255, 255, 255)); } // draw_sprite(buffer, mouse_sprite, mouse_x, mouse_y); blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); } destroy_map(map); deinit(); return 0; }END_OF_MAIN()
void render_col(BITMAP* buffer, MAP* map, short idx, VEC2F vp, float cam_h, VEC2F ray_dir, int col, int* minh, int* maxh) { if(idx & SHORT_SIGN_FLAG) { //printf("ASDF = %d %d\n", (short)(idx & ~SHORT_SIGN_FLAG), idx); SSECTOR* ssector = &map->ssectors[(short)(idx & ~SHORT_SIGN_FLAG)]; int i; for(i = 0; i < ssector->seg_num; ++i) { SEG* seg = &map->segs[ssector->first_seg_idx + i]; VEC2F v1 = get_vertex(map, seg->v1_idx); VEC2F v2 = get_vertex(map, seg->v2_idx); RAY_VS_SEGMENT_RESULT res = ray_vs_segment(v1, v2, vp, ray_dir); VEC2F n = vec2f(v1.y - v2.y, v2.x - v1.x); LINEDEF* linedef = &map->linedefs[seg->linedef_idx]; SIDEDEF *sidedef1, *sidedef2; SECTOR *sector1, *sector2; if(seg->dir) { sidedef1 = &map->sidedefs[linedef->neg_sidedef_idx]; sector1 = &map->sectors[sidedef1->sector_idx]; sidedef2 = linedef->pos_sidedef_idx == -1 ? NULL : &map->sidedefs[linedef->pos_sidedef_idx]; sector2 = linedef->pos_sidedef_idx == -1 ? NULL : &map->sectors[sidedef2->sector_idx]; } else { sidedef1 = &map->sidedefs[linedef->pos_sidedef_idx]; sector1 = &map->sectors[sidedef1->sector_idx]; sidedef2 = linedef->neg_sidedef_idx == -1 ? NULL : &map->sidedefs[linedef->neg_sidedef_idx]; sector2 = linedef->neg_sidedef_idx == -1 ? NULL : &map->sectors[sidedef2->sector_idx]; } //printf("%c%c%c%c%c%c%c%c\n", sidedef->mid_tex_name[0], sidedef->mid_tex_name[1], //sidedef->mid_tex_name[2], sidedef->mid_tex_name[3], sidedef->mid_tex_name[4], sidedef->mid_tex_name[5], //sidedef->mid_tex_name[6], sidedef->mid_tex_name[7]); if(res.t > 0 && res.k >= 0 && res.k <= 1.0) { // VEC2F d = vec2f_diff(v2, v1); //VEC2F wall_normal = vec2f(-d.y, d.x); //float wall_len = sqrt(d.x * d.x + d.y * d.y); //wall_normal.x /= wall_len; //wall_normal.y /= wall_len; //int r = clamp255((int)(fabs(wall_normal.x) * 4000 / sqrt(res.t))); //int g = clamp255((int)(fabs(wall_normal.y) * 4000 / sqrt(res.t))); int color = random_colors[(ssector->first_seg_idx + i) % RANDOM_COLOR_NUM];//makecol(r, g, 0); if(sidedef1 && !sidedef2) { //render_col_helper(col, sector1->ceil_height + cam_h, sector1->floor_height + cam_h, res.t, color); float top_y = sector1->ceil_height - cam_h; float bottom_y = sector1->floor_height - cam_h; float z = res.t; float top_h = MAX(SCREEN_H / 2 + top_y / z * FOCAL_DIST, *minh); float bottom_h = MIN(SCREEN_H / 2 + bottom_y / z * FOCAL_DIST, *maxh); printf("%f %f\n", top_h, bottom_h); //if(bottom_h >= top_h) { if(vec2f_dot(n, vec2f_diff(vp, v1)) < 0) rectfill(buffer, col * 2, (int)top_h/2*2, col * 2 + 2, (int)bottom_h/2*2, color); } *minh = MAX(*minh, bottom_h); *maxh = MIN(*maxh, top_h); } else { float y0 = sector1->ceil_height - cam_h; float y1 = sector2->ceil_height - cam_h; float z = res.t; float h1 = MAX(SCREEN_H / 2 + y0 * FOCAL_DIST / z, *minh); float h2 = MIN(SCREEN_H / 2 + y1 * FOCAL_DIST / z, *maxh); if(h2 >= h1) { if(vec2f_dot(n, vec2f_diff(vp, v1)) < 0) rectfill(buffer, col * 2, (int)h1/2*2, col * 2 + 2, (int)h2/2*2, color); } *minh = MAX(*minh, h1); y0 = sector2->floor_height - cam_h; y1 = sector1->floor_height - cam_h; h1 = MAX(SCREEN_H / 2 + y0 * FOCAL_DIST / z, *minh); h2 = MIN(SCREEN_H / 2 + y1 * FOCAL_DIST / z, *maxh); if(h2 >= h1) { if(vec2f_dot(n, vec2f_diff(vp, v1)) < 0) rectfill(buffer, col * 2, (int)h1/2*2, col * 2 + 2, (int)h2/2*2, color); } *maxh = MIN(*maxh, h2); } } } // render subsector... } else { NODE* node = &map->nodes[idx]; VEC2F n = vec2f(-node->y2, node->x2); if(vec2f_dot(n, vec2f(vp.x - node->x1, vp.y - node->y1)) < 0) { render_col(buffer, map, node->left_child_idx, vp, cam_h, ray_dir, col, minh, maxh); render_col(buffer, map, node->right_child_idx, vp, cam_h, ray_dir, col, minh, maxh); } else { render_col(buffer, map, node->right_child_idx, vp, cam_h, ray_dir, col, minh, maxh); render_col(buffer, map, node->left_child_idx, vp, cam_h, ray_dir, col, minh, maxh); } } }