# Initial work on fancy water.

Also, horizon height (skybox vertical offset) can now be set from the
console with renderer.horizonHeight.

This was SVN commit r3893.
This commit is contained in:
Matei 2006-05-25 05:46:17 +00:00
parent 965b4c9f92
commit f0615df318
8 changed files with 182 additions and 33 deletions

View File

@ -158,7 +158,7 @@ extern LibError LDR_NonprogressiveLoad();
#define LDR_CHECK_TIMEOUT(completed_jobs, total_jobs)\
if(get_time() > end_time)\
{\
int progress_percent = (completed_jobs*100 / total_jobs);\
int progress_percent = ((completed_jobs)*100 / (total_jobs));\
/* 0 means "finished", so don't return that! */\
if(progress_percent == 0)\
progress_percent = 1;\

View File

@ -1469,6 +1469,21 @@ void CRenderer::JSI_SetSky(JSContext* ctx, jsval newval)
m->skyManager.SetSkySet(skySet);
}
jsval CRenderer::JSI_GetHorizonHeight(JSContext*)
{
return ToJSVal(m->skyManager.m_HorizonHeight);
}
void CRenderer::JSI_SetHorizonHeight(JSContext* ctx, jsval newval)
{
float value;
if (!ToPrimitive<float>(ctx, newval, value))
return;
m->skyManager.m_HorizonHeight = value;
}
void CRenderer::ScriptingInit()
{
AddProperty(L"fastPlayerColor", &CRenderer::JSI_GetFastPlayerColor, &CRenderer::JSI_SetFastPlayerColor);
@ -1481,6 +1496,7 @@ void CRenderer::ScriptingInit()
AddProperty(L"disableCopyShadow", &CRenderer::m_DisableCopyShadow);
AddProperty(L"depthTextureBits", &CRenderer::JSI_GetDepthTextureBits, &CRenderer::JSI_SetDepthTextureBits);
AddProperty(L"skySet", &CRenderer::JSI_GetSky, &CRenderer::JSI_SetSky);
AddProperty(L"horizonHeight", &CRenderer::JSI_GetHorizonHeight, &CRenderer::JSI_SetHorizonHeight);
CJSObject<CRenderer>::ScriptingInit("Renderer");
}

View File

@ -331,6 +331,8 @@ protected:
void JSI_SetDepthTextureBits(JSContext* ctx, jsval newval);
jsval JSI_GetSky(JSContext*);
void JSI_SetSky(JSContext* ctx, jsval newval);
jsval JSI_GetHorizonHeight(JSContext*);
void JSI_SetHorizonHeight(JSContext* ctx, jsval newval);
static void ScriptingInit();
// patch rendering stuff

View File

@ -15,6 +15,8 @@
#include "lib/res/graphics/tex.h"
#include "lib/res/graphics/ogl_tex.h"
#include "maths/MathUtil.h"
#include "ps/CLogger.h"
#include "ps/Loader.h"
@ -22,6 +24,7 @@
#include "renderer/Renderer.h"
#include "graphics/Camera.h"
#include "graphics/LightEnv.h"
#define LOG_CATEGORY "graphics"
@ -50,6 +53,8 @@ SkyManager::SkyManager()
// TODO: add a way to set the initial skyset before progressive load
m_SkySet = L"default";
m_HorizonHeight = 0;
for (uint i = 0; i < ARRAY_SIZE(m_SkyTexture); i++)
m_SkyTexture[i] = 0;
@ -155,11 +160,15 @@ void SkyManager::RenderSky()
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Translate so we are at the camera in the X and Z directions,
// but put the horizon at Y=0 so it looks right when the camera is higher
// Translate so we are at the camera in the X and Z directions, but
// put the horizon at a fixed height regardless of camera Y
const CCamera& camera = g_Renderer.GetViewCamera();
CVector3D pos = camera.m_Orientation.GetTranslation();
glTranslatef( pos.X, 0.0f, pos.Z );
glTranslatef( pos.X, m_HorizonHeight, pos.Z );
// Rotate so that the "left" face, which contains the brightest part of each
// skymap, is in the direction of the sun from our light environment
glRotatef( 90.0f + g_Renderer.GetLightEnv().GetRotation()*180.0f/M_PI, 0.0f, 1.0f, 0.0f );
// Distance to draw the faces at
const float D = 2000.0;

View File

