From 4d2fbc241af8199e891788346fdbc32a60e9a7c9 Mon Sep 17 00:00:00 2001 From: OV2 Date: Sat, 2 Jul 2011 04:25:13 +0200 Subject: [PATCH] Win32: add support for cg meta shaders (currently opengl only) --- win32/CCGShader.cpp | 119 ++++++++ win32/CCGShader.h | 43 +++ win32/CGLCG.cpp | 594 ++++++++++++++++++++++++++++++++++++++++ win32/CGLCG.h | 87 ++++++ win32/COpenGL.cpp | 146 +++------- win32/COpenGL.h | 3 + win32/cgFunctions.cpp | 14 +- win32/cgFunctions.h | 9 +- win32/snes9xw.vcproj | 16 ++ win32/win32_display.cpp | 18 +- win32/wsnes9x.cpp | 5 +- 11 files changed, 940 insertions(+), 114 deletions(-) create mode 100644 win32/CCGShader.cpp create mode 100644 win32/CCGShader.h create mode 100644 win32/CGLCG.cpp create mode 100644 win32/CGLCG.h diff --git a/win32/CCGShader.cpp b/win32/CCGShader.cpp new file mode 100644 index 00000000..91bd530b --- /dev/null +++ b/win32/CCGShader.cpp @@ -0,0 +1,119 @@ +#include "CCGShader.h" +#include "../conffile.h" + +CCGShader::CCGShader(void) +{ + +} + +CCGShader::~CCGShader(void) +{ +} + +cgScaleType CCGShader::scaleStringToEnum(const char *scale) +{ + if(!strcasecmp(scale,"source")) { + return CG_SCALE_SOURCE; + } else if(!strcasecmp(scale,"viewport")) { + return CG_SCALE_VIEWPORT; + } else if(!strcasecmp(scale,"absolute")) { + return CG_SCALE_ABSOLUTE; + } else { + return CG_SCALE_NONE; + } +} + +bool CCGShader::LoadShader(const char *path) +{ + ConfigFile conf; + int shaderCount; + char keyName[100]; + + shaderPasses.clear(); + lookupTextures.clear(); + + if(strlen(path)<4 || strcasecmp(&path[strlen(path)-4],".cgp")) { + shaderPass pass; + pass.scaleParams.scaleTypeX = CG_SCALE_NONE; + pass.scaleParams.scaleTypeY = CG_SCALE_NONE; + pass.linearFilter = false; + pass.filterSet = false; + strcpy(pass.cgShaderFile,path); + shaderPasses.push_back(pass); + return true; + } else { + conf.LoadFile(path); + } + + shaderCount = conf.GetInt("::shaders",0); + + if(shaderCount<1) + return false; + + for(int i=0;i + +enum cgScaleType { CG_SCALE_NONE, CG_SCALE_SOURCE, CG_SCALE_VIEWPORT, CG_SCALE_ABSOLUTE }; +typedef struct _cgScaleParams { + cgScaleType scaleTypeX; + cgScaleType scaleTypeY; + float scaleX; + float scaleY; + unsigned absX; + unsigned absY; +} cgScaleParams; + +class CCGShader +{ +private: + cgScaleType scaleStringToEnum(const char* scale); +public: + typedef struct _shaderPass { + cgScaleParams scaleParams; + bool linearFilter; + bool filterSet; + char cgShaderFile[PATH_MAX]; + } shaderPass; + typedef struct _lookupTexture { + char id[PATH_MAX]; + char texturePath[PATH_MAX]; + bool linearfilter; + } lookupTexture; + + CCGShader(void); + ~CCGShader(void); + bool LoadShader(const char *path); + + std::vector shaderPasses; + std::vector lookupTextures; +}; + +#endif diff --git a/win32/CGLCG.cpp b/win32/CGLCG.cpp new file mode 100644 index 00000000..4aedf338 --- /dev/null +++ b/win32/CGLCG.cpp @@ -0,0 +1,594 @@ +#include "CGLCG.h" +#include "wsnes9x.h" +#include "win32_display.h" +#include + +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +float npot(float desired) +{ + float out=512.0; + while(outcgContext = cgContext; + fboFunctionsLoaded = FALSE; + ClearPasses(); + LoadFBOFunctions(); + frameCnt=0; +} + +CGLCG::~CGLCG(void) +{ +} + +void CGLCG::ClearPasses() +{ + if(shaderPasses.size()>1) { + for(std::vector::iterator it=(shaderPasses.begin()+1);it!=shaderPasses.end();it++) { + if(it->cgFragmentProgram) + cgDestroyProgram(it->cgFragmentProgram); + if(it->cgVertexProgram) + cgDestroyProgram(it->cgVertexProgram); + if(it->fbo) + glDeleteFramebuffers(1,&it->fbo); + if(it->tex) + glDeleteTextures(1,&it->tex); + } + } + for(std::vector::iterator it=lookupTextures.begin();it!=lookupTextures.end();it++) { + if(it->tex) + glDeleteTextures(1,&it->tex); + } + shaderPasses.clear(); + lookupTextures.clear(); + shaderLoaded = false; +} + +bool CGLCG::LoadFBOFunctions() +{ + if(fboFunctionsLoaded) + return true; + + const char *extensions = (const char *) glGetString(GL_EXTENSIONS); + + if(extensions && strstr(extensions, "framebuffer_object")) { + glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wglGetProcAddress("glGenFramebuffers"); + glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wglGetProcAddress("glDeleteFramebuffers"); + glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress("glBindFramebuffer"); + glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wglGetProcAddress("glFramebufferTexture2D"); + glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)wglGetProcAddress("glCheckFramebufferStatus"); + glClientActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glClientActiveTexture"); + + if(glGenFramebuffers && glDeleteFramebuffers && glBindFramebuffer && glFramebufferTexture2D && glClientActiveTexture) { + fboFunctionsLoaded = true; + } + + } + return fboFunctionsLoaded; +} + +void CGLCG::checkForCgError(const char *situation) +{ + char buffer[4096]; + CGerror error = cgGetError(); + const char *string = cgGetErrorString(error); + + if (error != CG_NO_ERROR) { + sprintf(buffer, + "Situation: %s\n" + "Error: %s\n\n" + "Cg compiler output...\n", situation, string); + MessageBoxA(0, buffer, + "Cg error", MB_OK|MB_ICONEXCLAMATION); + if (error == CG_COMPILER_ERROR) { + MessageBoxA(0, cgGetLastListing(cgContext), + "Cg compilation error", MB_OK|MB_ICONEXCLAMATION); + } + } +} + +#define IS_SLASH(x) ((x) == TEXT('\\') || (x) == TEXT('/')) + +bool CGLCG::LoadShader(const TCHAR *shaderFile) +{ + CCGShader cgShader; + TCHAR shaderPath[MAX_PATH]; + TCHAR tempPath[MAX_PATH]; + CGprofile vertexProfile, fragmentProfile; + GLenum error; + + if(!fboFunctionsLoaded) { + MessageBox(NULL, TEXT("Your OpenGL graphics driver does not support framebuffer objects.\nYou will not be able to use CG shaders in OpenGL mode."), TEXT("CG Error"), + MB_OK|MB_ICONEXCLAMATION); + return false; + } + + vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); + fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); + + cgGLDisableProfile(vertexProfile); + cgGLDisableProfile(fragmentProfile); + + ClearPasses(); + + if (shaderFile == NULL || *shaderFile==TEXT('\0')) + return true; + + lstrcpy(shaderPath,shaderFile); + for(int i=lstrlen(shaderPath); i>=0; i--){ + if(IS_SLASH(shaderPath[i])){ + shaderPath[i]=TEXT('\0'); + break; + } + } + + SetCurrentDirectory(shaderPath); + if(!cgShader.LoadShader(_tToChar(shaderFile))) + return false; + + cgGLSetOptimalOptions(vertexProfile); + cgGLSetOptimalOptions(fragmentProfile); + + shaderPasses.push_back(shaderPass()); + + for(std::vector::iterator it=cgShader.shaderPasses.begin();it!=cgShader.shaderPasses.end();it++) { + shaderPasses.push_back(shaderPass()); + shaderPass &pass = shaderPasses.back(); + pass.scaleParams = it->scaleParams; + pass.linearFilter = (pass.scaleParams.scaleTypeX==CG_SCALE_NONE && !it->filterSet)?GUI.BilinearFilter:it->linearFilter; + _tfullpath(tempPath,_tFromChar(it->cgShaderFile),MAX_PATH); + char *fileContents = ReadShaderFileContents(tempPath); + if(!fileContents) + return false; + + pass.cgVertexProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, + vertexProfile, "main_vertex", NULL); + + checkForCgError("Compiling vertex program"); + + pass.cgFragmentProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, + fragmentProfile, "main_fragment", NULL); + + checkForCgError("Compiling fragment program"); + + delete [] fileContents; + if(!pass.cgVertexProgram || !pass.cgFragmentProgram) { + return false; + } + cgGLLoadProgram(pass.cgVertexProgram); + cgGLLoadProgram(pass.cgFragmentProgram); + + glGenFramebuffers(1,&pass.fbo); + glGenTextures(1,&pass.tex); + glBindTexture(GL_TEXTURE_2D,pass.tex); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + for(std::vector::iterator it=cgShader.lookupTextures.begin();it!=cgShader.lookupTextures.end();it++) { + lookupTextures.push_back(lookupTexture()); + lookupTexture &tex = lookupTextures.back(); + strcpy(tex.id,it->id); + glGenTextures(1,&tex.tex); + glBindTexture(GL_TEXTURE_2D,tex.tex); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, it->linearfilter?GL_LINEAR:GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, it->linearfilter?GL_LINEAR:GL_NEAREST); + _tfullpath(tempPath,_tFromChar(it->texturePath),MAX_PATH); + int strLen = strlen(it->texturePath); + if(strLen>4) { + if(!strcasecmp(&it->texturePath[strLen-4],".png")) { + int width, height; + bool hasAlpha; + GLubyte *texData; + if(loadPngImage(tempPath,width,height,hasAlpha,&texData)) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, width); + glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, width, + height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, texData); + free(texData); + } + } else if(!strcasecmp(&it->texturePath[strLen-4],".tga")) { + STGA stga; + if(loadTGA(tempPath,stga)) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, stga.width); + glTexImage2D(GL_TEXTURE_2D, 0, 4, stga.width, + stga.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, stga.data); + } + } + + } + } + + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2,GL_FLOAT,0,lut_coords); + glClientActiveTexture(GL_TEXTURE0); + + shaderLoaded = true; + + return true; +} + +void CGLCG::setTexCoords(int pass,xySize inputSize,xySize textureSize,bool topdown) +{ + float tX = inputSize.x / textureSize.x; + float tY = inputSize.y / textureSize.y; + + if(topdown) { + shaderPasses[pass].texcoords[0] = 0.0f; + shaderPasses[pass].texcoords[1] = tY; + shaderPasses[pass].texcoords[2] = tX; + shaderPasses[pass].texcoords[3] = tY; + shaderPasses[pass].texcoords[4] = tX; + shaderPasses[pass].texcoords[5] = 0.0f; + shaderPasses[pass].texcoords[6] = 0.0f; + shaderPasses[pass].texcoords[7] = 0.0f; + } else { + shaderPasses[pass].texcoords[0] = 0.0f; + shaderPasses[pass].texcoords[1] = 0.0f; + shaderPasses[pass].texcoords[2] = tX; + shaderPasses[pass].texcoords[3] = 0.0f; + shaderPasses[pass].texcoords[4] = tX; + shaderPasses[pass].texcoords[5] = tY; + shaderPasses[pass].texcoords[6] = 0.0f; + shaderPasses[pass].texcoords[7] = tY; + } + + glTexCoordPointer(2, GL_FLOAT, 0, shaderPasses[pass].texcoords); +} + +void CGLCG::Render(GLuint origTex, xySize textureSize, xySize inputSize, xySize viewportSize, xySize windowSize) +{ + GLenum error; + frameCnt++; + CGprofile vertexProfile, fragmentProfile; + + if(!shaderLoaded) + return; + + vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); + fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); + + cgGLEnableProfile(vertexProfile); + cgGLEnableProfile(fragmentProfile); + + shaderPasses[0].tex = origTex; + shaderPasses[0].outputSize = inputSize; + shaderPasses[0].textureSize = textureSize; + + for(int i=1;i1) { + for(int i=1;iwidth; + outHeight = info_ptr->height; + switch (info_ptr->color_type) { + case PNG_COLOR_TYPE_RGBA: + outHasAlpha = true; + break; + case PNG_COLOR_TYPE_RGB: + outHasAlpha = false; + break; + default: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(fp); + return false; + } + unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr); + *outData = (unsigned char*) malloc(row_bytes * outHeight); + + png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); + + for (int i = 0; i < outHeight; i++) { + memcpy(*outData+(row_bytes * i), row_pointers[i], row_bytes); + } + + /* Clean up after the read, + * and free any memory allocated */ + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + + /* Close the file */ + fclose(fp); + + /* That's it */ + return true; +} + +bool CGLCG::loadTGA(const TCHAR *filename, STGA& tgaFile) +{ + FILE *file; + unsigned char type[4]; + unsigned char info[6]; + + file = _tfopen(filename, TEXT("rb")); + + if (!file) + return false; + + fread (&type, sizeof (char), 3, file); + fseek (file, 12, SEEK_SET); + fread (&info, sizeof (char), 6, file); + + //image type either 2 (color) or 3 (greyscale) + if (type[1] != 0 || (type[2] != 2 && type[2] != 3)) + { + fclose(file); + return false; + } + + tgaFile.width = info[0] + info[1] * 256; + tgaFile.height = info[2] + info[3] * 256; + tgaFile.byteCount = info[4] / 8; + + if (tgaFile.byteCount != 3 && tgaFile.byteCount != 4) { + fclose(file); + return false; + } + + long imageSize = tgaFile.width * tgaFile.height * tgaFile.byteCount; + + //allocate memory for image data + unsigned char *tempBuf = new unsigned char[imageSize]; + tgaFile.data = new unsigned char[tgaFile.width * tgaFile.height * 4]; + + //read in image data + fread(tempBuf, sizeof(unsigned char), imageSize, file); + + //swap line order and convert to RBGA + for(int i=0;i +#include +#include "glext.h" +#include "cgFunctions.h" +#include "CCGShader.h" +#include + +typedef struct _xySize { + double x; + double y; +} xySize; + +class CGLCG +{ +private: + typedef struct _STGA { + _STGA() {data = (unsigned char*)0; + width = 0; + height = 0; + byteCount = 0;} + + ~_STGA() { delete[] data; data = 0; } + + void destroy() { delete[] data; data = 0; } + + int width; + int height; + unsigned char byteCount; + unsigned char* data; + } STGA; + typedef struct _shaderPass { + cgScaleParams scaleParams; + bool linearFilter; + CGprogram cgVertexProgram, cgFragmentProgram; + GLuint tex; + GLuint fbo; + xySize outputSize; + xySize textureSize; + GLfloat texcoords[8]; + _shaderPass() {cgVertexProgram=NULL; + cgFragmentProgram=NULL; + fbo=NULL; + tex=NULL;} + } shaderPass; + typedef struct _lookupTexture { + char id[PATH_MAX]; + GLuint tex; + _lookupTexture() {tex=NULL;} + } lookupTexture; + + std::vector shaderPasses; + std::vector lookupTextures; + + bool fboFunctionsLoaded; + bool shaderLoaded; + bool LoadFBOFunctions(); + void checkForCgError(const char *situation); + void setTexCoords(int pass,xySize inputSize,xySize textureSize,bool topdown=false); + void setShaderVars(int pass); + bool loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData); + bool loadTGA(const TCHAR *filename, STGA& tgaFile); + + CGcontext cgContext; + int frameCnt; + static const GLfloat lut_coords[8]; + + + PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; + PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; + PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; + PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; + PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; + PFNGLACTIVETEXTUREPROC glClientActiveTexture; + +public: + CGLCG(CGcontext cgContext); + ~CGLCG(void); + + bool LoadShader(const TCHAR *shaderFile); + void Render(GLuint origTex, xySize textureSize, xySize inputSize, xySize viewportSize, xySize windowSize); + void ClearPasses(); +}; + +#endif diff --git a/win32/COpenGL.cpp b/win32/COpenGL.cpp index 66597c79..4819990f 100644 --- a/win32/COpenGL.cpp +++ b/win32/COpenGL.cpp @@ -211,6 +211,7 @@ COpenGL::COpenGL(void) cgVertexProgram = cgFragmentProgram = NULL; cgAvailable = false; frameCount = 0; + cgShader = NULL; } COpenGL::~COpenGL(void) @@ -285,6 +286,7 @@ bool COpenGL::Initialize(HWND hWnd) cgAvailable = loadCgFunctions(); if(cgAvailable) { cgContext = cgCreateContext(); + cgShader = new CGLCG(cgContext); } GetClientRect(hWnd,&windowRect); @@ -323,6 +325,10 @@ void COpenGL::DeInitialize() if(cgAvailable) unloadCgLibrary(); cgAvailable = false; + if(cgShader) { + delete cgShader; + cgShader = NULL; + } } void COpenGL::CreateDrawSurface() @@ -402,6 +408,7 @@ void COpenGL::SetupVertices() texcoords[5] = 0.0f; texcoords[6] = 0.0f; texcoords[7] = 0.0f; + glTexCoordPointer(2, GL_FLOAT, 0, texcoords); } void COpenGL::Render(SSurface Src) @@ -421,6 +428,7 @@ void COpenGL::Render(SSurface Src) } if(pboFunctionsLoaded) { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, drawBuffer); Dst.Surface = (unsigned char *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER,GL_WRITE_ONLY); } else { Dst.Surface = noPboBuffer; @@ -444,18 +452,25 @@ void COpenGL::Render(SSurface Src) ApplyDisplayChanges(); } - if (shader_type != OGL_SHADER_NONE) { - GLint location; + glBindTexture(GL_TEXTURE_2D,drawTexture); + glPixelStorei(GL_UNPACK_ROW_LENGTH, quadTextureSize); + glTexSubImage2D (GL_TEXTURE_2D,0,0,0,dstRect.right-dstRect.left,dstRect.bottom-dstRect.top,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,pboFunctionsLoaded?0:noPboBuffer); - float inputSize[2] = { (float)afterRenderWidth, (float)afterRenderHeight }; - RECT windowSize; - GetClientRect(hWnd,&windowSize); - float outputSize[2] = {(float)(GUI.Stretch?windowSize.right:afterRenderWidth), - (float)(GUI.Stretch?windowSize.bottom:afterRenderHeight) }; - float textureSize[2] = { (float)quadTextureSize, (float)quadTextureSize }; - float frameCnt = (float)++frameCount; + if(pboFunctionsLoaded) + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + if (shader_type != OGL_SHADER_NONE) { if(shader_type == OGL_SHADER_GLSL) { + GLint location; + + float inputSize[2] = { (float)afterRenderWidth, (float)afterRenderHeight }; + RECT windowSize; + GetClientRect(hWnd,&windowSize); + float outputSize[2] = {(float)(GUI.Stretch?windowSize.right:afterRenderWidth), + (float)(GUI.Stretch?windowSize.bottom:afterRenderHeight) }; + float textureSize[2] = { (float)quadTextureSize, (float)quadTextureSize }; + float frameCnt = (float)++frameCount; location = glGetUniformLocation (shaderProgram, "rubyInputSize"); glUniform2fv (location, 1, inputSize); @@ -465,37 +480,26 @@ void COpenGL::Render(SSurface Src) location = glGetUniformLocation (shaderProgram, "rubyTextureSize"); glUniform2fv (location, 1, textureSize); } else if(shader_type == OGL_SHADER_CG) { - CGparameter cgpModelViewProj = cgGetNamedParameter(cgVertexProgram, "modelViewProj"); - - cgGLSetStateMatrixParameter(cgpModelViewProj, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); - -#define setProgram2fv(program,varname,floats)\ -{\ - CGparameter cgp = cgGetNamedParameter(program, varname);\ - if(cgp)\ - cgGLSetParameter2fv(cgp,floats);\ -}\ - -#define setProgram1f(program,varname,val)\ -{\ - CGparameter cgp = cgGetNamedParameter(program, varname);\ - if(cgp)\ - cgGLSetParameter1f(cgp,val);\ -}\ - - setProgram2fv(cgFragmentProgram,"IN.video_size",inputSize); - setProgram2fv(cgFragmentProgram,"IN.texture_size",textureSize); - setProgram2fv(cgFragmentProgram,"IN.output_size",outputSize); - setProgram1f(cgFragmentProgram,"IN.frame_count",frameCnt); - setProgram2fv(cgVertexProgram,"IN.video_size",inputSize); - setProgram2fv(cgVertexProgram,"IN.texture_size",textureSize); - setProgram2fv(cgVertexProgram,"IN.output_size",outputSize); - setProgram1f(cgVertexProgram,"IN.frame_count",frameCnt); + xySize inputSize = { (float)afterRenderWidth, (float)afterRenderHeight }; + RECT windowSize, displayRect; + GetClientRect(hWnd,&windowSize); + xySize xywindowSize = { (double)windowSize.right, (double)windowSize.bottom }; + //Get maximum rect respecting AR setting + displayRect=CalculateDisplayRect(windowSize.right,windowSize.bottom,windowSize.right,windowSize.bottom); + xySize viewportSize = { (double)(displayRect.right - displayRect.left), + (double)(displayRect.bottom - displayRect.top) }; + xySize textureSize = { (double)quadTextureSize, (double)quadTextureSize }; + cgShader->Render(drawTexture, textureSize, inputSize, viewportSize, xywindowSize); } } - glPixelStorei(GL_UNPACK_ROW_LENGTH, quadTextureSize); - glTexSubImage2D (GL_TEXTURE_2D,0,0,0,dstRect.right-dstRect.left,dstRect.bottom-dstRect.top,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,pboFunctionsLoaded?0:noPboBuffer); + if(GUI.BilinearFilter) { + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glClear(GL_COLOR_BUFFER_BIT); @@ -515,13 +519,6 @@ bool COpenGL::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight) bool COpenGL::ApplyDisplayChanges(void) { - if(GUI.BilinearFilter) { - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } if(wglSwapIntervalEXT) { wglSwapIntervalEXT(GUI.Vsync?1:0); } @@ -683,7 +680,9 @@ bool COpenGL::SetShaders(const TCHAR *file) SetShadersCG(NULL); SetShadersGLSL(NULL); shader_type = OGL_SHADER_NONE; - if(file!=NULL && lstrlen(file)>3 && _tcsncicmp(&file[lstrlen(file)-3],TEXT(".cg"),3)==0) { + if(file!=NULL && ( + (lstrlen(file)>3 && _tcsncicmp(&file[lstrlen(file)-3],TEXT(".cg"),3)==0) || + (lstrlen(file)>4 && _tcsncicmp(&file[lstrlen(file)-4],TEXT(".cgp"),4)==0))) { return SetShadersCG(file); } else { return SetShadersGLSL(file); @@ -712,70 +711,15 @@ void COpenGL::checkForCgError(const char *situation) bool COpenGL::SetShadersCG(const TCHAR *file) { - TCHAR errorMsg[MAX_PATH + 50]; - HRESULT hr; - CGprofile vertexProfile, fragmentProfile; - - if(cgFragmentProgram) { - cgDestroyProgram(cgFragmentProgram); - cgFragmentProgram = NULL; - } - if(cgVertexProgram) { - cgDestroyProgram(cgVertexProgram); - cgVertexProgram = NULL; - } - - if(cgAvailable) { - vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); - fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); - - cgGLDisableProfile(vertexProfile); - cgGLDisableProfile(fragmentProfile); - } - - if (file == NULL || *file==TEXT('\0')) - return true; - if(!cgAvailable) { MessageBox(NULL, TEXT("The CG runtime is unavailable, CG shaders will not run.\nConsult the snes9x readme for information on how to obtain the runtime."), TEXT("CG Error"), MB_OK|MB_ICONEXCLAMATION); return false; } - cgGLSetOptimalOptions(vertexProfile); - cgGLSetOptimalOptions(fragmentProfile); - - char *fileContents = ReadShaderFileContents(file); - if(!fileContents) + if(!cgShader->LoadShader(file)) return false; - cgVertexProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, - vertexProfile, "main_vertex", NULL); - - checkForCgError("Compiling vertex program"); - - cgFragmentProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, - fragmentProfile, "main_fragment", NULL); - - checkForCgError("Compiling fragment program"); - - delete [] fileContents; - - if(!cgVertexProgram || !cgFragmentProgram) { - return false; - } - - if(cgVertexProgram) { - cgGLEnableProfile(vertexProfile); - cgGLLoadProgram(cgVertexProgram); - cgGLBindProgram(cgVertexProgram); - } - if(cgFragmentProgram) { - cgGLEnableProfile(fragmentProfile); - cgGLLoadProgram(cgFragmentProgram); - cgGLBindProgram(cgFragmentProgram); - } - shader_type = OGL_SHADER_CG; return true; diff --git a/win32/COpenGL.h b/win32/COpenGL.h index cd10f85b..12448c8a 100644 --- a/win32/COpenGL.h +++ b/win32/COpenGL.h @@ -183,6 +183,7 @@ #include #include #include "cgFunctions.h" +#include "CGLCG.h" #include "glext.h" #include "wglext.h" @@ -219,6 +220,8 @@ private: current_ogl_shader_type shader_type; bool cgAvailable; + CGLCG *cgShader; + GLuint shaderProgram; GLuint vertexShader; GLuint fragmentShader; diff --git a/win32/cgFunctions.cpp b/win32/cgFunctions.cpp index 7229f3e1..e458f486 100644 --- a/win32/cgFunctions.cpp +++ b/win32/cgFunctions.cpp @@ -211,6 +211,10 @@ CGGLDP cgGLDisableProfile = NULL; CGGLSOO cgGLSetOptimalOptions = NULL; CGGLLP cgGLLoadProgram = NULL; CGGLBP cgGLBindProgram = NULL; +CGGLSTP cgGLSetTextureParameter = NULL; +CGGLETP cgGLEnableTextureParameter = NULL; +CGGLSPP cgGLSetParameterPointer = NULL; +CGGLECS cgGLEnableClientState = NULL; bool loadCgFunctions() { @@ -256,6 +260,10 @@ bool loadCgFunctions() cgGLSetOptimalOptions = (CGGLSOO)GetProcAddress(hCgGLDll,"cgGLSetOptimalOptions"); cgGLLoadProgram = (CGGLLP)GetProcAddress(hCgGLDll,"cgGLLoadProgram"); cgGLBindProgram = (CGGLBP)GetProcAddress(hCgGLDll,"cgGLBindProgram"); + cgGLSetTextureParameter = (CGGLSTP)GetProcAddress(hCgGLDll,"cgGLSetTextureParameter"); + cgGLEnableTextureParameter = (CGGLETP)GetProcAddress(hCgGLDll,"cgGLEnableTextureParameter"); + cgGLSetParameterPointer = (CGGLSPP)GetProcAddress(hCgGLDll,"cgGLSetParameterPointer"); + cgGLEnableClientState = (CGGLECS)GetProcAddress(hCgGLDll,"cgGLEnableClientState"); if( //cg.dll @@ -285,7 +293,11 @@ bool loadCgFunctions() !cgGLDisableProfile || !cgGLSetOptimalOptions || !cgGLLoadProgram || - !cgGLBindProgram) { + !cgGLBindProgram || + !cgGLSetTextureParameter || + !cgGLEnableTextureParameter || + !cgGLSetParameterPointer || + !cgGLEnableClientState) { unloadCgLibrary(); return false; } diff --git a/win32/cgFunctions.h b/win32/cgFunctions.h index 324eca32..636dd833 100644 --- a/win32/cgFunctions.h +++ b/win32/cgFunctions.h @@ -243,7 +243,14 @@ typedef CGGL_API void (CGGLENTRY *CGGLLP)(CGprogram program); extern CGGLLP cgGLLoadProgram; typedef CGGL_API void (CGGLENTRY *CGGLBP)(CGprogram program); extern CGGLBP cgGLBindProgram; - +typedef CGGL_API void (CGGLENTRY *CGGLSTP)(CGparameter param, GLuint texobj); +extern CGGLSTP cgGLSetTextureParameter; +typedef CGGL_API void (CGGLENTRY *CGGLETP)(CGparameter param); +extern CGGLETP cgGLEnableTextureParameter; +typedef CGGL_API void (CGGLENTRY *CGGLSPP)(CGparameter param, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); +extern CGGLSPP cgGLSetParameterPointer; +typedef CGGL_API void (CGGLENTRY *CGGLECS)(CGparameter param); +extern CGGLECS cgGLEnableClientState; //cgfunctions.cpp diff --git a/win32/snes9xw.vcproj b/win32/snes9xw.vcproj index 4b5bda35..94d0dbb1 100644 --- a/win32/snes9xw.vcproj +++ b/win32/snes9xw.vcproj @@ -3129,6 +3129,14 @@ + + + + @@ -3209,6 +3217,14 @@ RelativePath=".\cgFunctions.h" > + + + + diff --git a/win32/win32_display.cpp b/win32/win32_display.cpp index 2809347b..72afd1ea 100644 --- a/win32/win32_display.cpp +++ b/win32/win32_display.cpp @@ -272,27 +272,27 @@ void WinDisplayApplyChanges() RECT CalculateDisplayRect(unsigned int sourceWidth,unsigned int sourceHeight, unsigned int displayWidth,unsigned int displayHeight) { - float xFactor; - float yFactor; - float minFactor; - float renderWidthCalc,renderHeightCalc; + double xFactor; + double yFactor; + double minFactor; + double renderWidthCalc,renderHeightCalc; int hExtend = GUI.HeightExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT; - float snesAspect = (float)GUI.AspectWidth/hExtend; + double snesAspect = (double)GUI.AspectWidth/hExtend; RECT drawRect; if(GUI.Stretch) { if(GUI.AspectRatio) { //fix for hi-res images with FILTER_NONE //where we need to correct the aspect ratio - renderWidthCalc = (float)sourceWidth; - renderHeightCalc = (float)sourceHeight; + renderWidthCalc = (double)sourceWidth; + renderHeightCalc = (double)sourceHeight; if(renderWidthCalc/renderHeightCalc>snesAspect) renderWidthCalc = renderHeightCalc * snesAspect; else if(renderWidthCalc/renderHeightCalc