Skip to content

Commit

Permalink
Improved the model tests, type foolproofing
Browse files Browse the repository at this point in the history
  • Loading branch information
TCA166 committed Jul 23, 2023
1 parent 73e1e85 commit e4b0154
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 41 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ clean:
rm -f *.ow
rm -f cNBT/*.ow

check: hTable.o regionParser.o chunkParser.o cNBT.o
check: hTable.o regionParser.o chunkParser.o cNBT.o model.o
#hTable tests
checkmk tests/hTable.check > tests/hTableCheck.c
gcc tests/hTableCheck.c hTable.o -lcheck -lm $(SUBUNIT) -Wall -o tests/hTableCheck
Expand All @@ -110,5 +110,5 @@ check: hTable.o regionParser.o chunkParser.o cNBT.o
./tests/chunkParserCheck
#model tests
checkmk tests/model.check > tests/modelCheck.c
gcc tests/modelCheck.c model.o hTable.o -lcheck -lm $(SUBUNIT) -o tests/modelCheck
gcc tests/modelCheck.c model.o hTable.o -lcheck -lm $(SUBUNIT) -o tests/modelCheck -g
./tests/modelCheck
13 changes: 7 additions & 6 deletions chunkParser.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ char* appendProperty(char* string, char* property, const char* propertyName){
return string;
}

int getSections(unsigned char* nbtFileData, long sz, struct section* sections){
unsigned int getSections(unsigned char* nbtFileData, long sz, struct section* sections){
nbt_node* node = nbt_parse(nbtFileData, sz);
if(errno != 0){
fprintf(stderr, "%d\n", errno);
Expand Down Expand Up @@ -187,24 +187,25 @@ unsigned int* getBlockStates(struct section s, int* outLen){
//first we need to decode the franken compression scheme
unsigned int* states = NULL;
if(s.paletteLen > 1){
short l = (short)ceilf(log2f((float)s.paletteLen));//length of indices in the long
unsigned short l = (unsigned short)ceilf(log2f((float)s.paletteLen));//length of indices in the long
//I did the math and we could have a problem if l>32. However for that to happen paletteLen would have to be 3999999999, which is larger than INT_MAX, and impossible because Minecraft has 820 blocks total
int m = 0;
if(l < 4){
l = 4;
}
short numPerLong = (short)(64/l);
unsigned short numPerLong = (unsigned short)(64/l);
//fprintf(stderr, "%d %d\n", l, numPerLong);
states = malloc(numPerLong * s.blockDataLen * sizeof(unsigned int));
//foreach long
for(int a=0; a < s.blockDataLen; a++){
uint64_t comp = s.blockData[a];
for(short b = 0; b < numPerLong; b++){
for(unsigned short b = 0; b < numPerLong; b++){
if(m >= 4096){
break;
}
short bits = b * l;
unsigned short bits = b * l;
uint64_t mask = createMask(bits, l);
states[m] = (uint64_t)((mask & comp) >> bits);
states[m] = (unsigned int)((mask & comp) >> bits);
//fprintf(stderr, "%ld&%ld=%ld, >>%d=%d\n", mask, comp, (mask & comp), bits, states[m]);
m++;
}
Expand Down
6 changes: 3 additions & 3 deletions chunkParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ struct section{
//we ignore the biomes because we don't need that data
uint64_t* blockData; //raw nbt file block data
char** blockPalette;
int blockDataLen; //the length of blockData in bytes
int paletteLen;
unsigned int blockDataLen; //the length of blockData in bytes
unsigned int paletteLen;
short y;
};

Expand All @@ -28,7 +28,7 @@ struct block{
Extracts sections from nbtFileData of size sz into sections array and returns the number of extracted sections
blockData, blockPalette and elements of blockPalette are allocated on the heap and will need to be freed
*/
int getSections(unsigned char* nbtFileData, long sz, struct section* sections);
unsigned int getSections(unsigned char* nbtFileData, long sz, struct section* sections);

