read scene graph from file
This commit is contained in:
parent
3c0b9f42c1
commit
70c611d0d6
|
@ -0,0 +1,84 @@
|
||||||
|
# Kommentar
|
||||||
|
|
||||||
|
# Definition eines Modells
|
||||||
|
# Model hat eindeutige numerische ID
|
||||||
|
# Durch diese ID kann ein Objekt dieses Modell verwenden
|
||||||
|
model 0
|
||||||
|
|
||||||
|
# Angabe der OBJ Datei
|
||||||
|
file ../obj/cube.obj
|
||||||
|
|
||||||
|
# Angabe der Textur Datei
|
||||||
|
texture ../texture/crate.png
|
||||||
|
|
||||||
|
|
||||||
|
# Definition eines Modells oder Objekts endet automatisch
|
||||||
|
# bei beginn einer neuen Definition
|
||||||
|
|
||||||
|
model 1
|
||||||
|
file ../obj/earth.obj
|
||||||
|
texture ../texture/pb.png
|
||||||
|
|
||||||
|
|
||||||
|
# Definition eines Objekts
|
||||||
|
# jedes Objekt braucht eindeutige numerische ID
|
||||||
|
obj 0
|
||||||
|
|
||||||
|
# Angabe welches Modell das Objekt nutzt
|
||||||
|
# Kann im Fall von Gruppenobjekten weggelassen werden
|
||||||
|
use 0
|
||||||
|
|
||||||
|
# lesbarer Name des Objekts
|
||||||
|
# eigentlich nur für debugging, muss wahrscheinlich
|
||||||
|
# garnicht implementiert werden
|
||||||
|
name myCrate1
|
||||||
|
|
||||||
|
# Position des Objekts
|
||||||
|
# relativ zur Position des Parent Elements
|
||||||
|
position 0.0 0.0 2.0
|
||||||
|
|
||||||
|
# Skalierung des Objekts
|
||||||
|
# relativ zur Skalierung des Parent Elements
|
||||||
|
scale 1.0 1.0 1.0
|
||||||
|
|
||||||
|
|
||||||
|
# rotationen
|
||||||
|
rotationX 0.0
|
||||||
|
rotationY 1.5
|
||||||
|
rotationZ 0.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
obj 1
|
||||||
|
use 0
|
||||||
|
name myCrate2
|
||||||
|
position 0.0 1.0 0.0
|
||||||
|
scale 0.5 0.5 0.5
|
||||||
|
# Definition des Parent Objekts
|
||||||
|
parent 0
|
||||||
|
|
||||||
|
|
||||||
|
obj 2
|
||||||
|
use 1
|
||||||
|
name Sonne
|
||||||
|
#texture ../texture/pb.png
|
||||||
|
position 0.0 0.0 0.0
|
||||||
|
scale 2.0 2.0 2.0
|
||||||
|
|
||||||
|
|
||||||
|
obj 3
|
||||||
|
use 1
|
||||||
|
name Erde
|
||||||
|
#texture ../texture/earth/day.png
|
||||||
|
position 4.0 0.0 0.0
|
||||||
|
scale 1.0 1.0 1.0
|
||||||
|
parent 2
|
||||||
|
|
||||||
|
|
||||||
|
obj 4
|
||||||
|
use 1
|
||||||
|
name Mond
|
||||||
|
#texture ../texture/checkerboard.png
|
||||||
|
position 2.0 0.0 0.0
|
||||||
|
scale 0.5 0.5 0.5
|
||||||
|
parent 3
|
106
src/main.c
106
src/main.c
|
@ -12,9 +12,6 @@
|
||||||
#include "wavefrontobj.h"
|
#include "wavefrontobj.h"
|
||||||
#include "sceneGraph.h"
|
#include "sceneGraph.h"
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "../lib/stb_image.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -32,17 +29,6 @@ GLuint program;
|
||||||
|
|
||||||
int flipFlag = 1;
|
int flipFlag = 1;
|
||||||
|
|
||||||
GLuint textures[NUM_TEXTURES];
|
|
||||||
char* textureFiles[NUM_TEXTURES] = {
|
|
||||||
"../texture/earth/day.png",
|
|
||||||
"../texture/earth/night.png",
|
|
||||||
"../texture/earth/clouds.png",
|
|
||||||
"../texture/earth/ocean_mask.png",
|
|
||||||
"../texture/earth/normal.png"
|
|
||||||
};
|
|
||||||
|
|
||||||
ObjectData* objectData;
|
|
||||||
|
|
||||||
bool exitRequested = false;
|
bool exitRequested = false;
|
||||||
|
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
|
@ -65,15 +51,6 @@ mat4 viewingTransformation;
|
||||||
// Define a global scene graph root node
|
// Define a global scene graph root node
|
||||||
SceneNode* rootNode;
|
SceneNode* rootNode;
|
||||||
|
|
||||||
|
|
||||||
int numModels = 0;
|
|
||||||
char* models[] = {
|
|
||||||
"../obj/Xblock.obj",
|
|
||||||
"../obj/Yblock.obj",
|
|
||||||
"../obj/Yblock_rotated.obj",
|
|
||||||
"../obj/Zblock.obj",
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input handler for camera movement.
|
* Input handler for camera movement.
|
||||||
* */
|
* */
|
||||||
|
@ -126,38 +103,9 @@ void keyboardHandler(GLFWwindow* window, int key, int scancode, int action, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads textures.
|
|
||||||
*/
|
|
||||||
void loadTexture(char* textureFile, GLuint* texture) {
|
|
||||||
int width, height, nrChannels;
|
|
||||||
unsigned char* image = stbi_load(textureFile, &width, &height, &nrChannels, 0);
|
|
||||||
|
|
||||||
// default: 3 channels, RGB
|
|
||||||
|
|
||||||
GLenum channelFormats[] = {
|
|
||||||
0,
|
|
||||||
GL_RED,
|
|
||||||
GL_RG,
|
|
||||||
GL_RGB,
|
|
||||||
GL_RGBA
|
|
||||||
};
|
|
||||||
GLenum format = channelFormats[nrChannels];
|
|
||||||
|
|
||||||
glGenTextures(1, texture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, *texture);
|
|
||||||
|
|
||||||
printf("%s - %d\n", textureFile, nrChannels);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, format, GL_UNSIGNED_BYTE, image);
|
|
||||||
// load texture using previously determined format ----- ^^^^^^
|
|
||||||
|
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
|
|
||||||
stbi_image_free(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderNode(SceneNode* node) {
|
void renderNode(SceneNode* node) {
|
||||||
|
if (!node->model) return;
|
||||||
|
|
||||||
mat4 modelView;
|
mat4 modelView;
|
||||||
identity(&modelView);
|
identity(&modelView);
|
||||||
multiply(&modelView, &node->worldTransformation, &modelView);
|
multiply(&modelView, &node->worldTransformation, &modelView);
|
||||||
|
@ -182,14 +130,14 @@ void renderNode(SceneNode* node) {
|
||||||
textureLocation = glGetUniformLocation(program, "textureSampler");
|
textureLocation = glGetUniformLocation(program, "textureSampler");
|
||||||
glUniform1i(textureLocation, 0);
|
glUniform1i(textureLocation, 0);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[DAY]);
|
glBindTexture(GL_TEXTURE_2D, node->model->texture);
|
||||||
|
|
||||||
textureLocation = glGetUniformLocation(program, "normalMap");
|
// textureLocation = glGetUniformLocation(program, "normalMap");
|
||||||
glUniform1i(textureLocation, 4);
|
// glUniform1i(textureLocation, 4);
|
||||||
glActiveTexture(GL_TEXTURE4);
|
// glActiveTexture(GL_TEXTURE4);
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[NORMAL]);
|
// glBindTexture(GL_TEXTURE_2D, textures[NORMAL]);
|
||||||
|
|
||||||
draw_object(node->objectData);
|
draw_object(node->model->objectData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(void) {
|
void init(void) {
|
||||||
|
@ -260,30 +208,11 @@ void init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------------- READ MODEL FILES
|
// --------------- READ SCENE GRAPH
|
||||||
|
|
||||||
//objectData = readObjFiles(&models, numModels);
|
|
||||||
char* c = "../obj/new/Window.obj";
|
|
||||||
objectData = readSingleObjFile(&c);
|
|
||||||
|
|
||||||
stbi_set_flip_vertically_on_load(flipFlag);
|
|
||||||
// -------------- READ TEXTURE FILES
|
|
||||||
for (int i = 0; i < NUM_TEXTURES; i++) {
|
|
||||||
loadTexture(textureFiles[i], &textures[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
setNodeRenderFunction(&renderNode);
|
setNodeRenderFunction(&renderNode);
|
||||||
|
|
||||||
// Create the root scene node
|
// read scene graph
|
||||||
rootNode = createSceneNode();
|
rootNode = loadSceneGraphFromFile("../scene-graph-example.scg");
|
||||||
|
|
||||||
// Create a child node (e.g., for the model)
|
|
||||||
SceneNode* modelNode = createSceneNode();
|
|
||||||
modelNode->objectData = objectData;
|
|
||||||
addChild(rootNode, modelNode);
|
|
||||||
|
|
||||||
// Set transformations for the modelNode (example)
|
|
||||||
rotateY(&modelNode->transformation, &modelNode->transformation, pi / 4);
|
|
||||||
|
|
||||||
// ENABLE BACKFACE CULLING
|
// ENABLE BACKFACE CULLING
|
||||||
glFrontFace(GL_CCW);
|
glFrontFace(GL_CCW);
|
||||||
|
@ -361,17 +290,10 @@ void draw(void) {
|
||||||
glUniform4f(glGetUniformLocation(program, "lightColor"), 1.0f, 1.0f, 1.0f, 1.0f);
|
glUniform4f(glGetUniformLocation(program, "lightColor"), 1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
glUniform4f(glGetUniformLocation(program, "ambientLight"), 0.05f, 0.05f, 0.05f, 1.0f);
|
glUniform4f(glGetUniformLocation(program, "ambientLight"), 0.05f, 0.05f, 0.05f, 1.0f);
|
||||||
|
|
||||||
// BIND TEXTURES
|
vec4 lightPosition = {cos(stepi) * 5.0f, 5.0f, sin(stepi) * 5.0f, 1.0f};
|
||||||
GLuint textureLocation;
|
multiplyAny(&lightPosition, &viewingTransformation, &lightPosition, 4, 4, 1);
|
||||||
textureLocation = glGetUniformLocation(program, "textureSampler");
|
|
||||||
glUniform1i(textureLocation, 0);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[DAY]);
|
|
||||||
|
|
||||||
textureLocation = glGetUniformLocation(program, "normalMap");
|
glUniform3f(glGetUniformLocation(program, "lightPosition"), lightPosition.x, lightPosition.y, lightPosition.z);
|
||||||
glUniform1i(textureLocation, 4);
|
|
||||||
glActiveTexture(GL_TEXTURE4);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[NORMAL]);
|
|
||||||
|
|
||||||
|
|
||||||
renderSceneNode(rootNode);
|
renderSceneNode(rootNode);
|
||||||
|
|
|
@ -94,7 +94,7 @@ ObjectData* readObjFiles(char** path, int numModels, int* count) {
|
||||||
* Takes a single object and reads it a certain number of times.
|
* Takes a single object and reads it a certain number of times.
|
||||||
* Returns an array of objects.
|
* Returns an array of objects.
|
||||||
*/
|
*/
|
||||||
ObjectData* readSingleObjFile(char** path) {
|
ObjectData* readSingleObjFile(char* path) {
|
||||||
ObjectData* objectData = (ObjectData*) malloc(sizeof(ObjectData));
|
ObjectData* objectData = (ObjectData*) malloc(sizeof(ObjectData));
|
||||||
|
|
||||||
if (!objectData) {
|
if (!objectData) {
|
||||||
|
@ -103,7 +103,7 @@ ObjectData* readSingleObjFile(char** path) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
objectData->object = readObjFile(*path);
|
objectData->object = readObjFile(path);
|
||||||
load_object(objectData);
|
load_object(objectData);
|
||||||
|
|
||||||
return objectData;
|
return objectData;
|
||||||
|
|
|
@ -11,7 +11,7 @@ typedef struct {
|
||||||
|
|
||||||
extern void load_object(ObjectData* objectData);
|
extern void load_object(ObjectData* objectData);
|
||||||
extern ObjectData* readObjFiles(char** path, int numModels, int* count);
|
extern ObjectData* readObjFiles(char** path, int numModels, int* count);
|
||||||
extern ObjectData* readSingleObjFile(char** path);
|
extern ObjectData* readSingleObjFile(char* path);
|
||||||
extern void draw_object(ObjectData* objectData);
|
extern void draw_object(ObjectData* objectData);
|
||||||
|
|
||||||
#endif
|
#endif
|
273
src/sceneGraph.c
273
src/sceneGraph.c
|
@ -3,6 +3,16 @@
|
||||||
#include "sceneGraph.h"
|
#include "sceneGraph.h"
|
||||||
#include "objectHandler.h"
|
#include "objectHandler.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "../lib/stb_image.h"
|
||||||
|
|
||||||
|
#define SCG_LINE_BUFFER_SIZE 1024
|
||||||
|
#define SCG_KEYWORD_BUFFER_SIZE 32
|
||||||
|
|
||||||
void (*renderFunction)(SceneNode*);
|
void (*renderFunction)(SceneNode*);
|
||||||
|
|
||||||
|
@ -10,13 +20,15 @@ void setNodeRenderFunction(void (*newRenderFunction)(SceneNode*)) {
|
||||||
renderFunction = newRenderFunction;
|
renderFunction = newRenderFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneNode* createSceneNode() {
|
SceneNode* createSceneNode(int id) {
|
||||||
SceneNode* node = (SceneNode*)malloc(sizeof(SceneNode));
|
SceneNode* node = (SceneNode*)malloc(sizeof(SceneNode));
|
||||||
identity(&node->transformation);
|
identity(&node->transformation);
|
||||||
identity(&node->worldTransformation);
|
identity(&node->worldTransformation);
|
||||||
|
node->id = id;
|
||||||
node->children = NULL;
|
node->children = NULL;
|
||||||
node->numChildren = 0;
|
node->numChildren = 0;
|
||||||
node->objectData = NULL;
|
node->model = NULL;
|
||||||
|
node->name = NULL;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +46,7 @@ void updateSceneNode(SceneNode* node, mat4* parentTransformation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSceneNode(SceneNode* node) {
|
void renderSceneNode(SceneNode* node) {
|
||||||
if (node->objectData) {
|
if (node->model) {
|
||||||
renderFunction(node);
|
renderFunction(node);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < node->numChildren; i++) {
|
for (int i = 0; i < node->numChildren; i++) {
|
||||||
|
@ -49,3 +61,258 @@ void freeSceneNode(SceneNode* node) {
|
||||||
free(node->children);
|
free(node->children);
|
||||||
free(node);
|
free(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadTexture(char* textureFile, GLuint* texture) {
|
||||||
|
int width, height, nrChannels;
|
||||||
|
unsigned char* image = stbi_load(textureFile, &width, &height, &nrChannels, 0);
|
||||||
|
|
||||||
|
// default: 3 channels, RGB
|
||||||
|
|
||||||
|
GLenum channelFormats[] = {
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
GL_RG,
|
||||||
|
GL_RGB,
|
||||||
|
GL_RGBA
|
||||||
|
};
|
||||||
|
GLenum format = channelFormats[nrChannels];
|
||||||
|
|
||||||
|
glGenTextures(1, texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, *texture);
|
||||||
|
|
||||||
|
printf("%s - %d\n", textureFile, nrChannels);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, format, GL_UNSIGNED_BYTE, image);
|
||||||
|
// load texture using previously determined format ----- ^^^^^^
|
||||||
|
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
stbi_image_free(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SceneNode* findNode(int id, SceneNode* root) {
|
||||||
|
if (root->id == id) return root;
|
||||||
|
for (int i = 0; i < root->numChildren; i++) {
|
||||||
|
SceneNode* node = findNode(id, root->children[i]);
|
||||||
|
if (node) return node;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printSceneGraph(SceneNode* node, int level) {
|
||||||
|
for (int i = 0; i < level; i++) {
|
||||||
|
printf(" - ");
|
||||||
|
}
|
||||||
|
if (node->name) {
|
||||||
|
printf("%s\n", node->name);
|
||||||
|
} else {
|
||||||
|
printf("%d\n", node->id);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < node->numChildren; i++) {
|
||||||
|
printSceneGraph(node->children[i], level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneNode* loadSceneGraphFromFile(char* path) {
|
||||||
|
FILE* fp = fopen(path, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
fprintf(stderr, "File could not be opened: %s\n", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[SCG_LINE_BUFFER_SIZE];
|
||||||
|
char keyword[SCG_KEYWORD_BUFFER_SIZE];
|
||||||
|
|
||||||
|
// generate keyword buffer format string using SCG_KEYWORD_BUFFER_SIZE
|
||||||
|
// when SCK_KEYWORD_BUFFER_SIZE is 32 keywordBufferFormat will contain "%32s"
|
||||||
|
// avoid buffer overflow while reading buffer while also allowing for dynamic buffer scaling
|
||||||
|
// there is probably a better solution for this but I couldn't find one :(
|
||||||
|
char* keywordBufferFormat = (char*)malloc(sizeof(char) * (4 + (int)log10((double)SCG_KEYWORD_BUFFER_SIZE)));
|
||||||
|
sprintf(keywordBufferFormat, "%%%ds", SCG_KEYWORD_BUFFER_SIZE);
|
||||||
|
|
||||||
|
SceneNode* root = createSceneNode(-1);
|
||||||
|
root->name = "ROOT";
|
||||||
|
|
||||||
|
int maxModelId = 0;
|
||||||
|
int maxObjId = 0;
|
||||||
|
|
||||||
|
while (fgets(buf, SCG_LINE_BUFFER_SIZE, fp)) {
|
||||||
|
if (buf[0] == '#') continue;
|
||||||
|
sscanf(buf, keywordBufferFormat, keyword);
|
||||||
|
// printf("%s\n", keyword);
|
||||||
|
|
||||||
|
if (strcmp(keyword, "model") == 0) {
|
||||||
|
int modelId = 0;
|
||||||
|
sscanf(buf, "model %d", &modelId);
|
||||||
|
if (modelId > maxModelId) {
|
||||||
|
maxModelId = modelId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* models = (Model*)malloc(sizeof(Model) * (maxModelId + 1));
|
||||||
|
|
||||||
|
int currentModel = 0;
|
||||||
|
|
||||||
|
SceneNode* currentNode = NULL;
|
||||||
|
bool currentNodeHasParent = false;
|
||||||
|
|
||||||
|
char filepathBuffer[1024];
|
||||||
|
|
||||||
|
rewind(fp);
|
||||||
|
int currentLine = 0;
|
||||||
|
while (fgets(buf, SCG_LINE_BUFFER_SIZE, fp)) {
|
||||||
|
currentLine++;
|
||||||
|
if (buf[0] == '#') continue;
|
||||||
|
if (buf[0] == '\r' || buf[0] == '\n' || buf[0] == '\0') continue;
|
||||||
|
sscanf(buf, keywordBufferFormat, keyword);
|
||||||
|
|
||||||
|
if (strcmp(keyword, "model") == 0) {
|
||||||
|
sscanf(buf, "model %d", ¤tModel);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(keyword, "file") == 0) {
|
||||||
|
sscanf(buf, "file %s", filepathBuffer);
|
||||||
|
models[currentModel].objectData = readSingleObjFile(filepathBuffer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(keyword, "texture") == 0) {
|
||||||
|
sscanf(buf, "texture %s", filepathBuffer);
|
||||||
|
loadTexture(filepathBuffer, &models[currentModel].texture);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (strcmp(keyword, "obj") == 0) {
|
||||||
|
|
||||||
|
if (currentNode && !currentNodeHasParent) {
|
||||||
|
addChild(root, currentNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNode = NULL;
|
||||||
|
currentNodeHasParent = false;
|
||||||
|
|
||||||
|
int nodeId = 0;
|
||||||
|
sscanf(buf, "obj %d", &nodeId);
|
||||||
|
if (findNode(nodeId, root)) {
|
||||||
|
fprintf(stderr, "redeclaration of objet with id %d - line %d\n", nodeId, currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
currentNode = createSceneNode(nodeId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(keyword, "name") == 0) {
|
||||||
|
if (!currentNode) {
|
||||||
|
fprintf(stderr, "no node selected, can't assign name - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sscanf(buf, "name %s", filepathBuffer);
|
||||||
|
char* name = (char*)malloc(strlen(filepathBuffer) * sizeof(char) + 1);
|
||||||
|
strcpy(name, filepathBuffer);
|
||||||
|
currentNode->name = name;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(keyword, "parent") == 0) {
|
||||||
|
if (!currentNode) {
|
||||||
|
fprintf(stderr, "no node selected, can't assign parent - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (currentNodeHasParent) {
|
||||||
|
fprintf(stderr, "selected node already has parent - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parentId = 0;
|
||||||
|
sscanf(buf, "parent %d", &parentId);
|
||||||
|
|
||||||
|
SceneNode* parent = findNode(parentId, root);
|
||||||
|
if (!parent) {
|
||||||
|
fprintf(stderr, "parent node with id %d not found - line %d\n", parentId, currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(parent, currentNode);
|
||||||
|
currentNodeHasParent = true;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(keyword, "use") == 0) {
|
||||||
|
if (!currentNode) {
|
||||||
|
fprintf(stderr, "no node selected to assign model to - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usedModel = 0;
|
||||||
|
sscanf(buf, "use %d", &usedModel);
|
||||||
|
|
||||||
|
if (usedModel > maxModelId || usedModel < 0) {
|
||||||
|
fprintf(stderr, "model with id %d not found - line %d\n", usedModel, currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNode->model = &models[usedModel];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(keyword, "position") == 0) {
|
||||||
|
if (!currentNode) {
|
||||||
|
fprintf(stderr, "no node selected to assign position to - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
vec3 translation;
|
||||||
|
sscanf(buf, "position %f %f %f", &translation.x, &translation.y, &translation.z);
|
||||||
|
translate(¤tNode->transformation, ¤tNode->transformation, &translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(keyword, "scale") == 0) {
|
||||||
|
if (!currentNode) {
|
||||||
|
fprintf(stderr, "no node selected to assign scale to - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
vec3 translation;
|
||||||
|
sscanf(buf, "scale %f %f %f", &translation.x, &translation.y, &translation.z);
|
||||||
|
scale(¤tNode->transformation, ¤tNode->transformation, &translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(keyword, "rotationX") == 0) {
|
||||||
|
if (!currentNode) {
|
||||||
|
fprintf(stderr, "no node selected to assign rotationX to - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GLfloat angle;
|
||||||
|
sscanf(buf, "rotationX %f", &angle);
|
||||||
|
rotateX(¤tNode->transformation, ¤tNode->transformation, angle);
|
||||||
|
}
|
||||||
|
if (strcmp(keyword, "rotationY") == 0) {
|
||||||
|
if (!currentNode) {
|
||||||
|
fprintf(stderr, "no node selected to assign rotationY to - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GLfloat angle;
|
||||||
|
sscanf(buf, "rotationY %f", &angle);
|
||||||
|
rotateY(¤tNode->transformation, ¤tNode->transformation, angle);
|
||||||
|
}
|
||||||
|
if (strcmp(keyword, "rotationZ") == 0) {
|
||||||
|
if (!currentNode) {
|
||||||
|
fprintf(stderr, "no node selected to assign rotationZ to - line %d\n", currentLine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GLfloat angle;
|
||||||
|
sscanf(buf, "rotationZ %f", &angle);
|
||||||
|
rotateZ(¤tNode->transformation, ¤tNode->transformation, angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentNode && !currentNodeHasParent) {
|
||||||
|
addChild(root, currentNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4 rootTransform;
|
||||||
|
identity(&rootTransform);
|
||||||
|
updateSceneNode(root, &rootTransform);
|
||||||
|
|
||||||
|
printSceneGraph(root, 0);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
|
@ -11,20 +11,27 @@
|
||||||
|
|
||||||
typedef struct SceneNode SceneNode;
|
typedef struct SceneNode SceneNode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ObjectData* objectData;
|
||||||
|
GLuint texture;
|
||||||
|
} Model;
|
||||||
|
|
||||||
struct SceneNode {
|
struct SceneNode {
|
||||||
|
int id;
|
||||||
mat4 transformation; // Local transformation matrix
|
mat4 transformation; // Local transformation matrix
|
||||||
mat4 worldTransformation; // World transformation matrix
|
mat4 worldTransformation; // World transformation matrix
|
||||||
SceneNode** children; // Array of pointers to child nodes
|
SceneNode** children; // Array of pointers to child nodes
|
||||||
int numChildren; // Number of child nodes
|
int numChildren; // Number of child nodes
|
||||||
ObjectData* objectData;
|
Model* model;
|
||||||
|
char* name;
|
||||||
};
|
};
|
||||||
|
|
||||||
void setNodeRenderFunction(void (*newRenderFunction)(SceneNode*));
|
extern void setNodeRenderFunction(void (*newRenderFunction)(SceneNode*));
|
||||||
extern SceneNode* createSceneNode();
|
extern SceneNode* createSceneNode();
|
||||||
extern void addChild(SceneNode* parent, SceneNode* child);
|
extern void addChild(SceneNode* parent, SceneNode* child);
|
||||||
extern void updateSceneNode(SceneNode* node, mat4* parentTransformation);
|
extern void updateSceneNode(SceneNode* node, mat4* parentTransformation);
|
||||||
extern void renderSceneNode(SceneNode* node);
|
extern void renderSceneNode(SceneNode* node);
|
||||||
extern void freeSceneNode(SceneNode* node);
|
extern void freeSceneNode(SceneNode* node);
|
||||||
|
extern SceneNode* loadSceneGraphFromFile(char* path);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,26 @@
|
||||||
|
model 0
|
||||||
|
file ../obj/cube.obj
|
||||||
|
texture ../texture/crate/texture.jpg
|
||||||
|
|
||||||
|
obj 0
|
||||||
|
use 0
|
||||||
|
scale 0.1 1.0 0.1
|
||||||
|
name box1
|
||||||
|
|
||||||
|
obj 1
|
||||||
|
parent 0
|
||||||
|
scale 0.2 0.8 0.2
|
||||||
|
position 0.5 0.0 0.0
|
||||||
|
name box2
|
||||||
|
|
||||||
|
obj 2
|
||||||
|
parent 1
|
||||||
|
scale 0.3 0.6 0.3
|
||||||
|
position 0.5 0.0 0.0
|
||||||
|
name box3
|
||||||
|
|
||||||
|
obj 3
|
||||||
|
parent 2
|
||||||
|
scale 0.4 0.4 0.4
|
||||||
|
position 0.5 0.0 0.0
|
||||||
|
name box4
|
Loading…
Reference in New Issue