1
0
mirror of https://github.com/ssloy/tinyraycaster.git synced 2025-01-16 12:49:38 +01: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

73
gui.cpp
View File

@ -9,6 +9,11 @@
#include "tinyraycaster.h"
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))};
GameState gs{ Map(), // game map
{3.456, 2.345, 1.523, M_PI/3., 0, 0}, // player
@ -17,8 +22,8 @@ int main() {
{5.323, 5.365, 1, 0},
{14.32, 13.36, 3, 0},
{4.123, 10.76, 1, 0} },
Texture("../walltext.png"), // textures for the walls
Texture("../monsters.png") }; // textures for the monsters
Texture("../walltext.bmp", SDL_PIXELFORMAT_ABGR8888), // textures for the walls
Texture("../monsters.bmp", SDL_PIXELFORMAT_ABGR8888)}; // textures for the monsters
if (!gs.tex_walls.count || !gs.tex_monst.count) {
std::cerr << "Failed to load textures" << std::endl;
return -1;
@ -27,44 +32,47 @@ int main() {
SDL_Window *window = 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)) {
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;
}
SDL_Texture *framebuffer_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, fb.w, fb.h);
SDL_Event event;
if (!framebuffer_texture) {
std::cerr << "Failed to create framebuffer texture : " << SDL_GetError() << std::endl;
return -1;
}
auto t1 = std::chrono::high_resolution_clock::now();
while (1) {
auto t2 = std::chrono::high_resolution_clock::now();
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
std::this_thread::sleep_for(std::chrono::milliseconds(3));
{ // 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();
std::chrono::duration<double, std::milli> fp_ms = t2 - t1;
if (fp_ms.count()<20) {
std::this_thread::sleep_for(std::chrono::milliseconds(3));
continue;
}
t1 = t2;
}
if (SDL_PollEvent(&event)) { // update player's state (walking/turning)
if (SDL_QUIT==event.type || (SDL_KEYDOWN==event.type && SDLK_ESCAPE==event.key.keysym.sym)) break;
if (SDL_KEYUP==event.type) {
if ('a'==event.key.keysym.sym || 'd'==event.key.keysym.sym) gs.player.turn = 0;
if ('w'==event.key.keysym.sym || 's'==event.key.keysym.sym) gs.player.walk = 0;
}
if (SDL_KEYDOWN==event.type) {
if ('a'==event.key.keysym.sym) gs.player.turn = -1;
if ('d'==event.key.keysym.sym) gs.player.turn = 1;
if ('w'==event.key.keysym.sym) gs.player.walk = 1;
if ('s'==event.key.keysym.sym) gs.player.walk = -1;
{ // 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_KEYUP==event.type) {
if ('a'==event.key.keysym.sym || 'd'==event.key.keysym.sym) gs.player.turn = 0;
if ('w'==event.key.keysym.sym || 's'==event.key.keysym.sym) gs.player.walk = 0;
}
if (SDL_KEYDOWN==event.type) {
if ('a'==event.key.keysym.sym) gs.player.turn = -1;
if ('d'==event.key.keysym.sym) gs.player.turn = 1;
if ('w'==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
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;
@ -79,18 +87,19 @@ int main() {
std::sort(gs.monsters.begin(), gs.monsters.end()); // sort it from farthest to closest
}
render(fb, gs);
SDL_UpdateTexture(framebuffer_texture, NULL, reinterpret_cast<void *>(fb.img.data()), fb.w*4);
render(fb, gs); // render the scene to the frambuffer
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, framebuffer_texture, NULL, NULL);
SDL_RenderPresent(renderer);
{ // 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_RenderCopy(renderer, framebuffer_texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
}
SDL_DestroyTexture(framebuffer_texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
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 <cassert>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "SDL.h"
#include "utils.h"
#include "textures.h"
Texture::Texture(const std::string filename) : img_w(0), img_h(0), count(0), size(0), img() {
int nchannels = -1, w, h;
unsigned char *pixmap = stbi_load(filename.c_str(), &w, &h, &nchannels, 0);
if (!pixmap) {
std::cerr << "Error: can not load the textures" << std::endl;
Texture::Texture(const std::string filename, const uint32_t format) : img_w(0), img_h(0), count(0), size(0), img() {
SDL_Surface *tmp = SDL_LoadBMP(filename.c_str());
if (!tmp) {
std::cerr << "Error in SDL_LoadBMP: " << SDL_GetError() << std::endl;
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;
stbi_image_free(pixmap);
SDL_FreeSurface(surface);
return;
}
if (w!=h*int(w/h)) {
std::cerr << "Error: the texture file must contain N square textures packed horizontally" << std::endl;
stbi_image_free(pixmap);
SDL_FreeSurface(surface);
return;
}
count = w/h;
size = w/count;
img_w = w;
img_h = h;
uint8_t *pixmap = reinterpret_cast<uint8_t *>(surface->pixels);
img = std::vector<uint32_t>(w*h);
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);
}
}
stbi_image_free(pixmap);
SDL_FreeSurface(surface);
}
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
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
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