/*
Creates the block states array based on a section.
Expand Down
6 changes: 3 additions & 3 deletions generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "errorDefs.h"
#include "generator.h"

model generateFromNbt(unsigned char* data, long dataSize, hashTable* materials, hashTable* objects, bool yLim, int upLim, int downLim, bool b, bool f, int side, int chunkX, int chunkZ){
model generateFromNbt(unsigned char* data, int dataSize, hashTable* materials, hashTable* objects, bool yLim, int upLim, int downLim, bool b, bool f, unsigned int side, int chunkX, int chunkZ){
//Array of sections in this chunk
struct section sections[maxSections] = {0};
int n = getSections(data, dataSize, sections);
Expand Down Expand Up @@ -64,7 +64,7 @@ model generateFromNbt(unsigned char* data, long dataSize, hashTable* materials,
return newModel;
}

struct cubeModel createCubeModel(struct section* sections, int sectionLen, hashTable* materials, bool yLim, int upLim, int downLim, int side, bool matCheck, int xOff, int zOff){
struct cubeModel createCubeModel(struct section* sections, int sectionLen, hashTable* materials, bool yLim, int upLim, int downLim, unsigned int side, bool matCheck, int xOff, int zOff){
struct cubeModel cubeModel = initCubeModel(16,16 * sectionLen, 16);
for(int i = 0; i < sectionLen; i++){
//create the block state array
Expand Down Expand Up @@ -110,7 +110,7 @@ struct cubeModel createCubeModel(struct section* sections, int sectionLen, hashT
return cubeModel;
}

struct cube cubeFromBlock(struct block block, const int side, struct material* material){
struct cube cubeFromBlock(struct block block, const unsigned int side, struct material* material){
struct cube newCube = createGenericCube(side);

newCube.x = block.x;
Expand Down
6 changes: 3 additions & 3 deletions generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@
Creates a new cube object based on a block object.
material can be NULL
*/
struct cube cubeFromBlock(struct block block, const int side, struct material* material);
struct cube cubeFromBlock(struct block block, const unsigned int side, struct material* material);

/*
Isolated from the main code to maybe in the future enable for a multithreaded version that can do multiple chunks.
materials can be NULL
*/
struct cubeModel createCubeModel(struct section* sections, int sectionLen, hashTable* materials, bool yLim, int upLim, int downLim, int side, bool matCheck, int xOff, int zOff);
struct cubeModel createCubeModel(struct section* sections, int sectionLen, hashTable* materials, bool yLim, int upLim, int downLim, unsigned int side, bool matCheck, int xOff, int zOff);

//Generally speaking i could just pass a whole chunk object from regionParser here, but I like the design of having that be completely separate

