Browse Source

Embed the texture atlas data inside the exported .ps1bsp file and name those files after the actual map.

Makes it a bit easier to switch between maps for testing.
master
Nico de Poel 3 years ago
parent
commit
8d51e7e252
  1. 41
      main.cpp
  2. 6
      ps1bsp.h
  3. 6
      texture.cpp

41
main.cpp

@ -15,6 +15,34 @@ template<class TData> size_t writeMapData(const std::vector<TData>& data, ps1bsp
return fwrite(data.data(), sizeof(TData), data.size(), f);
}
size_t writeAtlasData(const char* timPath, ps1bsp_dentry_t& dentry, FILE* f)
{
FILE* ftim;
fopen_s(&ftim, timPath, "rb");
if (ftim == NULL)
return 0;
fseek(ftim, 0, SEEK_END);
size_t numBytes = ftell(ftim);
fseek(ftim, 0, SEEK_SET);
// Round the data size up to multiples of 4 bytes, for 32-bit alignment
size_t numWords = numBytes / 4;
if (numBytes % 4 != 0)
numWords++;
unsigned long* timData = new unsigned long[numWords];
fread(timData, sizeof(unsigned char), numBytes, ftim);
fclose(ftim);
dentry.offset = (unsigned int)ftell(f);
dentry.size = numWords * 4;
size_t written = fwrite(timData, sizeof(unsigned long), numWords, f);
delete[] timData;
return written;
}
static float computeFaceArea(const world_t* world, const face_t* face)
{
const plane_t* plane = &world->planes[face->plane_id];
@ -50,7 +78,8 @@ int process_faces(const world_t* world, const TextureList& textures)
{
// Write some data to a file
FILE* fbsp;
fopen_s(&fbsp, "test.ps1bsp", "wb");
sprintf_s(path, _MAX_PATH, "%s.ps1bsp", world->name);
fopen_s(&fbsp, path, "wb");
if (!fbsp)
return 0;
@ -62,6 +91,8 @@ int process_faces(const world_t* world, const TextureList& textures)
ps1bsp_worldspawn_t outWorldSpawn = { 0 };
Tesselator tesselator(world);
printf("Analyzing %d faces...\n", world->numFaces);
// Convert faces defined by edges into faces defined by vertex indices
std::vector<ps1bsp_face_t> outFaces;
@ -126,6 +157,8 @@ int process_faces(const world_t* world, const TextureList& textures)
outFaces.push_back(outFace);
}
printf("Tesselating faces...\n");
std::vector<ps1bsp_polyvertex_t> outPolyVertices;
std::vector<ps1bsp_polygon_t> outPolygons;
@ -254,6 +287,8 @@ int process_faces(const world_t* world, const TextureList& textures)
outFace->numPolygons = (unsigned char)(outPolygons.size() - outFace->firstPolygon);
}
printf("Converting data...\n");
// Convert vertex data
const auto& inVertices = tesselator.getVertices();
std::vector<ps1bsp_vertex_t> outVertices;
@ -356,8 +391,12 @@ int process_faces(const world_t* world, const TextureList& textures)
outWorldSpawns.push_back(outWorldSpawn);
printf("Writing output file...\n");
// Write collected data to file and update header info
writeMapData(outWorldSpawns, outHeader.worldSpawn, fbsp);
sprintf_s(path, _MAX_PATH, "atlas-%s.tim", world->name);
writeAtlasData(path, outHeader.atlases, fbsp);
writeMapData(outTextures, outHeader.textures, fbsp);
writeMapData(outVertices, outHeader.vertices, fbsp);
writeMapData(outPolygons, outHeader.polygons, fbsp);

6
ps1bsp.h

@ -29,6 +29,7 @@ typedef struct
u_short version;
ps1bsp_dentry_t worldSpawn;
ps1bsp_dentry_t atlases;
ps1bsp_dentry_t textures;
ps1bsp_dentry_t vertices;
ps1bsp_dentry_t polygons;
@ -48,6 +49,11 @@ typedef struct
unsigned char skyColor[4];
} ps1bsp_worldspawn_t;
typedef struct
{
unsigned long timData[1]; // Variable length
} ps1bsp_atlas_t;
typedef struct
{
unsigned short tpage; // Texture page in PS1 VRAM (precalculated when generating the texture atlas)

6
texture.cpp

@ -29,7 +29,7 @@ Keep in mind that the coordinates will be rounded down to the next lowest textur
// So we desaturate the palette ahead of time to more closely match the original Quake's look.
static void desaturate(const unsigned char inColor[3], unsigned char outColor[3])
{
double f = 0.15; // desaturate by 15%
double f = 0.1; // desaturate by 10%
double L = 0.3 * inColor[0] + 0.6 * inColor[1] + 0.1 * inColor[2];
outColor[0] = (unsigned char)((double)inColor[0] + f * (L - inColor[0]));
outColor[1] = (unsigned char)((double)inColor[1] + f * (L - inColor[1]));
@ -185,6 +185,8 @@ bool process_textures(const world_t* world, TextureList& outTextures) // TODO: r
const auto max_bin = rectpack2D::rect_wh(1024, 256); // 8-bit textures take up half the horizontal space so this is 512x256 in practice, or a quarter of the PS1's VRAM allocation.
const auto discard_step = -4;
printf("Finding best texture packing...\n");
std::vector<rect_type> rectangles;
// Try some texture packing and see if we fit inside the PS1's VRAM
@ -253,6 +255,8 @@ bool process_textures(const world_t* world, TextureList& outTextures) // TODO: r
memset(outTim.imgData, 0, result_size.w * result_size.h * sizeof(unsigned char));
printf("Constructing texture atlas...\n");
// Try to construct the texture atlas, see what we get
for (int texNum = 0; texNum < world->mipheader.numtex; ++texNum)
{

Loading…
Cancel
Save