Browse Source

Added Cg (untested)

Marko Pintera 13 years ago
parent
commit
506d8e10b3

+ 4 - 0
CamelotD3D9Renderer/Source/CmD3D9HLSLProgram.cpp

@@ -100,6 +100,8 @@ namespace CamelotEngine {
 			return "ps_2_b";
 		case GPP_PS_3_0:
 			return "ps_3_0";
+		case GPP_PS_4_0:
+			return "ps_4_0";
 		case GPP_VS_1_1:
 			return "vs_1_1";
 		case GPP_VS_2_0:
@@ -108,6 +110,8 @@ namespace CamelotEngine {
 			return "vs_2_a";
 		case GPP_VS_3_0:
 			return "vs_3_1";
+		case GPP_VS_4_0:
+			return "vs_4_0";
 		default:
 			assert(false); // Unsupported profile
 		}

+ 6 - 3
CamelotRenderer/CamelotRenderer.vcxproj

@@ -63,7 +63,7 @@
     <Link>
       <SubSystem>NotSet</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>CamelotUtility.lib;libboost_signals-vc110-mt-gd-1_49.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotUtility.lib;libboost_signals-vc110-mt-gd-1_49.lib;cg.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>../lib/$(Configuration);../Dependencies/lib/Debug</AdditionalLibraryDirectories>
       <ImportLibrary>..\lib\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
@@ -84,19 +84,20 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>CamelotUtility.lib;libboost_signals-vc110-mt-1_49.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotUtility.lib;libboost_signals-vc110-mt-1_49.lib;cg.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>../lib/$(Configuration);../Dependencies/lib/Release</AdditionalLibraryDirectories>
       <ImportLibrary>..\lib\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
     <Text Include="HighLevelTODO.txt" />
-    <Text Include="ReadMe.txt" />
     <Text Include="TODO.txt" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\CmApplication.h" />
     <ClInclude Include="Include\CmCamera.h" />
+    <ClInclude Include="Include\CmCgProgram.h" />
+    <ClInclude Include="Include\CmCgProgramFactory.h" />
     <ClInclude Include="Include\CmCommon.h" />
     <ClInclude Include="Include\CmConfigOptionMap.h" />
     <ClInclude Include="Include\CmDefaultHardwareBufferManager.h" />
@@ -140,6 +141,8 @@
     <ClCompile Include="Source\CamelotRenderer.cpp" />
     <ClCompile Include="Source\CmApplication.cpp" />
     <ClCompile Include="Source\CmCamera.cpp" />
+    <ClCompile Include="Source\CmCgProgram.cpp" />
+    <ClCompile Include="Source\CmCgProgramFactory.cpp" />
     <ClCompile Include="Source\CmDefaultHardwareBufferManager.cpp" />
     <ClCompile Include="Source\CmFrustum.cpp" />
     <ClCompile Include="Source\CmGpuProgram.cpp" />

+ 18 - 1
CamelotRenderer/CamelotRenderer.vcxproj.filters

@@ -46,9 +46,14 @@
     <Filter Include="Header Files\Serialization">
       <UniqueIdentifier>{75249db9-4f2e-43c3-8df4-37250c4b60a2}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files\Cg">
+      <UniqueIdentifier>{7477862a-2ebf-43ed-adb9-725c453b0b50}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Cg">
+      <UniqueIdentifier>{eeb7d0ea-f842-4f3c-b462-135af2eff493}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
-    <Text Include="ReadMe.txt" />
     <Text Include="TODO.txt" />
     <Text Include="HighLevelTODO.txt" />
   </ItemGroup>
@@ -173,6 +178,12 @@
     <ClInclude Include="Include\CmTextureST.h">
       <Filter>Header Files\Serialization</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmCgProgram.h">
+      <Filter>Header Files\Cg</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmCgProgramFactory.h">
+      <Filter>Header Files\Cg</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CamelotRenderer.cpp">
@@ -268,5 +279,11 @@
     <ClCompile Include="Source\CmResource.cpp">
       <Filter>Source Files\Resources</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmCgProgram.cpp">
+      <Filter>Source Files\Cg</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\CmCgProgramFactory.cpp">
+      <Filter>Source Files\Cg</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 118 - 0
CamelotRenderer/Include/CmCgProgram.h

@@ -0,0 +1,118 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2011 Torus Knot Software Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+-----------------------------------------------------------------------------
+*/
+#ifndef __CgProgram_H__
+#define __CgProgram_H__
+
+#include "CmPrerequisites.h"
+#include <Cg/cg.h>
+#include "CmHighLevelGpuProgram.h"
+
+namespace CamelotEngine {
+    /** Specialisation of HighLevelGpuProgram to provide support for nVidia's CG language.
+    @remarks
+        Cg can be used to compile common, high-level, C-like code down to assembler
+        language for both GL and Direct3D, for multiple graphics cards. You must
+        supply a list of profiles which your program must support using
+        setProfiles() before the program is loaded in order for this to work. The
+        program will then negotiate with the renderer to compile the appropriate program
+        for the API and graphics card capabilities.
+    */
+    class CM_EXPORT CgProgram : public HighLevelGpuProgram
+    {
+    protected:
+        /// The CG context to use, passed in by factory
+        CGcontext mCgContext;
+        /// Program handle
+        CGprogram mCgProgram;
+        /** Internal load implementation, must be implemented by subclasses.
+        */
+        void loadFromSource(void);
+        /** Internal method for creating an appropriate low-level program from this
+        high-level program, must be implemented by subclasses. */
+        void createLowLevelImpl(void);
+        /// Internal unload implementation, must be implemented by subclasses
+        void unloadHighLevelImpl(void);
+        /// Populate the passed parameters with name->index map, must be overridden
+        void buildConstantDefinitions() const;
+
+		/// Recurse down structures getting data on parameters
+		void recurseParams(CGparameter param, size_t contextArraySize = 1) const;
+		/// Turn a Cg type into a GpuConstantType and number of elements
+		void mapTypeAndElementSize(CGtype cgType, bool isRegisterCombiner, GpuConstantDefinition& def) const;
+
+        vector<String>::type mProfiles;
+        String mEntryPoint;
+        String mSelectedProfile;
+        CGprofile mSelectedCgProfile;
+        String mCompileArgs;
+        // Unfortunately Cg uses char** for arguments - bleh
+        // This is a null-terminated list of char* (each null terminated)
+        char** mCgArguments;
+
+        /// Internal method which works out which profile to use for this program
+        void selectProfile(void);
+        /// Internal method which merges manual and automatic compile arguments
+        void buildArgs(void);
+        /// Releases memory for the horrible Cg char**
+        void freeCgArgs(void);
+
+
+    public:
+        CgProgram(CGcontext context);
+        ~CgProgram();
+
+        /** Sets the entry point for this program ie the first method called. */
+        void setEntryPoint(const String& entryPoint) { mEntryPoint = entryPoint; }
+        /** Gets the entry point defined for this program. */
+        const String& getEntryPoint(void) const { return mEntryPoint; }
+        /** Sets the Cg profiles which can be supported by the program. */
+        void setProfiles(const vector<String>::type& profiles);
+        /** Gets the Cg profiles which can be supported by the program. */
+        const vector<String>::type& getProfiles(void) const { return mProfiles; }
+        /** Sets the compilation arguments for this program ie the first method called. */
+        void setCompileArguments(const String& args) { mCompileArgs = args; }
+        /** Gets the entry point defined for this program. */
+        const String& getCompileArguments(void) const { return mCompileArgs; }
+        /// Overridden from GpuProgram
+        bool isSupported(void) const;
+        /// Overridden from GpuProgram
+        const String& getLanguage(void) const;
+
+		/// scan the file for #include and replace with source from the OGRE resources
+		static String resolveCgIncludes(const String& source, Resource* resourceBeingLoaded, const String& fileName);
+
+    };
+
+	/** Utility function, checks Cg for errors, throw exception if detected.
+    @param ogreMethod Ogre method name, as Class::method
+    @param errorTextPrefix The text to prefix the Cg error text with
+    */
+    void checkForCgError(const String& ogreMethod, const String& errorTextPrefix, CGcontext context);
+}
+
+#endif

+ 54 - 0
CamelotRenderer/Include/CmCgProgramFactory.h

@@ -0,0 +1,54 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2011 Torus Knot Software Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+-----------------------------------------------------------------------------
+*/
+#ifndef __CgProgramFactory_H__
+#define __CgProgramFactory_H__
+
+#include "CmPrerequisites.h"
+#include <Cg/cg.h>
+#include "CmHighLevelGpuProgramManager.h"
+
+namespace CamelotEngine
+{
+    /** Factory class for Cg programs. */
+    class CgProgramFactory : public HighLevelGpuProgramFactory
+    {
+    protected:
+        CGcontext mCgContext;
+		static String sLanguageName;
+    public:
+        CgProgramFactory();
+        ~CgProgramFactory();
+		/// Get the name of the language this factory creates programs for
+		const String& getLanguage(void) const;
+        HighLevelGpuProgram* create(const String& source, const String& entryPoint, GpuProgramProfile profile);
+		void destroy(HighLevelGpuProgram* prog);
+
+    };
+}
+
+#endif

+ 3 - 1
CamelotRenderer/Include/CmGpuProgram.h

@@ -60,10 +60,12 @@ namespace CamelotEngine {
 		GPP_PS_2_a,
 		GPP_PS_2_b,
 		GPP_PS_3_0,
+		GPP_PS_4_0,
 		GPP_VS_1_1,
 		GPP_VS_2_0,
 		GPP_VS_2_a,
-		GPP_VS_3_0
+		GPP_VS_3_0,
+		GPP_VS_4_0
 	};
 
 	/** Defines a program which runs on the GPU such as a vertex or fragment program. 

+ 14 - 11
CamelotRenderer/Source/CmApplication.cpp

@@ -46,24 +46,28 @@ namespace CamelotEngine
 
 		/////////////////// HLSL SHADERS //////////////////////////
 
-		//String fragShaderCode = "float4 ps_main() : COLOR0	\
+		//String fragShaderCode = "sampler2D diffuseMap;			\
+		//	float4 ps_main(float2 uv : TEXCOORD0) : COLOR0		\
 		//{														\
-		//	float4 color = float4(0, 0, 0, 0);					\
-		//	color.r = 1.0f;										\
-		//	color.a = 1.0f;										\
+		//	float4 color = tex2D(diffuseMap, uv);				\
 		//	return color;										\
 		//}";
 
-		//mFragProg = mGpuProgramManager->createProgram(fragShaderCode, "ps_main", "hlsl", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
+		//mFragProg =  HighLevelGpuProgramManager::instance().createProgram(fragShaderCode, "ps_main", "hlsl", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
 		//mFragProg->load();
 
-		//String vertShaderCode = "float4x4 matViewProjection; \
-		//float4 vs_main(float4 inPos : POSITION) : POSITION \
-		//{ \
-		//	return mul(matViewProjection, inPos); \
+		//String vertShaderCode = "float4x4 matViewProjection;	\
+		//	void vs_main(										\
+		//	float4 inPos : POSITION,							\
+		//	float2 uv : TEXCOORD0,								\
+		//	out float4 oPosition : POSITION,					\
+		//	out float2 oUv : TEXCOORD0)							\
+		//{														\
+		//	oPosition = mul(matViewProjection, inPos);			\
+		//	oUv = uv;											\
 		//}";
 
-		//mVertProg = mGpuProgramManager->createProgram(vertShaderCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
+		//mVertProg =  HighLevelGpuProgramManager::instance().createProgram(vertShaderCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
 		//mVertProg->load();
 
 		///////////////// GLSL SHADERS ////////////////////////////
@@ -109,7 +113,6 @@ namespace CamelotEngine
 		gResources().save(testTex, "C:\\ExportTest.tex");
 		mDbgTexture = std::static_pointer_cast<Texture>(gResources().load("C:\\ExportTest.tex"));
 		mDbgTexture = testTex;
-		// TODO - Compare first few bytes of TextureData before and after save
 	}
 
 	void Application::runMainLoop()

+ 645 - 0
CamelotRenderer/Source/CmCgProgram.cpp

@@ -0,0 +1,645 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2011 Torus Knot Software Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+-----------------------------------------------------------------------------
+*/
+#include "CmCgProgram.h"
+#include "CmGpuProgramManager.h"
+#include "CmHighLevelGpuProgramManager.h"
+#include "CmDebug.h"
+#include "CmException.h"
+
+namespace CamelotEngine {
+
+	void checkForCgError(const String& ogreMethod, const String& errorTextPrefix, CGcontext context)
+	{
+		CGerror error = cgGetError();
+		if (error != CG_NO_ERROR)
+		{
+			String msg = errorTextPrefix + cgGetErrorString(error); 
+
+			if (error == CG_COMPILER_ERROR)
+			{
+				// Get listing with full compile errors
+				msg = msg + "\n" + cgGetLastListing(context);
+			}
+
+			CM_EXCEPT(InternalErrorException, msg);
+		}
+	}
+
+	GpuProgramProfile cgProfileToGpuProgramProfile(const String& profile)
+	{
+		if(profile == "ps_1_1")
+			return GPP_PS_1_1;
+		else if(profile == "ps_1_2")
+			return GPP_PS_1_2;
+		else if(profile == "ps_1_3")
+			return GPP_PS_1_3;
+		else if(profile == "ps_1_4")
+			return GPP_PS_1_4;
+		else if(profile == "ps_2_0")
+			return GPP_PS_2_0;
+		else if(profile == "ps_2_a")
+			return GPP_PS_2_a;
+		else if(profile == "ps_2_b")
+			return GPP_PS_2_b;
+		else if(profile == "ps_3_0")
+			return GPP_PS_3_0;
+		else if(profile == "ps_4_0")
+			return GPP_PS_4_0;
+		else if(profile == "vs_1_1")
+			return GPP_VS_1_1;
+		else if(profile == "vs_2_0")
+			return GPP_VS_2_0;
+		else if(profile == "vs_2_a")
+			return GPP_VS_2_a;
+		else if(profile == "vs_3_1")
+			return GPP_VS_3_0;
+		else if(profile == "vs_4_0")
+			return GPP_VS_4_0;
+		else
+			assert(false); // Unsupported profile
+
+		return GPP_NONE;
+	}
+
+    //-----------------------------------------------------------------------
+    void CgProgram::selectProfile(void)
+    {
+        mSelectedProfile.clear();
+        mSelectedCgProfile = CG_PROFILE_UNKNOWN;
+
+        vector<String>::type::iterator i, iend;
+        iend = mProfiles.end();
+        GpuProgramManager& gpuMgr = GpuProgramManager::instance();
+        for (i = mProfiles.begin(); i != iend; ++i)
+        {
+            if (gpuMgr.isSyntaxSupported(*i))
+            {
+                mSelectedProfile = *i;
+                mSelectedCgProfile = cgGetProfile(mSelectedProfile.c_str());
+                // Check for errors
+                checkForCgError("CgProgram::selectProfile", 
+                    "Unable to find CG profile enum for program.", mCgContext);
+                break;
+            }
+        }
+    }
+    //-----------------------------------------------------------------------
+    void CgProgram::buildArgs(void)
+    {
+        vector<String>::type args;
+        if (!mCompileArgs.empty())
+            args = StringUtil::split(mCompileArgs);
+
+        vector<String>::type::const_iterator i;
+        if (mSelectedCgProfile == CG_PROFILE_VS_1_1)
+        {
+            // Need the 'dcls' argument whenever we use this profile
+            // otherwise compilation of the assembler will fail
+            bool dclsFound = false;
+            for (i = args.begin(); i != args.end(); ++i)
+            {
+                if (*i == "dcls")
+                {
+                    dclsFound = true;
+                    break;
+                }
+            }
+            if (!dclsFound)
+            {
+                args.push_back("-profileopts");
+				args.push_back("dcls");
+            }
+        }
+        // Now split args into that god-awful char** that Cg insists on
+        freeCgArgs();
+        mCgArguments = (char**)malloc(sizeof(char*) * (args.size() + 1));
+        int index = 0;
+        for (i = args.begin(); i != args.end(); ++i, ++index)
+        {
+            mCgArguments[index] = (char*)malloc(sizeof(char) * (i->length() + 1));
+            strcpy(mCgArguments[index], i->c_str());
+        }
+        // Null terminate list
+        mCgArguments[index] = 0;
+
+
+    }
+    //-----------------------------------------------------------------------
+    void CgProgram::freeCgArgs(void)
+    {
+        if (mCgArguments)
+        {
+            size_t index = 0;
+            char* current = mCgArguments[index];
+            while (current)
+            {
+				free(current);
+				mCgArguments[index] = 0;
+                current = mCgArguments[++index];
+            }
+			free(mCgArguments);
+            mCgArguments = 0;
+        }
+    }
+    //-----------------------------------------------------------------------
+    void CgProgram::loadFromSource(void)
+    {
+        // Create Cg Program
+        selectProfile();
+		if (mSelectedCgProfile == CG_PROFILE_UNKNOWN)
+		{
+			gDebug().log("Attempted to load Cg program but no supported "
+				"profile was found.", "RenderSystem");
+			return;
+		}
+        buildArgs();
+
+		// TODO PORT - This doesn't load includes
+		// deal with includes
+		String sourceToUse = mSource;
+		//String sourceToUse = resolveCgIncludes(mSource, this, mFilename);
+        mCgProgram = cgCreateProgram(mCgContext, CG_SOURCE, sourceToUse.c_str(), 
+            mSelectedCgProfile, mEntryPoint.c_str(), const_cast<const char**>(mCgArguments));
+
+        // Test
+        //LogManager::getSingleton().logMessage(cgGetProgramString(mCgProgram, CG_COMPILED_PROGRAM));
+
+        // Check for errors
+        checkForCgError("CgProgram::loadFromSource", 
+            "Unable to compile Cg program", mCgContext);
+
+    }
+    //-----------------------------------------------------------------------
+    void CgProgram::createLowLevelImpl(void)
+    {
+		// ignore any previous error
+		if (mSelectedCgProfile != CG_PROFILE_UNKNOWN && !mCompileError)
+		{
+			if (mSelectedCgProfile == CG_PROFILE_VS_4_0 || mSelectedCgProfile == CG_PROFILE_PS_4_0)
+			{
+				String hlslSourceFromCg = cgGetProgramString(mCgProgram, CG_COMPILED_PROGRAM);
+
+				// Create a high-level program, give it the same name as us
+				HighLevelGpuProgramPtr vp = 
+					HighLevelGpuProgramManager::instance().createProgram(
+					hlslSourceFromCg, "main", "hlsl", mType, cgProfileToGpuProgramProfile(mSelectedProfile));
+
+				vp->load();
+
+				mAssemblerProgram = vp;
+			}
+			else
+			{
+
+				String shaderAssemblerCode = cgGetProgramString(mCgProgram, CG_COMPILED_PROGRAM);
+
+				// Create a low-level program, give it the same name as us
+				mAssemblerProgram = 
+					GpuProgramManager::instance().createProgram(
+					shaderAssemblerCode,
+					mType, 
+					mSelectedProfile);
+			}
+			// Shader params need to be forwarded to low level implementation
+			mAssemblerProgram->setAdjacencyInfoRequired(isAdjacencyInfoRequired());
+		}
+    }
+    //-----------------------------------------------------------------------
+    void CgProgram::unloadHighLevelImpl(void)
+    {
+        // Unload Cg Program
+        // Lowlevel program will get unloaded elsewhere
+        if (mCgProgram)
+        {
+            cgDestroyProgram(mCgProgram);
+            checkForCgError("CgProgram::unloadImpl", 
+                "Error while unloading Cg program", 
+                mCgContext);
+            mCgProgram = 0;
+        }
+    }
+    //-----------------------------------------------------------------------
+    void CgProgram::buildConstantDefinitions() const
+    {
+        // Derive parameter names from Cg
+		createParameterMappingStructures(true);
+
+		if (!mCgProgram)
+			return;
+
+		recurseParams(cgGetFirstParameter(mCgProgram, CG_PROGRAM));
+        recurseParams(cgGetFirstParameter(mCgProgram, CG_GLOBAL));
+	}
+	//---------------------------------------------------------------------
+	void CgProgram::recurseParams(CGparameter parameter, size_t contextArraySize) const
+	{
+		while (parameter != 0)
+        {
+            // Look for uniform (non-sampler) parameters only
+            // Don't bother enumerating unused parameters, especially since they will
+            // be optimised out and therefore not in the indexed versions
+            CGtype paramType = cgGetParameterType(parameter);
+
+            if (cgGetParameterVariability(parameter) == CG_UNIFORM &&
+                paramType != CG_SAMPLER1D &&
+                paramType != CG_SAMPLER2D &&
+                paramType != CG_SAMPLER3D &&
+                paramType != CG_SAMPLERCUBE &&
+                paramType != CG_SAMPLERRECT &&
+                cgGetParameterDirection(parameter) != CG_OUT && 
+                cgIsParameterReferenced(parameter))
+            {
+				int arraySize;
+
+				switch(paramType)
+				{
+				case CG_STRUCT:
+					recurseParams(cgGetFirstStructParameter(parameter));
+					break;
+				case CG_ARRAY:
+					// Support only 1-dimensional arrays
+					arraySize = cgGetArraySize(parameter, 0);
+					recurseParams(cgGetArrayParameter(parameter, 0), (size_t)arraySize);
+					break;
+				default:
+					// Normal path (leaf)
+					String paramName = cgGetParameterName(parameter);
+					size_t logicalIndex = cgGetParameterResourceIndex(parameter);
+
+					// Get the parameter resource, to calculate the physical index
+					CGresource res = cgGetParameterResource(parameter);
+					bool isRegisterCombiner = false;
+					size_t regCombinerPhysicalIndex = 0;
+					switch (res)
+					{
+					case CG_COMBINER_STAGE_CONST0:
+						// register combiner, const 0
+						// the index relates to the texture stage; store this as (stage * 2) + 0
+						regCombinerPhysicalIndex = logicalIndex * 2;
+						isRegisterCombiner = true;
+						break;
+					case CG_COMBINER_STAGE_CONST1:
+						// register combiner, const 1
+						// the index relates to the texture stage; store this as (stage * 2) + 1
+						regCombinerPhysicalIndex = (logicalIndex * 2) + 1;
+						isRegisterCombiner = true;
+						break;
+					default:
+						// normal constant
+						break;
+					}
+
+					// Trim the '[0]' suffix if it exists, we will add our own indexing later
+					if (StringUtil::endsWith(paramName, "[0]", false))
+					{
+						paramName.erase(paramName.size() - 3);
+					}
+
+
+					GpuConstantDefinition def;
+					def.arraySize = contextArraySize;
+					mapTypeAndElementSize(paramType, isRegisterCombiner, def);
+
+					if (def.constType == GCT_UNKNOWN)
+					{
+						gDebug().log("Problem parsing the following Cg Uniform: '" + paramName + "'", "RenderSystem");
+						// next uniform
+						parameter = cgGetNextParameter(parameter);
+						continue;
+					}
+					if (isRegisterCombiner)
+					{
+						def.physicalIndex = regCombinerPhysicalIndex;
+					}
+					else
+					{
+						// base position on existing buffer contents
+						if (def.isFloat())
+						{
+							def.physicalIndex = mFloatLogicalToPhysical->bufferSize;
+						}
+						else
+						{
+							def.physicalIndex = mIntLogicalToPhysical->bufferSize;
+						}
+					}
+
+
+					def.logicalIndex = logicalIndex;
+					mConstantDefs->map.insert(GpuConstantDefinitionMap::value_type(paramName, def));
+
+					// Record logical / physical mapping
+					if (def.isFloat())
+					{
+						CM_LOCK_MUTEX(mFloatLogicalToPhysical->mutex)
+						mFloatLogicalToPhysical->map.insert(
+							GpuLogicalIndexUseMap::value_type(logicalIndex, 
+								GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize, GPV_GLOBAL)));
+						mFloatLogicalToPhysical->bufferSize += def.arraySize * def.elementSize;
+						mConstantDefs->floatBufferSize = mFloatLogicalToPhysical->bufferSize;
+					}
+					else
+					{
+						CM_LOCK_MUTEX(mIntLogicalToPhysical->mutex)
+						mIntLogicalToPhysical->map.insert(
+							GpuLogicalIndexUseMap::value_type(logicalIndex, 
+								GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize, GPV_GLOBAL)));
+						mIntLogicalToPhysical->bufferSize += def.arraySize * def.elementSize;
+						mConstantDefs->intBufferSize = mIntLogicalToPhysical->bufferSize;
+					}
+
+					// Deal with array indexing
+					mConstantDefs->generateConstantDefinitionArrayEntries(paramName, def);
+
+					break;
+		
+				}
+					
+            }
+            // Get next
+            parameter = cgGetNextParameter(parameter);
+        }
+
+        
+    }
+	//-----------------------------------------------------------------------
+	void CgProgram::mapTypeAndElementSize(CGtype cgType, bool isRegisterCombiner, 
+		GpuConstantDefinition& def) const
+	{
+		if (isRegisterCombiner)
+		{
+			// register combiners are the only single-float entries in our buffer
+			def.constType = GCT_FLOAT1;
+			def.elementSize = 1;
+		}
+		else
+		{
+			switch(cgType)
+			{
+			case CG_FLOAT:
+			case CG_FLOAT1:
+			case CG_HALF:
+			case CG_HALF1:
+				def.constType = GCT_FLOAT1;
+				break;
+			case CG_FLOAT2:
+			case CG_HALF2:
+				def.constType = GCT_FLOAT2;
+				break;
+			case CG_FLOAT3:
+			case CG_HALF3:
+				def.constType = GCT_FLOAT3;
+				break;
+			case CG_FLOAT4:
+			case CG_HALF4:
+				def.constType = GCT_FLOAT4;
+				break;
+			case CG_FLOAT2x2:
+			case CG_HALF2x2:
+				def.constType = GCT_MATRIX_2X2;
+				break;
+			case CG_FLOAT2x3:
+			case CG_HALF2x3:
+				def.constType = GCT_MATRIX_2X3;
+				break;
+			case CG_FLOAT2x4:
+			case CG_HALF2x4:
+				def.constType = GCT_MATRIX_2X4;
+				break;
+			case CG_FLOAT3x2:
+			case CG_HALF3x2:
+				def.constType = GCT_MATRIX_3X2;
+				break;
+			case CG_FLOAT3x3:
+			case CG_HALF3x3:
+				def.constType = GCT_MATRIX_3X3;
+				break;
+			case CG_FLOAT3x4:
+			case CG_HALF3x4:
+				def.constType = GCT_MATRIX_3X4;
+				break;
+			case CG_FLOAT4x2:
+			case CG_HALF4x2:
+				def.constType = GCT_MATRIX_4X2;
+				break;
+			case CG_FLOAT4x3:
+			case CG_HALF4x3:
+				def.constType = GCT_MATRIX_4X3;
+				break;
+			case CG_FLOAT4x4:
+			case CG_HALF4x4:
+				def.constType = GCT_MATRIX_4X4;
+				break;
+			case CG_INT:
+			case CG_INT1:
+				def.constType = GCT_INT1;
+				break;
+			case CG_INT2:
+				def.constType = GCT_INT2;
+				break;
+			case CG_INT3:
+				def.constType = GCT_INT3;
+				break;
+			case CG_INT4:
+				def.constType = GCT_INT4;
+				break;
+			default:
+				def.constType = GCT_UNKNOWN;
+				break;
+			}
+			// Cg pads
+			def.elementSize = GpuConstantDefinition::getElementSize(def.constType, true);
+		}
+	}
+    //-----------------------------------------------------------------------
+    CgProgram::CgProgram(CGcontext context)
+        : HighLevelGpuProgram(), 
+        mCgContext(context), mCgProgram(0), 
+        mSelectedCgProfile(CG_PROFILE_UNKNOWN), mCgArguments(0)
+    {
+
+    }
+    //-----------------------------------------------------------------------
+    CgProgram::~CgProgram()
+    {
+        freeCgArgs();
+
+        unloadHighLevel();
+    }
+    //-----------------------------------------------------------------------
+    bool CgProgram::isSupported(void) const
+    {
+        if (mCompileError || !isRequiredCapabilitiesSupported())
+            return false;
+
+		vector<String>::type::const_iterator i, iend;
+        iend = mProfiles.end();
+        // Check to see if any of the profiles are supported
+        for (i = mProfiles.begin(); i != iend; ++i)
+        {
+            if (GpuProgramManager::instance().isSyntaxSupported(*i))
+            {
+                return true;
+            }
+        }
+        return false;
+
+    }
+    //-----------------------------------------------------------------------
+    void CgProgram::setProfiles(const vector<String>::type& profiles)
+    {
+        mProfiles.clear();
+        vector<String>::type::const_iterator i, iend;
+        iend = profiles.end();
+        for (i = profiles.begin(); i != iend; ++i)
+        {
+            mProfiles.push_back(*i);
+        }
+    }
+	//-----------------------------------------------------------------------
+	String CgProgram::resolveCgIncludes(const String& inSource, Resource* resourceBeingLoaded, const String& fileName)
+	{
+		String outSource;
+		// TODO PORT - Includes are not handled ATM
+		// output will be at least this big
+		//outSource.reserve(inSource.length());
+
+		//size_t startMarker = 0;
+		//size_t i = inSource.find("#include");
+		//while (i != String::npos)
+		//{
+		//	size_t includePos = i;
+		//	size_t afterIncludePos = includePos + 8;
+		//	size_t newLineBefore = inSource.rfind("\n", includePos);
+
+		//	// check we're not in a comment
+		//	size_t lineCommentIt = inSource.rfind("//", includePos);
+		//	if (lineCommentIt != String::npos)
+		//	{
+		//		if (newLineBefore == String::npos || lineCommentIt > newLineBefore)
+		//		{
+		//			// commented
+		//			i = inSource.find("#include", afterIncludePos);
+		//			continue;
+		//		}
+
+		//	}
+		//	size_t blockCommentIt = inSource.rfind("/*", includePos);
+		//	if (blockCommentIt != String::npos)
+		//	{
+		//		size_t closeCommentIt = inSource.rfind("*/", includePos);
+		//		if (closeCommentIt == String::npos || closeCommentIt < blockCommentIt)
+		//		{
+		//			// commented
+		//			i = inSource.find("#include", afterIncludePos);
+		//			continue;
+		//		}
+
+		//	}
+
+		//	// find following newline (or EOF)
+		//	size_t newLineAfter = inSource.find("\n", afterIncludePos);
+		//	// find include file string container
+		//	String endDelimeter = "\"";
+		//	size_t startIt = inSource.find("\"", afterIncludePos);
+		//	if (startIt == String::npos || startIt > newLineAfter)
+		//	{
+		//		// try <>
+		//		startIt = inSource.find("<", afterIncludePos);
+		//		if (startIt == String::npos || startIt > newLineAfter)
+		//		{
+		//			CM_EXCEPT(InternalErrorException,
+		//				"Badly formed #include directive (expected \" or <) in file "
+		//				+ fileName + ": " + inSource.substr(includePos, newLineAfter-includePos));
+		//		}
+		//		else
+		//		{
+		//			endDelimeter = ">";
+		//		}
+		//	}
+		//	size_t endIt = inSource.find(endDelimeter, startIt+1);
+		//	if (endIt == String::npos || endIt <= startIt)
+		//	{
+		//		CM_EXCEPT(InternalErrorException,
+		//			"Badly formed #include directive (expected " + endDelimeter + ") in file "
+		//			+ fileName + ": " + inSource.substr(includePos, newLineAfter-includePos));
+		//	}
+
+		//	// extract filename
+		//	String filename(inSource.substr(startIt+1, endIt-startIt-1));
+
+		//	// open included file
+		//	DataStreamPtr resource = ResourceGroupManager::getSingleton().
+		//		openResource(filename, resourceBeingLoaded->getGroup(), true, resourceBeingLoaded);
+
+		//	// replace entire include directive line
+		//	// copy up to just before include
+		//	if (newLineBefore != String::npos && newLineBefore >= startMarker)
+		//		outSource.append(inSource.substr(startMarker, newLineBefore-startMarker+1));
+
+		//	size_t lineCount = 0;
+		//	size_t lineCountPos = 0;
+		//	
+		//	// Count the line number of #include statement
+		//	lineCountPos = outSource.find('\n');
+		//	while(lineCountPos != String::npos)
+		//	{
+		//		lineCountPos = outSource.find('\n', lineCountPos+1);
+		//		lineCount++;
+		//	}
+
+		//	// Add #line to the start of the included file to correct the line count
+		//	outSource.append("#line 1 \"" + filename + "\"\n");
+
+		//	outSource.append(resource->getAsString());
+
+		//	// Add #line to the end of the included file to correct the line count
+		//	outSource.append("\n#line " + toString(lineCount) + 
+		//		"\"" + fileName + "\"\n");
+
+		//	startMarker = newLineAfter;
+
+		//	if (startMarker != String::npos)
+		//		i = inSource.find("#include", startMarker);
+		//	else
+		//		i = String::npos;
+
+		//}
+		//// copy any remaining characters
+		//outSource.append(inSource.substr(startMarker));
+
+		return outSource;
+	}
+    //-----------------------------------------------------------------------
+    const String& CgProgram::getLanguage(void) const
+    {
+        static const String language = "cg";
+
+        return language;
+    }
+}