/*
Generates a model object from binary nbt data.
materials and objects can be NULL.
*/
model generateFromNbt(unsigned char* data, long dataSize, hashTable* materials, hashTable* objects, bool yLim, int upLim, int downLim, bool b, bool f, int side, int chunkX, int chunkZ);
model generateFromNbt(unsigned char* data, int dataSize, hashTable* materials, hashTable* objects, bool yLim, int upLim, int downLim, bool b, bool f, unsigned int side, int chunkX, int chunkZ);
16 changes: 12 additions & 4 deletions model.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ bool verticesEqual(struct vertex a, struct vertex b){
model initModel(int objectCount){
model newModel;
newModel.materialArr = NULL;
newModel.materialCount = -1;
newModel.materialCount = 0;
newModel.objects = calloc(objectCount, sizeof(struct object*));
newModel.objectCount = objectCount;
return newModel;
Expand Down Expand Up @@ -129,7 +129,7 @@ bool isPresent(char* string, hashTable* objects){
return ptr != NULL;
}

int cullFaces(struct cubeModel* thisModel, bool cullChunkBorder, hashTable* specialObjects){
unsigned int cullFaces(struct cubeModel* thisModel, bool cullChunkBorder, hashTable* specialObjects){
long count = 0;
for(int x = 0; x < thisModel->x; x++){
for(int y = 0; y < thisModel->y; y++){
Expand Down Expand Up @@ -299,6 +299,10 @@ char* appendMtlLine(const char* mtlName, char* appendTo, size_t* outSize){

char* generateModel(model* thisModel, size_t* outSize, char* materialFileName, unsigned long* offset){
char* fileContents = NULL;
size_t locSize = 0;
if(outSize == NULL){
outSize = &locSize;
}
(*outSize)++;
fileContents = malloc(*outSize);
fileContents[0] = '\0';
Expand Down Expand Up @@ -329,11 +333,15 @@ char* generateModel(model* thisModel, size_t* outSize, char* materialFileName, u
int x = (int)thisObject->x;
int y = (int)thisObject->y;
int z = (int)thisObject->z;
char* type = thisObject->type;
if(type == NULL){
type = "NULL";
}
//object definition
size_t objectLineSize = 12 + digits(thisObject->x) + digits(y) + digits(z) + strlen(thisObject->type) + digits(*offset);
size_t objectLineSize = 12 + digits(thisObject->x) + digits(y) + digits(z) + strlen(type) + digits(*offset);
char* objectLine = NULL;
objectLine = malloc(objectLineSize);
snprintf(objectLine, objectLineSize, "o cube%d-%d-%d:%s:%ld\n", x, y, z, thisObject->type, *offset);
snprintf(objectLine, objectLineSize, "o cube%d-%d-%d:%s:%ld\n", x, y, z, type, *offset);
*outSize += objectLineSize - 1;
fileContents = realloc(fileContents, *outSize);
strcat(fileContents, objectLine);
Expand Down
30 changes: 15 additions & 15 deletions model.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct cube{
float x;
float y;
float z;
float side;
float side; //Cannot be lower than 0 for very obvious reasons
struct vertex vertices[8]; //array of relative to x,y,z vertices
struct cubeFace* faces[6]; //array of pointers so that it may be nullable
char* type; //text representing a cube name or a broad type. Feel free to make it NULL
Expand All @@ -22,15 +22,15 @@ struct cube{

//A face with only 4 vertices. V variables point to vertices in the associated cube object
struct cubeFace{
int v1;
int v2;
int v3;
int v4;
unsigned int v1;
unsigned int v2;
unsigned int v3;
unsigned int v4;
};

//A dynamic array of vertices - an object face
struct objFace{
int vertexCount;
unsigned int vertexCount;
int* vertices;
struct material* m;
};
Expand All @@ -40,9 +40,9 @@ struct object{
float x;
float y;
float z;
int vertexCount;
unsigned int vertexCount;
struct vertex* vertices; //array of relative to x, y, z vertices
int faceCount;
unsigned int faceCount;
struct objFace* faces; //doesn't need to be nullable
struct material* m;
char* type;
Expand All @@ -55,9 +55,9 @@ A loose array of even looser objects with an associated array of materials that
*/
struct model{
struct object** objects; //Nullable array of objects
int objectCount; //Size of objects
unsigned int objectCount; //Size of objects
struct material** materialArr; //Optional array of materials, that objects can point to
int materialCount; //Size of materialArr
unsigned int materialCount; //Size of materialArr
};

#define dimensionalFor(xLim, yLim, zLim) \
Expand All @@ -81,9 +81,9 @@ Can be transformed into a normal loose model.
Ideally if you plan on generating a model of something that can be represented by cubes you first generate this.
*/
struct cubeModel{
int x; //Max x index
int y; //Max y index
int z; //Max z index
unsigned int x; //Max x index
unsigned int y; //Max y index
unsigned int z; //Max z index
struct cube**** cubes; //nullable 3d array of cubes
};

Expand Down Expand Up @@ -117,7 +117,7 @@ Removes all outward or internal faces from a model.
All cubes that are NULL or whose type is in ignoreType are considered to be outward and faces touching those cubes are not culled.
Culled faces are free'd and set as null.
*/
int cullFaces(struct cubeModel* thisModel, bool cullChunkBorder, hashTable* specialObjects);
unsigned int cullFaces(struct cubeModel* thisModel, bool cullChunkBorder, hashTable* specialObjects);

/*
Converts a cubeModel to a normal model, and inserts special objects if specialObjects!=NULL when types match.
Expand Down Expand Up @@ -176,7 +176,7 @@ double distanceBetweenVectors(struct vertex a, struct vertex b);
//Returns true if two vertices are equal
bool verticesEqual(struct vertex a, struct vertex b);

//Returns the number of vertices in the model. Should be equivalent to the offset value if the model were to be generated
//Returns the number of vertices in the model. Should be equivalent to the offset value if the model were to be generated -1
unsigned long getTotalVertexCount(model m);

//Returns a generic cube object
Expand Down
2 changes: 1 addition & 1 deletion regionParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct chunk{
unsigned int offset; //3 bytes of offset
byte sectorCount; //1 byte indicating chunk data length
unsigned int timestamp;
unsigned int byteLength;
int byteLength; //it actually is signed in the files
byte compression;
byte* data; //pointer to decompressed bytes
};
Expand Down
6 changes: 3 additions & 3 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ hTableCheck.c: hTable.check
checkmk hTable.check > hTableCheck.c

hTableCheck: hTableCheck.c ../hTable.o
gcc hTableCheck.c ../hTable.o -lcheck -lm -lsubunit -o hTableCheck
gcc hTableCheck.c ../hTable.o -lcheck -lm -lsubunit -o hTableCheck -g

regionParserCheck.c: regionParser.check
checkmk regionParser.check > regionParserCheck.c

regionParserCheck: regionParserCheck.c ../regionParser.o
gcc regionParserCheck.c ../regionParser.o -lcheck -lm -lz -lsubunit -o regionParserCheck
gcc regionParserCheck.c ../regionParser.o -lcheck -lm -lz -lsubunit -o regionParserCheck -g

chunkParserCheck.c: chunkParser.check
checkmk chunkParser.check > chunkParserCheck.c

chunkParserCheck: chunkParserCheck.c ../chunkParser.o ../cNBT.o
gcc chunkParserCheck.c ../chunkParser.o ../cNBT.o -lcheck -lm -lsubunit -o chunkParserCheck
gcc chunkParserCheck.c ../chunkParser.o ../cNBT.o -lcheck -lm -lsubunit -o chunkParserCheck -g

modelCheck.c: model.check
checkmk model.check > modelCheck.c
Expand Down
49 changes: 48 additions & 1 deletion tests/model.check
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,58 @@
cModel.cubes[x][y][z] = malloc(sizeof(struct cube));
*(cModel.cubes[x][y][z]) = createGenericCube(2);
}
ck_assert_msg(i == 27, "test model creation failed");
model preCull = cubeModelToModel(&cModel, NULL);
int culled = cullFaces(&cModel, false, NULL);
model postCull = cubeModelToModel(&cModel, NULL);
freeCubeModel(&cModel);
unsigned long preVertex = getTotalVertexCount(preCull);
unsigned long postVertex = getTotalVertexCount(postCull);
ck_assert_msg(preVertex == postVertex + 8, "Vertex counts aren't valid");

#test vertexCountTest
struct cubeModel cModel = initCubeModel(3, 3, 3);
int i = 0;
dimensionalFor(3, 3, 3){
i++;
cModel.cubes[x][y][z] = malloc(sizeof(struct cube));
*(cModel.cubes[x][y][z]) = createGenericCube(2);
}
model nModel = cubeModelToModel(&cModel, NULL);
freeCubeModel(&cModel);
unsigned long vertexCount = getTotalVertexCount(nModel);
ck_assert_msg(vertexCount > 0, "Vertex count invalid");
unsigned long actualCount = 1;
free(generateModel(&nModel, NULL, NULL, &actualCount));
freeModel(&nModel);
ck_assert_msg(actualCount == vertexCount + 1, "vertexCount isn't accurate");

#test generateTest
struct cubeModel cModel = initCubeModel(3, 3, 3);
int i = 0;
dimensionalFor(3, 3, 3){
i++;
cModel.cubes[x][y][z] = malloc(sizeof(struct cube));
*(cModel.cubes[x][y][z]) = createGenericCube(2);
}
model nModel = cubeModelToModel(&cModel, NULL);
freeCubeModel(&cModel);
size_t sz = 0;
unsigned long vertexCount = 1;
char* modelStr = generateModel(&nModel, &sz, NULL, &vertexCount);
char* token = strtok(modelStr, "\n");
while(token != NULL){
if(token[0] == 'f'){
char* nextGap = token + 2;
char* prev = nextGap;
while((nextGap = strchr(nextGap, ' ')) != NULL){
*nextGap = '\0';
nextGap++;
if(prev != NULL){
int index = atoi(prev);
ck_assert_msg(index < vertexCount && index > 0, "invalid face vertex index");
}
prev = nextGap;
}
}
token = strtok(NULL, "\n");
}

0 comments on commit e4b0154

Please sign in to comment.