Files
wolf/wad.cpp

194 lines
6.7 KiB
C++

#include "wad.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unordered_map>
#include <string>
#include <vector>
#include <SDL3/SDL.h>
namespace wad {
char file[13];
filelump_t *directory;
uint32_t numlumps;
struct patch_t {
};
std::unordered_map<std::string, draw::surface_t*> flats;
std::unordered_map<std::string, draw::surface_t*> textures;
std::unordered_map<std::string, draw::surface_t*> patches;
std::vector<std::string> patch_names;
//char (*patch_names)[8];
void init(const char *filename) {
strcpy(file, filename);
FILE *f = fopen(filename, "rb");
char header[4]; fread(header, 4, 1, f);// printf("header: %*.s\n", 4, header);
uint32_t infotableofs;
fread(&numlumps, 4, 1, f);// printf("num lumps: %i\n", numlumps);
fread(&infotableofs, 4, 1, f);// printf("directory offset: %i\n\n", infotableofs);
directory = (filelump_t*)malloc(sizeof(filelump_t)*numlumps);
fseek(f, infotableofs, SEEK_SET);
for (int i=0; i<numlumps; ++i) {
fread(&directory[i].filepos, 4, 1, f);
fread(&directory[i].size, 4, 1, f);
fread(directory[i].name, 8, 1, f);
//if (strncmp("TEXTURE1", directory[i].name, 8)==0)
// printf("num lumps: %8.10s % 6i % 6i\n", directory[i].name,directory[i].filepos, directory[i].size);
}
fclose(f);
uint8_t *pnames = load("PNAMES");
int num_pnames = *(uint32_t*)pnames;
//printf("num pnames: %i\n", num_pnames);
//patch_names = (char (*)[8]) malloc(num_pnames * sizeof *patch_names);
char *names = (char*)(pnames+4);
for (int i=0;i<num_pnames;++i) {
char name[9]; name[8]=0;
for (int j=0;j<8;++j) name[j] = toupper(names[8*i+j]);
patch_names.push_back(name);
}
free(pnames);
//for (int i=0;i<num_pnames;++i) printf("%s\n", patch_names[i].c_str());
}
uint8_t *load(const char *name) {
int i=-1;
for (i=0; i<numlumps; ++i) if (strncmp(name, directory[i].name,8)==0) break;
if (i==-1) return nullptr;
FILE *f = fopen(file, "rb");
fseek(f, directory[i].filepos, SEEK_SET);
uint8_t *buffer = (uint8_t*)malloc(directory[i].size);
fread(buffer, directory[i].size, 1, f);
fclose(f);
return buffer;
}
uint8_t *load(const char *prev, const char *name, int *size)
{
int i=-1;
for (i=0; i<numlumps; ++i) if (strncmp(prev, directory[i].name,8)==0) break;
if (i==-1) return nullptr;
for (; i<numlumps; ++i) if (strncmp(name, directory[i].name,8)==0) break;
if (i==-1) return nullptr;
FILE *f = fopen(file, "rb");
fseek(f, directory[i].filepos, SEEK_SET);
uint8_t *buffer = (uint8_t*)malloc(directory[i].size);
fread(buffer, directory[i].size, 1, f);
fclose(f);
if (size) *size = directory[i].size;
return buffer;
}
uint32_t *loadPalette(int index)
{
uint8_t *palettes = wad::load("PLAYPAL");
uint32_t *palette = (uint32_t*)malloc(1024);
for (int i=0;i<256;++i) {
uint8_t r = palettes[(768*index)+(i*3)];
uint8_t g = palettes[(768*index)+(i*3)+1];
uint8_t b = palettes[(768*index)+(i*3)+2];
palette[i] = (r<<16) | (g<<8) | b;
}
free(palettes);
return palette;
}
draw::surface_t *loadFlat(const char *name)
{
if (flats.find(name) != flats.end()) return flats[name];
uint8_t *flat = load(name);
draw::surface_t *surf = draw::newsurf(64, 64);
int i=0;
for (int y=0;y<64;++y)
for (int x=0;x<64;++x)
surf->pixels[x+y*64] = flat[i++];
free(flat);
flats[name] = surf;
return surf;
}
draw::surface_t *loadTexture(const char *name)
{
if (textures.find(name) != textures.end()) return textures[name];
uint8_t *textures_lump = load("TEXTURE1");
int num_textures_in_lump = ((uint32_t*)textures_lump)[0];
uint32_t *offsets = &((uint32_t*)textures_lump)[1];
int i = 0;
while (i<num_textures_in_lump) {
char *texture_name = (char*)textures_lump+offsets[i];
if (strncmp(name, texture_name, 8)==0) break;
i++;
}
SDL_assert(i<num_textures_in_lump);
//if (i==num_textures_in_lump) { printf("TEXTURA '%s' NO TROBADA!\n", name); return nullptr; }
uint8_t *texture_info = textures_lump+offsets[i]+12;
const int texture_width = ((uint16_t*)texture_info)[0];
const int texture_height = ((uint16_t*)texture_info)[1];
draw::surface_t *surf = draw::newsurf(texture_width, texture_height);
const int patch_count = ((uint16_t*)texture_info)[4];
//printf("Texture: %s (%ix%i)\n Patch count: %i\n", name, texture_width, texture_height, patch_count);
uint16_t *patches = &((uint16_t*)texture_info)[5];
for (int i=0; i<patch_count; ++i) {
const int originx = int16_t(patches[i*5+0]);
const int originy = int16_t(patches[i*5+1]);
const int patch_index = patches[i*5+2];
const char *patch_name = patch_names[patch_index].c_str();
//printf("Patch. Index:%i, Name:%s, ox:%i, oy:%i\n", patch_index, patch_name, originx, originy);
draw::surface_t *patch = loadPatch(patch_name);
draw::drawsurf(originx, originy, patch, surf);
}
free(textures_lump);
textures[name] = surf;
return surf;
}
draw::surface_t *loadPatch(const char *name)
{
if (patches.find(name) != patches.end()) return patches[name];
uint8_t *patch_lump = load(name);
const int patch_width = ((uint16_t*)patch_lump)[0];
const int patch_height = ((uint16_t*)patch_lump)[1];
//printf("Patch:%s, %ix%i\n", name, patch_width, patch_height);
draw::surface_t *surf = draw::newsurf(patch_width, patch_height);
uint32_t *offsets = (uint32_t*)(patch_lump+8);
for (int i=0; i<patch_width; ++i) {
uint8_t *post = patch_lump+offsets[i];
while(true) {
if (*post == 0xff) break;
const int offset = *(post++);
const int length = *(post++);
post++;
for (int j=0;j<length;++j) {
draw::putpsurf(surf, i, offset+j, *(post++));
}
post++;
}
}
//https://www.doomwiki.org/wiki/Picture_format
free(patch_lump);
patches[name] = surf;
return surf;
}
}