+ 73 - 0
CamelotRenderer/Source/CmCgProgramFactory.cpp

@@ -0,0 +1,73 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2011 Torus Knot Software Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+-----------------------------------------------------------------------------
+*/
+
+#include "CmCgProgramFactory.h"
+#include "CmCgProgram.h"
+
+namespace CamelotEngine {
+    //-----------------------------------------------------------------------
+    String CgProgramFactory::sLanguageName = "cg";
+    //-----------------------------------------------------------------------
+    CgProgramFactory::CgProgramFactory()
+    {
+        mCgContext = cgCreateContext();
+        // Check for errors
+        checkForCgError("CgProgramFactory::CgProgramFactory", 
+            "Unable to create initial Cg context: ", mCgContext);
+    }
+    //-----------------------------------------------------------------------
+    CgProgramFactory::~CgProgramFactory()
+    {
+        cgDestroyContext(mCgContext);
+        // Check for errors
+        checkForCgError("CgProgramFactory::~CgProgramFactory", 
+            "Unable to destroy Cg context: ", mCgContext);
+    }
+    //-----------------------------------------------------------------------
+    const String& CgProgramFactory::getLanguage(void) const
+    {
+        return sLanguageName;
+    }
+    //-----------------------------------------------------------------------
+    HighLevelGpuProgram* CgProgramFactory::create(const String& source, const String& entryPoint, GpuProgramProfile profile)
+    {
+		CgProgram* prog = new CgProgram(mCgContext);
+		prog->setSource(source);
+		prog->setEntryPoint(entryPoint);
+		prog->setProfile(profile);
+
+		return prog;
+    }
+    //-----------------------------------------------------------------------
+	void CgProgramFactory::destroy(HighLevelGpuProgram* prog)
+    {
+        delete prog;
+    }
+    //-----------------------------------------------------------------------
+
+}

