diff --git a/nif/controlled.h b/nif/controlled.h index 25a65d8ad6..763461e6a3 100644 --- a/nif/controlled.h +++ b/nif/controlled.h @@ -54,7 +54,6 @@ struct Named : Controlled }; typedef Named NiSequenceStreamHelper; - struct NiParticleGrowFade : Controlled { void read(NIFFile *nif) diff --git a/nif/extra.h b/nif/extra.h index c37a87d743..d682bce42b 100644 --- a/nif/extra.h +++ b/nif/extra.h @@ -51,9 +51,9 @@ struct NiVertWeightsExtraData : Extra // We should have s*4+2 == i, for some reason. Might simply be the // size of the rest of the record, unhelpful as that may be. int i = nif->getInt(); - int s = nif->getShort(); + int s = nif->getShort(); // number of vertices - nif->getFloatLen(s); + nif->getFloatLen(s); // vertex weights I guess } }; diff --git a/nif/nif_file.cpp b/nif/nif_file.cpp index 4f57ec067b..01a7158474 100644 --- a/nif/nif_file.cpp +++ b/nif/nif_file.cpp @@ -53,6 +53,15 @@ void NIFFile::parse() int recNum = getInt(); records.resize(recNum); + /* The format for 10.0.1.0 seems to be a bit different. After the + header, it contains the number of records, r (int), just like + 4.0.0.2, but following that it contains a short x, followed by x + strings. Then again by r shorts, one for each record, giving + which of the above strings to use to identify the record. After + this follows two ints (zero?) and then the record data. However + we do not support or plan to support other versions yet. + */ + for(int i=0;iread(this); } + + /* After the data, the nif contains an int N and then a list of N + ints following it. This might be a list of the root nodes in the + tree, but for the moment we ignore it. + */ } diff --git a/nif/node.h b/nif/node.h index 2b94a54435..b84f3fc9a3 100644 --- a/nif/node.h +++ b/nif/node.h @@ -57,7 +57,7 @@ struct Node : Named hasBounds = nif->getInt(); if(hasBounds) { - nif->getInt(); + nif->getInt(); // always 1 boundPos = nif->getVector(); boundRot = nif->getMatrix(); boundXYZ = nif->getVector(); @@ -70,6 +70,15 @@ struct NiNode : Node NodeList children; NodeList effects; + /* Known NiNode flags: + + 0x01 hidden + 0x02 use mesh for collision + 0x04 use bounding box for collision (?) + 0x08 unknown, but common + 0x20, 0x40, 0x80 unknown + */ + void read(NIFFile *nif) { Node::read(nif); @@ -80,6 +89,13 @@ struct NiNode : Node struct NiTriShape : Node { + /* Possible flags: + 0x40 - mesh has no vertex normals ? + + Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have + been observed so far. + */ + NiTriShapeDataPtr data; NiSkinInstancePtr skin; diff --git a/nif/property.h b/nif/property.h index d22cfcc984..1ed11a0c91 100644 --- a/nif/property.h +++ b/nif/property.h @@ -174,7 +174,7 @@ struct S_VertexColorProperty struct S_AlphaProperty { /* - In NiAlphaProperty, the flags have the following meaning. + In NiAlphaProperty, the flags have the following meaning: Bit 0 : alpha blending enable Bits 1-4 : source blend mode diff --git a/old_d_version/nif/base.d b/old_d_version/nif/base.d deleted file mode 100644 index d27428ea76..0000000000 --- a/old_d_version/nif/base.d +++ /dev/null @@ -1,211 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (base.d) 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/ . - - */ - -// Basic file structure -module nif.base; - -import nif.nif; -import nif.niffile; -import nif.misc; -import monster.util.string; - -//import nif.controller; -//import nif.node; -import nif.record; - -debug(verbose) public import std.stdio; - -void parseFile() -{ - with(nifFile) - { // Read header - int ver; // Hex-encoded version - char[40] head; // Header string - - // Read and check header string - getString(head); - - if(!begins(head,"NetImmerse File Format")) - fail("Not a NetImmerse file"); - - debug(verbose) writefln("Header: \"%s\"", head[0..39]); - debug(strict) - if(head[0..39] != "NetImmerse File Format, Version 4.0.0.2" || head[39] != 0x0a) - fail("Unrecognized header string, most likely an unsupported NIF version"); - - // Get binary coded version - ver = getInt; - - debug(verbose) - { - writef("BCD version tag: "); - for(ubyte *b = (cast(ubyte*)&ver)+3; b > (cast(ubyte*)&ver); b--) - writef(*b, "."); - writefln(cast(ubyte)ver); - } - - if(ver != 0x04_00_00_02) - fail("Don't know how to process this version"); - - // The number of records in the file - nifMesh.records = nifRegion.allocateT!(Record)(getInt); - debug(verbose) writefln("Number of records: ", nifMesh.records.length); - - // The format for 10.0.1.0 seems to be a bit different. After the - // header, it contains the number of records, r (int), just like - // 4.0.0.2, but following that it contains a short x, followed by - // x strings. Then again by r shorts, one for each record, giving - // which of the above strings to use to identify the record. After - // this follows two ints (zero?) and then the record data. - - // Besides giving me more work to do, this structure suggests some - // obvious code optimizations we can now apply to the reading - // structure. Since we now know in advance how many records there - // are of each type, we could allocate the structures in bulk. D - // doesn't allow this for classes directly, but we can make a - // custom allocator and whatnot. I doubt we save a lot of time - // with it, though. I'll save this for later. - - // As for the record data itself, I do not know what has - // changed. There are some new records. I might as well have - // separate reading functions for the entire main structure. - - // EDIT 14. feb 06: Since we are concentrating on Morrowind, let - // us drop other versions for now. It would be nice to support - // other versions (or even other mesh formats), but the priority - // of this is very low at the moment. - } - - endFor: - foreach(int i, ref Record o; nifMesh.records) - { - // Get type string, and update the NIFFiles error message to - // match it. - char[] recName = nifFile.getString; - nifFile.setRec(i,recName); - - debug(verbose) - { - writefln("\n%d: %s (%x)", i, recName, nifFile.position); - } - - switch(recName) - { - // These are the record types we know how to read - - // Time controllers - case "NiVisController": o = new NiVisController; break; - case "NiGeomMorpherController": o = new NiGeomMorpherController; break; - case "NiKeyframeController": o = new NiKeyframeController; break; - case "NiAlphaController": o = new NiAlphaController; break; - case "NiUVController": o = new NiUVController; break; - case "NiPathController": o = new NiPathController; break; - case "NiMaterialColorController": o = new NiMaterialColorController; break; - case "NiBSPArrayController": o = new NiBSPArrayController; break; - case "NiParticleSystemController": o = new NiParticleSystemController; break; - - // NiNodes - case "RootCollisionNode": - case "NiBSParticleNode": - case "NiBSAnimationNode": - case "NiBillboardNode": - case "AvoidNode": - case "NiNode": o = new NiNode; break; - - // Other nodes - case "NiTriShape": o = new NiTriShape; break; - case "NiRotatingParticles": o = new NiRotatingParticles; break; - case "NiAutoNormalParticles": o = new NiAutoNormalParticles; break; - case "NiCamera": o = new NiCamera; break; - - // Effects - case "NiAmbientLight": - case "NiDirectionalLight": o = new Light; break; - case "NiTextureEffect": o = new NiTextureEffect; break; - - // Properties - case "NiTexturingProperty": o = new NiTexturingProperty; break; - case "NiMaterialProperty": o = new NiMaterialProperty; break; - case "NiZBufferProperty": o = new NiZBufferProperty; break; - case "NiAlphaProperty": o = new NiAlphaProperty; break; - case "NiVertexColorProperty": o = new NiVertexColorProperty; break; - case "NiShadeProperty": o = new NiShadeProperty; break; - case "NiDitherProperty": o = new NiDitherProperty; break; - case "NiWireframeProperty": o = new NiWireframeProperty; break; - case "NiSpecularProperty": o = new NiSpecularProperty; break; - - // Extra Data - case "NiVertWeightsExtraData": o = new NiVertWeightsExtraData; break; - case "NiTextKeyExtraData": o = new NiTextKeyExtraData; break; - case "NiStringExtraData": o = new NiStringExtraData; break; - - case "NiGravity": o = new NiGravity; break; - case "NiPlanarCollider": o = new NiPlanarCollider; break; - case "NiParticleGrowFade": o = new NiParticleGrowFade; break; - case "NiParticleColorModifier": o = new NiParticleColorModifier; break; - case "NiParticleRotation": o = new NiParticleRotation; break; - - // Data - case "NiFloatData": o = new NiFloatData; break; - case "NiTriShapeData": o = new NiTriShapeData; break; - case "NiVisData": o = new NiVisData; break; - case "NiColorData": o = new NiColorData; break; - case "NiPixelData": o = new NiPixelData; break; - case "NiMorphData": o = new NiMorphData; break; - case "NiKeyframeData": o = new NiKeyframeData; break; - case "NiSkinData": o = new NiSkinData; break; - case "NiUVData": o = new NiUVData; break; - case "NiPosData": o = new NiPosData; break; - case "NiRotatingParticlesData": o = new NiRotatingParticlesData; break; - case "NiAutoNormalParticlesData": o = new NiAutoNormalParticlesData; break; - - // Other - case "NiSequenceStreamHelper": o = new NiSequenceStreamHelper; break; - case "NiSourceTexture": o = new NiSourceTexture; break; - case "NiSkinInstance": o = new NiSkinInstance; break; - - default: - nifFile.fail("Unknown record type " ~ recName); - } - - if(o !is null) - { - //nifFile.setRec(i,recName ~ " (" ~ o.toString ~ ")"); - o.read(); - } - } - // Clear error message. - nifFile.setRec(-1,""); - - // The 'footer', which it seems isn't always constant after all. I - // have no clue what it is for though. - int roots = nifFile.getInt; - for(int i; i - WWW: http://openmw.snaptoad.com/ - - This file (controlled.d) 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/ . - - */ - -module nif.controlled; - -import nif.record; -import nif.extra; - -// 'Controlled' is something that has a controller -abstract class Controlled : Extra -{ - Controller controller; - - override: - void read() - { - super.read(); - debug(verbose) writef("Controller "); - getIndex(); - } - - void sortOut(Record[] list) - { - super.sortOut(list); - controller = lookup!(Controller)(list); - } -} - -// Record with name and controller/extra data link -abstract class Named : Controlled -{ - // Name of this object. This is used to refer to the object from .kf - // files. - char[] name; - - override: - char[] toString() - { - if(name.length) - return super.toString() ~ " '" ~ name ~ "'"; - else - return super.toString(); - } - - void read() - { - //super.read(f); - name = nifFile.getString(); - debug(verbose) writefln("Name: %s", name); - super.read(); - } -} - -class NiSequenceStreamHelper : Named {} diff --git a/old_d_version/nif/controller.d b/old_d_version/nif/controller.d deleted file mode 100644 index b9e00ec537..0000000000 --- a/old_d_version/nif/controller.d +++ /dev/null @@ -1,316 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (controller.d) 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/ . - - */ - -module nif.controller; - -import nif.record; - -// Time controller -abstract class Controller : Record -{ - Controller next; - ushort flags; - float frequency, phase; // Don't know what these do. - float timeStart, timeStop; - Controlled target; - - override: - void read() - {with(nifFile){ - super.read(); - - debug(verbose) writef("Next controller "); - getIndex(); - - flags = getUshort; - - frequency = getFloatIs(1); - phase = getFloat; - timeStart = getFloat; - timeStop = getFloat; - - debug(verbose) writef("Target "); - getIndex(); - - debug(verbose) - { - writefln("Flags: %x", flags); - writefln("Frequency: ", frequency); - writefln("Phase: ", phase); - writefln("Start time: ", timeStart); - writefln("Stop time: ", timeStop); - } - }} - - void sortOut(Record[] list) - { - super.sortOut(list); - next = lookup!(Controller)(list); - target = lookup!(Controlled)(list); - } -} - -alias NiBSPArrayController NiParticleSystemController; - -class NiBSPArrayController : Controller -{ - override: - void read() - {with(nifFile){ - super.read(); - - // At the moment, just skip it all - - //* - // 23 floats = 92 bytes - // 3 ints = 12 bytes - // 3 shorts = 6 bytes - // 1 byte = 1 byte - // Total: 111 bytes - seekCur(111); - - short s = wgetShort; - - seekCur(15 + s*40); - /*/ - float speed, speedRandom, angle, angleRandom; - - speed = wgetFloat; - speedRandom = wgetFloat; - angle = wgetFloat; - angleRandom = wgetFloat; - - wgetFloat(); // Unknown - wgetFloat(); // Sometimes pi - - for(int i; i<10; i++) - wgetFloat(); - - wgetByte(); - - wgetFloat(); - wgetFloat(); - wgetFloat(); - - wgetShort(); - - wgetVector(); - - debug(verbose) writef("Emitter: "); - wgetInt(); - - wgetShort(); - - wgetFloat(); - - wgetInt(); - wgetInt(); - - wgetShort(); - - debug(verbose) writefln("begin particle group"); - short s = wgetShort; - wgetShort(); - for(short i; i - WWW: http://openmw.snaptoad.com/ - - This file (data.d) 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/ . - - */ - -module nif.data; -import nif.record; - -class NiSourceTexture : Named -{ - byte external; - union - { - char[] filename; - NiPixelData data; - } - - /* Pixel layout - 0 - Palettised - 1 - High color 16 - 2 - True color 32 - 3 - Compressed - 4 - Bumpmap - 5 - Default */ - int pixel; - - /* Mipmap format - 0 - no - 1 - yes - 2 - default */ - int mipmap; - - /* Alpha - 0 - none - 1 - binary - 2 - smooth - 3 - default (use material alpha, or multiply material with texture if present) - */ - int alpha; - - override: - void sortOut(Record[] list) - { - super.sortOut(list); - if(!external) - data = lookup!(NiPixelData)(list); - } - - void read() - { - super.read(); - - external = nifFile.getByteIs(0,1); - debug(verbose) writefln("Use external file: ", external); - - if(external) - { - filename = nifFile.getString; - debug(verbose) writefln("Filename: ", filename); - } - else - { - nifFile.wgetByteIs(1); - debug(verbose) writef("Pixel Data "); - getIndex(); - } - - pixel = nifFile.getInt; - mipmap = nifFile.getInt; - alpha = nifFile.getIntIs(3); - - debug(verbose) - { - writefln("Pixel layout: ", pixel); - writefln("Mipmap: ", mipmap); - writefln("Alpha: ", alpha); - } - - nifFile.wgetByteIs(1); - } -} - -// Common ancestor for several classes -class ShapeData : Record -{ - float[] vertices, normals, colors, uvlist; - Vector center; - float radius; - - override: - void read() - { - super.read(); - - short verts = nifFile.getShort; - debug(verbose) writefln("Vertices: ", verts); - - if(nifFile.getInt != 0) - { - debug(verbose) writefln("Reading vertices"); - if(verts == 0) nifFile.warn("Empty vertex array"); - vertices = nifFile.getArraySize!(float)(verts*3); - } - else nifFile.warn("No vertices found"); - - if(nifFile.getInt != 0) - { - debug(verbose) writefln("Reading normals"); - normals = nifFile.getArraySize!(float)(verts*3); - } - - center = nifFile.getVector(); - radius = nifFile.getFloat(); - debug(verbose) - { - writefln("Center: ", center.toString); - writefln("Radius: ", radius); - } - - if(nifFile.getInt != 0) - { - debug(verbose) writefln("Reading vertex colors"); - colors = nifFile.getArraySize!(float)(verts*4); - } - - short uvs = nifFile.getShort; - debug(verbose) writefln("Number of UV sets: ", uvs); - - if(nifFile.getInt != 0) - { - if(uvs == 0) nifFile.warn("Empty UV list"); - - // Only the 6 first bits are used as a count, the rest are - // (unknown) flags. - if(uvs > 0b111111) - { - nifFile.warn("UV count contains (unknown) flags"); - uvs = cast(short)(uvs & 0b111111); - } - - uvlist = nifFile.getArraySize!(float)(uvs*verts*2); - } - else if(uvs != 0) nifFile.warn("UV list was unexpectedly missing"); - } -} - -class NiAutoNormalParticlesData : ShapeData -{ - ushort activeCount; - - override: - void read() - { - super.read(); - - nifFile.assertWarn(uvlist.length == 0, "UV coordinates are not expected in this record"); - - debug(verbose) writef("Active vertices: "); - - // Number of active vertices (always matches count?) - activeCount = nifFile.wgetUshortIs(cast(ushort)(vertices.length/3)); - - nifFile.wgetFloat(); // Active radius (?) - nifFile.wgetShort(); // Number of valid entries in the following arrays - - //writefln("%x", nifFile.position); - if(nifFile.wgetInt == 0) nifFile.warn("Particle size list is missing"); - else - for(int i; i>3); - - debug(verbose) - { - writefln("Red mask %8xh", rmask); - writefln("Green mask %8xh", gmask); - writefln("Blue mask %8xh", bmask); - writefln("Alpha mask %8xh", amask); - writefln("Bits per pixel: ", bpp); - writefln("Number of mipmaps: ", mips); - writefln("Bytes per pixel: ", bytes); - } - - for(int i; i=verts || sh < 0) - nifFile.warn("Presumed vertex index was out of bounds"); - s = nifFile.getArraySize!(short)(sh); - } - } - } -} - -class NiMorphData : Record -{ - //float[] vertexList; - - override: - void read() - { - super.read(); - - int morphCount = nifFile.getInt; - - int vertCount = nifFile.getInt; - - debug(verbose) - { - writefln("Number of morphs: ", morphCount); - writefln("Vertices: ", vertCount); - } - - nifFile.wgetByteIs(1); - - //nifFile.getIntIs(0); - //nifFile.getIntIs(1); - //vertexList = nifFile.getArraySize!(float)(3*vertCount); - - for(int i=0; i - WWW: http://openmw.snaptoad.com/ - - This file (effect.d) 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/ . - - */ - -module nif.effect; -import nif.record; - -class Effect : Node {} - -// Used for NiAmbientLight and NiDirectionalLight. Might also work for -// NiPointLight and NiSpotLight? -class Light : Effect -{ - float dimmer; - Vector ambient, diffuse, specular; - - override: - void read() - { - super.read(); - - debug(check) - if(flags != 2 && flags != 4) nifFile.warn("Unknown flags"); - - nifFile.getIntIs(1); - if(nifFile.getInt == 0) nifFile.warn("Light list might be missing"); - - dimmer = nifFile.getFloat; - ambient = nifFile.getVector; - diffuse = nifFile.getVector; - specular = nifFile.getVector; - - debug(verbose) - { - writefln("Dimmer: ", dimmer); - writefln("Ambient: ", ambient.toString); - writefln("Diffuse: ", diffuse.toString); - writefln("Specular: ", specular.toString); - } - } -} - -class NiTextureEffect : Effect -{ - NiSourceTexture texture; - - override: - void read() - { - super.read(); - - debug(check) - if(flags != 2 && flags != 4) nifFile.warn("Unknown flags"); - - int i = nifFile.wgetInt; // 0 or 1 - - if(i == 1) {if(nifFile.getInt == 0) nifFile.warn("List might be missing");} - else if(i != 0) nifFile.warn("Unknown value"); - - for(int j; j<3; j++) - { - nifFile.wgetFloatIs(1); - nifFile.wgetFloatIs(0); - nifFile.wgetFloatIs(0); - nifFile.wgetFloatIs(0); - } - - nifFile.wgetIntIs(2); - nifFile.wgetIntIs(0,3); - nifFile.wgetIntIs(2); - nifFile.wgetIntIs(2); - debug(verbose) writef("Source Texture "); - getIndex(); - nifFile.wgetByteIs(0); - - nifFile.wgetFloatIs(1); - nifFile.wgetFloatIs(0); - nifFile.wgetFloatIs(0); - nifFile.wgetFloatIs(0); - - nifFile.wgetShortIs(0); - nifFile.wgetShortIs(-75); - nifFile.wgetShortIs(0); - } - - void sortOut(Record[] list) - { - super.sortOut(list); - texture = lookup!(NiSourceTexture)(list); - } -} diff --git a/old_d_version/nif/extra.d b/old_d_version/nif/extra.d deleted file mode 100644 index 2a9eabbfdd..0000000000 --- a/old_d_version/nif/extra.d +++ /dev/null @@ -1,212 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (extra.d) 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/ . - - */ - -module nif.extra; -import nif.record; -import nif.controlled; - -import util.utfconvert; - -abstract class Extra : Record -{ - Extra extra; - - override: - void read() - { - super.read(); - debug(verbose) nifFile.writef("Extra Data "); - getIndex(); - } - - void sortOut(Record[] list) - { - super.sortOut(list); - extra = lookup!(Extra)(list); - } -} - -class NiVertWeightsExtraData : Extra -{ - override: - void read() - { - super.read(); - - int i = nifFile.getInt; - short s = nifFile.getShort; // = number of vertices - - if(s*4+2 != i) - nifFile.warn("Sizes don't add up"); - - debug(verbose) - { - writefln("Total bytes in record: ", i); - writefln("Number of vertex weights: ", s); - } - - for(int j; j - WWW: http://openmw.snaptoad.com/ - - This file (misc.d) 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/ . - - */ - -// This doesn't have to be part of the nif package at all. -module nif.misc; - -import std.string; -import monster.util.string; - -struct Vector -{ - float array[3]; - - void set(float x, float y, float z) - { - array[0] = x; - array[1] = y; - array[2] = z; - } - - char[] toString() - { - return format(array); - //return format("[", array[0], ",", array[1], ",", array[2], "]"); - } - - int opEquals(ref Vector v) - { - return v.array == array; - } - - static assert(Vector.sizeof == 4*3); -} - -unittest -{ - Vector a, b; - a.set(1,2,3); - assert(a!=b); - b = a; - assert(a==b); -} - -struct Vector4 -{ - float array[4]; - - void set(float x, float y, float z, float a) - { - array[0] = x; - array[1] = y; - array[2] = z; - array[3] = a; - } - - char[] toString() - { - return format(array); - //return format("[", array[0], ",", array[1], ",", array[2], ",", array[3], "]"); - } - - int opEquals(ref Vector4 v) - { - return v.array == array; - } - - static assert(Vector4.sizeof == 4*4); -} - -unittest -{ - Vector4 a, b; - a.set(1,2,3,5); - assert(a!=b); - b = a; - assert(a==b); -} - -align(1) -struct Matrix -{ - union - { - Vector v[3]; - float[9] array; - } - - char[] toString() - { - char[] res; - res ~= " Right: " ~ v[0].toString; - res ~= "\n Up: " ~ v[1].toString; - res ~= "\n Front: " ~ v[2].toString; - return res; - } - static assert(Matrix.sizeof == 3*3*4); -} - - -align(1) -struct Transformation -{ - Vector pos; - Matrix rotation; - float scale; - Vector velocity; - - char[] toString() - { - char[] res; - res ~= " Translation: " ~ pos.toString(); - res ~= "\n" ~ rotation.toString(); - res ~= "\n Scale: " ~ format(scale); - res ~= "\n Velocity: " ~ velocity.toString(); - return res; - } - - static assert(Transformation.sizeof == 5*Vector.sizeof + 4); -} diff --git a/old_d_version/nif/nif.d b/old_d_version/nif/nif.d deleted file mode 100644 index fe9d3e1dcf..0000000000 --- a/old_d_version/nif/nif.d +++ /dev/null @@ -1,106 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (nif.d) 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/ . - - */ - -module nif.nif; - -import nif.base; -import nif.niffile; -import nif.record; - -import core.memory; - -/* The NIFMesh struct will open, read and close a .nif file. Unlike - * NIFFile (which it uses), it stores all the data from the NIF. - */ -NIFMesh nifMesh; - -struct NIFMesh -{ - public: - Record records[]; - - // Read from a file - void open(char[] file) - { - nifFile.open(file); - loadData(); // Load the data - } - - // Read from a memory slice. The optitional file name is used for - // error messages only. - void open(void[] s, char[] name = "") - { - nifFile.open(s, name); - loadData(); // Load the data - } - - // Clear all loaded data - void clear() - { - records = null; - - // Clear the region manager - nifRegion.freeAll(); - } - - /* - void fail(char[] msg) - { - throw new NIFMeshException(msg); - } - */ - - private void loadData() - { - // Remove any previously loaded data - clear(); - - // The actual parsing is done somewhere else. - nif.base.parseFile(); - - // Close the file - nifFile.close(); - - // Resolve inter-record references into object pointers. - foreach(int i, Record o; records) - if(o !is null) - { - nifFile.setRec(i, o); - o.sortOut(records); - } - - // Let the records do consistency checks on their data. - foreach(int i, Record o; records) - if(o !is null) - { - nifFile.setRec(i, o); - o.check(); - } - - // Internal state check, used for debugging - debug(statecheck) - foreach(Record o; records) - if(o !is null) o.finalCheck(); - } - -} diff --git a/old_d_version/nif/niffile.d b/old_d_version/nif/niffile.d deleted file mode 100644 index 79f44c1dda..0000000000 --- a/old_d_version/nif/niffile.d +++ /dev/null @@ -1,482 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (niffile.d) 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/ . - - */ - -module nif.niffile; - -public import std.stream; -public import util.regions; - -import std.string; -import nif.misc; - -public import core.memory; - -// Exception class thrown by most exceptions originating within the -// nif package -class NIFFileException : Exception -{ - this(char[] msg) {super("NIFFile Exception: " ~ msg);} -} - -/* The NIFFile struct is used for the task of reading from NIF - files. It provides specialized methods for handling common types, - records, etc., and also provides mechanisms for output and error - handling. It does not store any (non-transient) NIF data. - */ -NIFFile nifFile; - -struct NIFFile -{ - private: - Stream f; // Input stream - BufferedFile bf; // Used and reused for direct file input. - TArrayStream!(ubyte[]) ss; // For stream reading - - // These are used for warnings and error messages only - char[] filename; - int recNum; // Record number - char[] recName; // Record name - Object recObj; // Record object - public: - - /* ------------------------------------------------ - * Object initialization and file management - * ------------------------------------------------ - */ - - // Open a file from the file system - void open(char[] file) - { - close(); - - // Create a BufferedFile, and reuse it later. - if(bf is null) - bf = new BufferedFile(); - - bf.open(file); - - f = bf; - filename = file; - } - - // Open a memory slice, the name is used for error messages. - void open(void[] data, char[] name) - { - close(); - - // Create a TArrayStream, and reuse it - if(ss is null) - { - ss = new TArrayStream!(ubyte[])(cast(ubyte[])data); - ss.writeable = false; // Read-only - } - else - { - // TArrayStream lacks the open() method. Instead, all the - // members are public. - ss.buf = cast(ubyte[])data; - ss.len = ss.buf.length; - ss.cur = 0; - } - - f = ss; - filename = name; - } - - // Close the file handle - void close() - { - // Close the buffered file - if(f !is null && f is bf) f.close(); - f = null; - - // Zero out variables - filename = null; - recNum = 0; - recName = null; - recObj = null; - } - - ulong size() - in - { - if(f is null) fail("Cannot get size, file is not open"); - } - body - { - return f.size(); - } - - bool eof() { return f.eof(); } - - void seekCur(long skip) - in - { - if(f is null) fail("Cannot seek, file is not open"); - } - body - { - f.seekCur(skip); - } - - ulong position() - { - return f.position(); - } - - /* ------------------------------------------------ - * Error reporting - * ------------------------------------------------ - */ - - // Used to format error messages - private char[] makeError(char[] str) - { - if(recNum > 0) - { - if(recName == "" && recObj !is null) recName = recObj.toString; - str = format("%s\n Record %d: %s", str, recNum-1, recName); - } - if(filename != "") str = format("%s\n File: %s", str, filename); - if(f !is null) - if(f.eof()) str = format("%s\n At end of file", str); - else str = format("%s\n Offset 0x%x", str, f.position); - return str ~ "\n"; - } - - void fail(char[] msg) - { - throw new NIFFileException(makeError(msg)); - } - - debug(warnstd) import std.stdio; - - void warn(char[] msg) - { - debug(strict) fail("(fail on warning) " ~ msg); - else - { - debug(warnstd) writefln("WARNING: ", makeError(msg)); - debug(warnlog) log.writefln("WARNING: ", makeError(msg)); - } - } - - void assertWarn(bool condition, char[] str) - { if(!condition) warn(str); } - - /* - void assertFail(bool condition, char[] str) - { if(!condition) fail(str); } - */ - - // Used for error message handling, hackish. - void setRec(int i, char[] n) - { - recNum = i+1; - recName = n; - recObj = null; - } - - // This variant takes an object instead of a name. That way we only - // need to call toString when the name is needed (which it mostly - // isn't.) - void setRec(int i, Object o) - { - recNum = i+1; - recObj = o; - recName = null; - } - - /* ------------------------------------------------ - * Reader method templates (skip to next section - * for usable methods) - * ------------------------------------------------ - */ - - // Read a variable of a given type T - T getType(T)() - { - T t; - f.read(t); - return t; - } - - // Read a variable and compare it to what we want it to be - template getTypeIs(T) - { - T getTypeIs(T[] pt ...) - { - T t = getType!(T)(); - debug(check) - { - bool match; - foreach(T a; pt) - if(a == t) {match = true; break;} - - if(!match) - { - char[] errMsg = format(typeid(T), - " mismatch: got %s, expected ", t); - if(pt.length > 1) errMsg ~= "one of: "; - foreach(T a; pt) - errMsg ~= format("%s ", a); - warn(errMsg); - } - } - return t; - } - } - - debug(verbose) - { - // Read a variable of a given type T and print it to screen - template wgetType(T) - { - T wgetType() - { - T t; - f.read(t); - writefln(typeid(T), ": ", t); - return t; - } - } - - // Read a variable and compare it to what we want it to be - template wgetTypeIs(T) - { - T wgetTypeIs(T pt[] ...) - { - T t = getType!(T)(); - - char[] wanted; - if(pt.length > 1) wanted = "one of: "; - foreach(T a; pt) wanted ~= format("%s ", a); - - writefln(typeid(T), ": ", t, " (wanted %s)", wanted); - - debug(check) - { - bool match; - foreach(T a; pt) - if(a == t) {match = true; break;} - - if(!match) - { - warn(format(typeid(T), - " mismatch: got %s, expected %s", t, wanted)); - } - } - return t; - } - } - } - - // Fill the provided array of Ts - template getArrayLen(T) - { - T[] getArrayLen(T[] arr) - { - f.readExact(arr.ptr, arr.length*T.sizeof); - return arr; - } - } - - // Set the size of the provided array to 'count', and fill it. - T[] getArraySize(T)(int count) - { - T[] arr; - fitArray(count, T.sizeof); - arr = cast(T[])nifRegion.allocate(count * T.sizeof); - getArrayLen!(T)(arr); - return arr; - } - - // Get an array of Ts preceded by an array length of type Index - // (assumed to be an integer type) - template getArray(T,Index) - { - T[] getArray() - { - // Read array length - Index s = getType!(Index)(); - - // Is array larger than file? - fitArray(s,T.sizeof); - - // Allocate the buffer - T[] result = cast(T[])nifRegion.allocate(s * T.sizeof); - - // Read the buffer - return getArrayLen!(T)(result); - } - } - - /* ------------------------------------------------ - * Reader methods - * ------------------------------------------------ - */ - - // Strings - alias getArrayLen!(char) getString; - alias getArray!(char,int) getString; - - // Other arrays - alias getArray!(int,int) getInts; - - // Checks if an array of size elements each of size esize could - // possibly follow in the file. - void fitArray(int size, int esize) - in - { - assert(esize > 0); - } - body - { - if((size*esize+8) > (f.size() - f.position()) || size < 0) - fail(format( - "Array out of bounds: %d*%d + 8 bytes needed, but only %d bytes left in file", - size,esize,(f.size-f.position))); - } - - // Base types - alias getType!(byte) getByte; - alias getType!(ubyte) getUbyte; - alias getType!(short) getShort; - alias getType!(ushort) getUshort; - alias getType!(int) getInt; - alias getType!(uint) getUint; - alias getType!(float) getFloat; - - // Base types with error checking - alias getTypeIs!(short) getShortIs; - alias getTypeIs!(ushort) getUshortIs; - alias getTypeIs!(byte) getByteIs; - alias getTypeIs!(ubyte) getUbyteIs; - alias getTypeIs!(int) getIntIs; - alias getTypeIs!(uint) getUintIs; - alias getTypeIs!(float) getFloatIs; - - debug(verbose) - { - // Base types - alias wgetType!(byte) wgetByte; - alias wgetType!(ubyte) wgetUbyte; - alias wgetType!(short) wgetShort; - alias wgetType!(ushort) wgetUshort; - alias wgetType!(int) wgetInt; - alias wgetType!(uint) wgetUint; - alias wgetType!(float) wgetFloat; - - // Base types with error checking - alias wgetTypeIs!(short) wgetShortIs; - alias wgetTypeIs!(ushort) wgetUshortIs; - alias wgetTypeIs!(byte) wgetByteIs; - alias wgetTypeIs!(ubyte) wgetUbyteIs; - alias wgetTypeIs!(int) wgetIntIs; - alias wgetTypeIs!(uint) wgetUintIs; - alias wgetTypeIs!(float) wgetFloatIs; - } - else - { - // Base types - alias getByte wgetByte; - alias getUbyte wgetUbyte; - alias getShort wgetShort; - alias getUshort wgetUshort; - alias getInt wgetInt; - alias getUint wgetUint; - alias getFloat wgetFloat; - - // Base types with error checking - alias getByteIs wgetByteIs; - alias getUbyteIs wgetUbyteIs; - alias getShortIs wgetShortIs; - alias getUshortIs wgetUshortIs; - alias getIntIs wgetIntIs; - alias getUintIs wgetUintIs; - alias getFloatIs wgetFloatIs; - } - - // Vectors - Vector getVector() - { - Vector v; - getArrayLen!(float)(v.array); - return v; - } - - Vector4 getVector4() - { - Vector4 v; - getArrayLen!(float)(v.array); - return v; - } - - Vector getVectorIs(float x, float y, float z) - { - Vector v = getVector(); - debug(check) - { - Vector u; - u.set(x,y,z); - if(v != u) - warn("Vector mismatch: expected " ~ u.toString ~ ", got " ~ v.toString); - } - return v; - } - - debug(verbose) - { - Vector wgetVector() - { - Vector v = getVector(); - writefln("vector: ", v.toString); - return v; - } - - Vector4 wgetVector4() - { - Vector4 v = getVector4(); - writefln("4-vector: ", v.toString); - return v; - } - } - else - { - alias getVector wgetVector; - alias getVector4 wgetVector4; - } - - void getMatrix(ref Matrix m) - { - getArrayLen!(float)(m.array); - } - - void getTransformation(ref Transformation t) - { - t.pos = getVector(); - getMatrix(t.rotation); - t.scale = getFloat/*Is(1)*/; - t.velocity = getVectorIs(0,0,0); - } -} diff --git a/old_d_version/nif/node.d b/old_d_version/nif/node.d deleted file mode 100644 index b4e7842f81..0000000000 --- a/old_d_version/nif/node.d +++ /dev/null @@ -1,324 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (node.d) 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/ . - - */ - -module nif.node; - -import nif.record; - -// Tree node -abstract class Node : Named -{ - ushort flags; - Transformation trafo; - //Extra properties[]; - Property properties[]; - - Node parent; - - // Bounding box info - bool hasBounding; - Vector boundPos; - Matrix boundRot; - Vector boundXYZ; - - void setParent(Node p) - { - debug(veryverbose) - writefln("Setting parent of ", toString, " to ", p); - - if(parent !is null) - { - char str[] = toString() ~ " already has parent " ~ parent.toString() - ~ ", but setting "; - if(p !is null) str ~= p.toString; - else str ~= "to null"; - - nifFile.warn(str); - } - - parent = p; - } - - override: - void read() - { - super.read(); - - flags = nifFile.getUshort(); - nifFile.getTransformation(trafo); - - debug(verbose) - { - writefln("Flags: %x", flags); - writefln("Transformation:\n", trafo.toString); - writef("Properties: "); - } - - properties = nifRegion.allocateT!(Property)(getIndexList()); - - if(nifFile.getInt != 0) - { - hasBounding = true; - nifFile.getIntIs(1); - boundPos = nifFile.getVector; - nifFile.getMatrix(boundRot); - boundXYZ = nifFile.getVector; - //if(name != "Bounding Box") nifFile.warn("Node name is not 'Bounding Box'"); - debug(verbose) - { - writefln("Bounding box: ", boundPos.toString); - writefln(boundRot.toString); - writefln("XYZ: ", boundXYZ.toString); - } - } - } - - void sortOut(Record[] list) - { - super.sortOut(list); - lookupList!(Property)(list,properties); - } - -} - -class NiCamera : Node -{ - float left, right, top, bottom, near, far, - vleft, vright, vtop, vbottom, LOD; - - override: - void read() - { - super.read(); - - left = nifFile.getFloat; - right = nifFile.getFloat; - top = nifFile.getFloat; - bottom = nifFile.getFloat; - near = nifFile.getFloat; - far = nifFile.getFloat; - - vleft = nifFile.getFloat; - vright = nifFile.getFloat; - vtop = nifFile.getFloat; - vbottom = nifFile.getFloat; - - LOD = nifFile.getFloat; - - nifFile.getIntIs(-1); - nifFile.getIntIs(0); - - debug(verbose) - { - writefln("Camera frustrum:"); - writefln(" Left: ", left); - writefln(" Right: ", right); - writefln(" Top: ", top); - writefln(" Bottom: ", bottom); - writefln(" Near: ", near); - writefln(" Far: ", far); - - writefln("View port:"); - writefln(" Left: ", vleft); - writefln(" Right: ", vright); - writefln(" Top: ", vtop); - writefln(" Bottom: ", vbottom); - - writefln("LOD adjust: ", LOD); - } - } -} - -class NiAutoNormalParticles : Node -{ - NiAutoNormalParticlesData data; - - override: - void read() - { - super.read(); - - debug(check) - { - if(flags & 0xffff-6) - nifFile.warn("Unknown flags"); - } - - debug(verbose) writef("Particle Data "); - getIndex(); - - nifFile.getIntIs(-1); - } - - void sortOut(Record[] list) - { - super.sortOut(list); - data = lookup!(NiAutoNormalParticlesData)(list); - - debug(check) - { - if(castCheck!(NiParticleSystemController)(controller) - && castCheck!(NiBSPArrayController)(controller)) - nifFile.warn("In " ~ toString ~ ": did not expect controller " - ~ controller.toString); - } - } -} - -class NiRotatingParticles : Node -{ - NiRotatingParticlesData data; - - override: - void read() - { - super.read(); - - debug(check) - { - if(flags & 0xffff-6) - nifFile.warn("Unknown flags"); - } - - //nifFile.getIntIs(0); - - debug(verbose) writef("Particle Data "); - getIndex(); - - nifFile.getIntIs(-1); - } - - void sortOut(Record[] list) - { - super.sortOut(list); - data = lookup!(NiRotatingParticlesData)(list); - - debug(check) - { - if(castCheck!(NiParticleSystemController)(controller) - && castCheck!(NiBSPArrayController)(controller) ) - nifFile.warn("In " ~ toString ~ ": did not expect controller " - ~ controller.toString); - } - //castWarn!(NiParticleSystemController)(controller); - } -} - -class NiTriShape : Node -{ - NiTriShapeData data; - NiSkinInstance skin; - - override: - void read() - { - super.read(); - - debug(verbose) - { - // If this is correct, it suggests how one might decode - // other flags. Check if this one is correct in sortOut(). - if(flags&0x40) writefln("Mesh has no normals?"); - } - debug(check) - { - if(flags & (0xffff-0x47)) - nifFile.warn("Unknown flags were set"); - } - - //nifFile.getIntIs(0); - debug(verbose) writef("Mesh index: "); - getIndex(); - debug(verbose) writef("Skin index: "); - getIndex(); - } - - void sortOut(Record[] list) - { - super.sortOut(list); - data = lookup!(NiTriShapeData)(list); - skin = lookup!(NiSkinInstance)(list); - - debug(check) - { - if(data is null) nifFile.warn("Data missing from NiTriShape"); - - if(castCheck!(NiGeomMorpherController)(controller) - && castCheck!(NiUVController)(controller) - && castCheck!(NiVisController)(controller) ) - nifFile.warn("In " ~ toString ~ ": did not expect controller " - ~ controller.toString); - - if((data.normals.length == 0) && (flags & 0x40 == 0) || - (data.normals.length != 0) && (flags & 0x40)) - nifFile.warn("0x40 present but normals missing, or vice versa"); - } - } -} - -class NiNode : Node -{ - Node children[]; - Effect effects[]; - - override: - void read() - { - super.read(); - - debug(verbose) - { - if(flags & 1) writefln(" 0x01 Hidden"); - if(flags & 2) writefln(" 0x02 Collision detection?"); - if(flags & 4) writefln(" 0x04 Collision detection2 ?"); - if(flags & 8) writefln(" 0x08 Unknown but common"); - if(flags & 0x20) writefln(" 0x20 Unknown"); - if(flags & 0x40) writefln(" 0x40 Unknown"); - if(flags & 0x80) writefln(" 0x80 Unknown"); - } - debug(check) - if(flags & 0x10) nifFile.warn("Unknown flags were set"); - - debug(verbose) writef("Child nodes: "); - children = nifRegion.allocateT!(Node)(getIndexList()); - debug(verbose) writef("Effects: "); - effects = nifRegion.allocateT!(Effect)(getIndexList()); - } - - void sortOut(Record[] list) - { - super.sortOut(list); - - lookupList!(Node)(list,children); - lookupList!(Effect)(list,effects); - - if(castCheck!(NiKeyframeController)(controller) - && castCheck!(NiVisController)(controller) - && castCheck!(NiPathController)(controller)) - nifFile.warn("In " ~ toString ~ ": did not expect controller " - ~ controller.toString); - - foreach(Node n; children) - n.setParent(this); - } -} diff --git a/old_d_version/nif/property.d b/old_d_version/nif/property.d deleted file mode 100644 index 97e9072d2f..0000000000 --- a/old_d_version/nif/property.d +++ /dev/null @@ -1,313 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (property.d) 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/ . - - */ - -module nif.property; -import nif.record; - -abstract class Property : Named -{ - // The meaning of these depends on the actual property type. - ushort flags; - - override: - void read() - { - super.read(); - flags = nifFile.getUshort; - debug(verbose) writefln("Flags: %x", flags); - } -} - -// Check the specs on this one again -class NiTexturingProperty : Property -{ - /* Apply mode: - 0 - replace - 1 - decal - 2 - modulate - 3 - hilight // These two are for PS2 only? - 4 - hilight2 - */ - int apply; - - struct Texture - { - bool inUse; - NiSourceTexture texture; - - /* Clamp mode - 0 - clampS clampT - 1 - clampS wrapT - 2 - wrapS clampT - 3 - wrapS wrapT - */ - - /* Filter: - 0 - nearest - 1 - bilinear - 2 - trilinear - 3, 4, 5 - who knows - */ - - int clamp, set, filter; - short ps2L, ps2K, unknown2; - - void read(NiTexturingProperty caller) - { - if(nifFile.getInt == 0) - { - debug(verbose) writefln("No texture"); - return; - } - - inUse = 1; - - debug(verbose) writef(" Texture "); - caller.getIndex(); - - clamp = nifFile.getIntIs(0,1,2,3); - filter = nifFile.getIntIs(0,1,2); - set = nifFile.getInt; - - // The combination 1222, 322, 212 was used in a bump map - // NIF. Might just be bogus numbers, I should probably allow all - // values here since we ignore them anyway. - ps2L = nifFile.getShortIs(0,1222); - ps2K = nifFile.getShortIs(-75,-2,322); - - debug(verbose) - { - writefln(" Clamp ", clamp); - writefln(" Filter ", filter); - writefln(" Set? ", set); - writefln(" ps2L ", ps2L); - writefln(" ps2K ", ps2K); - } - - unknown2 = nifFile.wgetShortIs(0,257,212); - } - } - - /* - * The textures in this list is as follows: - * - * 0 - Base texture - * 1 - Dark texture - * 2 - Detail texture - * 3 - Gloss texture (never used?) - * 4 - Glow texture - * 5 - Bump map texture - * 6 - Decal texture - */ - Texture[7] textures; - - override: - void read() - { - super.read(); - if(flags > 1) nifFile.warn("Unknown flags"); - - apply = nifFile.getInt; - debug(verbose) writefln("Apply mode: ", apply); - nifFile.getIntIs(7); - - textures[0].read(this); // Base - textures[1].read(this); // Dark - textures[2].read(this); // Detail - - nifFile.getIntIs(0); // Gloss - - textures[4].read(this); // Glow - textures[5].read(this); // Bump map - - if(textures[5].inUse) - { - float lumaScale = nifFile.wgetFloat; - float lumaOffset = nifFile.wgetFloat; - Vector4 lumaMatrix = nifFile.wgetVector4; - } - - textures[6].read(this); // Decal - } - - void sortOut(Record[] list) - { - super.sortOut(list); - foreach(ref Texture t; textures) - if(t.inUse) t.texture = lookup!(NiSourceTexture)(list); - } -} - -class NiMaterialProperty : Property -{ - Vector ambient, diffuse, specular, emissive; - float glossiness, alpha; - - override: - void read() - { - super.read(); - if(flags != 1) nifFile.warn("Unknown flags"); - - ambient = nifFile.getVector; - diffuse = nifFile.getVector; - specular = nifFile.getVector; - emissive = nifFile.getVector; - glossiness = nifFile.getFloat; - alpha = nifFile.getFloat; // Use Alpha Property when this is not 1 - - debug(verbose) - { - writefln("Ambient: ", ambient.toString); - writefln("Diffuse: ", diffuse.toString); - writefln("Specular: ", specular.toString); - writefln("Emissive: ", emissive.toString); - writefln("Glossiness: ", glossiness); - writefln("Alpha: ", alpha); - } - } -} -class NiVertexColorProperty : Property -{ - /* Vertex mode: - 0 - source ignore - 1 - source emmisive - 2 - source amb diff - - Lighting mode - 0 - lighting emmisive - 1 - lighting emmisive ambient/diffuse - */ - int vertmode, lightmode; - - override: - void read() - { - super.read(); - if(flags != 0) nifFile.warn("Unknown flags"); - vertmode = nifFile.getIntIs(0,1,2); - lightmode = nifFile.getIntIs(0,1); - debug(verbose) - { - writefln("Vertex mode: ", vertmode); - writefln("Lighting mode: ", lightmode); - } - } -} - -alias NiWireframeProperty NiDitherProperty; -alias NiWireframeProperty NiSpecularProperty; - -class NiWireframeProperty : Property -{ - override: - void read() - { - super.read(); - if(flags != 1) nifFile.warn("Unknown flags"); - } -} - -class NiShadeProperty : Property -{ - override: - void read() - { - super.read(); - if(flags != 0) nifFile.warn("Unknown flags"); - } -} - -class NiAlphaProperty : Property -{ - /* - In NiAlphaProperty, the flags have the following meaning. - - Bit 0 : alpha blending enable - Bits 1-4 : source blend mode - Bits 5-8 : destination blend mode - Bit 9 : alpha test enable - Bit 10-12 : alpha test mode - Bit 13 : no sorter flag ( disables triangle sorting ) - - blend modes (glBlendFunc): - 0000 GL_ONE - 0001 GL_ZERO - 0010 GL_SRC_COLOR - 0011 GL_ONE_MINUS_SRC_COLOR - 0100 GL_DST_COLOR - 0101 GL_ONE_MINUS_DST_COLOR - 0110 GL_SRC_ALPHA - 0111 GL_ONE_MINUS_SRC_ALPHA - 1000 GL_DST_ALPHA - 1001 GL_ONE_MINUS_DST_ALPHA - 1010 GL_SRC_ALPHA_SATURATE - - test modes (glAlphaFunc): - 000 GL_ALWAYS - 001 GL_LESS - 010 GL_EQUAL - 011 GL_LEQUAL - 100 GL_GREATER - 101 GL_NOTEQUAL - 110 GL_GEQUAL - 111 GL_NEVER - - Taken from: - http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html - - Right now we only use standard alpha blending (see the Ogre code - that sets it up) and it appears that this is the only blending - used in the original game. Bloodmoon (along with several mods) do - however use other settings, such as discarding pixel values with - alpha < 1.0. This is faster because we don't have to mess with the - depth stuff like we did for blending. And OGRE has settings for - this too. - */ - - // Tested against when certain flags are set (see above.) - ubyte threshold; - - override: - void read() - { - super.read(); - ubyte b = nifFile.getUbyte; - debug(verbose) writefln("Unknown byte: ", b); - } -} - -class NiZBufferProperty : Property -{ - override: - void read() - { - super.read(); - debug(verbose) - { - if(flags&1) writefln(" 0x01 ZTest"); - if(flags&2) writefln(" 0x02 ZWrite"); - } - if(flags & 0xfc) nifFile.warn("Unknown flags"); - } -} diff --git a/old_d_version/nif/record.d b/old_d_version/nif/record.d deleted file mode 100644 index d93213a13d..0000000000 --- a/old_d_version/nif/record.d +++ /dev/null @@ -1,302 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (record.d) 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/ . - - */ - -module nif.record; - -public -{ - import util.regions; - - import nif.base; - import nif.controller; - import nif.controlled; - import nif.node; - import nif.data; - import nif.extra; - import nif.property; - import nif.effect; - - import nif.niffile; - import nif.misc; - - import std.string; -} - -// Base class for all NIF records -abstract class Record -{ - protected: - // List of dependency indices. We throw this away after the entire - // file is loaded and the dependencies have been converted to object - // pointers. - RegionBuffer!(int) depList; - - debug(statecheck) - { - // An internal 'state', this check is only intended for - // debugging purposes (hence the surrounding debug block ;-) - int state; - /* 0 - nothing has been done - * 1 - record has been read - * 2 - sortOut has been called - * 3 - check has been called - */ - } - public: - - // Allocate objects of this class (and all subclasses) in the - // nifRegion. This means we can allocate and deallocate the entire - // nif tree very quickly, without involving the GC, and with zero - // chance of memory leaks or heap fragmentation. - new(uint sz) - { - return nifRegion.allocate(sz).ptr; - } - - delete(void *p) { assert(0); } - - debug(statecheck) - final void finalCheck() - { - debug(veryverbose) - writefln("Final check on ", this); - assert(state==3); - } - - // Read record data from file f. All indices are stored temporarily - // as integers, as they appear in the file. - void read() - { - // Allocate the dependency list. 50 should be enough entries. - depList = nifRegion.getBuffer!(int)(0,50); - - debug(veryverbose) - writefln("Reading ", this, " at offset %x", nifFile.position); - debug(statecheck) assert(state++ == 0); - } - - // Sort out dependencies between records. Called after all records - // have been read from file. Paramter 'list' contains all records in - // the order they appear in the file. Used to convert integer - // indices into object pointers, and checking that all types are - // correct. Can also be used for data checks than only require this - // objects dependencies. - void sortOut(Record[] list) - { - debug(veryverbose) writefln("Sorting out ", this); - debug(statecheck) assert(state++ == 1); - } - - // Consistancy check. Called after all dependencies have been - // sorted. Can be used for checking that vertex counts are the same - // in different records, etc. It checks the depList array. - void check() - { - debug(veryverbose) writefln("Consistancy check on ", this); - - // Check that all dependencies have been resolved. delList is - // successively sliced down to zero when indices are looked up. - assert(depList.length == 0); - - debug(statecheck) assert(state++ == 2); - } - - // Convert an integer record index to an object pointer of type T. - template lookup(T: Record) - { - T lookup(Record[] list) - { - // Get the next dependency from the list - int i = depList[0]; - depList = depList[1..depList.length()]; - - debug(verbose) - { - T t = lookupCast!(T)(i, list); - debug(veryverbose) - { - writef(" Resolved ", i, " to "); - if(t is null) writefln("(null)"); - else writefln(t); - } - return t; - } - else - return lookupCast!(T)(i, list); - } - } - - template lookupList(T: Record) - { - void lookupList(Record[] list, T[] deps) - { - foreach(ref T t; deps) - t = lookup!(T)(list); - } - } - - // Reads an index (int) and adds it to the list of - // dependencies. These can be returned later by lookup(). - void getIndex() - { - depList ~= nifFile.getInt; - debug(verbose) writefln("Index ", depList[depList.length()-1]); - } - - int getIndexList() - { - int[] l = nifFile.getInts; - int num; - - // Only add non-null references - foreach(int i; l) - if(i != -1) - { - depList ~= i; - num++; - } - - //depList ~= l; - - debug(verbose) - { - writef("Index list: "); - foreach(int i; l) - writef(i, " "); - writefln("(%d kept)", num); - } - - return num; - } -} - -// Lookup with casting and error checking. -template lookupCast(T: Record) -{ - T lookupCast(int i, Record[] list) - { - if(i == -1) return null; - - if(i < 0 || i >= list.length) - nifFile.fail(format("Record index %d out of bounds (got %d records.)", - i, list.length)); - - Record r = list[i]; - - if(r is null) - { - nifFile.warn("Referenced an unknown record type"); - return null; - } - - T t = cast(T)r; - if(t is null) - nifFile.fail("Cannot convert " ~ r.toString() ~ " to " ~ - (cast(TypeInfo_Class)typeid(T)).info.name); - - return t; - } -} - -template castCheck(T: Record) -{ - bool castCheck(Record r) - { - if(r !is null && cast(T)r is null) return true; - else return false; - } -} - -template castWarn(T: Record) -{ - debug(check) - { - void castWarn(Record r) - { - if(castCheck!(T)(r)) - nifFile.warn("Could not cast " ~ r.toString() ~ " to " ~ - (cast(TypeInfo_Class)typeid(T)).info.name); - } - } - else - void castWarn(Record r) {}; -} - -class NiSkinInstance : Record -{ - NiSkinData data; - NiNode root; - NiNode bones[]; - - override: - void read() - { - super.read(); - - debug(verbose) writef("Skin data "); - getIndex(); - - debug(verbose) writef("Scene root "); - getIndex(); - - debug(verbose) writef("Bone "); - bones = nifRegion.allocateT!(NiNode)(getIndexList()); - } - - void sortOut(Record[] l) - { - super.sortOut(l); - data = lookup!(NiSkinData)(l); - root = lookup!(NiNode)(l); - lookupList!(NiNode)(l,bones); - } - - void check() - { - super.check(); - debug(check) if(data !is null) - { - if(bones.length != data.weights.length) - nifFile.warn(format("NiSkinInstance has ", bones.length, - " bones, but NiSkinData has ", data.weights.length)); - - /* - int meshCount = root.getFirstMesh(r).data.vertices.length/3; - - foreach(int i, NiSkinData.Weight[] wl; data.weights) - { - if(bones[i] is null) - r.warn("Bone object missing!"); - - if(meshCount < data.weights[i].length) - r.warn(format("More skin weights than vertices in bone %d (%d < %d)", - i, meshCount, data.weights[i].length)); - - foreach(ref NiSkinData.Weight w; data.weights[i]) - if(w.vertex >= meshCount) - r.warn("Skin weight vertex index out of bounds"); - } - */ - } - } -}