diff --git a/source/graphics/ProgramManager.cpp b/source/graphics/ProgramManager.cpp new file mode 100755 index 0000000000..a52cf0caa5 --- /dev/null +++ b/source/graphics/ProgramManager.cpp @@ -0,0 +1,118 @@ +#include "precompiled.h" +#include "graphics/ProgramManager.h" + +CProgramManager::CProgramManager() +{ +#ifdef BUILD_CG + m_Context = cgCreateContext(); + assert(m_Context); + FindPPVersion(); +#endif +} + +CProgramManager::~CProgramManager() +{ +#ifdef BUILD_CG + if(m_Context) + cgDestroyContext(m_Context); +#endif +} + +CVertexProgram *CProgramManager::FindVertexProgram(const char *file) +{ + CVertexProgram *prog = NULL; + std::hash_map::iterator iter; + + if((iter = m_VertexProgs.find(std::string(file))) != m_VertexProgs.end()) + return (CVertexProgram *)(*iter).second; + else + { + prog = new CVertexProgram(file); + if(prog && prog->IsValid()) + m_VertexProgs[std::string(file)] = prog; + else + prog = NULL; + } + + return prog; +} + +void CProgramManager::Bind(CVertexProgram *prog) +{ +#ifdef BUILD_CG + assert(prog); + if(m_VPProfile == CG_PROFILE_UNKNOWN || !prog->IsValid()) + return; + + prog->Bind(); +#endif +} + +void CProgramManager::WritePPInfo(FILE *file) +{ +#ifdef BUILD_CG + std::string version = ""; + switch(m_VPProfile) + { + case CG_PROFILE_VP30: + version = "VP 3.0"; + break; + case CG_PROFILE_VP20: + version = "VP 2.0"; + break; + case CG_PROFILE_ARBVP1: + version = "ARB VP1"; + break; + default: + version = "No VP support"; + break; + } + fprintf(file, "Vertex Programs: %s\n", version.c_str()); + + switch(m_FPProfile) + { + case CG_PROFILE_FP30: + version = "FP 3.0"; + break; + case CG_PROFILE_FP20: + version = "FP 2.0"; + break; + case CG_PROFILE_ARBVP1: + version = "ARB FP1"; + break; + default: + version = "No FP support"; + break; + } + fprintf(file, "Fragment Programs: %s\n", version.c_str()); +#else + fprintf(file, "VP/FP support not compiled!\n"); +#endif +} + +#ifdef BUILD_CG + +void CProgramManager::FindPPVersion() +{ +#if BUILD_CG + if(cgGLIsProfileSupported(CG_PROFILE_VP30)) + m_VPProfile = CG_PROFILE_VP30; + else if(cgGLIsProfileSupported(CG_PROFILE_FP20)) + m_VPProfile = CG_PROFILE_VP20; + else if(cgGLIsProfileSupported(CG_PROFILE_ARBVP1)) + m_VPProfile = CG_PROFILE_ARBVP1; + else + m_VPProfile = CG_PROFILE_UNKNOWN; + + if(cgGLIsProfileSupported(CG_PROFILE_FP30)) + m_FPProfile = CG_PROFILE_FP30; + else if(cgGLIsProfileSupported(CG_PROFILE_FP20)) + m_FPProfile = CG_PROFILE_FP20; + else if(cgGLIsProfileSupported(CG_PROFILE_ARBFP1)) + m_FPProfile = CG_PROFILE_ARBFP1; + else + m_FPProfile = CG_PROFILE_UNKNOWN; +#endif +} + +#endif diff --git a/source/graphics/ProgramManager.h b/source/graphics/ProgramManager.h new file mode 100755 index 0000000000..703cc1efc2 --- /dev/null +++ b/source/graphics/ProgramManager.h @@ -0,0 +1,43 @@ +#ifndef __H_SHADERMANAGER_H__ +#define __H_SHADERMANAGER_H__ + +#if _MSC_VER < 1300 +# include +# define hash_map map +#else +# include +#endif + +#include +#include "Singleton.h" +#include "renderer/VertexProgram.h" + +#define g_ProgramManager CProgramManager::GetSingleton() + + +class CProgramManager : public Singleton +{ +public: + CProgramManager(); + ~CProgramManager(); + + CVertexProgram *FindVertexProgram(const char *file); + void Bind(CVertexProgram *prog); + + void WritePPInfo(FILE *file); +#ifdef BUILD_CG + CGcontext GetContext() { return m_Context; } +#endif +private: +#ifdef BUILD_CG + void FindPPVersion(); +#endif + std::hash_map m_VertexProgs; +#ifdef BUILD_CG + CGcontext m_Context; + CGprofile m_VPProfile; + CGprofile m_FPProfile; +#endif +}; + +#endif \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index 87e10df076..f15b4878b6 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -38,6 +38,7 @@ #include "Model.h" #include "UnitManager.h" #include "MaterialManager.h" +#include "ProgramManager.h" #include "Interact.h" #include "Hotkey.h" @@ -182,7 +183,27 @@ void TestingUnicode (void) } +static std::string SplitExts(const char *exts) +{ + std::string str = exts; + std::string ret = ""; + size_t idx = str.find_first_of(" "); + while(idx != std::string::npos) + { + if(idx >= str.length() - 1) + { + ret += str; + break; + } + ret += str.substr(0, idx); + ret += "\n"; + str = str.substr(idx + 1); + idx = str.find_first_of(" "); + } + + return ret; +} static int write_sys_info() { @@ -217,6 +238,9 @@ static int write_sys_info() fprintf(f, "%s\n", gfx_drv_ver); fprintf(f, "%dx%d:%d@%d\n", g_xres, g_yres, g_bpp, g_freq); + + g_ProgramManager.WritePPInfo(f); + // .. network name / ips // note: can't use un.nodename because it is for an // "implementation-defined communications network". @@ -237,7 +261,7 @@ static int write_sys_info() // Write extensions last, because there are lots of them const char* exts = oglExtList(); if (!exts) exts = "{unknown}"; - fprintf(f, "\nSupported extensions: %s\n", exts); + fprintf(f, "\nSupported extensions: \n%s\n", SplitExts(exts).c_str()); fclose(f); return 0; @@ -792,6 +816,7 @@ static void Shutdown() delete &g_SkelAnimMan; delete &g_MaterialManager; + delete &g_ProgramManager; // destroy terrain related stuff delete &g_TexMan; @@ -915,6 +940,12 @@ sle(11340106); } SDL_WM_SetCaption("0 A.D.", "0 A.D."); + + // create the program manager + // NOTE: We need to create this BEFORE we write the sys-info, so the PP stuff + // will be written to the system_info.txt file + new CProgramManager; + write_sys_info(); if(!oglExtAvail("GL_ARB_multitexture") || !oglExtAvail("GL_ARB_texture_env_combine") || diff --git a/source/renderer/VertexProgram.cpp b/source/renderer/VertexProgram.cpp new file mode 100755 index 0000000000..65cb6dc87b --- /dev/null +++ b/source/renderer/VertexProgram.cpp @@ -0,0 +1,106 @@ +#include "precompiled.h" +#include "res/vfs.h" +#include "res/mem.h" +#include "renderer/VertexProgram.h" +#include "graphics/ProgramManager.h" +#include "CLogger.h" + +#define LOG_CATEGORY "shaders" + +CVertexProgram::CVertexProgram(const char *file) +{ + Load(file); +} + +CVertexProgram::~CVertexProgram() +{ +#ifdef BUILD_CG + if(m_Program) + cgDestroyProgram(m_Program); +#endif +} + +bool CVertexProgram::IsValid() +{ +#ifdef BUILD_CG + return (m_Program != NULL); +#else + return false; +#endif +} + +void CVertexProgram::Bind() +{ +#ifdef BUILD_CG + if(!IsValid()) + return; + + CGparameter param = cgGetFirstParameter(m_Program, CG_PROGRAM); + while(param) + { + PushParameter(param); + param = cgGetNextParameter(param); + } + + if(!cgGLIsProgramLoaded(m_Program)) + cgGLLoadProgram(m_Program); + + cgGLBindProgram(m_Program); +#endif +} + +void CVertexProgram::Load(const char *file) +{ +#ifdef BUILD_CG + m_Program = NULL; + if(!file || !vfs_exists(file)) + return; + + void *data; + size_t size; + Handle h = vfs_load(file, data, size, 0); + if(h <= 0) + { + LOG(ERROR, LOG_CATEGORY, "CVertexShader::LoadShader: vfs_load for %s failed!\n", file); + return; + } + + std::string src = (char*)data; + mem_free_h(h); + + m_Program = cgCreateProgram( + g_ProgramManager.GetContext(), + CG_SOURCE, + src.c_str(), + CG_PROFILE_ARBVP1, + "main", + NULL + ); + if(!m_Program) + { + LOG(ERROR, LOG_CATEGORY, "CVertexShader::LoadShader: Could not compile Cg shader: %s", cgGetErrorString(cgGetError())); + return; + } +#endif +} + +#ifdef BUILD_CG + +void CVertexProgram::PushParameter(CGparameter param) +{ + assert(param); + + std::string name = cgGetParameterName(param); + if(name == "ModelViewProj") + cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); + else if(name == "ModelView") + cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY); + else if(name == "Projection") + cgGLSetStateMatrixParameter(param, CG_GL_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); + else if(name == "Texture") + cgGLSetStateMatrixParameter(param, CG_GL_TEXTURE_MATRIX, CG_GL_MATRIX_IDENTITY); + else + LOG(WARNING, LOG_CATEGORY, "CVertexShader::LoadShader: Unknown parameter name: %s", name.c_str()); +} + +#endif diff --git a/source/renderer/VertexProgram.h b/source/renderer/VertexProgram.h new file mode 100755 index 0000000000..c602130476 --- /dev/null +++ b/source/renderer/VertexProgram.h @@ -0,0 +1,34 @@ +#ifndef __H_VERTEXPROGRAM_H__ +#define __H_VERTEXPROGRAM_H__ + +#ifdef BUILD_CG + +#pragma comment(lib, "cg.lib") +#pragma comment(lib, "cgGL.lib") + +#include "ogl.h" +#include "Cg/Cg.h" +#include "Cg/cgGL.h" + +#endif + +class CProgramManager; + +class CVertexProgram +{ +friend class CProgramManager; +public: + CVertexProgram(const char *file); + ~CVertexProgram(); + + bool IsValid(); +private: + void Bind(); + void Load(const char *file); +#ifdef BUILD_CG + void PushParameter(CGparameter param); + CGprogram m_Program; +#endif +}; + +#endif \ No newline at end of file