+ 2 - 0
CamelotRenderer/TODO.txt

@@ -45,6 +45,7 @@ TODO:
  - OpenGL too
 
 TOMORROW:
+ - Incorporate CG into the engine!
  - Are resource getting properly unloaded? e.g. when shared_ptr destroys a texture is it removed from gpu?
  - Depth test is disabled by default (OpenGL renderer at least)
  - Serializable callbacks can't be null otherwise compiler complains
@@ -59,6 +60,7 @@ TOMORROW:
     - Make sure all resources have default resource that will be used before actual resource is loaded
  - Add precompiled headers to all projects
  - Make sure they include Exception & Log classes
+ - HLSL & Cg don't handle include files yet
 
 Other notes:
  - Search for all remaining "TODO PORT" comments and fix them

+ 9 - 3
Dependencies.txt

@@ -1,8 +1,14 @@
 Camelot relies on following 3rd party libraries:
  - Boost 1.49 (Later versions might work as well, but you need to test it on your own)
+    - http://www.boost.org
+ - Cg 3.1
+    - http://developer.nvidia.com/cg-toolkit
 
-
-Make sure to include:
+Place dependency files in:
  - Library include files in /Dependencies/Include
  - Static library files in /Dependencies/lib/Debug and /Dependencies/lib/Release
- - Dynamic library files in /bin/Debug and /bin/Release (Possibly others if you define other configuration types)
+ - Dynamic library files in /bin/Debug and /bin/Release (Possibly others if you define other configuration types)
+
+Listed dependencies have not been provided with the engine source code. 
+You will need to grab them manually from the specified links, and place them 
+in the above specified folders.