From 4128462add7af876d6eaca9094872ee4a6062eb8 Mon Sep 17 00:00:00 2001 From: Nicolay Korslund Date: Wed, 6 Jan 2010 15:00:08 +0100 Subject: [PATCH] NIF: implemented NiNode and NiTriShape --- nif/nif_file.cpp | 17 ++++++++----- nif/nif_file.h | 10 +++++++- nif/nif_types.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ nif/node.h | 50 +++++++++++++++++++++++++++++++++++- nif/record_ptr.h | 63 ++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 193 insertions(+), 13 deletions(-) create mode 100644 nif/nif_types.h diff --git a/nif/nif_file.cpp b/nif/nif_file.cpp index fadd64728..624abd7b6 100644 --- a/nif/nif_file.cpp +++ b/nif/nif_file.cpp @@ -53,14 +53,17 @@ void NIFFile::parse() { SString rec = getString(); - cout << i << ": " << rec.toString() << endl; + cout << endl << i << ": " << rec.toString() << endl; - Node r; - r.read(this); - cout << r.name.toString() << endl; - cout << r.extra.getIndex() << endl; - cout << r.controller.getIndex() << endl; + Record *r; - break; + // This can be heavily optimized later if needed. For example, a + // hash table or a FSM-based parser could be used to look up + // node names. + if(rec == "NiNode") r = new NiNode; + else if(rec == "NiTriShape") r = new NiTriShape; + else break; + + r->read(this); } } diff --git a/nif/nif_file.h b/nif/nif_file.h index 3152bd076..2d6dc594c 100644 --- a/nif/nif_file.h +++ b/nif/nif_file.h @@ -35,6 +35,7 @@ #include #include "record.h" +#include "nif_types.h" using namespace Mangle::Stream; @@ -107,7 +108,9 @@ class NIFFile ****************************************************/ - template X getType() { return *((X*)inp->getPtr(sizeof(X))); } + template const X* getPtr() { return (const X*)inp->getPtr(sizeof(X)); } + template X getType() { return *getPtr(); } + unsigned short getUshort() { return getType(); } int getInt() { return getType(); } template @@ -119,6 +122,11 @@ class NIFFile SString getString() { return getArray(); } + const Vector *getVector() { return getPtr(); } + const Matrix *getMatrix() { return getPtr(); } + const Transformation *getTrafo() { return getPtr(); } + + // For fixed-size strings where you already know the size const char *getString(int size) { return (const char*)inp->getPtr(size); } }; diff --git a/nif/nif_types.h b/nif/nif_types.h new file mode 100644 index 000000000..17cec19bc --- /dev/null +++ b/nif/nif_types.h @@ -0,0 +1,66 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008-2010 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.sourceforge.net/ + + This file (nif_types.h) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +#ifndef _NIF_TYPES_H_ +#define _NIF_TYPES_H_ + +// Common types used in NIF files + +namespace Nif +{ + +/* These packing #pragmas aren't really necessary on 32 bit + machines. I haven't tested on 64 bit yet. In any case it doesn't + hurt to include them. We can't allow any compiler-generated padding + in any of these structs, since they are used to interface directly + with raw data from the NIF files. +*/ +#pragma pack(push) +#pragma pack(1) + +struct Vector +{ + float array[3]; +}; + +struct Vector4 +{ + float array[4]; +}; + +struct Matrix +{ + Vector v[3]; +}; + +struct Transformation +{ + Vector pos; + Matrix rotation; + float scale; + Vector velocity; +}; +#pragma pack(pop) + +} // Namespace +#endif diff --git a/nif/node.h b/nif/node.h index 6434555d3..571a46246 100644 --- a/nif/node.h +++ b/nif/node.h @@ -35,11 +35,59 @@ namespace Nif */ struct Node : Named { - // Not done + // Node flags. Interpretation depends somewhat on the type of node. + int flags; + const Transformation *trafo; + PropertyList props; + + // Bounding box info + bool hasBounds; + const Vector *boundPos; + const Matrix *boundRot; + const Vector *boundXYZ; void read(NIFFile *nif) { Named::read(nif); + + flags = nif->getUshort(); + trafo = nif->getTrafo(); + props.read(nif); + + hasBounds = nif->getInt(); + if(hasBounds) + { + nif->getInt(); + boundPos = nif->getVector(); + boundRot = nif->getMatrix(); + boundXYZ = nif->getVector(); + } + } +}; + +struct NiNode : Node +{ + NodeList children; + NodeList effects; + + void read(NIFFile *nif) + { + Node::read(nif); + children.read(nif); + effects.read(nif); + } +}; + +struct NiTriShape : Node +{ + NiTriShapeDataPtr data; + NiSkinInstancePtr skin; + + void read(NIFFile *nif) + { + Node::read(nif); + data.read(nif); + skin.read(nif); } }; diff --git a/nif/record_ptr.h b/nif/record_ptr.h index 998c4fc48..1d7f2295e 100644 --- a/nif/record_ptr.h +++ b/nif/record_ptr.h @@ -25,9 +25,15 @@ #define _NIF_RECORD_PTR_H_ #include "nif_file.h" +#include namespace Nif { + +/** A reference to another record. It is read as an index from the + NIF, and later looked up in the index table to get an actual + pointer. +*/ template class RecordPtrT { @@ -53,7 +59,7 @@ class RecordPtrT } /// Look up the actual object from the index - X* operator->() + X* getPtr() { // Have we found the pointer already? if(ptr == NULL) @@ -69,20 +75,69 @@ class RecordPtrT return ptr; } + /// Syntactic sugar + X* operator->() { return getPtr(); } + X& get() { return *getPtr(); } + /// Pointers are allowed to be empty bool empty() { return index == -1; } int getIndex() { return index; } }; +/** A list of references to other records. These are read as a list, + and later converted to pointers as needed. Not an optimized + implementation. + */ +template +class RecordListT +{ + typedef RecordPtrT Ptr; + std::vector list; + + public: + + void read(NIFFile *nif) + { + int len = nif->getInt(); + list.resize(len); + + assert(len >= 0 && len < 1000); + for(int i=0;i= 0 && index < list.size()); + return list[index].get(); + } + + bool has(int index) + { + assert(index >= 0 && index < list.size()); + return !list[index].empty(); + } + + int length() { return list.size(); } +}; + -class Extra; -class Controller; class Node; +class Extra; +class Property; +class Controller; +class NiTriShapeData; +class NiSkinInstance; +typedef RecordPtrT NodePtr; typedef RecordPtrT ExtraPtr; typedef RecordPtrT ControllerPtr; -typedef RecordPtrT NodePtr; +typedef RecordPtrT NiTriShapeDataPtr; +typedef RecordPtrT NiSkinInstancePtr; + +typedef RecordListT NodeList; +typedef RecordListT PropertyList; } // Namespace #endif