#include #include #include #include "jdebug.h" #include "util.h" #include "draw.h" #include "wad.h" #include #include #define FOV 277 std::vector verts; struct wall { Uint16 v1 {0}; Uint16 v2 {0}; vec2 normal {0.0f, 0.0f}; float u1 {0.0f}; float u2 {0.0f}; int portal {-1}; draw::surface_t *surf {nullptr}; draw::surface_t *upper_surf {nullptr}; draw::surface_t *lower_surf {nullptr}; }; struct sector { float floor_height {0.0f}; float ceiling_height {64.0f}; draw::surface_t *floor_surf {nullptr}; draw::surface_t *ceil_surf {nullptr}; std::vector walls; }; std::vector sectors; int current_sector = 38; int current_sector2 = 38; vec2 position = { 1056.0f, -3616.0f }; float height = 48.0f; float real_height = 48.0f; float orientation = 270.0f; float accel = 500.0f; float speed = 0.0f; float max_speed = 200.0f; float rspeed = 200.0f; float bobbing = 0.0f; float dt; Uint32 *palette; //draw::surface_t *gif; draw::surface_t *spr; #pragma pack(push, 1) struct sidedef { int16_t xoffset; int16_t yoffset; char upper_texture[8]; char lower_texture[8]; char middle_texture[8]; int16_t sector; }; #pragma pack(pop) void loadMap(const char* name) { int size; int16_t *vertices = (int16_t *)wad::load(name, "VERTEXES", &size); const int num_vertices = size/4; for (int i=0;iw : w.upper_surf ? w.upper_surf->w : w.lower_surf ? w.lower_surf->w : 64; SDL_assert(width>=0); w.u2 = distance(verts[w.v1], verts[w.v2]) / width; //w.v2 = distance(s.verts[w.v1], s.verts[w.v2]) / 32.0f; vec2 norm = { verts[w.v2].x - verts[w.v1].x, verts[w.v2].y - verts[w.v1].y}; normalize(&norm); const float tmp = norm.x; norm.x = -norm.y; norm.y = tmp; w.normal = norm; } } } /* void createMap() { current_sector = 0; { sector s; s.floor_height = 32.0f; s.ceiling_height = 96.0f; s.floor_surf = wad::loadFlat("FLOOR4_8"); s.ceil_surf = wad::loadFlat("CEIL3_1"); s.verts.push_back({ 64.0f, 0.0f}); s.verts.push_back({256.0f, 0.0f}); s.verts.push_back({256.0f, 64.0f}); s.verts.push_back({320.0f, 64.0f}); s.verts.push_back({320.0f, 320.0f}); s.verts.push_back({ 0.0f, 320.0f}); s.verts.push_back({ 0.0f, 64.0f}); s.verts.push_back({ 64.0f, 64.0f}); s.walls.push_back({0,1,{0,0},0.0f,0.0f, 1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({1,2,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({2,3,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({3,4,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({4,5,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({5,6,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({6,7,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({7,0,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); sectors.push_back(s); } { sector s; s.floor_height = 0.0f; s.ceiling_height = 128.0f; s.floor_surf = wad::loadFlat("FLOOR4_8"); s.ceil_surf = wad::loadFlat("CEIL3_1"); s.verts.push_back({256.0f, 0.0f}); s.verts.push_back({ 64.0f, 0.0f}); s.verts.push_back({ 64.0f,-256.0f}); s.verts.push_back({256.0f,-256.0f}); s.verts.push_back({128.0f,-128.0f}); s.verts.push_back({192.0f,-128.0f}); s.verts.push_back({192.0f,-192.0f}); s.verts.push_back({128.0f,-192.0f}); s.walls.push_back({0,1,{0,0},0.0f,0.0f, 0, wad::loadTexture("BROWNPIP")}); s.walls.push_back({1,2,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({2,3,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({3,0,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({4,5,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({5,6,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({6,7,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); s.walls.push_back({7,4,{0,0},0.0f,0.0f,-1, wad::loadTexture("BROWNPIP")}); sectors.push_back(s); } for (auto &s : sectors ) { for (auto &w : s.walls ) { w.u2 = distance(s.verts[w.v1], s.verts[w.v2]) / w.surf->w; //w.v2 = distance(s.verts[w.v1], s.verts[w.v2]) / 32.0f; vec2 norm = { s.verts[w.v2].x - s.verts[w.v1].x, s.verts[w.v2].y - s.verts[w.v1].y}; normalize(&norm); const float tmp = norm.x; norm.x = -norm.y; norm.y = tmp; w.normal = norm; } } } */ int actual_sector = -1; int last_sector = -1; void drawColumn(sector &s, int screen_column, int start, int end, float a_inc, vec2 infi) { const float angle = orientation + a_inc; vec2 normal = { SDL_cosf(angle*DEG_TO_RAD), SDL_sinf(angle*DEG_TO_RAD) }; vec2 result, tmp_result; wall *w = nullptr; float stright_dist=100000.0f; for (auto &wall : s.walls) { if (dot(normal, wall.normal) >= 0) continue; if (get_line_intersection(position, infi, verts[wall.v1], verts[wall.v2], &tmp_result)) { const float d = distance(position, tmp_result);// * SDL_cosf(a_inc*DEG_TO_RAD); if (dh; //64; const float sector_height = s.ceiling_height - s.floor_height; const int width = w->surf ? w->surf->w : w->upper_surf ? w->upper_surf->w : w->lower_surf ? w->lower_surf->w : 64; draw::map::putp(result.x, result.y, 6); float dist = stright_dist * SDL_cosf(a_inc*DEG_TO_RAD); const vec2 AB = {verts[w->v2].x-verts[w->v1].x, verts[w->v2].y-verts[w->v1].y}; const vec2 AP = {result.x-verts[w->v1].x, result.y-verts[w->v1].y}; float v = dot(AP,AB) / dot(AB,AB); v *= w->u2; v = v*width; //w->surf->w; //(v-int(v))*gif->w; float wall_height = (sector_height*FOV)/dist; // [64=altura sector] float wall_cut = 0.0f; float dpix = sector_height/wall_height; // [64=crec que altura sector] float cpix = 0; float wall_start = 120-(wall_height/sector_height)*(sector_height-(height-s.floor_height)); // [64=els dos crec que altura sector] if (wall_start> 1)); float actual_dist = straight_dist / SDL_cosf(a_inc*DEG_TO_RAD); int tx = SDL_abs(int(actual_dist * SDL_cosf(angle*DEG_TO_RAD) - position.x)) % s.ceil_surf->w; int ty = SDL_abs(int(actual_dist * SDL_sinf(angle*DEG_TO_RAD) - position.y)) % s.ceil_surf->h; draw::putpd(screen_column, y, s.ceil_surf->pixels[tx+ty*s.ceil_surf->w], -straight_dist); } if (w->portal == -1) { // Pinta la pared draw::surface_t *surf = w->surf; if (surf) { for (int i=0; i=end) break; draw::putpd(screen_column, wall_start+i, surf->pixels[(int(v)%surf->w)+(int(cpix)%surf->h)*surf->w], stright_dist); cpix += dpix; } } } else { if (sectors[w->portal].ceiling_height < s.ceiling_height) { float upper_height = s.ceiling_height - sectors[w->portal].ceiling_height; float upper_wall_height = (upper_height*FOV)/dist; upper_wall_height -= wall_cut; if (upper_wall_height>0.0f) { // Pinta la pared for (int i=0; i=end) break; draw::putpd(screen_column, wall_start+i, w->surf->pixels[(int(v)%w->surf->w)+(int(cpix)%w->surf->h)*w->surf->w], stright_dist); cpix += dpix; } wall_start += upper_wall_height; wall_height -= upper_wall_height; } } float lower_height = sectors[w->portal].floor_height - s.floor_height; float lower_wall_height = (lower_height*FOV)/dist; int wall_end = wall_start+wall_height+1; if (lower_wall_height>0.0f) wall_end -= lower_wall_height; wall_end = SDL_min(wall_end, end); //SDL_assert(&s != §ors[w->portal]); printf("Anem al sector: %i\n", w->portal); //SDL_assert(w->portal != last_sector); last_sector = actual_sector; actual_sector = w->portal; drawColumn(sectors[w->portal], screen_column, wall_start, wall_end, a_inc, infi); if (lower_wall_height>0.0f) { cpix += (wall_height-lower_wall_height)*dpix; // Pinta la pared for (int i=0; i=end) break; draw::putpd(screen_column, wall_end+i, w->surf->pixels[(int(v)%w->surf->w)+(int(cpix)%w->surf->h)*w->surf->w], stright_dist); cpix += dpix; } //wall_start += upper_wall_height; //wall_height -= upper_wall_height; } } // Pinta el piso int paint_end = wall_start+wall_height-1; for (int y=paint_end+1; y> 1)); float actual_dist = straight_dist / SDL_cosf(a_inc*DEG_TO_RAD); int tx = SDL_abs(int(actual_dist * SDL_cosf(angle*DEG_TO_RAD) + position.x)) % s.floor_surf->w; int ty = SDL_abs(int(actual_dist * SDL_sinf(angle*DEG_TO_RAD) + position.y)) % s.floor_surf->h; draw::putpd(screen_column, y, s.floor_surf->pixels[tx+ty*s.floor_surf->w], straight_dist); } //line(screen_column, 120-(wall_height), screen_column, 120+(wall_height), 5); } } bool tryMove(float angle, float speed) { float sign = speed > 0 ? 1.0f : -1.0f; bool moved = false; sector &s = sectors[current_sector]; vec2 newpos = { position.x + SDL_cosf(angle*DEG_TO_RAD)*5*sign, position.y }; bool collision=false; for (auto w : s.walls) { if (get_line_intersection(position, newpos, verts[w.v1], verts[w.v2], NULL)) { if (w.portal != -1) { newpos.x = position.x + SDL_cosf(angle*DEG_TO_RAD)*dt*speed; if (get_line_intersection(position, newpos, verts[w.v1], verts[w.v2], NULL) ) current_sector = w.portal; } else { collision=true; } break; } } if (!collision) { moved = true; position.x += SDL_cosf(angle*DEG_TO_RAD)*dt*speed; } newpos = { position.x, position.y + SDL_sinf(angle*DEG_TO_RAD)*5*sign }; collision=false; for (auto w : s.walls) { if (get_line_intersection(position, newpos, verts[w.v1], verts[w.v2], NULL)) { if (w.portal != -1) { newpos.y = position.y + SDL_sinf(angle*DEG_TO_RAD)*dt*speed; if (get_line_intersection(position, newpos, verts[w.v1], verts[w.v2], NULL) ) current_sector = w.portal; } else { collision=true; } break; } } if (!collision) { moved = true; position.y += SDL_sinf(angle*DEG_TO_RAD)*dt*speed; } return moved; } int main(int argc, char *argv[]) { wad::init("doom1.wad"); draw::init(); //gif = draw::loadgif("walls.gif"); //gif = wad::loadFlat("FLOOR4_8"); //gif = wad::loadTexture("BROWNPIP"); //gif = wad::loadPatch("LADDER16"); //palette = draw::loadpal("walls.gif"); palette = wad::loadPalette(0); draw::setpal(palette); spr = draw::loadgif("player1.gif"); // [DEBUG] Paleta per al depth buffer //for(int i=0;i<256;++i) palette[i] = (255-i) | ((255-i)<<8) | ((255-i)<<16); //createMap(); loadMap("E1M1"); SDL_Event e; bool should_exit = false; Uint32 millis = SDL_GetTicks(); int fps = 0; int fps_count = 0; int fps_time = SDL_GetTicks(); while (!should_exit) { dt = float(SDL_GetTicks() - millis)/1000.0f; millis = SDL_GetTicks(); bobbing += dt*1000.0f; height = real_height + SDL_sinf(bobbing*DEG_TO_RAD)*(speed/100.0f); while (SDL_PollEvent(&e)) { if (e.type==SDL_EVENT_QUIT) { should_exit=true; break; } if (e.type==SDL_EVENT_KEY_DOWN && e.key.scancode==SDL_SCANCODE_ESCAPE) { should_exit=true; break; } if (e.type==SDL_EVENT_MOUSE_WHEEL) { if (e.wheel.y>0) current_sector2++; else current_sector2--; printf("Current sector: %i\n", current_sector2); } } const bool *keys = SDL_GetKeyboardState(NULL); if (keys[SDL_SCANCODE_Q]) { real_height += dt*100.0f; } if (keys[SDL_SCANCODE_A]) { real_height -= dt*100.0f; } if (keys[SDL_SCANCODE_W]) { //real_height += dt*100.0f; sectors[0].ceiling_height -= dt*100.0f; sectors[1].ceiling_height -= dt*100.0f; sectors[0].floor_height -= dt*100.0f; sectors[1].floor_height -= dt*100.0f; } if (keys[SDL_SCANCODE_S]) { //real_height -= dt*100.0f; sectors[0].ceiling_height += dt*100.0f; sectors[1].ceiling_height += dt*100.0f; sectors[0].floor_height += dt*100.0f; sectors[1].floor_height += dt*100.0f; } if (keys[SDL_SCANCODE_RIGHT]) { orientation += dt*rspeed; } else if (keys[SDL_SCANCODE_LEFT]) { orientation -= dt*rspeed; } if (keys[SDL_SCANCODE_UP]) { if (speed < max_speed) speed += dt*accel; } else if (keys[SDL_SCANCODE_DOWN]) { if (speed > -max_speed) speed -= dt*accel; } else { if (speed > 0.0f) { speed -= dt*accel; if (speed < 0.0f) speed = 0.0f; } if (speed < 0.0f) { speed += dt*accel; if (speed > 0.0f) speed = 0.0f; } } if (speed != 0.0f) if (!tryMove(orientation, speed)) speed = 0.0f; draw::cls(); sector &s = sectors[current_sector]; actual_sector = current_sector; //printf("Current sector: %i\n", current_sector); // Clear screen //SDL_memset4(screen, 0x00000000, (320*240)>>2); int screen_column = 0; for (float a_inc=-32.0f; a_inc<=32.0f; a_inc+=0.2f) { const float angle = orientation + a_inc; vec2 infi; infi.x = position.x + SDL_cosf(angle*DEG_TO_RAD)*40000; infi.y = position.y + SDL_sinf(angle*DEG_TO_RAD)*40000; //printf("Column %i...\n", screen_column); drawColumn(s, screen_column, 0, 240, a_inc, infi); screen_column++; } debug::print("angle:");debug::print(orientation);debug::newline(); vec2 enemy = {256.0f, 256.0f}; draw::map::putp(enemy.x, enemy.y, 9); float angle_to_enemy = is_enemy_in_fov(position.x, position.y, orientation, enemy.x, enemy.y); if (SDL_fabsf(angle_to_enemy) <= 64.0f) { const float d = distance(position, enemy);// * SDL_cosf(a_inc*DEG_TO_RAD); float dist = d * SDL_cosf(angle_to_enemy*DEG_TO_RAD); float wall_height = (32.0f*FOV)/dist; float wall_start = 120-(wall_height/32.0f)*(32.0f-(height-sectors[0].floor_height)); debug::println("enemy height: ", wall_height); debug::println("enemy start: ", wall_start); int column = int((angle_to_enemy+32.0f)/0.2f); for (int i=0; i=0 && c<320) { for (int j=0;j>4)*2, i); draw::putp((i&0xf)*2+1, (i>>4)*2, i); draw::putp((i&0xf)*2+1, (i>>4)*2+1, i); draw::putp((i&0xf)*2, (i>>4)*2+1, i); } draw::render(); fps_count++; if (SDL_GetTicks()-fps_time>=1000) { fps = fps_count; fps_count = 0; fps_time = SDL_GetTicks(); } debug::println("fps:", fps); debug::println("sector:", current_sector); debug::println("height:", real_height); debug::println("ceil_height:", sectors[0].ceiling_height); debug::println("floor_height:", sectors[0].floor_height); debug::render(); draw::flip(); } return 0; }