@ -20,6 +20,7 @@ class SkyManager
{
public:
bool m_RenderSky;
float m_HorizonHeight;
public:
SkyManager();

View File

@ -30,6 +30,8 @@
#include "renderer/TerrainRenderer.h"
#include "renderer/WaterManager.h"
#include "lib/res/graphics/ogl_shader.h"
///////////////////////////////////////////////////////////////////////////////////////////////
// TerrainRenderer implementation
@ -59,6 +61,9 @@ struct TerrainRendererInternals
* @todo Merge this list with CPatchRData list
*/
std::vector<CPatch*> visiblePatches;
/// Fancy water shader
Handle fancyWaterShader;
};
@ -69,10 +74,15 @@ TerrainRenderer::TerrainRenderer()
{
m = new TerrainRendererInternals();
m->phase = Phase_Submit;
m->fancyWaterShader = 0;
}
TerrainRenderer::~TerrainRenderer()
{
if( m->fancyWaterShader )
{
ogl_program_free( m->fancyWaterShader );
}
delete m;
}
@ -375,6 +385,14 @@ void TerrainRenderer::RenderWater()
{
PROFILE( "render water" );
bool fancy = g_Renderer.m_Options.m_FancyWater;
// If we're using fancy water, make sure its shader is loaded
if(fancy && !m->fancyWaterShader)
{
m->fancyWaterShader = ogl_program_load( "shaders/water_high.xml" );
//debug_printf("Loaded the water shader!!\n");
}
//(Crappy) fresnel effect
CCamera* Camera=g_Game->GetView()->GetCamera();
@ -384,15 +402,11 @@ void TerrainRenderer::RenderWater()
//Invert and set boundaries
FresnelScalar = (1 - FresnelScalar) * 0.4f + 0.6f;
const int DX[] = {1,1,0,0};
const int DZ[] = {0,1,1,0};
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
int mapSize = terrain->GetVerticesPerSide();
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_FALSE);
@ -401,27 +415,90 @@ void TerrainRenderer::RenderWater()
double period = 1.6;
int curTex = (int)(time*60/period) % 60;
ogl_tex_bind(WaterMgr->m_WaterTexture[curTex], 0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
float tx = -fmod(time, 20.0)/20.0;
float ty = fmod(time, 35.0)/35.0;
glTranslatef(tx, ty, 0);
if(fancy)
{
ogl_tex_bind(WaterMgr->m_NormalMap[curTex], 0);
}
else
{
ogl_tex_bind(WaterMgr->m_WaterTexture[curTex], 0);
}
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
if(!fancy)
{
// Shift the texture coordinates to make it "flow"
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
float tx = -fmod(time, 20.0)/20.0;
float ty = fmod(time, 35.0)/35.0;
glTranslatef(tx, ty, 0);
}
if(!fancy)
{
// Set up texture environment to multiply vertex RGB by texture RGB and use vertex alpha
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
else
{
// Temp stuff for testing
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
// Set the proper LOD bias
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
// Some offsets used to go around counterclockwise while keeping code concise
const int DX[] = {1,1,0,0};
const int DZ[] = {0,1,1,0};
GLint vertexDepth = 0; // water depth attribute, if using fancy water
if(fancy)
{
ogl_program_use( m->fancyWaterShader );
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
//SetAmbient(lightenv.m_TerrainAmbientColor);
//SetSunDir(lightenv.GetSunDir());
//SetSunColor(lightenv.m_SunColor);
GLint ambient = ogl_program_get_uniform_location( m->fancyWaterShader, "ambient" );
GLint sunDir = ogl_program_get_uniform_location( m->fancyWaterShader, "sunDir" );
GLint sunColor = ogl_program_get_uniform_location( m->fancyWaterShader, "sunColor" );
GLint shininess = ogl_program_get_uniform_location( m->fancyWaterShader, "shininess" );
GLint cameraPos = ogl_program_get_uniform_location( m->fancyWaterShader, "cameraPos" );
GLint normalMap = ogl_program_get_uniform_location( m->fancyWaterShader, "normalMap" );
pglUniform3fvARB( ambient, 1, &lightEnv.m_TerrainAmbientColor.X );
pglUniform3fvARB( sunDir, 1, &lightEnv.GetSunDir().X );
pglUniform3fvARB( sunColor, 1, &lightEnv.m_SunColor.X );
pglUniform1fARB( shininess, 200.0f );
pglUniform1iARB( normalMap, 0 ); // texture unit 0
const CCamera& camera = g_Renderer.GetViewCamera();
CVector3D camPos = camera.m_Orientation.GetTranslation();
pglUniform3fvARB( cameraPos, 1, &camPos.X );
vertexDepth = ogl_program_get_attrib_location( m->fancyWaterShader, "vertexDepth" );
}
float repeatFreq = (fancy ? 10.0f : 16.0f);
glBegin(GL_QUADS);
for(size_t i=0; i<m->visiblePatches.size(); i++)
@ -481,8 +558,13 @@ void TerrainRenderer::RenderWater()
}
}
if(fancy)
{
pglVertexAttrib1fARB( vertexDepth, WaterMgr->m_WaterHeight - terrainHeight );
}
glColor4f(WaterMgr->m_WaterColor.r*losMod, WaterMgr->m_WaterColor.g*losMod, WaterMgr->m_WaterColor.b*losMod, alpha * FresnelScalar);
pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/16.0f, vertZ/16.0f);
pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/repeatFreq, vertZ/repeatFreq);
glVertex3f(vertX, WaterMgr->m_WaterHeight, vertZ);
}
} //end of x loop
@ -490,6 +572,11 @@ void TerrainRenderer::RenderWater()
}
glEnd();
if(fancy)
{
ogl_program_use( 0 );
}
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glDepthMask(GL_TRUE);

