1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-15 15:02:34 +02:00

Improve map rendering, UI viewport

+ UI Viewport is now window sized
+ Map renderer now supports rotating
This commit is contained in:
Daniel Evans 2015-02-15 01:41:24 +00:00
parent 2344024f08
commit 9855bf2967
8 changed files with 150 additions and 88 deletions

View File

@ -14,18 +14,22 @@ public:
struct MapInfo
{
glm::vec2 viewport;
float scale;
float scale = 1.f;
/// World coordinate center
glm::vec2 center;
/// yaw of the map
float rotation = 0.f;
glm::vec2 mapSize;
glm::vec2 mapPos;
/// Top of the map on the screen
glm::vec2 mapScreenBottom;
/// Bottom of the map on the screen
glm::vec2 mapScreenTop;
};
MapRenderer(GameWorld* world, Renderer* renderer);
glm::vec2 worldToMap(const glm::vec2& coord);
glm::vec2 mapToScreen(const glm::vec2& map, const MapInfo& mi);
glm::vec2 sizeOnScreen(const glm::vec2& map, const MapInfo& mi);
void draw(const MapInfo& mi);
@ -38,5 +42,5 @@ private:
Renderer::ShaderProgram* rectProg;
void drawBlip(const glm::vec2& map, const MapInfo& mi, const std::string& texture);
void drawBlip(const glm::vec2& map, const glm::mat4& model, const MapInfo& mi, const std::string& texture, float heading = 0.f);
};

View File

@ -90,15 +90,16 @@ public:
virtual void draw(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) = 0;
virtual void drawArrays(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) = 0;
void setViewport(const glm::ivec2& vp) { viewport = vp; }
void setViewport(const glm::ivec2& vp);
const glm::ivec2& getViewport() const { return viewport; }
glm::mat4 get2DProjection() const;
const glm::mat4& get2DProjection() const { return projection2D; }
virtual void invalidate() = 0;
private:
glm::ivec2 viewport;
glm::mat4 projection2D;
};
class OpenGLRenderer : public Renderer

View File

@ -257,6 +257,10 @@ void GameRenderer::renderWorld(const ViewCamera &camera, float alpha)
// Store the input camera,
_camera = camera;
// Set the viewport
const glm::ivec2& vp = getRenderer()->getViewport();
glViewport(0, 0, vp.x, vp.y);
glBindVertexArray( vao );

View File

@ -4,75 +4,119 @@
#include <ai/PlayerController.hpp>
#include <objects/CharacterObject.hpp>
const char* MapVertexShader = R"(
#version 130
#extension GL_ARB_explicit_attrib_location : enable
#extension GL_ARB_uniform_buffer_object : enable
layout(location = 0) in vec2 position;
out vec2 TexCoord;
uniform mat4 proj;
uniform mat4 view;
uniform mat4 model;
void main()
{
gl_Position = proj * view * model * vec4(position, 0.0, 1.0);
// UI space is top to bottom, so flip Y.
TexCoord = position + vec2( 0.5 );
})";
const char* MapFragmentShader = R"(
#version 130
in vec2 TexCoord;
uniform vec4 colour;
uniform sampler2D spriteTexture;
out vec4 outColour;
void main()
{
vec4 c = texture(spriteTexture, TexCoord);
outColour = colour + c;
})";
MapRenderer::MapRenderer(GameWorld* world, Renderer* renderer)
: world( world ), renderer(renderer)
{
rectGeom.uploadVertices<VertexP2>({
{-1.f, -1.f},
{ 1.f, -1.f},
{-1.f, 1.f},
{ 1.f, 1.f}
{-.5f, .5f},
{ .5f, .5f},
{-.5f, -.5f},
{ .5f, -.5f}
});
rect.addGeometry(&rectGeom);
rect.setFaceType(GL_TRIANGLE_STRIP);
rectProg = renderer->createShader(
GameShaders::ScreenSpaceRect::VertexShader,
GameShaders::ScreenSpaceRect::FragmentShader
MapVertexShader,
MapFragmentShader
);
renderer->setUniform(rectProg, "colour", glm::vec4(1.f));
renderer->setUniform(rectProg, "size", glm::vec2(1.f, 1.f));
renderer->setUniform(rectProg, "offset", glm::vec2(1.f, 1.f));
}
#define GAME_MAP_SIZE 4000
glm::vec2 MapRenderer::mapToScreen(const glm::vec2& map, const MapInfo& mi)
glm::vec2 MapRenderer::worldToMap(const glm::vec2& coord)
{
glm::vec2 screenSize = ((map-mi.center) * mi.scale) / mi.viewport;
glm::vec2 screenCenter = mi.mapPos / (mi.viewport/2.f) - 1.f;
return screenSize + screenCenter;
return glm::vec2(coord.x, -coord.y);
}
glm::vec2 MapRenderer::sizeOnScreen(const glm::vec2& map, const MapRenderer::MapInfo& mi)
glm::vec2 MapRenderer::mapToScreen(const glm::vec2& map, const MapInfo& mi)
{
glm::vec2 screenSize = ((map) * mi.scale) / mi.viewport;
return screenSize;
glm::vec2 screenSize = ((map-mi.center) * mi.scale);
glm::vec2 screenCenter(500.f, 500.f);
return screenSize + screenCenter;
}
void MapRenderer::draw(const MapInfo& mi)
{
const glm::vec2& viewport = mi.viewport;
const glm::vec2& offset = -mi.center;
renderer->useProgram(rectProg);
glm::vec2 bottom = glm::min(mi.mapScreenBottom, mi.mapScreenTop);
glm::vec2 top = glm::max(mi.mapScreenBottom, mi.mapScreenTop);
glm::vec2 screenPos = (bottom+top)/2.f;
glm::vec2 scissorSize = top - bottom;
const glm::ivec2& vp = renderer->getViewport();
glEnable(GL_SCISSOR_TEST);
glScissor(bottom.x, vp.y - bottom.y - scissorSize.y, scissorSize.x, scissorSize.y);
auto proj = renderer->get2DProjection();
glm::mat4 view, model;
view = glm::translate(view, glm::vec3(screenPos, 0.f));
view = glm::scale(view, glm::vec3(mi.scale));
model = glm::rotate(model, mi.rotation, glm::vec3(0.f, 0.f, 1.f));
model = glm::translate(model, glm::vec3(-worldToMap(mi.center), 0.f));
renderer->setUniform(rectProg, "view", view);
renderer->setUniform(rectProg, "proj", proj);
glm::vec2 worldSize(GAME_MAP_SIZE);
const int mapBlockLine = 8;
glm::vec2 tileSize = worldSize / (float)mapBlockLine;
glm::vec2 tileScreenSize = sizeOnScreen(tileSize, mi);
glm::vec2 basePos = mi.mapPos - (mi.mapSize/2.f);
glEnable(GL_SCISSOR_TEST);
glScissor(basePos.x, basePos.y, mi.mapSize.x, mi.mapSize.y);
glBindVertexArray( rect.getVAOName() );
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
renderer->setUniformTexture(rectProg, "spriteTexture", 0);
glm::mat4 bg = glm::scale( model, glm::vec3( glm::vec2( worldSize ), 1.f ) );
// Draw backdrop
renderer->setUniform(rectProg, "size", sizeOnScreen(worldSize/2.f, mi));
renderer->setUniform(rectProg, "model", bg);
renderer->setUniform(rectProg, "colour", glm::vec4(0.0f, 0.0f, 0.0f, 1.f));
renderer->setUniform(rectProg, "offset", mapToScreen(glm::vec2(0.f, 0.f), mi));
glBindTexture(GL_TEXTURE_2D, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// 2048, -2048
renderer->setUniform(rectProg, "size", tileScreenSize/2.f);
renderer->setUniform(rectProg, "colour", glm::vec4(0.0f, 0.0f, 0.0f, 0.f));
renderer->setUniform(rectProg, "colour", glm::vec4(0.f));
int initX = -(mapBlockLine/2);
int initY = (mapBlockLine/2);
int initY = -(mapBlockLine/2);
for( int m = 0; m < MAP_BLOCK_SIZE; ++m )
{
std::string num = (m < 10 ? "0" : "");
@ -80,21 +124,25 @@ void MapRenderer::draw(const MapInfo& mi)
auto texture = world->gameData.textures[{name,""}];
glBindTexture(GL_TEXTURE_2D, texture.texName);
renderer->setUniformTexture(rectProg, "texture", 0);
int mX = initX + (m % mapBlockLine);
int mY = initY - (m / mapBlockLine);
auto tc = glm::vec2(mX, mY) * tileSize + (glm::vec2(tileSize.x,-tileSize.y)/2.f);
int mY = initY + (m / mapBlockLine);
auto screen = mapToScreen(tc, mi);
auto tc = glm::vec2(mX, mY) * tileSize + glm::vec2(tileSize/2.f);
renderer->setUniform(rectProg, "offset", screen);
glm::mat4 tilemodel = model;
tilemodel = glm::translate( tilemodel, glm::vec3( tc, 0.f ) );
tilemodel = glm::scale( tilemodel, glm::vec3( tileSize, 1.f ) );
renderer->setUniform(rectProg, "model", tilemodel);
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
}
glDisable(GL_SCISSOR_TEST);
renderer->setUniform(rectProg, "view", view);
for(auto& blip : world->state.radarBlips)
{
glm::vec2 blippos( blip.second.coord );
@ -103,7 +151,7 @@ void MapRenderer::draw(const MapInfo& mi)
blippos = glm::vec2( blip.second.target->getPosition() );
}
drawBlip(blippos, mi, "");
drawBlip(blippos, model, mi, "");
}
// Draw the player blip
@ -111,41 +159,52 @@ void MapRenderer::draw(const MapInfo& mi)
if( player )
{
glm::vec2 plyblip(player->getCharacter()->getPosition());
drawBlip(plyblip, mi, "radar_centre");
float hdg = glm::roll(player->getCharacter()->getRotation());
drawBlip(plyblip, model, mi, "radar_centre", hdg);
}
glBindVertexArray( 0 );
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
/// @TODO migrate to using the renderer
renderer->invalidate();
}
void MapRenderer::drawBlip(const glm::vec2& map, const MapInfo& mi, const std::string& texture)
void MapRenderer::drawBlip(const glm::vec2& coord, const glm::mat4& model, const MapInfo& mi, const std::string& texture, float heading)
{
glm::vec2 screen = mapToScreen(map, mi);
auto relPos = glm::vec2( model * glm::vec4( worldToMap(coord), 0.f, 1.f ) );
glm::vec2 screenCenter = mi.mapPos / (mi.viewport/2.f) - 1.f;
glm::vec2 screenSize = (mi.mapSize) / mi.viewport;
glm::vec2 screenMax = screenCenter + screenSize;
glm::vec2 screenMin = screenCenter - screenSize;
// Now that relPos is relative to the rotation of the map, we can clip it.
float invScale = 1.f/mi.scale;
glm::vec2 mapCenter( (mi.mapScreenTop + mi.mapScreenBottom) / 2.f );
glm::vec2 mapMin( (mi.mapScreenBottom - mapCenter) );
glm::vec2 mapMax( (mi.mapScreenTop - mapCenter) );
screen = glm::max(screen, screenMin);
screen = glm::min(screen, screenMax);
relPos = glm::max( mapMin * invScale, glm::min( mapMax * invScale, relPos ) );
glm::vec2 map = glm::vec2( glm::inverse(model) * glm::vec4( relPos, 0.f, 1.f ) );
glm::mat4 m = model;
m = glm::translate(m, glm::vec3(map, 0.f));
m = glm::scale(m, glm::vec3(16.f * 1.f/mi.scale));
m = glm::rotate(m, heading, glm::vec3(0.f, 0.f, -1.f));
renderer->setUniform(rectProg, "model", m);
GLuint tex = 0;
if ( !texture.empty() )
{
auto sprite= world->gameData.textures[{texture,""}];
tex = sprite.texName;
renderer->setUniform(rectProg, "colour", glm::vec4(0.0f, 0.0f, 0.0f, 0.f));
renderer->setUniform(rectProg, "colour", glm::vec4(0.f));
}
else
{
renderer->setUniform(rectProg, "colour", glm::vec4(1.0f, 1.0f, 1.0f, 1.f));
}
glBindTexture(GL_TEXTURE_2D, tex);
renderer->setUniform(rectProg, "size", 16.f/mi.viewport);
renderer->setUniform(rectProg, "offset", screen);
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
}

View File

@ -80,20 +80,11 @@ GLuint compileProgram(const char* vertex, const char* fragment)
return prog;
}
glm::mat4 Renderer::get2DProjection() const
void Renderer::setViewport(const glm::ivec2& vp)
{
glm::vec2 aspect(1.f, 1.f);
if( viewport.x > viewport.y )
{
// Widescreen
aspect.x = viewport.x / (float) viewport.y;
}
else
{
// Tall-o-vision
aspect.y = viewport.y / (float)viewport.x;
}
return glm::ortho(0.f, 800.f * aspect.x, 600.f * aspect.y, 0.f, -1.f, 1.f);
viewport = vp;
projection2D = glm::ortho(0.f, (float)viewport.x, (float)viewport.y, 0.f, -1.f, 1.f);
}
void OpenGLRenderer::useDrawBuffer(DrawBuffer* dbuff)

View File

@ -191,7 +191,7 @@ void IngameState::draw(GameRenderer* r)
{
if( !getWorld()->state.isCinematic && getWorld()->isCutsceneDone() )
{
drawHUD(getWindow());
drawHUD(r);
}
State::draw(r);
@ -299,17 +299,25 @@ const ViewCamera &IngameState::getCamera()
return _look;
}
void IngameState::drawHUD(const sf::RenderWindow& w)
void IngameState::drawHUD(GameRenderer* renderer)
{
MapRenderer::MapInfo map;
map.scale = 0.5f;
map.viewport = glm::vec2(w.getSize().x, w.getSize().y);
map.scale = 0.4f;
map.mapPos = glm::vec2(map.viewport.x * 0.2f, map.viewport.y * 0.2f);
float aspect = map.viewport.x / map.viewport.y;
map.mapSize = map.viewport * 0.3f;
map.mapPos.x /= aspect;
map.mapSize.x /= aspect;
glm::quat plyRot;
if( getPlayer() )
{
auto p = getPlayer();
plyRot = p->getCharacter()->getRotation();
}
map.rotation = glm::roll(plyRot);
const glm::ivec2& vp = renderer->getRenderer()->getViewport();
map.mapScreenTop = glm::vec2(260.f, vp.y - 10.f);
map.mapScreenBottom = glm::vec2(10.f, vp.y - 210.f);
if( getWorld()->state.player )
{

View File

@ -31,7 +31,7 @@ public:
const ViewCamera& getCamera();
private:
void drawHUD(const sf::RenderWindow& w);
void drawHUD(GameRenderer* r);
};
#endif // INGAMESTATE_HPP

View File

@ -33,17 +33,12 @@ void PauseState::draw(GameRenderer* r)
{
MapRenderer::MapInfo map;
auto& w = getWindow();
auto& vp = r->getRenderer()->getViewport();
map.scale = 0.25f;
map.viewport = glm::vec2(w.getSize().x, w.getSize().y);
map.mapSize = map.viewport;
map.mapPos = map.viewport / 2.f;
map.scale = 0.2f;
map.mapScreenTop = glm::vec2(vp.x, vp.y);
map.mapScreenBottom = glm::vec2(0.f, 0.f);
if( getWorld()->state.player )
{
map.center = glm::vec2(getWorld()->state.player->getCharacter()->getPosition());
}
getWorld()->renderer.map.draw(map);
State::draw(r);