1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 02:12:45 +01:00

Primitive water rendering

This commit is contained in:
Daniel Evans 2014-06-08 19:04:47 +01:00
parent ad6eda9024
commit 208a2a9897
5 changed files with 117 additions and 45 deletions

View File

@ -229,10 +229,22 @@ public:
*/
std::map<std::string, std::shared_ptr<DynamicObjectData>> dynamicObjectData;
/**
* Water Rectangles
* @struct WaterArea
* Stores Water Rectangle Information
*/
std::vector<RWTypes::WaterRect> waterRects;
struct WaterArea
{
float height;
float xLeft, yBottom;
float xRight, yTop;
};
/**
* Water Areas
*/
std::vector<WaterArea> waterBlocks;
/**
* Water heights

View File

@ -46,16 +46,6 @@ struct RGBA
uint8_t r, g, b, a;
};
/**
* @struct WaterRect
* Rectangle with water information
*/
struct WaterRect
{
float height;
float xLeft, yBottom;
float xRight, yTop;
};
}
#endif

View File

@ -59,12 +59,13 @@ public:
GLint uniMatDiffuse, uniMatAmbient, uniFogStart, uniFogEnd;
GLuint worldProgram;
GLuint skyProgram;
GLuint waterProgram, waterMVP, waterHeight, waterTexture, waterSize;
GLint skyUniView, skyUniProj, skyUniTop, skyUniBottom;
/// Internal VAO to avoid clobbering global state.
GLuint vao, debugVAO;
GLuint planeVBO, skydomeVBO, skydomeIBO, debugVBO;
GLuint skydomeVBO, skydomeIBO, debugVBO;
GLuint debugTex;
/**

View File

@ -347,12 +347,13 @@ void GameData::loadWaterpro(const std::string& path)
std::ifstream ifstr(path.c_str());
if(ifstr.is_open()) {
uint32_t numlevels;
uint32_t numlevels;
ifstr.read(reinterpret_cast<char*>(&numlevels), sizeof(uint32_t));
ifstr.read(reinterpret_cast<char*>(&waterHeights), sizeof(float)*48);
ifstr.seekg(0x03C4);
ifstr.read(reinterpret_cast<char*>(&visibleWater), sizeof(float)*64*64);
ifstr.read(reinterpret_cast<char*>(&realWater), sizeof(float)*128*128);
}
}
@ -377,7 +378,7 @@ void GameData::loadWater(const std::string& path)
fc = atof(c.c_str());
fd = atof(d.c_str());
fe = atof(e.c_str());
waterRects.push_back({
waterBlocks.push_back({
fa,
fb,
fc,

View File

@ -80,30 +80,51 @@ const char *skydomeFragmentShaderSource = "#version 130\n"
"}";
const size_t skydomeSegments = 8, skydomeRows = 10;
struct WaterVertex {
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 2, sizeof(WaterVertex), 0ul}
};
}
float planedata[] = {
// Vertices
1.0f, 1.0f, 0.f,
-0.0f, 1.0f, 0.f,
1.0f,-0.0f, 0.f,
-0.0f,-0.0f, 0.f,
// UV coords
1.f, 1.f,
0.f, 1.f,
1.f, 0.f,
0.f, 0.f,
// Normals
0.f, 0.f, 1.f,
0.f, 0.f, 1.f,
0.f, 0.f, 1.f,
0.f, 0.f, 1.f,
// Colours
1.f, 1.f, 1.f,
1.f, 1.f, 1.f,
1.f, 1.f, 1.f,
1.f, 1.f, 1.f
float x, y;
};
std::vector<WaterVertex> planeVerts = {
{1.0f, 1.0f},
{0.0f, 1.0f},
{1.0f,-0.0f},
{0.0f,-0.0f}
};
GeometryBuffer waterBuffer;
DrawBuffer waterDraw;
const char *waterVSSource = R"(
#version 130
#extension GL_ARB_explicit_attrib_location : enable
layout(location = 0) in vec2 position;
out vec2 TexCoords;
uniform float height;
uniform float size;
uniform mat4 MVP;
void main()
{
TexCoords = position;
gl_Position = MVP * vec4(position * size, height, 1.0);
})";
const char *waterFSSource = R"(
#version 130
in vec3 Normal;
in vec2 TexCoords;
uniform sampler2D texture;
void main() {
vec4 c = texture2D(texture, TexCoords);
gl_FragColor = c;
})";
GLuint compileShader(GLenum type, const char *source)
{
GLuint shader = glCreateShader(type);
@ -118,7 +139,7 @@ GLuint compileShader(GLenum type, const char *source)
GLchar *buffer = new GLchar[len];
glGetShaderInfoLog(shader, len, NULL, buffer);
std::cerr << "ERROR compiling shader: " << buffer << std::endl;
std::cerr << "ERROR compiling shader: " << buffer << "\nSource: " << source << std::endl;
delete[] buffer;
exit(1);
}
@ -162,11 +183,22 @@ GameRenderer::GameRenderer(GameWorld* engine)
skyUniBottom = glGetUniformLocation(skyProgram, "BottomColor");
glGenVertexArrays( 1, &vao );
// prepare our special internal plane.
glGenBuffers(1, &planeVBO);
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(planedata), planedata, GL_STATIC_DRAW);
// Upload water plane
waterBuffer.uploadVertices(planeVerts);
waterDraw.addGeometry(&waterBuffer);
waterDraw.setFaceType(GL_TRIANGLE_STRIP);
GLuint waterVS = compileShader(GL_VERTEX_SHADER, waterVSSource);
GLuint waterFS = compileShader(GL_FRAGMENT_SHADER, waterFSSource);
waterProgram = glCreateProgram();
glAttachShader(waterProgram, waterVS);
glAttachShader(waterProgram, waterFS);
glLinkProgram(waterProgram);
waterHeight = glGetUniformLocation(waterProgram, "height");
waterTexture = glGetUniformLocation(waterProgram, "texture");
waterSize = glGetUniformLocation(waterProgram, "size");
waterMVP = glGetUniformLocation(waterProgram, "MVP");
// And our skydome while we're at it.
glGenBuffers(1, &skydomeVBO);
@ -212,6 +244,11 @@ float mix(uint8_t a, uint8_t b, float num)
return a+(b-a)*num;
}
#define GL_PLS() \
{ auto errc = glGetError(); \
if(errc != GL_NO_ERROR) std::cout << __LINE__ << ": " << errc << std::endl;\
}
void GameRenderer::renderWorld(float alpha)
{
_renderAlpha = alpha;
@ -369,7 +406,38 @@ void GameRenderer::renderWorld(float alpha)
renderSubgeometry(it->model, it->g, it->sg, it->matrix, it->object, false);
}
transparentDrawQueue.clear();
// Draw the water.
glBindVertexArray( waterDraw.getVAOName() );
glUseProgram( waterProgram );
// TODO: label all the variables!
#define NO_WATER_INDEX 48
glm::mat4 waterModel;
glUniform1i(waterTexture, 0);
float blockSize = 4096.f/64.f;
auto waterTex = engine->gameData.textures["water_old"];
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, waterTex.texName);
// TODO: high / low quality water. Projected grid?
for( int x = 0; x < 64; x++ ) {
for( int y = 0; y < 64; y++ ) {
int i = (x*64) + y;
int hI = engine->gameData.visibleWater[i];
if( hI >= NO_WATER_INDEX ) continue;
float h = engine->gameData.waterHeights[hI];
waterModel = glm::mat4();
waterModel = glm::translate(waterModel, {-2048.f + x * blockSize, -2048.f + y * blockSize, 0.f});
glUniform1f(waterSize, blockSize);
glUniform1f(waterHeight, h);
auto MVP = proj * view * waterModel;
glUniformMatrix4fv(waterMVP, 1, GL_FALSE, glm::value_ptr(MVP));
glDrawArrays(waterDraw.getFaceType(), 0, 4);
}
}
glBindVertexArray( vao );
glUseProgram(skyProgram);
@ -382,8 +450,8 @@ void GameRenderer::renderWorld(float alpha)
glUniformMatrix4fv(skyUniProj, 1, GL_FALSE, glm::value_ptr(proj));
glUniform4f(skyUniTop, skyTop.r, skyTop.g, skyTop.b, 1.f);
glUniform4f(skyUniBottom, skyBottom.r, skyBottom.g, skyBottom.b, 1.f);
glDrawElements(GL_TRIANGLES, skydomeSegments * skydomeRows * 6, GL_UNSIGNED_SHORT, NULL);
glDrawElements(GL_TRIANGLES, skydomeSegments * skydomeRows * 6, GL_UNSIGNED_SHORT, NULL);
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);