View File

@ -50,7 +50,11 @@ WaterManager::WaterManager()
for (uint i = 0; i < ARRAY_SIZE(m_WaterTexture); i++)
m_WaterTexture[i] = 0;
for (uint i = 0; i < ARRAY_SIZE(m_NormalMap); i++)
m_NormalMap[i] = 0;
cur_loading_water_tex = 0;
cur_loading_normal_map = 0;
}
WaterManager::~WaterManager()
@ -65,29 +69,48 @@ WaterManager::~WaterManager()
int WaterManager::LoadWaterTextures()
{
const uint num_textures = ARRAY_SIZE(m_WaterTexture);
const uint num_normal_maps = ARRAY_SIZE(m_NormalMap);
// TODO: add a member variable and setter for this. (can't make this
// a parameter because this function is called via delay-load code)
static const char* const water_type = "default";
// yield after this time is reached. balances increased progress bar
// smoothness vs. slowing down loading.
const double end_time = get_time() + 100e-3;
char filename[PATH_MAX];
while (cur_loading_water_tex < num_textures)
{
char waterName[PATH_MAX];
// TODO: add a member variable and setter for this. (can't make this
// a parameter because this function is called via delay-load code)
static const char* const water_type = "animation2";
snprintf(waterName, ARRAY_SIZE(waterName), "art/textures/terrain/types/water/%s/water%02d.dds", water_type, cur_loading_water_tex+1);
Handle ht = ogl_tex_load(waterName);
snprintf(filename, ARRAY_SIZE(filename), "art/textures/animated/water/%s/diffuse%02d.dds",
water_type, cur_loading_water_tex+1);
Handle ht = ogl_tex_load(filename);
if (ht <= 0)
{
LOG(ERROR, LOG_CATEGORY, "LoadWaterTextures failed on \"%s\"", waterName);
LOG(ERROR, LOG_CATEGORY, "LoadWaterTextures failed on \"%s\"", filename);
return ht;
}
m_WaterTexture[cur_loading_water_tex] = ht;
RETURN_ERR(ogl_tex_upload(ht));
cur_loading_water_tex++;
LDR_CHECK_TIMEOUT(cur_loading_water_tex, num_textures);
LDR_CHECK_TIMEOUT(cur_loading_water_tex, num_textures + num_normal_maps);
}
while (cur_loading_normal_map < num_normal_maps)
{
snprintf(filename, ARRAY_SIZE(filename), "art/textures/animated/water/%s/normal%02d.dds",
water_type, cur_loading_normal_map+1);
Handle ht = ogl_tex_load(filename);
if (ht <= 0)
{
LOG(ERROR, LOG_CATEGORY, "LoadWaterTextures failed on \"%s\"", filename);
return ht;
}
m_NormalMap[cur_loading_normal_map] = ht;
RETURN_ERR(ogl_tex_upload(ht));
cur_loading_normal_map++;
LDR_CHECK_TIMEOUT(num_textures + cur_loading_normal_map, num_textures + num_normal_maps);
}
return 0;
@ -103,5 +126,14 @@ void WaterManager::UnloadWaterTextures()
ogl_tex_free(m_WaterTexture[i]);
m_WaterTexture[i] = 0;
}
for(uint i = 0; i < ARRAY_SIZE(m_NormalMap); i++)
{
ogl_tex_free(m_NormalMap[i]);
m_NormalMap[i] = 0;
}
cur_loading_water_tex = 0; // so they will be reloaded if LoadWaterTextures is called again
cur_loading_normal_map = 0;
}

View File

@ -23,6 +23,7 @@ class WaterManager
{
public:
Handle m_WaterTexture[60];
Handle m_NormalMap[60];
int m_WaterCurrentTex;
CColor m_WaterColor;
bool m_RenderWater;
@ -62,6 +63,7 @@ public:
private:
/// State of progressive loading (in # of loaded textures)
uint cur_loading_water_tex;
uint cur_loading_normal_map;
};