From 6814ef1ed83df7b1dc65f07adaeca481329f9015 Mon Sep 17 00:00:00 2001 From: Bart Trzynadlowski Date: Mon, 6 Feb 2012 02:54:43 +0000 Subject: [PATCH] Added preliminary specular lighting to shaders. The "no spotlight" shader has not yet been updated. --- Makefiles/Makefile.SDL.Win32.GCC | 37 +- Src/Graphics/Shaders/Fragment.glsl | 24 +- Src/Graphics/Shaders/Vertex.glsl | 47 +- Src/Graphics/Shaders3D.h | 671 +++++++++++++++-------------- 4 files changed, 425 insertions(+), 354 deletions(-) diff --git a/Makefiles/Makefile.SDL.Win32.GCC b/Makefiles/Makefile.SDL.Win32.GCC index 3fae2de..3cf451c 100644 --- a/Makefiles/Makefile.SDL.Win32.GCC +++ b/Makefiles/Makefile.SDL.Win32.GCC @@ -22,8 +22,7 @@ # # Makefile.SDL.Win32.GCC # -# GNU Makefile for SDL port using GCC (MinGW) on Windows. Copy this Makefile -# to the base directory of the source distribution (one up from Src/ and here). +# GNU Makefile for SDL port using GCC (MinGW) on Windows. # @@ -89,10 +88,12 @@ OUTFILE = $(BIN_DIR)\Supermodel.exe ############################################################################### CC = gcc +CXX = g++ LD = g++ -COMPILER_FLAGS = -I$(SDL_INCLUDEPATH) -ISrc/ -ISrc/OSD/ -ISrc/OSD/SDL/ -ISrc/OSD/Windows/ -c -Wall -O3 -DSUPERMODEL_WIN32 -DGLEW_STATIC +COMPILER_FLAGS = -I$(SDL_INCLUDEPATH) -ISrc/ -ISrc/OSD/ -ISrc/OSD/SDL/ -ISrc/OSD/Windows/ -c -Wall -O3 -DSUPERMODEL_WIN32 -DGLEW_STATIC CFLAGS = $(COMPILER_FLAGS) CPPFLAGS = $(COMPILER_FLAGS) +#LFLAGS = -s -o $(OUTFILE) $(OBJ) -L$(SDL_LIBPATH) -lmingw32 -lSDLmain -lSDL -lopengl32 -lglu32 -ldinput8 -ldxguid -lole32 -loleaut32 -lz -l:$(WINSDK_LIBPATH)/WbemUuid.lib LFLAGS = -s -o $(OUTFILE) $(OBJ) -L$(SDL_LIBPATH) -lmingw32 -lSDLmain -lSDL -lopengl32 -lglu32 -ldinput8 -ldxguid -lole32 -loleaut32 -lz -l:$(WINSDK_LIBPATH)/WbemUuid.lib # @@ -188,40 +189,40 @@ $(OBJ_DIR)/m68kopnz.o: $(OBJ_DIR)/m68kopnz.c $(OBJ_DIR)/m68kmake.exe $(OBJ_DIR)/ # Rules for Supermodel C++ code # $(OBJ_DIR)/%.o: Src/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/Model3/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o -$(OBJ_DIR)/%.o: Src/Graphics/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o +$(OBJ_DIR)/%.o: Src/Graphics/%.cpp Src/Graphics/Shaders2D.h Src/Graphics/Shaders3D.h + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/Sound/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/Debugger/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/Debugger/CPU/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o -$(OBJ_DIR)/%.o: Src/CPU/PowerPC/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o +$(OBJ_DIR)/%.o: Src/CPU/PowerPC/%.cpp Src/CPU/PowerPC/ppc.h Src/CPU/PowerPC/ppc603.c Src/CPU/PowerPC/ppc_ops.c Src/CPU/PowerPC/ppc_ops.h + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/CPU/68K/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/CPU/Z80/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/Inputs/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/OSD/SDL/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/OSD/Windows/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o $(OBJ_DIR)/%.o: Src/Pkgs/%.c $(CC) $< $(CFLAGS) -o $(OBJ_DIR)/$(*F).o @@ -232,4 +233,4 @@ $(OBJ_DIR)/%.o: Src/Pkgs/%.c # To eliminate name conflicts, object files have the prefix "amp_" attached. # $(OBJ_DIR)/amp_%.o: Src/Sound/MPEG/%.cpp - $(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/amp_$(*F).o \ No newline at end of file + $(CXX) $< $(CPPFLAGS) -o $(OBJ_DIR)/amp_$(*F).o \ No newline at end of file diff --git a/Src/Graphics/Shaders/Fragment.glsl b/Src/Graphics/Shaders/Fragment.glsl index 09b2e6c..022387a 100644 --- a/Src/Graphics/Shaders/Fragment.glsl +++ b/Src/Graphics/Shaders/Fragment.glsl @@ -32,14 +32,16 @@ uniform sampler2D textureMap; // complete texture map, 2048x2048 texels uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height) uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit uniform vec3 spotColor; // spotlight RGB color +uniform vec3 lighting[2]; // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0) // Inputs from vertex shader varying vec4 fsSubTexture; // .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels) varying vec4 fsTexParams; // .x=texture enable (if 1, else 0), .y=use transparency (if > 0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode -varying float fsTexFormat; // .x=T1RGB5 contour texture (if > 0) +varying float fsTexFormat; // T1RGB5 contour texture (if > 0) varying float fsTransLevel; // translucence level, 0.0 (transparent) to 1.0 (opaque) varying vec3 fsLightIntensity; // lighting intensity -varying float fsFogFactor; // fog factor +varying float fsSpecularTerm; // specular highlight +varying float fsFogFactor; // fog factor varying float fsViewZ; // Z distance to fragment from viewpoint at origin /* @@ -82,12 +84,6 @@ vec4 WrapTexelCoords(vec4 texCoord, vec4 texOffset, vec4 texSize, vec4 mirrorEna (vec4(1.0,1.0,1.0,1.0)-mirror)*clampedCoord + texOffset ) / 2048.0; -/* - glTexCoord = ( mirror*(texSize-vec4(1.0,1.0,1.0,1.0)-clampedCoord) + - (vec4(1.0,1.0,1.0,1.0)-mirror)*clampedCoord + - texOffset - ) / 2048.0; -*/ return glTexCoord; } @@ -105,10 +101,11 @@ void main(void) vec2 ellipse; vec3 lightIntensity; float insideSpot; + int x; // Get polygon color for untextured polygons (textured polygons will overwrite) - if (fsTexParams.x==0.0) - fragColor = gl_Color; + if (fsTexParams.x < 0.5) + fragColor = gl_Color; else // Textured polygons: set fragment color to texel value { @@ -163,7 +160,7 @@ void main(void) * When the alpha value is 0.0 (or close), pixels are discarded * entirely. */ - if (fsTexParams.y > 0.0) // contour processing enabled + if (fsTexParams.y > 0.5) // contour processing enabled { if (fragColor.a < 0.01) // discard anything with alpha == 0 discard; @@ -182,12 +179,13 @@ void main(void) else lightIntensity = fsLightIntensity; fragColor.rgb *= lightIntensity; - + fragColor.rgb += vec3(fsSpecularTerm,fsSpecularTerm,fsSpecularTerm); + // Translucency (modulates existing alpha channel for RGBA4 texels) fragColor.a *= fsTransLevel; // Apply fog under the control of fog factor setting from polygon header - fragColor.rgb = mix(gl_Fog.color.rgb, fragColor.rgb, fsFogFactor ); + fragColor.rgb = mix(gl_Fog.color.rgb, fragColor.rgb, fsFogFactor); // Store final color gl_FragColor = fragColor; diff --git a/Src/Graphics/Shaders/Vertex.glsl b/Src/Graphics/Shaders/Vertex.glsl index 27274ab..4ba8952 100644 --- a/Src/Graphics/Shaders/Vertex.glsl +++ b/Src/Graphics/Shaders/Vertex.glsl @@ -34,14 +34,14 @@ uniform vec3 lighting[2]; // lighting state (lighting[0] = sun direction, light uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (normalized device coordinates), .y=Y position, .z=half-width, .w=half-height) uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit uniform vec3 spotColor; // spotlight RGB color -//uniform vec2 texOffset; // offset (within 2048x2048 texture sheet) to apply to texture base coordinates // Custom vertex attributes attribute vec4 subTexture; // .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels) attribute vec4 texParams; // .x=texture enable (if 1, else 0), .y=use transparency (if >=0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode -attribute float texFormat; // .x=T1RGB5 contour texture (if > 0) +attribute float texFormat; // T1RGB5 contour texture (if > 0) attribute float transLevel; // translucence level, 0.0 (transparent) to 1.0 (opaque). if less than 1.0, replace alpha value attribute float lightEnable; // lighting enabled (1.0) or luminous (0.0), drawn at full intensity +attribute float shininess; // specular shininess (if >= 0.0) or disable specular lighting (negative) attribute float fogIntensity; // fog intensity (1.0, full fog effect, 0.0, no fog) // Custom outputs to fragment shader @@ -50,8 +50,9 @@ varying vec4 fsTexParams; varying float fsTexFormat; varying float fsTransLevel; varying vec3 fsLightIntensity; // total light intensity for this vertex +varying float fsSpecularTerm; // specular light term (additive) varying float fsFogFactor; // fog factor -varying float fsViewZ; +varying float fsViewZ; // Gets the 3x3 matrix out of a 4x4 (because mat3(mat4matrix) does not work on ATI!) mat3 GetLinearPart( mat4 m ) @@ -104,7 +105,7 @@ void main(void) gl_FrontColor = gl_Color; // untextured polygons will use this gl_FrontColor.a = 1.0; fsLightIntensity = vec3(1.0,1.0,1.0); - if (texParams.x > 0.0) // textured + if (texParams.x > 0.5) // textured fsLightIntensity *= gl_Color.rgb; /* @@ -113,7 +114,8 @@ void main(void) * Parallel light source and ambient lighting are only applied for non- * luminous polygons. */ - if (lightEnable > 0.5) // not luminous + fsSpecularTerm = 0.0; + if (lightEnable > 0.5) // not luminous { // Normal -> view space viewNormal = normalize(GetLinearPart(modelViewMatrix)*gl_Normal); @@ -125,7 +127,39 @@ void main(void) sunFactor = max(dot(sunVector,viewNormal),0.0); // Total light intensity: sum of all components - fsLightIntensity *= (sunFactor*lighting[1].x+lighting[1].y); + fsLightIntensity *= (sunFactor*lighting[1].x+lighting[1].y); + + /* + * Specular Lighting + * + * The specular term is treated similarly to the "separate specular + * color" functionality of OpenGL: it is added as a highlight in the + * fragment shader. This allows even black textures to be lit. + * + * TO-DO: Ambient intensity viewport parameter is known but what about + * the intensity of the specular term? Always applied with full + * intensity here but this is unlikely to be correct. + */ + if (shininess >= 0.0) + { + // Standard specular lighting equation + vec3 V = normalize(-viewVertex); + vec3 H = normalize(sunVector+V); // halfway vector + float s = max(10,64-shininess); // seems to look nice, but probably not correct + fsSpecularTerm = pow(max(dot(viewNormal,H),0),s); + if (sunFactor <= 0) fsSpecularTerm = 0; + + // Faster approximation + //float temp = max(dot(viewNormal,H),0); + //float s = 64-shininess; + //fsSpecularTerm = temp/(s-temp*s+temp); + + // Phong formula + //vec3 R = normalize(2*dot(sunVector,viewNormal)*viewNormal - sunVector); + //vec3 V = normalize(-viewVertex); + //float s = max(2,64-shininess); + //fsSpecularTerm = pow(max(dot(R,V),0),s); + } } // Fog @@ -138,7 +172,6 @@ void main(void) // Pass remaining parameters to fragment shader gl_TexCoord[0] = gl_MultiTexCoord0; fsSubTexture = subTexture; - //fsSubTexture.xy += texOffset; // apply texture offset fsTexParams = texParams; fsTransLevel = transLevel; fsTexFormat = texFormat; diff --git a/Src/Graphics/Shaders3D.h b/Src/Graphics/Shaders3D.h index 391ef67..d83e02b 100644 --- a/Src/Graphics/Shaders3D.h +++ b/Src/Graphics/Shaders3D.h @@ -31,148 +31,183 @@ // Vertex shader static const char vertexShaderSource[] = { -"/** \n" -" ** Supermodel \n" -" ** A Sega Model 3 Arcade Emulator. \n" -" ** Copyright 2011 Bart Trzynadlowski \n" -" ** \n" -" ** This file is part of Supermodel. \n" -" ** \n" -" ** Supermodel is free software: you can redistribute it and/or modify it under \n" -" ** the terms of the GNU General Public License as published by the Free \n" -" ** Software Foundation, either version 3 of the License, or (at your option) \n" -" ** any later version. \n" -" ** \n" -" ** Supermodel is distributed in the hope that it will be useful, but WITHOUT \n" -" ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \n" -" ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for \n" -" ** more details. \n" -" ** \n" -" ** You should have received a copy of the GNU General Public License along \n" -" ** with Supermodel. If not, see . \n" -" **/ \n" -"\n" -"/* \n" -" * Vertex.glsl \n" -" * \n" -" * Vertex shader for 3D rendering. \n" -" */ \n" +"/**\n" +" ** Supermodel\n" +" ** A Sega Model 3 Arcade Emulator.\n" +" ** Copyright 2011 Bart Trzynadlowski, Nik Henson \n" +" **\n" +" ** This file is part of Supermodel.\n" +" **\n" +" ** Supermodel is free software: you can redistribute it and/or modify it under\n" +" ** the terms of the GNU General Public License as published by the Free \n" +" ** Software Foundation, either version 3 of the License, or (at your option)\n" +" ** any later version.\n" +" **\n" +" ** Supermodel is distributed in the hope that it will be useful, but WITHOUT\n" +" ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +" ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n" +" ** more details.\n" +" **\n" +" ** You should have received a copy of the GNU General Public License along\n" +" ** with Supermodel. If not, see .\n" +" **/\n" +" \n" +"/*\n" +" * Vertex.glsl\n" +" *\n" +" * Vertex shader for 3D rendering.\n" +" */\n" +" \n" +"#version 120\n" "\n" -"#version 120 \n" +"// Global uniforms\n" +"uniform mat4\tmodelViewMatrix;\t// model -> view space matrix\n" +"uniform mat4\tprojectionMatrix;\t// view space -> screen space matrix\n" +"uniform vec3\tlighting[2];\t\t// lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0)\n" +"uniform vec4\tspotEllipse;\t\t// spotlight ellipse position: .x=X position (normalized device coordinates), .y=Y position, .z=half-width, .w=half-height)\n" +"uniform vec2\tspotRange;\t\t\t// spotlight Z range: .x=start (viewspace coordinates), .y=limit\n" +"uniform vec3\tspotColor;\t\t\t// spotlight RGB color\n" "\n" -"// Global uniforms \n" -"uniform mat4 modelViewMatrix; // model -> view space matrix \n" -"uniform mat4 projectionMatrix; // view space -> screen space matrix \n" -"uniform vec3 lighting[2]; // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0) \n" -"uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (normalized device coordinates), .y=Y position, .z=half-width, .w=half-height) \n" -"uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit \n" -"uniform vec3 spotColor; // spotlight RGB color \n" +"// Custom vertex attributes\n" +"attribute vec4\tsubTexture;\t\t// .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels)\n" +"attribute vec4\ttexParams;\t\t// .x=texture enable (if 1, else 0), .y=use transparency (if >=0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode\n" +"attribute float\ttexFormat;\t\t// T1RGB5 contour texture (if > 0)\n" +"attribute float\ttransLevel;\t\t// translucence level, 0.0 (transparent) to 1.0 (opaque). if less than 1.0, replace alpha value\n" +"attribute float\tlightEnable;\t// lighting enabled (1.0) or luminous (0.0), drawn at full intensity\n" +"attribute float\tshininess;\t\t// specular shininess (if >= 0.0) or disable specular lighting (negative)\n" +"attribute float\tfogIntensity;\t// fog intensity (1.0, full fog effect, 0.0, no fog) \n" "\n" -"// Custom vertex attributes \n" -"attribute vec4 subTexture; // .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels) \n" -"attribute vec4 texParams; // .x=texture enable (if 1, else 0), .y=use transparency (if >=0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode \n" -"attribute float texFormat; // .x=T1RGB5 contour texture (if > 0) \n" -"attribute float transLevel; // translucence level, 0.0 (transparent) to 1.0 (opaque). if less than 1.0, replace alpha value \n" -"attribute float lightEnable; // lighting enabled (1.0) or luminous (0.0), drawn at full intensity \n" -"attribute float fogIntensity; // fog intensity (1.0, full fog effect, 0.0, no fog) \n" +"// Custom outputs to fragment shader\n" +"varying vec4\tfsSubTexture;\n" +"varying vec4\tfsTexParams;\n" +"varying float\tfsTexFormat;\n" +"varying float\tfsTransLevel;\n" +"varying vec3\tfsLightIntensity;\t// total light intensity for this vertex\n" +"varying float\tfsSpecularTerm;\t\t// specular light term (additive)\n" +"varying float\tfsFogFactor;\t\t// fog factor\n" +"varying float\tfsViewZ;\n" "\n" -"// Custom outputs to fragment shader \n" -"varying vec4 fsSubTexture; \n" -"varying vec4 fsTexParams; \n" -"varying float fsTexFormat; \n" -"varying float fsTransLevel; \n" -"varying vec3 fsLightIntensity; // total light intensity for this vertex \n" -"varying float fsFogFactor; // fog factor \n" -"varying float fsViewZ; \n" +"// Gets the 3x3 matrix out of a 4x4 (because mat3(mat4matrix) does not work on ATI!)\n" +"mat3 GetLinearPart( mat4 m )\n" +"{\n" +"\tmat3 result;\n" +"\t\n" +"\tresult[0][0] = m[0][0]; \n" +"\tresult[0][1] = m[0][1]; \n" +"\tresult[0][2] = m[0][2]; \n" "\n" -"// Gets the 3x3 matrix out of a 4x4 (because mat3(mat4matrix) does not work on ATI!) \n" -"mat3 GetLinearPart( mat4 m ) \n" -"{ \n" -" mat3 result; \n" +"\tresult[1][0] = m[1][0]; \n" +"\tresult[1][1] = m[1][1]; \n" +"\tresult[1][2] = m[1][2]; \n" +"\t\n" +"\tresult[2][0] = m[2][0]; \n" +"\tresult[2][1] = m[2][1]; \n" +"\tresult[2][2] = m[2][2]; \n" +"\t\n" +"\treturn result;\n" +"}\n" "\n" -" result[0][0] = m[0][0]; \n" -" result[0][1] = m[0][1]; \n" -" result[0][2] = m[0][2]; \n" +"void main(void)\n" +"{\n" +"\tvec3\tviewVertex;\t\t// vertex coordinates in view space\n" +"\tvec3\tviewNormal;\t\t// vertex normal in view space\n" +"\tvec3\tsunVector;\t\t// sun lighting vector (as reflecting away from vertex)\n" +"\tfloat\tsunFactor;\t\t// sun light projection along vertex normal (0.0 to 1.0)\n" +"\tvec3\thalfway;\n" +"\tfloat\tspecFactor;\n" +"\t\n" +"\t// Transform vertex\n" +"\tgl_Position = projectionMatrix * modelViewMatrix * gl_Vertex;\n" +"\tviewVertex = vec3(modelViewMatrix * gl_Vertex);\t\n" +"\t\n" +"\t/*\n" +"\t * Modulation\n" +"\t *\n" +" \t * Polygon color serves as material color (modulating the light intensity)\n" +"\t * for textured polygons. The fragment shader will ignore (overwrite) the\n" +"\t * the color passed to it if the fragment is textured. \n" +"\t *\n" +"\t * Untextured fragments must be set to the polygon color and the light\n" +"\t * intensity is initialized to 1.0 here. Alpha must be set to 1.0 because\n" +"\t * the fragment shader multiplies it by the polygon translucency setting. \n" +"\t *\n" +"\t * TO-DO: Does OpenGL set alpha to 1.0 by default if no alpha is specified\n" +"\t * for the vertex? If so, we can remove that line from here.\n" +"\t */\n" "\n" -" result[1][0] = m[1][0]; \n" -" result[1][1] = m[1][1]; \n" -" result[1][2] = m[1][2]; \n" +"\tgl_FrontColor = gl_Color;\t// untextured polygons will use this\n" +"\tgl_FrontColor.a = 1.0;\t\n" +"\tfsLightIntensity = vec3(1.0,1.0,1.0);\n" +"\tif (texParams.x > 0.5)\t\t// textured\n" +"\t\tfsLightIntensity *= gl_Color.rgb;\n" +"\t\t\n" +"\t/*\n" +" \t * Sun Light\n" +"\t *\n" +"\t * Parallel light source and ambient lighting are only applied for non-\n" +"\t * luminous polygons.\n" +" \t */\n" +"\tfsSpecularTerm = 0.0;\n" +" \tif (lightEnable > 0.5)\t// not luminous\n" +"\t{\n" +"\t\t// Normal -> view space\n" +"\t\tviewNormal = normalize(GetLinearPart(modelViewMatrix)*gl_Normal);\n" "\n" -" result[2][0] = m[2][0]; \n" -" result[2][1] = m[2][1]; \n" -" result[2][2] = m[2][2]; \n" +"\t\t// Real3D -> OpenGL view space convention (TO-DO: do this outside of shader)\n" +"\t\tsunVector = lighting[0]*vec3(1.0,-1.0,-1.0);\n" +"\t\t\n" +"\t\t// Compute diffuse factor for sunlight\n" +"\t\tsunFactor = max(dot(sunVector,viewNormal),0.0);\n" +"\t\t\n" +"\t\t// Total light intensity: sum of all components\n" +"\t\tfsLightIntensity *= (sunFactor*lighting[1].x+lighting[1].y);\n" +"\t\t\n" +"\t\t/*\n" +"\t\t * Specular Lighting\n" +"\t\t *\n" +"\t\t * The specular term is treated similarly to the \"separate specular\n" +"\t\t * color\" functionality of OpenGL: it is added as a highlight in the\n" +"\t\t * fragment shader. This allows even black textures to be lit.\n" +"\t\t *\n" +"\t\t * TO-DO: Ambient intensity viewport parameter is known but what about\n" +"\t\t * the intensity of the specular term? Always applied with full \n" +"\t\t * intensity here but this is unlikely to be correct.\n" +"\t\t */\n" +" \t\tif (shininess >= 0.0)\n" +" \t\t{\n" +" \t\t\t// Standard specular lighting equation\n" +" \t\t\tvec3 V = normalize(-viewVertex);\n" +" \t\t\tvec3 H = normalize(sunVector+V);\t// halfway vector\n" +" \t\t\tfloat s = max(10,64-shininess);\t\t// seems to look nice, but probably not correct\n" +" \t\t\tfsSpecularTerm = pow(max(dot(viewNormal,H),0),s);\n" +" \t\t\tif (sunFactor <= 0) fsSpecularTerm = 0;\n" +" \t\t\t\n" +" \t\t\t// Faster approximation \t\t\t\n" +" \t\t\t//float temp = max(dot(viewNormal,H),0);\n" +" \t\t\t//float s = 64-shininess;\n" +" \t\t\t//fsSpecularTerm = temp/(s-temp*s+temp);\n" +" \t\t\t\n" +" \t\t\t// Phong formula\n" +" \t\t\t//vec3 R = normalize(2*dot(sunVector,viewNormal)*viewNormal - sunVector);\n" +" \t\t\t//vec3 V = normalize(-viewVertex);\n" +" \t\t\t//float s = max(2,64-shininess);\n" +" \t\t\t//fsSpecularTerm = pow(max(dot(R,V),0),s);\n" +" \t\t}\n" +"\t}\n" +"\t\n" +"\t// Fog\n" +"\tfloat z = length(viewVertex);\n" +"\tfsFogFactor = clamp(1.0-fogIntensity*(gl_Fog.start+z*gl_Fog.density), 0.0, 1.0);\n" "\n" -" return result; \n" -"} \n" +"\t// Pass viewspace Z coordinate (for spotlight)\n" +"\tfsViewZ = -viewVertex.z;\t// convert Z from GL->Real3D convention (want +Z to be further into screen)\n" "\n" -"void main(void) \n" -"{ \n" -" vec3 viewVertex; // vertex coordinates in view space \n" -" vec3 viewNormal; // vertex normal in view space \n" -" vec3 sunVector; // sun lighting vector (as reflecting away from vertex) \n" -" float sunFactor; // sun light projection along vertex normal (0.0 to 1.0) \n" -" vec3 halfway; \n" -" float specFactor; \n" -" \n" -" // Transform vertex \n" -" gl_Position = projectionMatrix * modelViewMatrix * gl_Vertex; \n" -" viewVertex = vec3(modelViewMatrix * gl_Vertex); \n" -" \n" -" /* \n" -" * Modulation \n" -" * \n" -" * Polygon color serves as material color (modulating the light intensity) \n" -" * for textured polygons. The fragment shader will ignore (overwrite) the \n" -" * the color passed to it if the fragment is textured. \n" -" * \n" -" * Untextured fragments must be set to the polygon color and the light \n" -" * intensity is initialized to 1.0 here. Alpha must be set to 1.0 because \n" -" * the fragment shader multiplies it by the polygon translucency setting. \n" -" * \n" -" * To-do: Does OpenGL set alpha to 1.0 by default if no alpha is specified \n" -" * for the vertex? If so, we can remove that line from here. \n" -" */ \n" -" \n" -" gl_FrontColor = gl_Color; // untextured polygons will use this \n" -" gl_FrontColor.a = 1.0; \n" -" fsLightIntensity = vec3(1.0,1.0,1.0); \n" -" if (texParams.x > 0.0) // textured \n" -" fsLightIntensity *= gl_Color.rgb; \n" -" \n" -" /* \n" -" * Sun Light \n" -" * \n" -" * Parallel light source and ambient lighting are only applied for non- \n" -" * luminous polygons. \n" -" */ \n" -" if (lightEnable > 0.5) // not luminous \n" -" { \n" -" // Normal -> view space \n" -" viewNormal = normalize(GetLinearPart(modelViewMatrix)*gl_Normal); \n" -" \n" -" // Real3D -> OpenGL view space convention (TO-DO: do this outside of shader) \n" -" sunVector = lighting[0]*vec3(1.0,-1.0,-1.0); \n" -" \n" -" // Compute diffuse factor for sunlight \n" -" sunFactor = max(dot(sunVector,viewNormal),0.0); \n" -" \n" -" // Total light intensity: sum of all components \n" -" fsLightIntensity *= (sunFactor*lighting[1].x+lighting[1].y); \n" -" } \n" -" \n" -" // Fog \n" -" float z = length(viewVertex); \n" -" fsFogFactor = clamp(1.0-fogIntensity*(gl_Fog.start+z*gl_Fog.density), 0.0, 1.0); \n" -" \n" -" // Pass viewspace Z coordinate (for spotlight) \n" -" fsViewZ = -viewVertex.z; // convert Z from GL->Real3D convention (want +Z to be further into screen) \n" -" \n" -" // Pass remaining parameters to fragment shader \n" -" gl_TexCoord[0] = gl_MultiTexCoord0; \n" -" fsSubTexture = subTexture; \n" -" fsTexParams = texParams; \n" -" fsTransLevel = transLevel; \n" -" fsTexFormat = texFormat; \n" +"\t// Pass remaining parameters to fragment shader\n" +"\tgl_TexCoord[0] = gl_MultiTexCoord0;\n" +"\tfsSubTexture = subTexture;\n" +"\tfsTexParams = texParams;\n" +"\tfsTransLevel = transLevel;\n" +"\tfsTexFormat = texFormat;\n" "}\n" }; @@ -180,194 +215,198 @@ static const char vertexShaderSource[] = // Fragment shader static const char fragmentShaderSource[] = { -"/** \n" -" ** Supermodel \n" -" ** A Sega Model 3 Arcade Emulator. \n" -" ** Copyright 2011 Bart Trzynadlowski \n" -" ** \n" -" ** This file is part of Supermodel. \n" -" ** \n" -" ** Supermodel is free software: you can redistribute it and/or modify it under \n" -" ** the terms of the GNU General Public License as published by the Free \n" -" ** Software Foundation, either version 3 of the License, or (at your option) \n" -" ** any later version. \n" -" ** \n" -" ** Supermodel is distributed in the hope that it will be useful, but WITHOUT \n" -" ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \n" -" ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for \n" -" ** more details. \n" -" ** \n" -" ** You should have received a copy of the GNU General Public License along \n" -" ** with Supermodel. If not, see . \n" -" **/ \n" -" \n" -"/* \n" -" * Fragment.glsl \n" -" * \n" -" * Fragment shader for 3D rendering. \n" -" */ \n" -" \n" -"#version 120 \n" -" \n" -"// Global uniforms \n" -"uniform sampler2D textureMap; // complete texture map, 2048x2048 texels \n" -"uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (normalized device coordinates), .y=Y position, .z=half-width, .w=half-height) \n" -"uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit \n" -"uniform vec3 spotColor; // spotlight RGB color \n" +"/**\n" +" ** Supermodel\n" +" ** A Sega Model 3 Arcade Emulator.\n" +" ** Copyright 2011 Bart Trzynadlowski, Nik Henson \n" +" **\n" +" ** This file is part of Supermodel.\n" +" **\n" +" ** Supermodel is free software: you can redistribute it and/or modify it under\n" +" ** the terms of the GNU General Public License as published by the Free \n" +" ** Software Foundation, either version 3 of the License, or (at your option)\n" +" ** any later version.\n" +" **\n" +" ** Supermodel is distributed in the hope that it will be useful, but WITHOUT\n" +" ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +" ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n" +" ** more details.\n" +" **\n" +" ** You should have received a copy of the GNU General Public License along\n" +" ** with Supermodel. If not, see .\n" +" **/\n" +" \n" +"/*\n" +" * Fragment.glsl\n" +" *\n" +" * Fragment shader for 3D rendering.\n" +" */\n" "\n" -"// Inputs from vertex shader \n" -"varying vec4 fsSubTexture; // .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels) \n" -"varying vec4 fsTexParams; // .x=texture enable (if 1, else 0), .y=use transparency (if > 0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode \n" -"varying float fsTexFormat; // .x=T1RGB5 contour texture (if > 0) \n" -"varying float fsTransLevel; // translucence level, 0.0 (transparent) to 1.0 (opaque) \n" -"varying vec3 fsLightIntensity; // lighting intensity \n" -"varying float fsFogFactor; // fog factor \n" -"varying float fsViewZ; // Z distance to fragment from viewpoint at origin \n" +"#version 120\n" "\n" -"/* \n" -" * WrapTexelCoords(): \n" -" * \n" -" * Computes the normalized OpenGL S,T coordinates within the 2048x2048 texture \n" -" * sheet, taking into account wrapping behavior. \n" -" * \n" -" * Computing normalized OpenGL texture coordinates (0 to 1) within the \n" -" * Real3D texture sheet: \n" -" * \n" -" * If the texture is not mirrored, we simply have to clamp the \n" -" * coordinates to fit within the texture dimensions, add the texture \n" -" * X, Y position to select the appropriate one, and normalize by 2048 \n" -" * (the dimensions of the Real3D texture sheet). \n" -" * \n" -" * = [(u,v)%(w,h)+(x,y)]/(2048,2048) \n" -" * \n" -" * If mirroring is enabled, textures are mirrored every odd multiple of \n" -" * the original texture. To detect whether we are in an odd multiple, \n" -" * simply divide the coordinate by the texture dimension and check \n" -" * whether the result is odd. Then, clamp the coordinates as before but \n" -" * subtract from the last texel to mirror them: \n" -" * \n" -" * = [M*((w-1,h-1)-(u,v)%(w,h)) + (1-M)*(u,v)%(w,h) + (x,y)]/(2048,2048) \n" -" * where M is 1.0 if the texture must be mirrored. \n" -" * \n" -" * As an optimization, this function computes TWO texture coordinates \n" -" * simultaneously. The first is texCoord.xy, the second is in .zw. The other \n" -" * parameters must have .xy = .zw. \n" -" */ \n" -"vec4 WrapTexelCoords(vec4 texCoord, vec4 texOffset, vec4 texSize, vec4 mirrorEnable) \n" -"{ \n" -" vec4 clampedCoord, mirror, glTexCoord; \n" -" \n" -" clampedCoord = mod(texCoord,texSize); // clamp coordinates to within texture size \n" -" mirror = mirrorEnable * mod(floor(texCoord/texSize),2.0); // whether this texel needs to be mirrored \n" -" \n" -" glTexCoord = ( mirror*(texSize-clampedCoord) + \n" -" (vec4(1.0,1.0,1.0,1.0)-mirror)*clampedCoord + \n" -" texOffset \n" -" ) / 2048.0; \n" -" return glTexCoord; \n" -"} \n" +"// Global uniforms\n" +"uniform sampler2D\ttextureMap;\t\t// complete texture map, 2048x2048 texels\n" +"uniform vec4\tspotEllipse;\t\t// spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height)\n" +"uniform vec2\tspotRange;\t\t\t// spotlight Z range: .x=start (viewspace coordinates), .y=limit\n" +"uniform vec3\tspotColor;\t\t\t// spotlight RGB color\n" +"uniform vec3\tlighting[2];\t\t// lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0)\n" "\n" -"/* \n" -" * main(): \n" -" * \n" -" * Fragment shader entry point. \n" -" */ \n" +"// Inputs from vertex shader \n" +"varying vec4\t\tfsSubTexture;\t// .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels)\n" +"varying vec4\t\tfsTexParams;\t// .x=texture enable (if 1, else 0), .y=use transparency (if > 0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode\n" +"varying float\t\tfsTexFormat;\t// T1RGB5 contour texture (if > 0)\n" +"varying float\t\tfsTransLevel;\t// translucence level, 0.0 (transparent) to 1.0 (opaque)\n" +"varying vec3\t\tfsLightIntensity;\t// lighting intensity \n" +"varying float\t\tfsSpecularTerm;\t// specular highlight\n" +"varying float\t\tfsFogFactor;\t// fog factor\n" +"varying float\t\tfsViewZ;\t\t// Z distance to fragment from viewpoint at origin\n" "\n" -"void main(void) \n" -"{ \n" -" vec4 uv_top, uv_bot, c[4]; \n" -" vec2 r; \n" -" vec4 fragColor; \n" -" vec2 ellipse; \n" -" vec3 lightIntensity; \n" -" float insideSpot; \n" -" \n" -" // Get polygon color for untextured polygons (textured polygons will overwrite) \n" -" if (fsTexParams.x==0.0) \n" -" fragColor = gl_Color; \n" -" else \n" -" // Textured polygons: set fragment color to texel value \n" -" { \n" -" /* \n" -" * Bilinear Filtering \n" -" * \n" -" * In order to get this working on ATI, the number of operations is \n" -" * reduced by putting everything into vec4s. uv_top holds the UV \n" -" * coordinates for the top two texels (.xy=left, .zw=right) and uv_bot \n" -" * is for the lower two. \n" -" */ \n" -" \n" -" // Compute fractional blending factor, r, and lower left corner of texel 0 \n" -" uv_bot.xy = gl_TexCoord[0].st-vec2(0.5,0.5); // move into the lower left blending texel \n" -" r = uv_bot.xy-floor(uv_bot.xy); // fractional part \n" -" uv_bot.xy = floor(uv_bot.xy); // integral part \n" -" \n" -" // Compute texel coordinates \n" -" uv_bot.xy += vec2(0.5,0.5); // offset to center of pixel (should not be needed but it fixes a lot of glitches, esp. on Nvidia) \n" -" uv_bot.zw = uv_bot.xy + vec2(1.0,0.0); // compute coordinates of the other three neighbors \n" -" uv_top = uv_bot + vec4(0.0,1.0,0.0,1.0); \n" -" \n" -" // Compute the properly wrapped texel coordinates \n" -" uv_top = WrapTexelCoords(uv_top,vec4(fsSubTexture.xy,fsSubTexture.xy),vec4(fsSubTexture.zw,fsSubTexture.zw), vec4(fsTexParams.zw,fsTexParams.zw)); \n" -" uv_bot = WrapTexelCoords(uv_bot,vec4(fsSubTexture.xy,fsSubTexture.xy),vec4(fsSubTexture.zw,fsSubTexture.zw), vec4(fsTexParams.zw,fsTexParams.zw)); \n" -" \n" -" // Fetch the texels \n" -" c[0]=texture2D(textureMap,uv_bot.xy); // bottom-left (base texel) \n" -" c[1]=texture2D(textureMap,uv_bot.zw); // bottom-right \n" -" c[2]=texture2D(textureMap,uv_top.xy); // top-left \n" -" c[3]=texture2D(textureMap,uv_top.zw); // top-right \n" -" \n" -" // Interpolate texels and blend result with material color to determine final (unlit) fragment color \n" -" // fragColor = (c[0]*(1.0-r.s)*(1.0-r.t) + c[1]*r.s*(1.0-r.t) + c[2]*(1.0-r.s)*r.t + c[3]*r.s*r.t); \n" -" // Faster method: \n" -" c[0] += (c[1]-c[0])*r.s; // 2 alu \n" -" c[2] += (c[3]-c[2])*r.s; // 2 alu \n" -" fragColor = c[0]+(c[2]-c[0])*r.t; // 2 alu \n" -" \n" -" /* \n" -" * T1RGB5: \n" -" * \n" -" * The transparency bit determines whether to discard pixels (if set). \n" -" * What is unknown is how this bit behaves when interpolated. OpenGL \n" -" * processes it as an alpha value, so it might concievably be blended \n" -" * with neighbors. Here, an arbitrary threshold is chosen. \n" -" * \n" -" * To-do: blending could probably enabled and this would work even \n" -" * better with a hard threshold. \n" -" * \n" -" * Countour processing also seems to be enabled for RGBA4 textures. \n" -" * When the alpha value is 0.0 (or close), pixels are discarded \n" -" * entirely. \n" -" */ \n" -" if (fsTexParams.y > 0.0) // contour processing enabled \n" -" { \n" -" if (fragColor.a < 0.01) // discard anything with alpha == 0 \n" -" discard; \n" -" } \n" -" \n" -" // If contour texture and not discarded, force alpha to 1.0 because will later be modified by polygon translucency \n" -" if (fsTexFormat > 0.0) // contour (T1RGB5) texture map \n" -" fragColor.a = 1.0; \n" -" } \n" -" \n" -" // Compute spotlight and apply lighting \n" -" ellipse = (gl_FragCoord.xy-spotEllipse.xy)/spotEllipse.zw; \n" -" insideSpot = dot(ellipse,ellipse); \n" -" if ((insideSpot <= 1.0) && (fsViewZ>=spotRange.x) && (fsViewZ 0.5)\t// contour processing enabled\n" +"\t\t{\n" +"\t\t\tif (fragColor.a < 0.01)\t// discard anything with alpha == 0\n" +"\t\t\t\tdiscard;\n" +"\t\t}\n" +"\t\t\n" +"\t\t// If contour texture and not discarded, force alpha to 1.0 because will later be modified by polygon translucency\n" +"\t\tif (fsTexFormat > 0.0)\t\t// contour (T1RGB5) texture map\n" +"\t\t\tfragColor.a = 1.0;\n" +"\t}\n" +"\n" +"\t// Compute spotlight and apply lighting\n" +"\tellipse = (gl_FragCoord.xy-spotEllipse.xy)/spotEllipse.zw;\n" +"\tinsideSpot = dot(ellipse,ellipse);\n" +"\tif ((insideSpot <= 1.0) && (fsViewZ>=spotRange.x) && (fsViewZ