1
0
mirror of https://github.com/ssloy/tinyraycaster.git synced 2025-08-31 17:41:56 +02:00

load textures

This commit is contained in:
Dmitry V. Sokolov
2019-02-09 16:47:05 +01:00
parent 35ed743b6f
commit f84ae5aac9
5 changed files with 7546 additions and 39 deletions

BIN
doc/009.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
monsters.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

7462
stb_image.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,11 +2,11 @@
#include <cmath>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <cstdint>
#include <cassert>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
uint32_t pack_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a=255) {
return (a<<24) + (b<<16) + (g<<8) + r;
@@ -43,6 +43,43 @@ void draw_rectangle(std::vector<uint32_t> &img, const size_t img_w, const size_t
}
}
bool load_texture(const std::string filename, std::vector<uint32_t> &texture, size_t &text_size, size_t &text_cnt) {
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;
return false;
}
if (4!=nchannels) {
std::cerr << "Error: the texture must be a 32 bit image" << std::endl;
stbi_image_free(pixmap);
return false;
}
text_cnt = w/h;
text_size = w/text_cnt;
if (w!=h*int(text_cnt)) {
std::cerr << "Error: the texture file must contain N square textures packed horizontally" << std::endl;
stbi_image_free(pixmap);
return false;
}
texture = std::vector<uint32_t>(w*h);
for (int j=0; j<h; j++) {
for (int i=0; i<w; i++) {
uint8_t r = pixmap[(i+j*w)*4+0];
uint8_t g = pixmap[(i+j*w)*4+1];
uint8_t b = pixmap[(i+j*w)*4+2];
uint8_t a = pixmap[(i+j*w)*4+3];
texture[i+j*w] = pack_color(r, g, b, a);
}
}
stbi_image_free(pixmap);
return true;
}
int main() {
const size_t win_w = 1024; // image width
const size_t win_h = 512; // image height
@@ -78,48 +115,56 @@ int main() {
colors[i] = pack_color(rand()%255, rand()%255, rand()%255);
}
std::vector<uint32_t> walltext; // textures for the walls
size_t walltext_size; // texture dimensions (it is a square)
size_t walltext_cnt; // number of different textures in the image
if (!load_texture("../walltext.png", walltext, walltext_size, walltext_cnt)) {
std::cerr << "Failed to load wall textures" << std::endl;
return -1;
}
const size_t rect_w = win_w/(map_w*2);
const size_t rect_h = win_h/map_h;
for (size_t frame=0; frame<360; frame++) {
std::stringstream ss;
ss << std::setfill('0') << std::setw(5) << frame << ".ppm";
player_a += 2*M_PI/360;
framebuffer = std::vector<uint32_t>(win_w*win_h, pack_color(255, 255, 255)); // clear the screen
for (size_t j=0; j<map_h; j++) { // draw the map
for (size_t i=0; i<map_w; i++) {
if (map[i+j*map_w]==' ') continue; // skip empty spaces
size_t rect_x = i*rect_w;
size_t rect_y = j*rect_h;
size_t icolor = map[i+j*map_w] - '0';
assert(icolor<ncolors);
draw_rectangle(framebuffer, win_w, win_h, rect_x, rect_y, rect_w, rect_h, colors[icolor]);
}
for (size_t j=0; j<map_h; j++) { // draw the map
for (size_t i=0; i<map_w; i++) {
if (map[i+j*map_w]==' ') continue; // skip empty spaces
size_t rect_x = i*rect_w;
size_t rect_y = j*rect_h;
size_t icolor = map[i+j*map_w] - '0';
assert(icolor<ncolors);
draw_rectangle(framebuffer, win_w, win_h, rect_x, rect_y, rect_w, rect_h, colors[icolor]);
}
for (size_t i=0; i<win_w/2; i++) { // draw the visibility cone AND the "3D" view
float angle = player_a-fov/2 + fov*i/float(win_w/2);
for (float t=0; t<20; t+=.01) {
float cx = player_x + t*cos(angle);
float cy = player_y + t*sin(angle);
size_t pix_x = cx*rect_w;
size_t pix_y = cy*rect_h;
framebuffer[pix_x + pix_y*win_w] = pack_color(160, 160, 160); // this draws the visibility cone
if (map[int(cx)+int(cy)*map_w]!=' ') { // our ray touches a wall, so draw the vertical column to create an illusion of 3D
size_t icolor = map[int(cx)+int(cy)*map_w] - '0';
assert(icolor<ncolors);
size_t column_height = win_h/(t*cos(angle-player_a));
draw_rectangle(framebuffer, win_w, win_h, win_w/2+i, win_h/2-column_height/2, 1, column_height, colors[icolor]);
break;
}
}
}
drop_ppm_image(ss.str(), framebuffer, win_w, win_h);
}
for (size_t i=0; i<win_w/2; i++) { // draw the visibility cone AND the "3D" view
float angle = player_a-fov/2 + fov*i/float(win_w/2);
for (float t=0; t<20; t+=.01) {
float cx = player_x + t*cos(angle);
float cy = player_y + t*sin(angle);
size_t pix_x = cx*rect_w;
size_t pix_y = cy*rect_h;
framebuffer[pix_x + pix_y*win_w] = pack_color(160, 160, 160); // this draws the visibility cone
if (map[int(cx)+int(cy)*map_w]!=' ') { // our ray touches a wall, so draw the vertical column to create an illusion of 3D
size_t icolor = map[int(cx)+int(cy)*map_w] - '0';
assert(icolor<ncolors);
size_t column_height = win_h/(t*cos(angle-player_a));
draw_rectangle(framebuffer, win_w, win_h, win_w/2+i, win_h/2-column_height/2, 1, column_height, colors[icolor]);
break;
}
}
}
const size_t texid = 4; // draw the 4th texture on the screen
for (size_t i=0; i<walltext_size; i++) {
for (size_t j=0; j<walltext_size; j++) {
framebuffer[i+j*win_w] = walltext[i + texid*walltext_size + j*walltext_size*walltext_cnt];
}
}
drop_ppm_image("./out.ppm", framebuffer, win_w, win_h);
return 0;
}

BIN
walltext.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB