1
0
mirror of https://github.com/ssloy/tinyraycaster.git synced 2025-08-15 10:33:59 +02:00

Few bugfixes (e.g. FPS control); SDL knows to load .bmp files, so I remove the dependency to stb_image.h, because it is slow to compile

This commit is contained in:
Dmitry V. Sokolov
2019-02-10 09:54:12 +01:00
parent bb8b2f4ca1
commit da425dbe9f
6 changed files with 62 additions and 7507 deletions

41
gui.cpp
View File

@@ -9,6 +9,11 @@
#include "tinyraycaster.h" #include "tinyraycaster.h"
int main() { int main() {
if (SDL_Init(SDL_INIT_VIDEO)) {
std::cerr << "Failed to initialize SDL: " << SDL_GetError() << std::endl;
return -1;
}
FrameBuffer fb{1024, 512, std::vector<uint32_t>(1024*512, pack_color(255, 255, 255))}; FrameBuffer fb{1024, 512, std::vector<uint32_t>(1024*512, pack_color(255, 255, 255))};
GameState gs{ Map(), // game map GameState gs{ Map(), // game map
{3.456, 2.345, 1.523, M_PI/3., 0, 0}, // player {3.456, 2.345, 1.523, M_PI/3., 0, 0}, // player
@@ -17,8 +22,8 @@ int main() {
{5.323, 5.365, 1, 0}, {5.323, 5.365, 1, 0},
{14.32, 13.36, 3, 0}, {14.32, 13.36, 3, 0},
{4.123, 10.76, 1, 0} }, {4.123, 10.76, 1, 0} },
Texture("../walltext.png"), // textures for the walls Texture("../walltext.bmp", SDL_PIXELFORMAT_ABGR8888), // textures for the walls
Texture("../monsters.png") }; // textures for the monsters Texture("../monsters.bmp", SDL_PIXELFORMAT_ABGR8888)}; // textures for the monsters
if (!gs.tex_walls.count || !gs.tex_monst.count) { if (!gs.tex_walls.count || !gs.tex_monst.count) {
std::cerr << "Failed to load textures" << std::endl; std::cerr << "Failed to load textures" << std::endl;
return -1; return -1;
@@ -27,30 +32,32 @@ int main() {
SDL_Window *window = nullptr; SDL_Window *window = nullptr;
SDL_Renderer *renderer = nullptr; SDL_Renderer *renderer = nullptr;
if (SDL_Init(SDL_INIT_VIDEO)) {
std::cerr << "Couldn't initialize SDL: " << SDL_GetError() << std::endl;
return -1;
}
if (SDL_CreateWindowAndRenderer(fb.w, fb.h, SDL_WINDOW_SHOWN | SDL_WINDOW_INPUT_FOCUS, &window, &renderer)) { if (SDL_CreateWindowAndRenderer(fb.w, fb.h, SDL_WINDOW_SHOWN | SDL_WINDOW_INPUT_FOCUS, &window, &renderer)) {
std::cerr << "Couldn't create window and renderer: " << SDL_GetError() << std::endl; std::cerr << "Failed to create window and renderer: " << SDL_GetError() << std::endl;
return -1; return -1;
} }
SDL_Texture *framebuffer_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, fb.w, fb.h); SDL_Texture *framebuffer_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, fb.w, fb.h);
if (!framebuffer_texture) {
SDL_Event event; std::cerr << "Failed to create framebuffer texture : " << SDL_GetError() << std::endl;
return -1;
}
auto t1 = std::chrono::high_resolution_clock::now(); auto t1 = std::chrono::high_resolution_clock::now();
while (1) { while (1) {
{ // sleep if less than 20 ms since last re-rendering; TODO: decouple rendering and event polling frequencies
auto t2 = std::chrono::high_resolution_clock::now(); auto t2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> fp_ms = t2 - t1; std::chrono::duration<double, std::milli> fp_ms = t2 - t1;
if (fp_ms.count()<20) { // sleep if less than 20 ms since last re-rendering if (fp_ms.count()<20) {
std::this_thread::sleep_for(std::chrono::milliseconds(3)); std::this_thread::sleep_for(std::chrono::milliseconds(3));
continue;
}
t1 = t2; t1 = t2;
} }
if (SDL_PollEvent(&event)) { // update player's state (walking/turning) { // poll events and update player's state (walk/turn flags); TODO: move this block to a more appropriate place
SDL_Event event;
if (SDL_PollEvent(&event)) {
if (SDL_QUIT==event.type || (SDL_KEYDOWN==event.type && SDLK_ESCAPE==event.key.keysym.sym)) break; if (SDL_QUIT==event.type || (SDL_KEYDOWN==event.type && SDLK_ESCAPE==event.key.keysym.sym)) break;
if (SDL_KEYUP==event.type) { if (SDL_KEYUP==event.type) {
if ('a'==event.key.keysym.sym || 'd'==event.key.keysym.sym) gs.player.turn = 0; if ('a'==event.key.keysym.sym || 'd'==event.key.keysym.sym) gs.player.turn = 0;
@@ -63,8 +70,9 @@ int main() {
if ('s'==event.key.keysym.sym) gs.player.walk = -1; if ('s'==event.key.keysym.sym) gs.player.walk = -1;
} }
} }
}
{ // update player's position { // update player's position; TODO: move this block to a more appropriate place
gs.player.a += float(gs.player.turn)*.05; // TODO measure elapsed time and modify the speed accordingly gs.player.a += float(gs.player.turn)*.05; // TODO measure elapsed time and modify the speed accordingly
float nx = gs.player.x + gs.player.walk*cos(gs.player.a)*.05; float nx = gs.player.x + gs.player.walk*cos(gs.player.a)*.05;
float ny = gs.player.y + gs.player.walk*sin(gs.player.a)*.05; float ny = gs.player.y + gs.player.walk*sin(gs.player.a)*.05;
@@ -79,18 +87,19 @@ int main() {
std::sort(gs.monsters.begin(), gs.monsters.end()); // sort it from farthest to closest std::sort(gs.monsters.begin(), gs.monsters.end()); // sort it from farthest to closest
} }
render(fb, gs); render(fb, gs); // render the scene to the frambuffer
SDL_UpdateTexture(framebuffer_texture, NULL, reinterpret_cast<void *>(fb.img.data()), fb.w*4);
{ // copy the framebuffer contents to the screen
SDL_UpdateTexture(framebuffer_texture, NULL, reinterpret_cast<void *>(fb.img.data()), fb.w*4);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, framebuffer_texture, NULL, NULL); SDL_RenderCopy(renderer, framebuffer_texture, NULL, NULL);
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }
}
SDL_DestroyTexture(framebuffer_texture); SDL_DestroyTexture(framebuffer_texture);
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
SDL_Quit(); SDL_Quit();
return 0; return 0;

BIN
monsters.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,42 @@
#include <iostream> #include <iostream>
#include <cassert> #include <cassert>
#define STB_IMAGE_IMPLEMENTATION #include "SDL.h"
#include "stb_image.h"
#include "utils.h" #include "utils.h"
#include "textures.h" #include "textures.h"
Texture::Texture(const std::string filename) : img_w(0), img_h(0), count(0), size(0), img() { Texture::Texture(const std::string filename, const uint32_t format) : img_w(0), img_h(0), count(0), size(0), img() {
int nchannels = -1, w, h; SDL_Surface *tmp = SDL_LoadBMP(filename.c_str());
unsigned char *pixmap = stbi_load(filename.c_str(), &w, &h, &nchannels, 0); if (!tmp) {
if (!pixmap) { std::cerr << "Error in SDL_LoadBMP: " << SDL_GetError() << std::endl;
std::cerr << "Error: can not load the textures" << std::endl;
return; return;
} }
if (4!=nchannels) { SDL_Surface *surface = SDL_ConvertSurfaceFormat(tmp, format, 0);
SDL_FreeSurface(tmp);
if (!surface) {
std::cerr << "Error in SDL_ConvertSurfaceFormat: " << SDL_GetError() << std::endl;
return;
}
int w = surface->w;
int h = surface->h;
if (w*4!=surface->pitch) {
std::cerr << "Error: the texture must be a 32 bit image" << std::endl; std::cerr << "Error: the texture must be a 32 bit image" << std::endl;
stbi_image_free(pixmap); SDL_FreeSurface(surface);
return; return;
} }
if (w!=h*int(w/h)) { if (w!=h*int(w/h)) {
std::cerr << "Error: the texture file must contain N square textures packed horizontally" << std::endl; std::cerr << "Error: the texture file must contain N square textures packed horizontally" << std::endl;
stbi_image_free(pixmap); SDL_FreeSurface(surface);
return; return;
} }
count = w/h; count = w/h;
size = w/count; size = w/count;
img_w = w; img_w = w;
img_h = h; img_h = h;
uint8_t *pixmap = reinterpret_cast<uint8_t *>(surface->pixels);
img = std::vector<uint32_t>(w*h); img = std::vector<uint32_t>(w*h);
for (int j=0; j<h; j++) { for (int j=0; j<h; j++) {
@@ -40,7 +48,7 @@ Texture::Texture(const std::string filename) : img_w(0), img_h(0), count(0), siz
img[i+j*w] = pack_color(r, g, b, a); img[i+j*w] = pack_color(r, g, b, a);
} }
} }
stbi_image_free(pixmap); SDL_FreeSurface(surface);
} }
uint32_t Texture::get(const size_t i, const size_t j, const size_t idx) const { uint32_t Texture::get(const size_t i, const size_t j, const size_t idx) const {

View File

@@ -9,7 +9,7 @@ struct Texture {
size_t count, size; // number of textures and size in pixels size_t count, size; // number of textures and size in pixels
std::vector<uint32_t> img; // textures storage container std::vector<uint32_t> img; // textures storage container
Texture(const std::string filename); Texture(const std::string filename, const uint32_t format);
uint32_t get(const size_t i, const size_t j, const size_t idx) const; // get the pixel (i,j) from the texture idx uint32_t get(const size_t i, const size_t j, const size_t idx) const; // get the pixel (i,j) from the texture idx
std::vector<uint32_t> get_scaled_column(const size_t texture_id, const size_t tex_coord, const size_t column_height) const; // retrieve one column (tex_coord) from the texture texture_id and scale it to the destination size std::vector<uint32_t> get_scaled_column(const size_t texture_id, const size_t tex_coord, const size_t column_height) const; // retrieve one column (tex_coord) from the texture texture_id and scale it to the destination size
}; };

BIN
walltext.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB