Add support for model files
Model files are zip archives with a "model.toml" file at the root describing the model and all its textures.
This commit is contained in:
		
							parent
							
								
									cbbdf5ff79
								
							
						
					
					
						commit
						4770c96d92
					
				| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
cmake_minimum_required( VERSION 3.0 )
 | 
			
		||||
project( Facecam2D VERSION 0.1.0 )
 | 
			
		||||
find_package( libzip REQUIRED )
 | 
			
		||||
find_package( OpenCV REQUIRED )
 | 
			
		||||
message (STATUS "Found OpenCV at: " ${OpenCV_INCLUDE_DIRS} )
 | 
			
		||||
find_package( OpenGL REQUIRED )
 | 
			
		||||
| 
						 | 
				
			
			@ -38,5 +39,8 @@ add_executable( fc2d
 | 
			
		|||
	src/cv.cpp
 | 
			
		||||
	src/paths.cpp
 | 
			
		||||
	src/args.cpp
 | 
			
		||||
	src/model.cpp
 | 
			
		||||
	src/toml.c
 | 
			
		||||
	src/tomlcpp.cpp
 | 
			
		||||
)
 | 
			
		||||
target_link_libraries( fc2d ${OpenCV_LIBS} ${OPENGL_LIBRARIES} FreeGLUT::freeglut GLEW::glew )
 | 
			
		||||
target_link_libraries( fc2d ${OpenCV_LIBS} ${OPENGL_LIBRARIES} FreeGLUT::freeglut GLEW::glew zip )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										
											BIN
										
									
								
								models/test.fma
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/test.fma
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 8.8 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 5.3 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 7.9 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 19 KiB  | 
							
								
								
									
										33
									
								
								src/cv.cpp
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								src/cv.cpp
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -6,6 +6,8 @@
 | 
			
		|||
#include <graphics.hpp>
 | 
			
		||||
#include <paths.hpp>
 | 
			
		||||
#include <args.hpp>
 | 
			
		||||
#include <cv.hpp>
 | 
			
		||||
#include <modelpart.hpp>
 | 
			
		||||
 | 
			
		||||
cv::Ptr<cv::face::Facemark> facemark;
 | 
			
		||||
cv::CascadeClassifier haarFaceDetector;
 | 
			
		||||
| 
						 | 
				
			
			@ -101,30 +103,29 @@ void cvFrame() {
 | 
			
		|||
 | 
			
		||||
		//send control information to graphics
 | 
			
		||||
		float faceSize = landmarks[biggestFace][14].x - landmarks[biggestFace][2].x;
 | 
			
		||||
		updateModel(
 | 
			
		||||
			//head position
 | 
			
		||||
			glm::vec2(
 | 
			
		||||
 | 
			
		||||
		struct FaceData faceData;
 | 
			
		||||
		faceData.positions[BIND_NULL] = glm::vec2(0.0f, 0.0f);
 | 
			
		||||
		faceData.positions[BIND_HEAD] = glm::vec2(
 | 
			
		||||
			(landmarks[biggestFace][2].x + landmarks[biggestFace][14].x) / 2
 | 
			
		||||
				* 2 / (float)frame.cols - 1,
 | 
			
		||||
			(landmarks[biggestFace][2].y + landmarks[biggestFace][14].y) / 2
 | 
			
		||||
				* 2 / (float)frame.rows - 1
 | 
			
		||||
			),
 | 
			
		||||
 | 
			
		||||
			//face position
 | 
			
		||||
			glm::vec2(
 | 
			
		||||
			);
 | 
			
		||||
		faceData.positions[BIND_FACE] = glm::vec2(
 | 
			
		||||
			landmarks[biggestFace][30].x * 2 / (float)frame.cols - 1,
 | 
			
		||||
			landmarks[biggestFace][30].y * 2 / (float)frame.rows - 1
 | 
			
		||||
			),
 | 
			
		||||
			);
 | 
			
		||||
		faceData.triggers[TRIGGER_NULL] = false;
 | 
			
		||||
		faceData.triggers[TRIGGER_MOUTH_OPEN] = 
 | 
			
		||||
		(landmarks[biggestFace][66].y - landmarks[biggestFace][62].y) / faceSize > 0.04f;
 | 
			
		||||
 | 
			
		||||
			//rotation
 | 
			
		||||
			atanf((float)(landmarks[biggestFace][14].y - landmarks[biggestFace][2].y) /
 | 
			
		||||
				(float)(landmarks[biggestFace][2].x - landmarks[biggestFace][14].x)),
 | 
			
		||||
		faceData.headRotation = atanf(
 | 
			
		||||
			(float)(landmarks[biggestFace][14].y - landmarks[biggestFace][2].y) /
 | 
			
		||||
			(float)(landmarks[biggestFace][2].x - landmarks[biggestFace][14].x));
 | 
			
		||||
		faceData.scale = faceSize * 6 / (float)frame.cols;
 | 
			
		||||
 | 
			
		||||
			//scale
 | 
			
		||||
			faceSize * 6 / (float)frame.cols,
 | 
			
		||||
 | 
			
		||||
			//mouth open/closed state
 | 
			
		||||
			(landmarks[biggestFace][66].y - landmarks[biggestFace][62].y) / faceSize > 0.04f);
 | 
			
		||||
		updateModel(faceData);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								src/cv.hpp
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/cv.hpp
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,6 +1,17 @@
 | 
			
		|||
#ifndef CV_HPP
 | 
			
		||||
#define CV_HPP
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <glm/vec2.hpp>
 | 
			
		||||
 | 
			
		||||
struct FaceData {
 | 
			
		||||
	std::map<int, glm::vec2> positions;
 | 
			
		||||
	std::map<int, bool> triggers;
 | 
			
		||||
 | 
			
		||||
	float headRotation;
 | 
			
		||||
	float scale;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void initCV();
 | 
			
		||||
 | 
			
		||||
void cvFrame();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,21 +12,21 @@
 | 
			
		|||
 | 
			
		||||
#include <graphics.hpp>
 | 
			
		||||
#include <modelpart.hpp>
 | 
			
		||||
#include <model.hpp>
 | 
			
		||||
#include <paths.hpp>
 | 
			
		||||
#include <config.hpp>
 | 
			
		||||
#include <cv.hpp>
 | 
			
		||||
 | 
			
		||||
GLuint shader;	//standard shader program used for all elements
 | 
			
		||||
GLuint transUniform;	//location of the "transMatrix" transformation matrix uniform in the shader
 | 
			
		||||
 | 
			
		||||
//parts of the model (see modelpart.hpp)
 | 
			
		||||
ModelPart parts[3];
 | 
			
		||||
Model* model;
 | 
			
		||||
 | 
			
		||||
void display () {
 | 
			
		||||
	glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < sizeof(parts)/sizeof(ModelPart); i++) {
 | 
			
		||||
		parts[i].bindAndDraw();
 | 
			
		||||
	}
 | 
			
		||||
	model->draw();
 | 
			
		||||
 | 
			
		||||
	glutSwapBuffers();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -82,10 +82,7 @@ void initGraphics () {
 | 
			
		|||
 | 
			
		||||
	initShader();
 | 
			
		||||
 | 
			
		||||
	parts[0] = ModelPart(resolvePath("models/test/head-base.png").c_str(), transUniform);
 | 
			
		||||
	parts[1] = ModelPart(resolvePath("models/test/face-eyes.png").c_str(), transUniform);
 | 
			
		||||
	parts[2] = ModelPart(resolvePath("models/test/face-mouth-closed.png").c_str(), transUniform);
 | 
			
		||||
	parts[2].addTexture(resolvePath("models/test/face-mouth-open.png").c_str(), 1);
 | 
			
		||||
	model = new Model(resolvePath("models/test.fma").c_str());
 | 
			
		||||
 | 
			
		||||
	//enable blending for alpha textures
 | 
			
		||||
	glEnable(GL_BLEND);
 | 
			
		||||
| 
						 | 
				
			
			@ -100,12 +97,12 @@ void initGraphics () {
 | 
			
		|||
	std::cout << "graphics init complete" << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void initTexture (GLuint* texNum, const char* path) {
 | 
			
		||||
void initTexture (GLuint* texNum, unsigned char* buffer, size_t bufferLength) {
 | 
			
		||||
	glGenTextures(1, texNum);
 | 
			
		||||
	glBindTexture(GL_TEXTURE_2D, *texNum);
 | 
			
		||||
 | 
			
		||||
	int x, y, channels;
 | 
			
		||||
	GLubyte* pixels = stbi_load(path, &x, &y, &channels, 4);
 | 
			
		||||
	GLubyte* pixels = stbi_load_from_memory(buffer, bufferLength, &x, &y, &channels, 4);
 | 
			
		||||
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 | 
			
		||||
 | 
			
		||||
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
			
		||||
| 
						 | 
				
			
			@ -175,11 +172,8 @@ void printShaderCompileLog(GLuint shader) {
 | 
			
		|||
	std::cout << logBuffer << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void initModel () {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void updateModel(glm::vec2 headPos, glm::vec2 facePos, float rotation, float scale, bool mouthOpen) {
 | 
			
		||||
void updateModel(struct FaceData faceData) {
 | 
			
		||||
	/*
 | 
			
		||||
	//calculate transforms
 | 
			
		||||
	parts[0].setTransform(headPos, rotation, scale);
 | 
			
		||||
	parts[1].setTransform(facePos, rotation, scale);
 | 
			
		||||
| 
						 | 
				
			
			@ -187,6 +181,8 @@ void updateModel(glm::vec2 headPos, glm::vec2 facePos, float rotation, float sca
 | 
			
		|||
 | 
			
		||||
	//set mouth texture to open or closed
 | 
			
		||||
	parts[2].selectTexture(mouthOpen ? 1 : 0);
 | 
			
		||||
	*/
 | 
			
		||||
	model->updateTransforms(faceData);
 | 
			
		||||
 | 
			
		||||
	//tell FreeGLUT to schedule a screen update
 | 
			
		||||
	glutPostRedisplay();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,18 +9,22 @@
 | 
			
		|||
 | 
			
		||||
#include <glm/vec2.hpp>
 | 
			
		||||
 | 
			
		||||
#include <cv.hpp>
 | 
			
		||||
 | 
			
		||||
extern GLuint transUniform;
 | 
			
		||||
 | 
			
		||||
void initGraphics ();
 | 
			
		||||
 | 
			
		||||
void graphicsFrame ();
 | 
			
		||||
 | 
			
		||||
void initBuffers (GLuint* vaoNum);
 | 
			
		||||
 | 
			
		||||
void initTexture (GLuint* texNum, const char* path);
 | 
			
		||||
void initTexture (GLuint* texNum, unsigned char* buffer, size_t bufferLength);
 | 
			
		||||
 | 
			
		||||
void initShader();
 | 
			
		||||
 | 
			
		||||
void printShaderCompileLog(GLuint shader);
 | 
			
		||||
 | 
			
		||||
void updateModel(glm::vec2 headPos, glm::vec2 facePos, float rotation, float scale, bool mouthOpen);
 | 
			
		||||
void updateModel(struct FaceData faceData);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@
 | 
			
		|||
#include <paths.hpp>
 | 
			
		||||
#include <args.hpp>
 | 
			
		||||
#include <config.hpp>
 | 
			
		||||
#include <model.hpp>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
| 
						 | 
				
			
			@ -17,8 +18,11 @@ int main (int argc, char** argv) {
 | 
			
		|||
	std::cout << "Default asset prefix: " << prefixDefault << std::endl;
 | 
			
		||||
 | 
			
		||||
	initGraphics();
 | 
			
		||||
 | 
			
		||||
	//Model model(resolvePath("models/test.fma").c_str());
 | 
			
		||||
	initCV();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	while (true) {
 | 
			
		||||
		cvFrame();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										113
									
								
								src/model.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/model.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,113 @@
 | 
			
		|||
#include <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <zip.h>
 | 
			
		||||
#include <tomlcpp.hpp> //dynamically link tomlcpp if it becomes common in repositories
 | 
			
		||||
#include <model.hpp>
 | 
			
		||||
 | 
			
		||||
#define BUFFER_SIZE_MODEL_DESC	8192		// 8 KiB
 | 
			
		||||
#define BUFFER_SIZE_TEXTURE	16777220	// 16 MiB
 | 
			
		||||
 | 
			
		||||
void textureFromArchive(zip_t* archive, const char* path, ModelPart* part, size_t slot, std::string triggerName) {
 | 
			
		||||
	zip_file_t* textureFile = zip_fopen(archive, path, 0);
 | 
			
		||||
	if (textureFile != NULL) {
 | 
			
		||||
		unsigned char* textureBuffer = new unsigned char[BUFFER_SIZE_TEXTURE];
 | 
			
		||||
		size_t textureLength = zip_fread(textureFile, textureBuffer, BUFFER_SIZE_TEXTURE-1);
 | 
			
		||||
 | 
			
		||||
		part->addTexture(textureBuffer, textureLength, slot, triggerName);
 | 
			
		||||
 | 
			
		||||
		delete [] textureBuffer;
 | 
			
		||||
	} else {
 | 
			
		||||
		std::cerr << path << " does not exist in archive!" << std::endl;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
Model::Model(const char* path) {
 | 
			
		||||
	int zipError;
 | 
			
		||||
	zip_t* archive = zip_open(path, ZIP_RDONLY, &zipError);
 | 
			
		||||
 | 
			
		||||
	if (!archive) {
 | 
			
		||||
		std::cerr << "Model file " << path << " does not exist!" << std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get model description file (model.toml)
 | 
			
		||||
	zip_file_t* modelDescFile = zip_fopen(archive, "model.toml", 0);
 | 
			
		||||
	char modelDescBuffer[BUFFER_SIZE_MODEL_DESC];
 | 
			
		||||
	size_t descLength = zip_fread(modelDescFile, modelDescBuffer, BUFFER_SIZE_MODEL_DESC-1);
 | 
			
		||||
	modelDescBuffer[descLength] = 0;	//null-terminate
 | 
			
		||||
 | 
			
		||||
	// parse model.toml
 | 
			
		||||
	auto modelDesc = toml::parse(std::string(modelDescBuffer));
 | 
			
		||||
	if (!modelDesc.table) {
 | 
			
		||||
		std::cerr << "cannot parse model.toml! " << std::endl << modelDesc.errmsg << std::endl;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto partsDescArray = modelDesc.table->getArray("part");
 | 
			
		||||
 | 
			
		||||
	auto partsVec = *partsDescArray->getTableVector();
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < partsVec.size(); i++) {
 | 
			
		||||
		ModelPart newPart;
 | 
			
		||||
 | 
			
		||||
		// position
 | 
			
		||||
		auto bindResult = partsVec[i].getString("bind");
 | 
			
		||||
		if (!bindResult.first) {
 | 
			
		||||
			std::cerr << "Part " << i << " does not define a bind!" << std::endl;
 | 
			
		||||
		} else {
 | 
			
		||||
			newPart.setBind(bindResult.second);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto parentResult = partsVec[i].getString("follow");
 | 
			
		||||
		auto factorResult = partsVec[i].getDouble("factor");
 | 
			
		||||
 | 
			
		||||
		if (parentResult.first) {
 | 
			
		||||
			newPart.setFollowTarget(parentResult.second);
 | 
			
		||||
 | 
			
		||||
			if (factorResult.first) {
 | 
			
		||||
				newPart.setFollowFactor((float)factorResult.second);
 | 
			
		||||
			} else {
 | 
			
		||||
				newPart.setFollowFactor(1.0f);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// texture
 | 
			
		||||
		auto textureSingle = partsVec[i].getString("texture");
 | 
			
		||||
 | 
			
		||||
		if (textureSingle.first) {
 | 
			
		||||
			// only a single texture was defined
 | 
			
		||||
			textureFromArchive(archive, textureSingle.second.c_str(), &newPart, 0, "null");
 | 
			
		||||
		} else {
 | 
			
		||||
			auto textureArray = partsVec[i].getArray("textures");
 | 
			
		||||
			auto textureVec = *textureArray->getTableVector().get();
 | 
			
		||||
 | 
			
		||||
			if (textureVec.size() < 1) {
 | 
			
		||||
				std::cerr << "Part " << i << " does not define any textures!" << std::endl;
 | 
			
		||||
			} else {
 | 
			
		||||
				// a list of textures with triggers were defined
 | 
			
		||||
				for (int j = 0; j < textureVec.size(); j++) {
 | 
			
		||||
					auto fileResult = textureVec[j].getString("file");
 | 
			
		||||
					auto triggerResult = textureVec[j].getString("trigger");
 | 
			
		||||
 | 
			
		||||
					if (fileResult.first) {
 | 
			
		||||
						std::string trigger = triggerResult.first ? triggerResult.second : "null";
 | 
			
		||||
						textureFromArchive(archive, fileResult.second.c_str(), &newPart, j, trigger);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
			parts.push_back(newPart);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Model::draw() {
 | 
			
		||||
	for (size_t i = 0; i < parts.size(); i++) {
 | 
			
		||||
		parts[i].bindAndDraw();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Model::updateTransforms(struct FaceData faceData) {
 | 
			
		||||
	for (size_t i = 0; i < parts.size(); i++) {
 | 
			
		||||
		parts[i].processFaceData(faceData);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/model.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/model.hpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
#ifndef MODEL_HPP
 | 
			
		||||
#define MODEL_HPP
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <modelpart.hpp>
 | 
			
		||||
#include <cv.hpp>
 | 
			
		||||
 | 
			
		||||
class Model {
 | 
			
		||||
	std::vector<ModelPart> parts;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		Model(const char* path);
 | 
			
		||||
 | 
			
		||||
		void draw();
 | 
			
		||||
 | 
			
		||||
		void updateTransforms(struct FaceData faceData);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
#include <GL/glew.h>
 | 
			
		||||
 | 
			
		||||
#include <glm/mat4x4.hpp>
 | 
			
		||||
#include <glm/gtc/type_ptr.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8,36 +7,72 @@
 | 
			
		|||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
ModelPart::ModelPart() {
 | 
			
		||||
}
 | 
			
		||||
std::map<std::string, int> bindStringToNum {
 | 
			
		||||
	{"null", BIND_NULL},
 | 
			
		||||
	{"head", BIND_HEAD},
 | 
			
		||||
	{"face", BIND_FACE},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ModelPart::ModelPart(const char* texPath, GLuint transUniformNum) {
 | 
			
		||||
std::map<std::string, bool> triggerStringToNum {
 | 
			
		||||
	{"null", TRIGGER_NULL},
 | 
			
		||||
	{"mouth-open", TRIGGER_MOUTH_OPEN},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ModelPart::ModelPart() {
 | 
			
		||||
	//create vbo, ebo, vao
 | 
			
		||||
	initBuffers(&vao);
 | 
			
		||||
	//create texture
 | 
			
		||||
	initTexture(&tex[0], texPath);
 | 
			
		||||
 | 
			
		||||
	transUniform = transUniformNum;
 | 
			
		||||
 | 
			
		||||
	empty = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelPart::bindAndDraw() {
 | 
			
		||||
	if (empty) { return; }
 | 
			
		||||
	glBindVertexArray(vao);
 | 
			
		||||
	glBindTexture(GL_TEXTURE_2D, tex[texSelection]);
 | 
			
		||||
	glUniformMatrix4fv(transUniform, 1, GL_FALSE, glm::value_ptr(transMatrix));
 | 
			
		||||
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelPart::setBind(std::string bindName) {
 | 
			
		||||
	bind = bindStringToNum[bindName];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelPart::setFollowTarget(std::string followTarget) {
 | 
			
		||||
	follow = bindStringToNum[followTarget];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelPart::setFollowFactor(float followFactor) {
 | 
			
		||||
	factor = followFactor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelPart::setTransform(glm::vec2 position, float rotation, float scale) {
 | 
			
		||||
	transMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(position.x, -position.y, 0.0f));
 | 
			
		||||
	transMatrix = glm::rotate(transMatrix, rotation, glm::vec3(0.0f, 0.0f, 1.0f));
 | 
			
		||||
	transMatrix = glm::scale(transMatrix, glm::vec3(scale, scale, scale));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelPart::addTexture(const char* texPath, size_t slot) {
 | 
			
		||||
	initTexture(&tex[slot], texPath);
 | 
			
		||||
void ModelPart::processFaceData(struct FaceData faceData) {
 | 
			
		||||
	// calculate position
 | 
			
		||||
	glm::vec2 bindPosition = faceData.positions[bind];
 | 
			
		||||
	glm::vec2 followPosition = faceData.positions[follow];
 | 
			
		||||
	glm::vec2 followDirection = followPosition - bindPosition;
 | 
			
		||||
	glm::vec2 newPosition = bindPosition + (followDirection * factor);
 | 
			
		||||
 | 
			
		||||
	setTransform(newPosition, faceData.headRotation, faceData.scale);
 | 
			
		||||
 | 
			
		||||
	// change textures
 | 
			
		||||
	selectTexture(0);	// if none are triggered, use the first one
 | 
			
		||||
	for (size_t i = 0; i < texCount; i++) {
 | 
			
		||||
		if (faceData.triggers[texTriggers[i]]) {
 | 
			
		||||
			selectTexture(i);
 | 
			
		||||
			break;	// if several textures are triggered, the first one defined in model.toml will get priority
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelPart::addTexture(unsigned char* texBuffer, size_t texLength, size_t slot, std::string triggerName) {
 | 
			
		||||
	initTexture(&tex[slot], texBuffer, texLength);
 | 
			
		||||
	texTriggers[slot] = triggerStringToNum[triggerName];
 | 
			
		||||
	texCount++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelPart::selectTexture(size_t slot) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,29 +1,49 @@
 | 
			
		|||
#ifndef MODELPART_HPP
 | 
			
		||||
#define MODELPART_HPP
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include <glm/ext/matrix_transform.hpp>
 | 
			
		||||
#include <graphics.hpp>
 | 
			
		||||
#include <cv.hpp>
 | 
			
		||||
 | 
			
		||||
#define BIND_NULL 0x00
 | 
			
		||||
#define BIND_HEAD 0x01
 | 
			
		||||
#define BIND_FACE 0x02
 | 
			
		||||
 | 
			
		||||
#define TRIGGER_NULL		0x00
 | 
			
		||||
#define TRIGGER_MOUTH_OPEN	0x01
 | 
			
		||||
 | 
			
		||||
class ModelPart {
 | 
			
		||||
	GLuint vao, transUniform;
 | 
			
		||||
	GLuint vao;
 | 
			
		||||
 | 
			
		||||
	GLuint tex[16];	//support 16 textures to switch between
 | 
			
		||||
	int texTriggers[16];
 | 
			
		||||
	size_t texSelection = 0;
 | 
			
		||||
	size_t texCount = 0;
 | 
			
		||||
 | 
			
		||||
	glm::mat4 transMatrix = glm::mat4(1.0f);
 | 
			
		||||
 | 
			
		||||
	int bind = BIND_NULL;
 | 
			
		||||
	int follow = BIND_NULL;
 | 
			
		||||
	float factor = 0.0f;	//default factor of 0 so part will not follow a null by default
 | 
			
		||||
 | 
			
		||||
	bool empty = true;
 | 
			
		||||
	
 | 
			
		||||
	public:
 | 
			
		||||
		ModelPart();
 | 
			
		||||
 | 
			
		||||
		ModelPart(const char* texPath, GLuint transUniformNum);
 | 
			
		||||
 | 
			
		||||
		void bindAndDraw();
 | 
			
		||||
 | 
			
		||||
		void setBind(std::string bindString);
 | 
			
		||||
		void setFollowTarget(std::string followString);
 | 
			
		||||
		void setFollowFactor(float followFactor);
 | 
			
		||||
 | 
			
		||||
		void setTransform(glm::vec2 position, float rotation, float scale);
 | 
			
		||||
 | 
			
		||||
		void addTexture(const char* texPath, size_t slot);
 | 
			
		||||
		void processFaceData(struct FaceData faceData);
 | 
			
		||||
 | 
			
		||||
		void addTexture(unsigned char* texBuffer, size_t texLength, size_t slot, std::string triggerName);
 | 
			
		||||
		void selectTexture(size_t slot);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2247
									
								
								src/toml.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2247
									
								
								src/toml.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										175
									
								
								src/toml.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								src/toml.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,175 @@
 | 
			
		|||
/*
 | 
			
		||||
  MIT License
 | 
			
		||||
  
 | 
			
		||||
  Copyright (c) 2017 - 2019 CK Tan
 | 
			
		||||
  https://github.com/cktan/tomlc99
 | 
			
		||||
  
 | 
			
		||||
  Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
  of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
  in the Software without restriction, including without limitation the rights
 | 
			
		||||
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
  copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
  furnished to do so, subject to the following conditions:
 | 
			
		||||
  
 | 
			
		||||
  The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
  copies or substantial portions of the Software.
 | 
			
		||||
  
 | 
			
		||||
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
  SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef TOML_H
 | 
			
		||||
#define TOML_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
#define TOML_EXTERN extern "C"
 | 
			
		||||
#else
 | 
			
		||||
#define TOML_EXTERN extern
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct toml_timestamp_t toml_timestamp_t;
 | 
			
		||||
typedef struct toml_table_t toml_table_t;
 | 
			
		||||
typedef struct toml_array_t toml_array_t;
 | 
			
		||||
typedef struct toml_datum_t toml_datum_t;
 | 
			
		||||
 | 
			
		||||
/* Parse a file. Return a table on success, or 0 otherwise. 
 | 
			
		||||
 * Caller must toml_free(the-return-value) after use.
 | 
			
		||||
 */
 | 
			
		||||
TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, 
 | 
			
		||||
										  char* errbuf,
 | 
			
		||||
										  int errbufsz);
 | 
			
		||||
 | 
			
		||||
/* Parse a string containing the full config. 
 | 
			
		||||
 * Return a table on success, or 0 otherwise.
 | 
			
		||||
 * Caller must toml_free(the-return-value) after use.
 | 
			
		||||
 */
 | 
			
		||||
TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */
 | 
			
		||||
									 char* errbuf,
 | 
			
		||||
									 int errbufsz);
 | 
			
		||||
 | 
			
		||||
/* Free the table returned by toml_parse() or toml_parse_file(). Once 
 | 
			
		||||
 * this function is called, any handles accessed through this tab 
 | 
			
		||||
 * directly or indirectly are no longer valid.
 | 
			
		||||
 */
 | 
			
		||||
TOML_EXTERN void toml_free(toml_table_t* tab);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Timestamp types. The year, month, day, hour, minute, second, z 
 | 
			
		||||
 * fields may be NULL if they are not relevant. e.g. In a DATE
 | 
			
		||||
 * type, the hour, minute, second and z fields will be NULLs.
 | 
			
		||||
 */
 | 
			
		||||
struct toml_timestamp_t {
 | 
			
		||||
	struct { /* internal. do not use. */
 | 
			
		||||
		int year, month, day;
 | 
			
		||||
		int hour, minute, second, millisec;
 | 
			
		||||
		char z[10];
 | 
			
		||||
	} __buffer;
 | 
			
		||||
	int *year, *month, *day;
 | 
			
		||||
	int *hour, *minute, *second, *millisec;
 | 
			
		||||
	char* z;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*-----------------------------------------------------------------
 | 
			
		||||
 *  Enhanced access methods 
 | 
			
		||||
 */
 | 
			
		||||
struct toml_datum_t {
 | 
			
		||||
	int ok;
 | 
			
		||||
	union {
 | 
			
		||||
		toml_timestamp_t* ts; /* ts must be freed after use */
 | 
			
		||||
		char*   s; /* string value. s must be freed after use */
 | 
			
		||||
		int     b; /* bool value */
 | 
			
		||||
		int64_t i; /* int value */
 | 
			
		||||
		double  d; /* double value */
 | 
			
		||||
	} u;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* on arrays: */
 | 
			
		||||
/* ... retrieve size of array. */
 | 
			
		||||
TOML_EXTERN int toml_array_nelem(const toml_array_t* arr);
 | 
			
		||||
/* ... retrieve values using index. */
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t* arr, int idx);
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t* arr, int idx);
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t* arr, int idx);
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t* arr, int idx);
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx);
 | 
			
		||||
/* ... retrieve array or table using index. */
 | 
			
		||||
TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx);
 | 
			
		||||
TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx);
 | 
			
		||||
 | 
			
		||||
/* on tables: */
 | 
			
		||||
/* ... retrieve the key in table at keyidx. Return 0 if out of range. */
 | 
			
		||||
TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx);
 | 
			
		||||
/* ... retrieve values using key. */
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t* arr, const char* key);
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key);
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t* arr, const char* key);
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t* arr, const char* key);
 | 
			
		||||
TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key);
 | 
			
		||||
/* .. retrieve array or table using key. */
 | 
			
		||||
TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab,
 | 
			
		||||
										const char* key);
 | 
			
		||||
TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab,
 | 
			
		||||
										const char* key);
 | 
			
		||||
 | 
			
		||||
/*-----------------------------------------------------------------
 | 
			
		||||
 * lesser used 
 | 
			
		||||
 */
 | 
			
		||||
/* Return the array kind: 't'able, 'a'rray, 'v'alue */
 | 
			
		||||
TOML_EXTERN char toml_array_kind(const toml_array_t* arr);
 | 
			
		||||
 | 
			
		||||
/* For array kind 'v'alue, return the type of values 
 | 
			
		||||
   i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp
 | 
			
		||||
   0 if unknown
 | 
			
		||||
*/
 | 
			
		||||
TOML_EXTERN char toml_array_type(const toml_array_t* arr);
 | 
			
		||||
 | 
			
		||||
/* Return the key of an array */
 | 
			
		||||
TOML_EXTERN const char* toml_array_key(const toml_array_t* arr);
 | 
			
		||||
 | 
			
		||||
/* Return the number of key-values in a table */
 | 
			
		||||
TOML_EXTERN int toml_table_nkval(const toml_table_t* tab);
 | 
			
		||||
 | 
			
		||||
/* Return the number of arrays in a table */
 | 
			
		||||
TOML_EXTERN int toml_table_narr(const toml_table_t* tab);
 | 
			
		||||
 | 
			
		||||
/* Return the number of sub-tables in a table */
 | 
			
		||||
TOML_EXTERN int toml_table_ntab(const toml_table_t* tab);
 | 
			
		||||
 | 
			
		||||
/* Return the key of a table*/
 | 
			
		||||
TOML_EXTERN const char* toml_table_key(const toml_table_t* tab);
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------------------
 | 
			
		||||
 * misc 
 | 
			
		||||
 */
 | 
			
		||||
TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret);
 | 
			
		||||
TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]);
 | 
			
		||||
TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t),
 | 
			
		||||
								  void	(*xxfree)(void*));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------------------
 | 
			
		||||
 *  deprecated 
 | 
			
		||||
 */
 | 
			
		||||
/* A raw value, must be processed by toml_rto* before using. */
 | 
			
		||||
typedef const char* toml_raw_t;
 | 
			
		||||
TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key);
 | 
			
		||||
TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx);
 | 
			
		||||
TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret);
 | 
			
		||||
TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret);
 | 
			
		||||
TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret);
 | 
			
		||||
TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret);
 | 
			
		||||
TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen);
 | 
			
		||||
TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* TOML_H */
 | 
			
		||||
							
								
								
									
										334
									
								
								src/tomlcpp.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								src/tomlcpp.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,334 @@
 | 
			
		|||
/*
 | 
			
		||||
 | 
			
		||||
  MIT License
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2020 CK Tan
 | 
			
		||||
  https://github.com/cktan/tomlcpp
 | 
			
		||||
 | 
			
		||||
  Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
  of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
  in the Software without restriction, including without limitation the rights
 | 
			
		||||
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
  copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
  furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
  The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
  copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
  SOFTWARE.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include "tomlcpp.hpp"
 | 
			
		||||
#include "toml.h"
 | 
			
		||||
 | 
			
		||||
using namespace toml;
 | 
			
		||||
using std::string;
 | 
			
		||||
using std::vector;
 | 
			
		||||
using std::pair;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void* toml_mymalloc(size_t sz)
 | 
			
		||||
{
 | 
			
		||||
	return new char[sz];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void toml_myfree(void* p)
 | 
			
		||||
{
 | 
			
		||||
	if (p) {
 | 
			
		||||
		char* pp = (char*) p;
 | 
			
		||||
		delete[] pp;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Keep track of memory to be freed when all references
 | 
			
		||||
 *  to the tree returned by toml::parse is no longer reachable.
 | 
			
		||||
 */
 | 
			
		||||
struct toml::Backing {
 | 
			
		||||
	char* ptr = 0;
 | 
			
		||||
	toml_table_t* root = 0;
 | 
			
		||||
	Backing(const string& conf) {
 | 
			
		||||
		ptr = new char[conf.length() + 1];
 | 
			
		||||
		strcpy(ptr, conf.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	~Backing() {
 | 
			
		||||
		if (ptr) delete[] ptr;
 | 
			
		||||
		if (root) toml_free(root);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pair<bool, string> Table::getString(const string& key) const
 | 
			
		||||
{
 | 
			
		||||
	string str;
 | 
			
		||||
	toml_datum_t p = toml_string_in(m_table, key.c_str());
 | 
			
		||||
	if (p.ok) {
 | 
			
		||||
		str = p.u.s;
 | 
			
		||||
		toml_myfree(p.u.s);
 | 
			
		||||
	}
 | 
			
		||||
	return {p.ok, str};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pair<bool, bool> Table::getBool(const string& key) const
 | 
			
		||||
{
 | 
			
		||||
	toml_datum_t p = toml_bool_in(m_table, key.c_str());
 | 
			
		||||
	return {p.ok, !!p.u.b};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pair<bool, int64_t> Table::getInt(const string& key) const
 | 
			
		||||
{
 | 
			
		||||
	toml_datum_t p = toml_int_in(m_table, key.c_str());
 | 
			
		||||
	return {p.ok, p.u.i};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pair<bool, double> Table::getDouble(const string& key) const
 | 
			
		||||
{
 | 
			
		||||
	toml_datum_t p = toml_double_in(m_table, key.c_str());
 | 
			
		||||
	return {p.ok, p.u.d};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pair<bool, Timestamp> Table::getTimestamp(const string& key) const
 | 
			
		||||
{
 | 
			
		||||
	Timestamp ret;
 | 
			
		||||
	toml_datum_t p = toml_timestamp_in(m_table, key.c_str());
 | 
			
		||||
	if (p.ok) {
 | 
			
		||||
		toml_timestamp_t& ts = *p.u.ts;
 | 
			
		||||
		ret.year = (ts.year ? *ts.year : -1);
 | 
			
		||||
		ret.month = (ts.month ? *ts.month : -1);
 | 
			
		||||
		ret.day = (ts.day ? *ts.day : -1);
 | 
			
		||||
		ret.hour = (ts.hour ? *ts.hour : -1);
 | 
			
		||||
		ret.second = (ts.second ? *ts.second : -1);
 | 
			
		||||
		ret.millisec = (ts.millisec ? *ts.millisec : -1);
 | 
			
		||||
		ret.z = ts.z ? string(ts.z) : "";
 | 
			
		||||
		toml_myfree(p.u.ts);
 | 
			
		||||
	}
 | 
			
		||||
	return {p.ok, ret};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<Array> Table::getArray(const string& key) const
 | 
			
		||||
{
 | 
			
		||||
	toml_array_t* a = toml_array_in(m_table, key.c_str());
 | 
			
		||||
	if (!a)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique<Array>(a, m_backing);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<Table> Table::getTable(const string& key) const
 | 
			
		||||
{
 | 
			
		||||
	toml_table_t* t = toml_table_in(m_table, key.c_str());
 | 
			
		||||
	if (!t)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique<Table>(t, m_backing);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vector<string> Table::keys() const
 | 
			
		||||
{
 | 
			
		||||
	vector<string> vec;
 | 
			
		||||
	for (int i = 0; ; i++) {
 | 
			
		||||
		const char* k = toml_key_in(m_table, i);
 | 
			
		||||
		if (!k) break;
 | 
			
		||||
		vec.push_back(k);
 | 
			
		||||
	}
 | 
			
		||||
	return vec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char Array::kind() const
 | 
			
		||||
{
 | 
			
		||||
	return toml_array_kind(m_array);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char Array::type() const
 | 
			
		||||
{
 | 
			
		||||
	return toml_array_type(m_array);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::unique_ptr< vector<Array>> Array::getArrayVector() const
 | 
			
		||||
{
 | 
			
		||||
	int top = toml_array_nelem(m_array);
 | 
			
		||||
	if (top < 0) return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique< vector<Array>>();
 | 
			
		||||
	ret->reserve(top);
 | 
			
		||||
	for (int i = 0; i < top; i++) {
 | 
			
		||||
		toml_array_t* a = toml_array_at(m_array, i);
 | 
			
		||||
		if (!a)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		ret->push_back(Array(a, m_backing));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr< vector<Table>> Array::getTableVector() const
 | 
			
		||||
{
 | 
			
		||||
	int top = toml_array_nelem(m_array);
 | 
			
		||||
	if (top < 0) return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique< vector<Table>>();
 | 
			
		||||
	ret->reserve(top);
 | 
			
		||||
	for (int i = 0; i < top; i++) {
 | 
			
		||||
		toml_table_t* t = toml_table_at(m_array, i);
 | 
			
		||||
		if (!t)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		ret->push_back(Table(t, m_backing));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr< vector<string> > Array::getStringVector() const
 | 
			
		||||
{
 | 
			
		||||
	int top = toml_array_nelem(m_array);
 | 
			
		||||
	if (top < 0) return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique< vector<string> >();
 | 
			
		||||
	ret->reserve(top);
 | 
			
		||||
	for (int i = 0; i < top; i++) {
 | 
			
		||||
		toml_datum_t p = toml_string_at(m_array, i);
 | 
			
		||||
		if (!p.ok) return 0;
 | 
			
		||||
		ret->push_back(p.u.s);
 | 
			
		||||
		toml_myfree(p.u.s);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::unique_ptr< vector<bool> > Array::getBoolVector() const
 | 
			
		||||
{
 | 
			
		||||
	int top = toml_array_nelem(m_array);
 | 
			
		||||
	if (top < 0) return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique< vector<bool> >();
 | 
			
		||||
	ret->reserve(top);
 | 
			
		||||
	for (int i = 0; i < top; i++) {
 | 
			
		||||
		toml_datum_t p = toml_bool_at(m_array, i);
 | 
			
		||||
		if (!p.ok) return 0;
 | 
			
		||||
		ret->push_back(!!p.u.b);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::unique_ptr< vector<int64_t> > Array::getIntVector() const
 | 
			
		||||
{
 | 
			
		||||
	int top = toml_array_nelem(m_array);
 | 
			
		||||
	if (top < 0) return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique< vector<int64_t> >();
 | 
			
		||||
	ret->reserve(top);
 | 
			
		||||
	for (int i = 0; i < top; i++) {
 | 
			
		||||
		toml_datum_t p = toml_int_at(m_array, i);
 | 
			
		||||
		if (!p.ok) return 0;
 | 
			
		||||
		ret->push_back(p.u.i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::unique_ptr< vector<Timestamp> > Array::getTimestampVector() const
 | 
			
		||||
{
 | 
			
		||||
	int top = toml_array_nelem(m_array);
 | 
			
		||||
	if (top < 0) return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique< vector<Timestamp> >();
 | 
			
		||||
	ret->reserve(top);
 | 
			
		||||
	for (int i = 0; i < top; i++) {
 | 
			
		||||
		toml_datum_t p = toml_timestamp_at(m_array, i);
 | 
			
		||||
		if (!p.ok) return 0;
 | 
			
		||||
 | 
			
		||||
		toml_timestamp_t& ts = *p.u.ts;
 | 
			
		||||
		Timestamp v;
 | 
			
		||||
		v.year = (ts.year ? *ts.year : -1);
 | 
			
		||||
		v.month = (ts.month ? *ts.month : -1);
 | 
			
		||||
		v.day = (ts.day ? *ts.day : -1);
 | 
			
		||||
		v.hour = (ts.hour ? *ts.hour : -1);
 | 
			
		||||
		v.second = (ts.second ? *ts.second : -1);
 | 
			
		||||
		v.millisec = (ts.millisec ? *ts.millisec : -1);
 | 
			
		||||
		v.z = ts.z ? string(ts.z) : "";
 | 
			
		||||
		toml_myfree(p.u.ts);
 | 
			
		||||
 | 
			
		||||
		ret->push_back(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::unique_ptr< vector<double> > Array::getDoubleVector() const
 | 
			
		||||
{
 | 
			
		||||
	int top = toml_array_nelem(m_array);
 | 
			
		||||
	if (top < 0) return 0;
 | 
			
		||||
 | 
			
		||||
	auto ret = std::make_unique< vector<double> >();
 | 
			
		||||
	ret->reserve(top);
 | 
			
		||||
	for (int i = 0; i < top; i++) {
 | 
			
		||||
		toml_datum_t p = toml_double_at(m_array, i);
 | 
			
		||||
		if (!p.ok) return 0;
 | 
			
		||||
		ret->push_back(p.u.d);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int toml::Array::size() const
 | 
			
		||||
{
 | 
			
		||||
	return toml_array_nelem(m_array);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
toml::Result toml::parse(const string& conf)
 | 
			
		||||
{
 | 
			
		||||
	toml::Result ret;
 | 
			
		||||
	char errbuf[200];
 | 
			
		||||
	auto backing = std::make_shared<Backing>(conf);
 | 
			
		||||
 | 
			
		||||
	toml_set_memutil(toml_mymalloc, toml_myfree);
 | 
			
		||||
	toml_table_t* t = toml_parse(backing->ptr, errbuf, sizeof(errbuf));
 | 
			
		||||
	if (t) {
 | 
			
		||||
		ret.table = std::make_shared<Table>(t, backing);
 | 
			
		||||
		backing->root = t;
 | 
			
		||||
	} else {
 | 
			
		||||
		ret.errmsg = (*errbuf) ? string(errbuf) : "unknown error";
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
toml::Result toml::parseFile(const string& path)
 | 
			
		||||
{
 | 
			
		||||
	toml::Result ret;
 | 
			
		||||
	std::ifstream stream(path);
 | 
			
		||||
	if (!stream) {
 | 
			
		||||
		ret.errmsg = strerror(errno);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	string conf(std::istreambuf_iterator<char>{stream}, {});
 | 
			
		||||
	return toml::parse(conf);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										128
									
								
								src/tomlcpp.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/tomlcpp.hpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,128 @@
 | 
			
		|||
/*
 | 
			
		||||
  MIT License
 | 
			
		||||
  
 | 
			
		||||
  Copyright (c) 2020 CK Tan
 | 
			
		||||
  https://github.com/cktan/tomlcpp
 | 
			
		||||
  
 | 
			
		||||
  Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
  of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
  in the Software without restriction, including without limitation the rights
 | 
			
		||||
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
  copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
  furnished to do so, subject to the following conditions:
 | 
			
		||||
  
 | 
			
		||||
  The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
  copies or substantial portions of the Software.
 | 
			
		||||
  
 | 
			
		||||
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
  SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef TOML_HPP
 | 
			
		||||
#define TOML_HPP
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
struct toml_table_t;
 | 
			
		||||
struct toml_array_t;
 | 
			
		||||
 | 
			
		||||
namespace toml {
 | 
			
		||||
 | 
			
		||||
	struct Backing;
 | 
			
		||||
	class Array;
 | 
			
		||||
	class Table;
 | 
			
		||||
	using std::pair;
 | 
			
		||||
	using std::string;
 | 
			
		||||
	using std::vector;
 | 
			
		||||
 | 
			
		||||
	/* A Timestamp value */
 | 
			
		||||
	struct Timestamp {
 | 
			
		||||
		// -1 means it is not valid
 | 
			
		||||
		int year = -1;
 | 
			
		||||
		int month = -1;
 | 
			
		||||
		int day = -1;
 | 
			
		||||
		int hour = -1;
 | 
			
		||||
		int minute = -1;
 | 
			
		||||
		int second = -1;
 | 
			
		||||
		int millisec = -1;
 | 
			
		||||
		string z;			// "" if no timezone
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/* A table in toml. You can extract value/table/array using a key. */
 | 
			
		||||
	class Table {
 | 
			
		||||
		public:
 | 
			
		||||
		vector<string> keys() const;
 | 
			
		||||
 | 
			
		||||
		// get content
 | 
			
		||||
		pair<bool, string>     getString(const string& key) const;
 | 
			
		||||
		pair<bool, bool>       getBool(const string& key) const;
 | 
			
		||||
		pair<bool, int64_t>    getInt(const string& key) const;
 | 
			
		||||
		pair<bool, double>     getDouble(const string& key) const;
 | 
			
		||||
		pair<bool, Timestamp>  getTimestamp(const string& key) const;
 | 
			
		||||
		std::unique_ptr<Table> getTable(const string& key) const;
 | 
			
		||||
		std::unique_ptr<Array> getArray(const string& key) const;
 | 
			
		||||
 | 
			
		||||
		// internal
 | 
			
		||||
		Table(toml_table_t* t, std::shared_ptr<Backing> backing) : m_table(t), m_backing(backing) {}
 | 
			
		||||
		
 | 
			
		||||
		private:
 | 
			
		||||
		toml_table_t* const m_table = 0;
 | 
			
		||||
		std::shared_ptr<Backing> m_backing;
 | 
			
		||||
		
 | 
			
		||||
		Table() = delete;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* An array in toml. You can extract value/table/array using an index. */
 | 
			
		||||
	class Array {
 | 
			
		||||
		public:
 | 
			
		||||
 | 
			
		||||
		// Content kind
 | 
			
		||||
		// t:table, a:array, v:value
 | 
			
		||||
		char kind() const;
 | 
			
		||||
 | 
			
		||||
		// For Value kind only, check the type of the value
 | 
			
		||||
		// i:int, d:double, b:bool, s:string, t:time, D: date, T:timestamp, 0:unknown
 | 
			
		||||
		char type() const;
 | 
			
		||||
 | 
			
		||||
		// Return the #elements in the array
 | 
			
		||||
		int size() const;
 | 
			
		||||
 | 
			
		||||
		// For values, some conveniet methods to obtain vector of values
 | 
			
		||||
		std::unique_ptr< vector<string> >     getStringVector() const;
 | 
			
		||||
		std::unique_ptr< vector<bool> >       getBoolVector() const;
 | 
			
		||||
		std::unique_ptr< vector<int64_t> >    getIntVector() const;
 | 
			
		||||
		std::unique_ptr< vector<double> >     getDoubleVector() const;
 | 
			
		||||
		std::unique_ptr< vector<Timestamp> >  getTimestampVector() const;
 | 
			
		||||
 | 
			
		||||
		// Obtain vectors of table or array
 | 
			
		||||
		std::unique_ptr< vector<Table>> getTableVector() const;
 | 
			
		||||
		std::unique_ptr< vector<Array>> getArrayVector() const;
 | 
			
		||||
 | 
			
		||||
		// internal
 | 
			
		||||
		Array(toml_array_t* a, std::shared_ptr<Backing> backing) : m_array(a), m_backing(backing) {}
 | 
			
		||||
		
 | 
			
		||||
		private:
 | 
			
		||||
		toml_array_t* const m_array = 0;
 | 
			
		||||
		std::shared_ptr<Backing> m_backing;
 | 
			
		||||
		
 | 
			
		||||
		Array() = delete;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* The main function: Parse */
 | 
			
		||||
	struct Result {
 | 
			
		||||
		std::shared_ptr<Table> table;
 | 
			
		||||
		string errmsg;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Result parse(const string& conf);
 | 
			
		||||
	Result parseFile(const string& path);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* TOML_HPP */
 | 
			
		||||
		Loading…
	
		Reference in a new issue