diff --git a/include/Vertex.h b/include/Vertex.h new file mode 100644 index 00000000..6755a282 --- /dev/null +++ b/include/Vertex.h @@ -0,0 +1,82 @@ +/****************************************************************************** +This file is part of a voxel plugin for OGRE +Copyright (C) 2006 David Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +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 +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +******************************************************************************/ + +#ifndef __Vertex_H__ +#define __Vertex_H__ + +#include "OgrePrerequisites.h" + +#include "OgreVector3.h" +#include "OgreVector4.h" + +namespace Ogre +{ + class Vertex + { + public: + Vector3 position; + Vector3 normal; + Vector4 colour; + + Vertex(Vector3 positionToSet) + :position(positionToSet) + { + } + + Vertex(Vector3 positionToSet, Vector3 normalToSet) + :position(positionToSet) + ,normal(normalToSet) + { + } + + bool matchesPosition(const Vector3& rhs) const + { + //return ((x == rhs.x) && (y == rhs.y) && (z == rhs.z)); + return ((position - rhs).length() < 0.01); + } + + /*bool operator < (const Vertex& rhs) const + { + if(z < rhs.z) + { + return true; + } + else + { + if(y < rhs.y) + { + return true; + } + else + { + if(x < rhs.x) + { + return true; + } + else + { + return false; + } + } + } + }*/ + }; +} + +#endif diff --git a/materials/programs/ColourMap2DFragmentProgram.cg b/materials/programs/ColourMap2DFragmentProgram.cg new file mode 100644 index 00000000..566ceda8 --- /dev/null +++ b/materials/programs/ColourMap2DFragmentProgram.cg @@ -0,0 +1,22 @@ +struct v2f +{ + float4 Position : POSITION; //in projection space + float4 Color : COLOR; + float4 TexCoordsXY : TEXCOORD0; + float4 TexCoordsYZ : TEXCOORD1; + float4 TexCoordsXZ : TEXCOORD2; + float4 Normal : TEXCOORD3; +}; + +float4 main(v2f IN, uniform sampler2D colourMap : TEXUNIT0) : COLOR +{ + float3 colourMapValueXY = tex2D(colourMap, IN.TexCoordsXY.xy).rgb * abs(IN.Normal.z); + float3 colourMapValueYZ = tex2D(colourMap, IN.TexCoordsYZ.xy).rgb * abs(IN.Normal.x); + float3 colourMapValueXZ = tex2D(colourMap, IN.TexCoordsXZ.xy).rgb * abs(IN.Normal.y); + + float3 colourMapValue = colourMapValueXY + colourMapValueYZ + colourMapValueXZ; + + //colourMapValue /= 3.0; + + return float4(colourMapValue/*IN.Color.rgb*/, pow(IN.Color.a,0.75)); +} \ No newline at end of file diff --git a/materials/programs/ColourMap2DVertexProgram.cg b/materials/programs/ColourMap2DVertexProgram.cg new file mode 100644 index 00000000..1c482fef --- /dev/null +++ b/materials/programs/ColourMap2DVertexProgram.cg @@ -0,0 +1,145 @@ +//NOTE - The code in this file might seem slightly strange. Intuitivy it would +//seem better to get Ogre to pass in an array of lights, rather than passing +//them individually and then building arrays. However, I have had problms with +//this approach (possibly a bug?) + +//See http://www.ogre3d.org/phpBB2/viewtopic.php?t=32391 + +struct a2v +{ + float4 Position : POSITION; //in object space + float3 Normal : NORMAL; + float4 Color : COLOR; +}; + +struct v2f +{ + float4 Position : POSITION; //in projection space + float4 Color : COLOR; + float4 TexCoordsXY : TEXCOORD0; + float4 TexCoordsYZ : TEXCOORD1; + float4 TexCoordsXZ : TEXCOORD2; + float4 Normal : TEXCOORD3; +}; + +struct light +{ + float4 position; + float4 diffuseColour; + float4 attenuation; +}; + +v2f doWork(a2v IN, float4x4 world, float4x4 viewProj, float textureScale, float4 ambient, int iNoOfLights, light lights[4]) +{ + v2f OUT; + + OUT.Position = mul(world, IN.Position); + + float3 uVec; + float3 vVec; + + IN.Normal = normalize(IN.Normal); + + /*float absX = abs(IN.Normal.x); + float absY = abs(IN.Normal.y); + float absZ = abs(IN.Normal.z); + if((absZ <= absX) && (absZ <= absY)) + { + //OUT.TexCoords.xy = OUT.Position.xy /textureScale; + uVec = float3(-IN.Normal.y, IN.Normal.x,0); + } + else if((absY <= absX) && (absY <= absZ)) + { + //OUT.TexCoords.xy = OUT.Position.xz /textureScale; + uVec = float3(-IN.Normal.z, 0, IN.Normal.x); + } + else if((absX <= absZ) && (absX <= absY)) + { + // OUT.TexCoords.xy = OUT.Position.yz /textureScale; + uVec = float3(0, -IN.Normal.z, IN.Normal.y); + } + vVec = cross(IN.Normal, uVec); + OUT.TexCoords.x = dot(OUT.Position.xyz, uVec); + OUT.TexCoords.y = dot(OUT.Position.xyz, vVec); */ + + //OUT.TexCoords.xy = OUT.Position.xy * IN.Normal.z * IN.Normal.z + OUT.Position.xz * IN.Normal.y * IN.Normal.y + OUT.Position.yz * IN.Normal.x * IN.Normal.x; + + //OUT.TexCoords.xy /= textureScale; + + OUT.TexCoordsXY.xy = OUT.Position.xy; + OUT.TexCoordsYZ.xy = OUT.Position.yz; + OUT.TexCoordsXZ.xy = OUT.Position.xz; + + OUT.TexCoordsXY.xy /= textureScale; + OUT.TexCoordsYZ.xy /= textureScale; + OUT.TexCoordsXZ.xy /= textureScale; + + OUT.Normal = float4(IN.Normal,0.0); + + + //OUT.TexCoords.xy = OUT.Position.yz /textureScale; + OUT.TexCoordsXY.w = 1; + OUT.TexCoordsYZ.w = 1; + OUT.TexCoordsXZ.w = 1; + + OUT.Color.rgba = float4(0.0,0.0,0.0,1.0); + + for(int lightCt = 0; lightCt < iNoOfLights; lightCt++) + { + float3 L = normalize(lights[lightCt].position.xyz - OUT.Position.xyz); + //Calculate attenuation factor. + float d = distance(lights[lightCt].position.xyz, OUT.Position.xyz); + float attenuationFactor = 1.0 / (lights[lightCt].attenuation.y + lights[lightCt].attenuation.z * d + lights[lightCt].attenuation.w * d * d); + // Calculate diffuse component + float LdotN = max(dot(L, IN.Normal) , 0); + OUT.Color.rgb += lights[lightCt].diffuseColour.rgb * LdotN * attenuationFactor; + } + + OUT.Color.rgb += ambient.rgb; + + //Temporary + OUT.Color = IN.Color; + + OUT.Position = mul(viewProj, OUT.Position); + + return OUT; +} + +v2f OneLight(a2v IN,uniform float4x4 world, uniform float4x4 viewProj, uniform float textureScale, uniform float4 ambient, uniform light light0) +{ + light lights[4]; + lights[0] = light0; + + return doWork(IN, world, viewProj, textureScale, ambient, 1, lights); +} + +v2f TwoLights(a2v IN,uniform float4x4 world, uniform float4x4 viewProj, uniform float textureScale, uniform float4 ambient, uniform light light0, uniform light light1) +{ + light lights[4]; + lights[0] = light0; + lights[1] = light1; + + return doWork(IN, world, viewProj, textureScale, ambient, 2, lights); +} + +v2f ThreeLights(a2v IN,uniform float4x4 world, uniform float4x4 viewProj, uniform float textureScale, uniform float4 ambient, uniform light light0, uniform light light1, uniform light light2) +{ + light lights[4]; + lights[0] = light0; + lights[1] = light1; + lights[2] = light2; + + return doWork(IN, world, viewProj, textureScale, ambient, 3, lights); +} + +v2f FourLights(a2v IN,uniform float4x4 world, uniform float4x4 viewProj, uniform float textureScale, uniform float4 ambient, uniform light light0, uniform light light1, uniform light light2, uniform light light3) +{ + light lights[4]; + lights[0] = light0; + lights[1] = light1; + lights[2] = light2; + lights[3] = light3; + + return doWork(IN, world, viewProj, textureScale, ambient, 4, lights); +} + diff --git a/source/PolyVoxSceneManager.cpp b/source/PolyVoxSceneManager.cpp index 3d955b43..9bbfe04b 100644 --- a/source/PolyVoxSceneManager.cpp +++ b/source/PolyVoxSceneManager.cpp @@ -588,6 +588,7 @@ namespace Ogre const Vector3 offset(firstX,firstY,firstZ); Vector3 vertlist[12]; + uchar vertMaterials[12]; VolumeIterator volIter(*volumeData); volIter.setValidRegion(firstX,firstY,firstZ,lastX,lastY,lastZ); @@ -639,72 +640,84 @@ namespace Ogre vertlist[0].x = (static_cast(x) + 0.5); vertlist[0].y = (static_cast(y)); vertlist[0].z = (static_cast(z)); + vertMaterials[0] = (std::max)(v000,v100); //FIXME - faster way? } if (edgeTable[iCubeIndex] & 2) { vertlist[1].x = (static_cast(x + 1)); vertlist[1].y = (static_cast(y) + 0.5); vertlist[1].z = (static_cast(z)); + vertMaterials[1] = (std::max)(v100,v110); } if (edgeTable[iCubeIndex] & 4) { vertlist[2].x = (static_cast(x) + 0.5); vertlist[2].y = (static_cast(y + 1)); vertlist[2].z = (static_cast(z)); + vertMaterials[2] = (std::max)(v010,v110); } if (edgeTable[iCubeIndex] & 8) { vertlist[3].x = (static_cast(x)); vertlist[3].y = (static_cast(y) + 0.5); vertlist[3].z = (static_cast(z)); + vertMaterials[3] = (std::max)(v000,v010); } if (edgeTable[iCubeIndex] & 16) { vertlist[4].x = (static_cast(x) + 0.5); vertlist[4].y = (static_cast(y)); vertlist[4].z = (static_cast(z + 1)); + vertMaterials[4] = (std::max)(v001,v101); } if (edgeTable[iCubeIndex] & 32) { vertlist[5].x = (static_cast(x + 1)); vertlist[5].y = (static_cast(y) + 0.5); vertlist[5].z = (static_cast(z + 1)); + vertMaterials[5] = (std::max)(v101,v111); } if (edgeTable[iCubeIndex] & 64) { vertlist[6].x = (static_cast(x) + 0.5); vertlist[6].y = (static_cast(y + 1)); vertlist[6].z = (static_cast(z + 1)); + vertMaterials[6] = (std::max)(v011,v111); } if (edgeTable[iCubeIndex] & 128) { vertlist[7].x = (static_cast(x)); vertlist[7].y = (static_cast(y) + 0.5); vertlist[7].z = (static_cast(z + 1)); + vertMaterials[7] = (std::max)(v001,v011); } if (edgeTable[iCubeIndex] & 256) { vertlist[8].x = (static_cast(x)); vertlist[8].y = (static_cast(y)); vertlist[8].z = (static_cast(z) + 0.5); + vertMaterials[8] = (std::max)(v000,v001); } if (edgeTable[iCubeIndex] & 512) { vertlist[9].x = (static_cast(x + 1)); vertlist[9].y = (static_cast(y)); vertlist[9].z = (static_cast(z) + 0.5); + vertMaterials[9] = (std::max)(v100,v101); } if (edgeTable[iCubeIndex] & 1024) { vertlist[10].x = (static_cast(x + 1)); vertlist[10].y = (static_cast(y + 1)); vertlist[10].z = (static_cast(z) + 0.5); + vertMaterials[10] = (std::max)(v110,v111); } if (edgeTable[iCubeIndex] & 2048) { vertlist[11].x = (static_cast(x)); vertlist[11].y = (static_cast(y + 1)); vertlist[11].z = (static_cast(z) + 0.5); + vertMaterials[11] = (std::max)(v010,v011); } for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) @@ -714,15 +727,24 @@ namespace Ogre const Vector3 vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset; const Vector3 vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset; + const uchar material0 = vertMaterials[triTable[iCubeIndex][i ]]; + const uchar material1 = vertMaterials[triTable[iCubeIndex][i+1]]; + const uchar material2 = vertMaterials[triTable[iCubeIndex][i+2]]; + //FIXME - for the time being the material is the highest vertex //Need to think about this... - uchar material = std::max(v000,v001); + /*uchar material = std::max(v000,v001); material = std::max(material,v010); material = std::max(material,v011); material = std::max(material,v100); material = std::max(material,v101); material = std::max(material,v110); - material = std::max(material,v111); + material = std::max(material,v111); */ + + std::set materials; //FIXME - set::set is pretty slow for this as it only holds up to 3 vertices. + materials.insert(material0); + materials.insert(material1); + materials.insert(material2); //vertexScaled values are always integers and so can be used as indices. //FIXME - these integer values can just be obtained by using floor()? @@ -733,74 +755,94 @@ namespace Ogre Triangle triangle; //Triangle to be created... - //Get scaled values for vertex 0 - vertexScaledX = static_cast((vertex0.x * 2.0) + 0.5); - vertexScaledY = static_cast((vertex0.y * 2.0) + 0.5); - vertexScaledZ = static_cast((vertex0.z * 2.0) + 0.5); - vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1; - vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1; - vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1; - //If a vertex has not yet been added, it's index is -1 - index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material]; - if((index == -1)) + for(std::set::iterator materialsIter = materials.begin(); materialsIter != materials.end(); ++materialsIter) { - //Add the vertex - vertexData[material].push_back(Vertex(vertex0)); - triangle.v0 = vertexData[material].size()-1; - vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1; - } - else - { - //Just reuse the existing vertex - triangle.v0 = index; - } + uchar material = *materialsIter; - //Get scaled values for vertex 1 - vertexScaledX = static_cast((vertex1.x * 2.0) + 0.5); - vertexScaledY = static_cast((vertex1.y * 2.0) + 0.5); - vertexScaledZ = static_cast((vertex1.z * 2.0) + 0.5); - vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1; - vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1; - vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1; - //If a vertex has not yet been added, it's index is -1 - index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material]; - if((index == -1)) - { - //Add the vertex - vertexData[material].push_back(Vertex(vertex1)); - triangle.v1 = vertexData[material].size()-1; - vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1; - } - else - { - //Just reuse the existing vertex - triangle.v1 = index; - } + //Get scaled values for vertex 0 + vertexScaledX = static_cast((vertex0.x * 2.0) + 0.5); + vertexScaledY = static_cast((vertex0.y * 2.0) + 0.5); + vertexScaledZ = static_cast((vertex0.z * 2.0) + 0.5); + vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1; + vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1; + vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1; + //If a vertex has not yet been added, it's index is -1 + index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material]; + if((index == -1)) + { + //Add the vertex + Vertex vertex(vertex0); + if(material0 == material) + vertex.colour = Vector4(1.0,1.0,1.0,1.0); + else + vertex.colour = Vector4(0.0,0.0,0.0,0.0); + vertexData[material].push_back(Vertex(vertex)); + triangle.v0 = vertexData[material].size()-1; + vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1; + } + else + { + //Just reuse the existing vertex + triangle.v0 = index; + } - //Get scaled values for vertex 2 - vertexScaledX = static_cast((vertex2.x * 2.0) + 0.5); - vertexScaledY = static_cast((vertex2.y * 2.0) + 0.5); - vertexScaledZ = static_cast((vertex2.z * 2.0) + 0.5); - vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1; - vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1; - vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1; - //If a vertex has not yet been added, it's index is -1 - index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material]; - if((index == -1)) - { - //Add the vertex - vertexData[material].push_back(Vertex(vertex2)); - triangle.v2 = vertexData[material].size()-1; - vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1; - } - else - { - //Just reuse the existing vertex - triangle.v2 = index; - } + //Get scaled values for vertex 1 + vertexScaledX = static_cast((vertex1.x * 2.0) + 0.5); + vertexScaledY = static_cast((vertex1.y * 2.0) + 0.5); + vertexScaledZ = static_cast((vertex1.z * 2.0) + 0.5); + vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1; + vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1; + vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1; + //If a vertex has not yet been added, it's index is -1 + index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material]; + if((index == -1)) + { + //Add the vertex + Vertex vertex(vertex1); + if(material1 == material) + vertex.colour = Vector4(1.0,1.0,1.0,1.0); + else + vertex.colour = Vector4(0.0,0.0,0.0,0.0); + vertexData[material].push_back(Vertex(vertex)); + triangle.v1 = vertexData[material].size()-1; + vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1; + } + else + { + //Just reuse the existing vertex + triangle.v1 = index; + } - //Add the triangle - indexData[material].push_back(triangle); + //Get scaled values for vertex 2 + vertexScaledX = static_cast((vertex2.x * 2.0) + 0.5); + vertexScaledY = static_cast((vertex2.y * 2.0) + 0.5); + vertexScaledZ = static_cast((vertex2.z * 2.0) + 0.5); + vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1; + vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1; + vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1; + //If a vertex has not yet been added, it's index is -1 + index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material]; + if((index == -1)) + { + //Add the vertex + Vertex vertex(vertex2); + if(material2 == material) + vertex.colour = Vector4(1.0,1.0,1.0,1.0); + else + vertex.colour = Vector4(0.0,0.0,0.0,0.0); + vertexData[material].push_back(Vertex(vertex)); + triangle.v2 = vertexData[material].size()-1; + vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1; + } + else + { + //Just reuse the existing vertex + triangle.v2 = index; + } + + //Add the triangle + indexData[material].push_back(triangle); + } } } diff --git a/source/Surface.cpp b/source/Surface.cpp index 604e1801..bb5475bc 100644 --- a/source/Surface.cpp +++ b/source/Surface.cpp @@ -40,6 +40,7 @@ namespace Ogre decl->removeAllElements(); decl->addElement(0, 0, VET_FLOAT3, VES_POSITION); decl->addElement(0, 3 * sizeof(float), VET_FLOAT3, VES_NORMAL); + decl->addElement(0, 6 * sizeof(float), VET_FLOAT4, VES_DIFFUSE); //LogManager::getSingleton().logMessage("Creating Vertex Buffer"); HardwareVertexBufferSharedPtr vbuf = @@ -80,6 +81,11 @@ namespace Ogre *prPos++ = verticesToSet[i].normal.y; *prPos++ = verticesToSet[i].normal.z; + *prPos++ = verticesToSet[i].colour.x; + *prPos++ = verticesToSet[i].colour.y; + *prPos++ = verticesToSet[i].colour.z; + *prPos++ = verticesToSet[i].colour.w; + if(verticesToSet[i].position.x < vaabMin.x) vaabMin.x = verticesToSet[i].position.x; if(verticesToSet[i].position.y < vaabMin.y) diff --git a/source/VolumeSerializer.cpp b/source/VolumeSerializer.cpp new file mode 100644 index 00000000..bc6bc3df --- /dev/null +++ b/source/VolumeSerializer.cpp @@ -0,0 +1,84 @@ +#include "VolumeSerializer.h" +#include "Volume.h" + +#include "VolumeIterator.h" + +#include "OgreLogManager.h" +#include "OgreStringConverter.h" + +namespace Ogre +{ + VolumeSerializer::VolumeSerializer () + { + + } + + VolumeSerializer::~VolumeSerializer () + { + + } + + /*void VolumeSerializer::exportVolume (const Volume *pText, const Ogre::String &fileName) + { + std::ofstream outFile; + outFile.open (fileName.c_str(), std::ios::out); + outFile << pText->getString (); + outFile.close (); + }*/ + + void VolumeSerializer::importVolume (Ogre::DataStreamPtr &stream, Volume *pDest) + { + //pDest->setString (stream->getAsString ()); + //Volume vol; + + //Read volume dimensions + uchar volumeWidth = 0; + uchar volumeHeight = 0; + uchar volumeDepth = 0; + stream->read(reinterpret_cast(&volumeWidth), sizeof(volumeWidth)); + stream->read(reinterpret_cast(&volumeHeight), sizeof(volumeHeight)); + stream->read(reinterpret_cast(&volumeDepth), sizeof(volumeDepth)); + /*if(stream->fail()) + { + LogManager::getSingleton().logMessage("Failed to read dimentions"); + return false; + } */ + + //Read data + VolumeIterator volIter(*pDest); + for(uint z = 0; z < OGRE_VOLUME_SIDE_LENGTH; ++z) + { + for(uint y = 0; y < OGRE_VOLUME_SIDE_LENGTH; ++y) + { + for(uint x = 0; x < OGRE_VOLUME_SIDE_LENGTH; ++x) + { + uchar value = 0; + stream->read(reinterpret_cast(&value), sizeof(value)); //FIXME - check for error here + /*if(value != 0) + { + LogManager::getSingleton().logMessage("Value is " + StringConverter::toString(int(value))); + }*/ + volIter.setVoxelAt(x,y,z,value); + /*if(z < 24) + { + if(x % 32 < 16) + volIter.setVoxelAt(x,y,z,4); + else + volIter.setVoxelAt(x,y,z,5); + } + else + volIter.setVoxelAt(x,y,z,0);*/ + } + } + + //Periodically see if we can tidy the memory to avoid excessive usage during loading. + if(z%OGRE_BLOCK_SIDE_LENGTH == OGRE_BLOCK_SIDE_LENGTH-1) + { + pDest->tidy(); //FIXME - we don't actually have to tidy the whole volume here - just the part we loaded since the last call to tidy. + } + } + + /*vol.load(stream->getName());*/ + //pDest->setVolume(vol); + } +} \ No newline at end of file