MegaGlest/source/glest_game/graphics/renderer.cpp
Mark Vejvoda e06639c78d - updated Internet games to use 2 new fields, country and game status.
for now svn users can edit glestuser.ini and add the following entry (pointing to your folder of course) to see the country flags in game:
CountryTexturePath=/home/softcoder/Code/megaglest/trunk/source/masterserver/flags
2011-01-25 07:41:12 +00:00

4802 lines
138 KiB
C++

// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2008 Martio Figueroa
//
// You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "renderer.h"
#include "texture_gl.h"
#include "main_menu.h"
#include "config.h"
#include "components.h"
#include "time_flow.h"
#include "graphics_interface.h"
#include "object.h"
#include "core_data.h"
#include "game.h"
#include "metrics.h"
#include "opengl.h"
#include "faction.h"
#include "factory_repository.h"
#include <cstdlib>
#include <algorithm>
#include "cache_manager.h"
#include "network_manager.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
using namespace Shared::Graphics::Gl;
using namespace Shared::Util;
using namespace Shared::Graphics;
namespace Glest { namespace Game{
// =====================================================
// class MeshCallbackTeamColor
// =====================================================
bool MeshCallbackTeamColor::noTeamColors = false;
void MeshCallbackTeamColor::execute(const Mesh *mesh) {
//team color
if( mesh->getCustomTexture() && teamTexture != NULL &&
MeshCallbackTeamColor::noTeamColors == false) {
//texture 0
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
//set color to interpolation
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
//set alpha to 1
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
//texture 1
glActiveTexture(GL_TEXTURE1);
glMultiTexCoord2f(GL_TEXTURE1, 0.f, 0.f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(teamTexture)->getHandle());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
//set alpha to 1
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
}
else {
glActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
}
// ===========================================================
// class Renderer
// ===========================================================
// ===================== PUBLIC ========================
const int Renderer::maxProgressBar= 100;
const Vec4f Renderer::progressBarBack1= Vec4f(0.7f, 0.7f, 0.7f, 0.7f);
const Vec4f Renderer::progressBarBack2= Vec4f(0.7f, 0.7f, 0.7f, 1.f);
const Vec4f Renderer::progressBarFront1= Vec4f(0.f, 0.5f, 0.f, 1.f);
const Vec4f Renderer::progressBarFront2= Vec4f(0.f, 0.1f, 0.f, 1.f);
const float Renderer::sunDist= 10e6;
const float Renderer::moonDist= 10e6;
const float Renderer::lightAmbFactor= 0.4f;
const int Renderer::maxMouse2dAnim= 100;
const GLenum Renderer::baseTexUnit= GL_TEXTURE0;
const GLenum Renderer::fowTexUnit= GL_TEXTURE1;
const GLenum Renderer::shadowTexUnit= GL_TEXTURE2;
const float Renderer::selectionCircleRadius= 0.7f;
const float Renderer::magicCircleRadius= 1.f;
//perspective values
const float Renderer::perspFov= 60.f;
const float Renderer::perspNearPlane= 1.f;
//const float Renderer::perspFarPlane= 50.f;
const float Renderer::perspFarPlane= 1000.f;
const float Renderer::ambFactor= 0.7f;
const Vec4f Renderer::fowColor= Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
const Vec4f Renderer::defSpecularColor= Vec4f(0.8f, 0.8f, 0.8f, 1.f);
const Vec4f Renderer::defDiffuseColor= Vec4f(1.f, 1.f, 1.f, 1.f);
const Vec4f Renderer::defAmbientColor= Vec4f(1.f * ambFactor, 1.f * ambFactor, 1.f * ambFactor, 1.f);
const Vec4f Renderer::defColor= Vec4f(1.f, 1.f, 1.f, 1.f);
//const float Renderer::maxLightDist= 100.f;
const float Renderer::maxLightDist= 1000.f;
const int MIN_FPS_NORMAL_RENDERING = 15;
const int MIN_FPS_NORMAL_RENDERING_TOP_THRESHOLD = 25;
// ==================== constructor and destructor ====================
Renderer::Renderer() {
this->allowRenderUnitTitles = false;
this->menu = NULL;
this->game = NULL;
showDebugUI = false;
modelRenderer = NULL;
textRenderer = NULL;
particleRenderer = NULL;
saveScreenShotThread = NULL;
lastRenderFps=MIN_FPS_NORMAL_RENDERING;
shadowsOffDueToMinRender=false;
//resources
for(int i=0; i < rsCount; ++i) {
modelManager[i] = NULL;
textureManager[i] = NULL;
particleManager[i] = NULL;
fontManager[i] = NULL;
}
GraphicsInterface &gi= GraphicsInterface::getInstance();
FactoryRepository &fr= FactoryRepository::getInstance();
Config &config= Config::getInstance();
this->no2DMouseRendering = config.getBool("No2DMouseRendering","false");
this->maxConsoleLines= config.getInt("ConsoleMaxLines");
gi.setFactory(fr.getGraphicsFactory(config.getString("FactoryGraphics")));
GraphicsFactory *graphicsFactory= GraphicsInterface::getInstance().getFactory();
modelRenderer= graphicsFactory->newModelRenderer();
textRenderer= graphicsFactory->newTextRenderer2D();
particleRenderer= graphicsFactory->newParticleRenderer();
//resources
for(int i=0; i< rsCount; ++i) {
modelManager[i]= graphicsFactory->newModelManager();
textureManager[i]= graphicsFactory->newTextureManager();
modelManager[i]->setTextureManager(textureManager[i]);
particleManager[i]= graphicsFactory->newParticleManager();
fontManager[i]= graphicsFactory->newFontManager();
}
saveScreenShotThread = new SimpleTaskThread(this,0,25);
saveScreenShotThread->setUniqueID(__FILE__);
saveScreenShotThread->start();
}
Renderer::~Renderer() {
delete modelRenderer;
modelRenderer = NULL;
delete textRenderer;
textRenderer = NULL;
delete particleRenderer;
particleRenderer = NULL;
//resources
for(int i=0; i<rsCount; ++i){
delete modelManager[i];
modelManager[i] = NULL;
delete textureManager[i];
textureManager[i] = NULL;
delete particleManager[i];
particleManager[i] = NULL;
delete fontManager[i];
fontManager[i] = NULL;
}
// Wait for the queue to become empty or timeout the thread at 7 seconds
for(time_t elapsed = time(NULL);
getSaveScreenQueueSize() > 0 && difftime(time(NULL),elapsed) <= 7;) {
sleep(10);
}
delete saveScreenShotThread;
saveScreenShotThread = NULL;
if(getSaveScreenQueueSize() > 0) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d] FORCING MEMORY CLEANUP and NOT SAVING screenshots, saveScreenQueue.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,saveScreenQueue.size());
for(std::list<std::pair<string,Pixmap2D *> >::iterator iter = saveScreenQueue.begin();
iter != saveScreenQueue.end(); ++iter) {
delete iter->second;
}
}
this->menu = NULL;
this->game = NULL;
}
void Renderer::simpleTask(BaseThread *callingThread) {
// This code reads pixmaps from a queue and saves them to disk
Pixmap2D *savePixMapBuffer=NULL;
string path="";
MutexSafeWrapper safeMutex(&saveScreenShotThreadAccessor);
if(saveScreenQueue.size() > 0) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d] saveScreenQueue.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,saveScreenQueue.size());
savePixMapBuffer = saveScreenQueue.front().second;
path = saveScreenQueue.front().first;
saveScreenQueue.pop_front();
}
safeMutex.ReleaseLock();
if(savePixMapBuffer != NULL) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d] about to save [%s]\n",__FILE__,__FUNCTION__,__LINE__,path.c_str());
savePixMapBuffer->save(path);
delete savePixMapBuffer;
}
}
Renderer &Renderer::getInstance(){
static Renderer renderer;
return renderer;
}
void Renderer::reinitAll() {
//resources
for(int i=0; i<rsCount; ++i){
//modelManager[i]->init();
textureManager[i]->init(true);
//particleManager[i]->init();
//fontManager[i]->init();
}
}
// ==================== init ====================
void Renderer::init() {
Config &config= Config::getInstance();
loadConfig();
if(config.getBool("CheckGlCaps")){
checkGlCaps();
}
if(config.getBool("FirstTime")){
config.setBool("FirstTime", false);
autoConfig();
config.save();
}
modelManager[rsGlobal]->init();
textureManager[rsGlobal]->init();
fontManager[rsGlobal]->init();
init2dList();
glHint(GL_FOG_HINT, GL_FASTEST);
//glHint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
//glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
//glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
glHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
}
void Renderer::initGame(const Game *game){
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
this->game= game;
worldToScreenPosCache.clear();
//check gl caps
checkGlOptionalCaps();
//vars
shadowMapFrame= 0;
waterAnim= 0;
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//shadows
if(shadows == sProjected || shadows == sShadowMapping) {
static_cast<ModelRendererGl*>(modelRenderer)->setSecondaryTexCoordUnit(2);
glGenTextures(1, &shadowMapHandle);
glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if(shadows == sShadowMapping) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//shadow mapping
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 1.0f-shadowAlpha);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32,
shadowTextureSize, shadowTextureSize,
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
}
else {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//projected
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
shadowTextureSize, shadowTextureSize,
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
}
shadowMapFrame= -1;
}
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
IF_DEBUG_EDITION( getDebugRenderer().init(); )
//texture init
modelManager[rsGame]->init();
textureManager[rsGame]->init();
fontManager[rsGame]->init();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
init3dList();
}
void Renderer::initMenu(const MainMenu *mm) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
this->menu = mm;
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
modelManager[rsMenu]->init();
textureManager[rsMenu]->init();
fontManager[rsMenu]->init();
//modelRenderer->setCustomTexture(CoreData::getInstance().getCustomTexture());
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
init3dListMenu(mm);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
void Renderer::reset3d() {
assertGl();
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
glCallList(list3d);
pointCount= 0;
triangleCount= 0;
assertGl();
}
void Renderer::reset2d() {
assertGl();
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
glCallList(list2d);
assertGl();
}
void Renderer::reset3dMenu() {
assertGl();
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
glCallList(list3dMenu);
assertGl();
}
// ==================== end ====================
void Renderer::end() {
//delete resources
modelManager[rsGlobal]->end();
textureManager[rsGlobal]->end();
fontManager[rsGlobal]->end();
particleManager[rsGlobal]->end();
//delete 2d list
glDeleteLists(list2d, 1);
}
void Renderer::endGame() {
game= NULL;
//delete resources
modelManager[rsGame]->end();
textureManager[rsGame]->end();
fontManager[rsGame]->end();
particleManager[rsGame]->end();
if(shadows == sProjected || shadows == sShadowMapping) {
glDeleteTextures(1, &shadowMapHandle);
}
glDeleteLists(list3d, 1);
worldToScreenPosCache.clear();
}
void Renderer::endMenu() {
this->menu = NULL;
//delete resources
modelManager[rsMenu]->end();
textureManager[rsMenu]->end();
fontManager[rsMenu]->end();
particleManager[rsMenu]->end();
glDeleteLists(list3dMenu, 1);
}
void Renderer::reloadResources() {
for(int i=0; i<rsCount; ++i) {
modelManager[i]->end();
textureManager[i]->end();
fontManager[i]->end();
}
for(int i=0; i<rsCount; ++i) {
modelManager[i]->init();
textureManager[i]->init();
fontManager[i]->init();
}
}
// ==================== engine interface ====================
void Renderer::initTexture(ResourceScope rs, Texture *texture) {
textureManager[rs]->initTexture(texture);
}
void Renderer::endTexture(ResourceScope rs, Texture *texture, bool mustExistInList) {
textureManager[rs]->endTexture(texture,mustExistInList);
}
void Renderer::endLastTexture(ResourceScope rs, bool mustExistInList) {
textureManager[rs]->endLastTexture(mustExistInList);
}
Model *Renderer::newModel(ResourceScope rs){
return modelManager[rs]->newModel();
}
void Renderer::endModel(ResourceScope rs, Model *model,bool mustExistInList) {
modelManager[rs]->endModel(model,mustExistInList);
}
void Renderer::endLastModel(ResourceScope rs, bool mustExistInList) {
modelManager[rs]->endLastModel(mustExistInList);
}
Texture2D *Renderer::newTexture2D(ResourceScope rs){
return textureManager[rs]->newTexture2D();
}
Texture3D *Renderer::newTexture3D(ResourceScope rs){
return textureManager[rs]->newTexture3D();
}
Font2D *Renderer::newFont(ResourceScope rs){
return fontManager[rs]->newFont2D();
}
void Renderer::manageParticleSystem(ParticleSystem *particleSystem, ResourceScope rs){
particleManager[rs]->manage(particleSystem);
}
bool Renderer::validateParticleSystemStillExists(ParticleSystem * particleSystem,ResourceScope rs) const {
return particleManager[rs]->validateParticleSystemStillExists(particleSystem);
}
void Renderer::cleanupParticleSystems(vector<ParticleSystem *> &particleSystems, ResourceScope rs) {
particleManager[rs]->cleanupParticleSystems(particleSystems);
}
void Renderer::cleanupUnitParticleSystems(vector<UnitParticleSystem *> &particleSystems, ResourceScope rs) {
particleManager[rs]->cleanupUnitParticleSystems(particleSystems);
}
void Renderer::updateParticleManager(ResourceScope rs, int renderFps) {
particleManager[rs]->update(renderFps);
}
void Renderer::renderParticleManager(ResourceScope rs){
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDepthFunc(GL_LESS);
particleRenderer->renderManager(particleManager[rs], modelRenderer);
glPopAttrib();
}
void Renderer::swapBuffers() {
//glFlush(); // should not be required - http://www.opengl.org/wiki/Common_Mistakes
glFlush();
GraphicsInterface::getInstance().getCurrentContext()->swapBuffers();
}
// ==================== lighting ====================
//places all the opengl lights
void Renderer::setupLighting() {
int lightCount= 0;
const World *world= game->getWorld();
const GameCamera *gameCamera= game->getGameCamera();
const TimeFlow *timeFlow= world->getTimeFlow();
float time= timeFlow->getTime();
assertGl();
//sun/moon light
Vec3f lightColor= computeLightColor(time);
Vec3f fogColor= world->getTileset()->getFogColor();
Vec4f lightPos= timeFlow->isDay()? computeSunPos(time): computeMoonPos(time);
nearestLightPos= lightPos;
glLightfv(GL_LIGHT0, GL_POSITION, lightPos.ptr());
glLightfv(GL_LIGHT0, GL_AMBIENT, Vec4f(lightColor*lightAmbFactor, 1.f).ptr());
glLightfv(GL_LIGHT0, GL_DIFFUSE, Vec4f(lightColor, 1.f).ptr());
glLightfv(GL_LIGHT0, GL_SPECULAR, Vec4f(0.0f, 0.0f, 0.f, 1.f).ptr());
glFogfv(GL_FOG_COLOR, Vec4f(fogColor*lightColor, 1.f).ptr());
lightCount++;
//disable all secondary lights
for(int i= 1; i < maxLights; ++i) {
glDisable(GL_LIGHT0 + i);
}
//unit lights (not projectiles)
if(timeFlow->isTotalNight()) {
for(int i=0; i<world->getFactionCount() && lightCount<maxLights; ++i){
for(int j=0; j<world->getFaction(i)->getUnitCount() && lightCount<maxLights; ++j){
Unit *unit= world->getFaction(i)->getUnit(j);
if(world->toRenderUnit(unit) &&
unit->getCurrVector().dist(gameCamera->getPos())<maxLightDist &&
unit->getType()->getLight() && unit->isOperative()){
Vec4f pos= Vec4f(unit->getCurrVector());
pos.y+=4.f;
GLenum lightEnum= GL_LIGHT0 + lightCount;
glEnable(lightEnum);
glLightfv(lightEnum, GL_POSITION, pos.ptr());
glLightfv(lightEnum, GL_AMBIENT, Vec4f(unit->getType()->getLightColor()).ptr());
glLightfv(lightEnum, GL_DIFFUSE, Vec4f(unit->getType()->getLightColor()).ptr());
glLightfv(lightEnum, GL_SPECULAR, Vec4f(unit->getType()->getLightColor()*0.3f).ptr());
glLightf(lightEnum, GL_QUADRATIC_ATTENUATION, 0.05f);
++lightCount;
const GameCamera *gameCamera= game->getGameCamera();
if(Vec3f(pos).dist(gameCamera->getPos())<Vec3f(nearestLightPos).dist(gameCamera->getPos())){
nearestLightPos= pos;
}
}
}
}
}
assertGl();
}
void Renderer::loadGameCameraMatrix() {
const GameCamera *gameCamera= game->getGameCamera();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(gameCamera->getVAng(), -1, 0, 0);
glRotatef(gameCamera->getHAng(), 0, 1, 0);
glTranslatef(-gameCamera->getPos().x, -gameCamera->getPos().y, -gameCamera->getPos().z);
}
void Renderer::loadCameraMatrix(const Camera *camera) {
const Vec3f &position= camera->getConstPosition();
Quaternion orientation= camera->getOrientation().conjugate();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(orientation.toMatrix4().ptr());
glTranslatef(-position.x, -position.y, -position.z);
}
void Renderer::computeVisibleQuad() {
const GameCamera *gameCamera = game->getGameCamera();
visibleQuad = gameCamera->computeVisibleQuad();
}
// =======================================
// basic rendering
// =======================================
void Renderer::renderMouse2d(int x, int y, int anim, float fade) {
if(no2DMouseRendering == true) {
return;
}
float color1 = 0.0, color2 = 0.0;
float fadeFactor = fade + 1.f;
anim= anim * 2 - maxMouse2dAnim;
color2= (abs(anim*(int)fadeFactor)/static_cast<float>(maxMouse2dAnim))/2.f+0.4f;
color1= (abs(anim*(int)fadeFactor)/static_cast<float>(maxMouse2dAnim))/2.f+0.8f;
glPushAttrib(GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT);
glEnable(GL_BLEND);
//inside
glColor4f(0.4f*fadeFactor, 0.2f*fadeFactor, 0.2f*fadeFactor, 0.5f*fadeFactor);
glBegin(GL_TRIANGLES);
glVertex2i(x, y);
glVertex2i(x+20, y-10);
glVertex2i(x+10, y-20);
glEnd();
//border
glLineWidth(2);
glBegin(GL_LINE_LOOP);
glColor4f(1.f, 0.2f, 0, color1);
glVertex2i(x, y);
glColor4f(1.f, 0.4f, 0, color2);
glVertex2i(x+20, y-10);
glColor4f(1.f, 0.4f, 0, color2);
glVertex2i(x+10, y-20);
glEnd();
glPopAttrib();
}
void Renderer::renderMouse3d() {
if(game == NULL) {
char szBuf[1024]="";
sprintf(szBuf,"In [%s::%s] Line: %d game == NULL",__FILE__,__FUNCTION__,__LINE__);
throw runtime_error(szBuf);
}
else if(game->getGui() == NULL) {
char szBuf[1024]="";
sprintf(szBuf,"In [%s::%s] Line: %d game->getGui() == NULL",__FILE__,__FUNCTION__,__LINE__);
throw runtime_error(szBuf);
}
else if(game->getGui()->getMouse3d() == NULL) {
char szBuf[1024]="";
sprintf(szBuf,"In [%s::%s] Line: %d game->getGui()->getMouse3d() == NULL",__FILE__,__FUNCTION__,__LINE__);
throw runtime_error(szBuf);
}
const Gui *gui= game->getGui();
const Mouse3d *mouse3d= gui->getMouse3d();
const Map *map= game->getWorld()->getMap();
if(map == NULL) {
char szBuf[1024]="";
sprintf(szBuf,"In [%s::%s] Line: %d map == NULL",__FILE__,__FUNCTION__,__LINE__);
throw runtime_error(szBuf);
}
GLUquadricObj *cilQuadric;
Vec4f color;
assertGl();
if((mouse3d->isEnabled() || gui->isPlacingBuilding()) && gui->isValidPosObjWorld()) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glPushAttrib(GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_COLOR_MATERIAL);
glDepthMask(GL_FALSE);
const Vec2i &pos= gui->getPosObjWorld();
Vec3f pos3f= Vec3f(pos.x, map->getCell(pos)->getHeight(), pos.y);
if(gui->isPlacingBuilding()) {
const UnitType *building= gui->getBuilding();
//selection building emplacement
float offset= building->getSize()/2.f-0.5f;
glTranslatef(pos3f.x+offset, pos3f.y, pos3f.z+offset);
//choose color
if(map->isFreeCells(pos, building->getSize(), fLand)){
color= Vec4f(1.f, 1.f, 1.f, 0.5f);
}
else {
color= Vec4f(1.f, 0.f, 0.f, 0.5f);
}
modelRenderer->begin(true, true, false);
glColor4fv(color.ptr());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color.ptr());
Model *buildingModel= building->getFirstStOfClass(scStop)->getAnimation();
if(gui->getSelectedFacing() != CardinalDir::NORTH) {
float rotateAmount = gui->getSelectedFacing() * 90.f;
if(rotateAmount > 0) {
glRotatef(rotateAmount, 0.f, 1.f, 0.f);
}
}
buildingModel->updateInterpolationData(0.f, false);
modelRenderer->render(buildingModel);
glDisable(GL_COLOR_MATERIAL);
modelRenderer->end();
}
else {
//standard mouse
glDisable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
color= Vec4f(1.f, 0.f, 0.f, 1.f-mouse3d->getFade());
glColor4fv(color.ptr());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color.ptr());
glTranslatef(pos3f.x, pos3f.y+2.f, pos3f.z);
glRotatef(90.f, 1.f, 0.f, 0.f);
glRotatef(static_cast<float>(mouse3d->getRot()), 0.f, 0.f, 1.f);
cilQuadric= gluNewQuadric();
gluQuadricDrawStyle(cilQuadric, GLU_FILL);
gluCylinder(cilQuadric, 0.5f, 0.f, 2.f, 4, 1);
gluCylinder(cilQuadric, 0.5f, 0.f, 0.f, 4, 1);
glTranslatef(0.f, 0.f, 1.f);
gluCylinder(cilQuadric, 0.7f, 0.f, 1.f, 4, 1);
gluCylinder(cilQuadric, 0.7f, 0.f, 0.f, 4, 1);
gluDeleteQuadric(cilQuadric);
}
glPopAttrib();
glPopMatrix();
}
}
void Renderer::renderBackground(const Texture2D *texture) {
const Metrics &metrics= Metrics::getInstance();
assertGl();
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
renderQuad(0, 0, metrics.getVirtualW(), metrics.getVirtualH(), texture);
glPopAttrib();
assertGl();
}
void Renderer::renderTextureQuad(int x, int y, int w, int h, const Texture2D *texture, float alpha,const Vec3f *color) {
assertGl();
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
if(color != NULL) {
Vec4f newColor(*color);
newColor.w = alpha;
glColor4fv(newColor.ptr());
}
else {
glColor4f(1.f, 1.f, 1.f, alpha);
}
renderQuad(x, y, w, h, texture);
glPopAttrib();
assertGl();
}
void Renderer::renderConsoleLine(int lineIndex, int xPosition, int yPosition, int lineHeight,
const Font2D* font, string stringToHightlight, const ConsoleLineInfo *lineInfo) {
Vec4f fontColor;
const Metrics &metrics= Metrics::getInstance();
const FontMetrics *fontMetrics= font->getMetrics();
if(game != NULL) {
fontColor = game->getGui()->getDisplay()->getColor();
}
else {
// white shadowed is default ( in the menu for example )
fontColor=Vec4f(1.f, 1.f, 1.f, 0.0f);
}
Vec4f defaultFontColor = fontColor;
if(lineInfo->PlayerIndex >= 0) {
std::map<int,Texture2D *> &crcPlayerTextureCache = CacheManager::getCachedItem< std::map<int,Texture2D *> >(GameConstants::playerTextureCacheLookupKey);
Vec3f playerColor = crcPlayerTextureCache[lineInfo->PlayerIndex]->getPixmap()->getPixel3f(0, 0);
fontColor.x = playerColor.x;
fontColor.y = playerColor.y;
fontColor.z = playerColor.z;
GameNetworkInterface *gameNetInterface = NetworkManager::getInstance().getGameNetworkInterface();
if(gameNetInterface != NULL && gameNetInterface->getGameSettings() != NULL) {
const GameSettings *gameSettings = gameNetInterface->getGameSettings();
string playerName = gameSettings->getNetworkPlayerNameByPlayerIndex(lineInfo->PlayerIndex);
if(playerName != lineInfo->originalPlayerName && lineInfo->originalPlayerName != "") {
playerName = lineInfo->originalPlayerName;
}
//printf("playerName [%s], line [%s]\n",playerName.c_str(),line.c_str());
//string headerLine = "*" + playerName + ":";
string headerLine = playerName + ": ";
if(fontMetrics == NULL) {
throw runtime_error("fontMetrics == NULL");
}
renderTextShadow(
headerLine,
font,
fontColor,
xPosition, lineIndex * lineHeight + yPosition);
fontColor = defaultFontColor;
//xPosition += (8 * (playerName.length() + 2));
// Proper font spacing after username portion of chat text rendering
xPosition += (metrics.toVirtualX(fontMetrics->getTextWidth(headerLine)));
}
}
else if(lineInfo->originalPlayerName != "") {
string playerName = lineInfo->originalPlayerName;
string headerLine = playerName + ": ";
if(fontMetrics == NULL) {
throw runtime_error("fontMetrics == NULL");
}
renderTextShadow(
headerLine,
font,
fontColor,
xPosition, lineIndex * lineHeight + yPosition);
fontColor = defaultFontColor;
//xPosition += (8 * (playerName.length() + 2));
// Proper font spacing after username portion of chat text rendering
xPosition += (metrics.toVirtualX(fontMetrics->getTextWidth(headerLine)));
}
else {
fontColor = defaultFontColor;
}
if(stringToHightlight!="" && lineInfo->text.find(stringToHightlight)!=string::npos){
fontColor=Vec4f(1.f, 0.5f, 0.5f, 0.0f);
}
renderTextShadow(
lineInfo->text,
font,
fontColor,
xPosition, (lineIndex * lineHeight) + yPosition);
}
void Renderer::renderConsole(const Console *console,const bool showFullConsole,const bool showMenuConsole){
if(console == NULL) {
throw runtime_error("console == NULL");
}
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_BLEND);
if(showFullConsole) {
for(int i = 0; i < console->getStoredLineCount(); ++i) {
const ConsoleLineInfo &lineInfo = console->getStoredLineItem(i);
renderConsoleLine(i, console->getXPos(), console->getYPos(),
console->getLineHeight(), console->getFont(), console->getStringToHighlight(), &lineInfo);
}
}
else if(showMenuConsole) {
for(int i = 0; i < console->getStoredLineCount() && i < maxConsoleLines; ++i) {
const ConsoleLineInfo &lineInfo = console->getStoredLineItem(i);
renderConsoleLine(i, console->getXPos(), console->getYPos(),
console->getLineHeight(), console->getFont(), console->getStringToHighlight(), &lineInfo);
}
}
else {
for(int i = 0; i < console->getLineCount(); ++i) {
const ConsoleLineInfo &lineInfo = console->getLineItem(i);
renderConsoleLine(i, console->getXPos(), console->getYPos(),
console->getLineHeight(), console->getFont(), console->getStringToHighlight(), &lineInfo);
}
}
glPopAttrib();
}
void Renderer::renderChatManager(const ChatManager *chatManager) {
Vec4f fontColor;
Lang &lang= Lang::getInstance();
if(chatManager->getEditEnabled()) {
string text="";
if(chatManager->getInMenu()){
text += lang.get("Chat");
}
else if(chatManager->getTeamMode()) {
text += lang.get("Team");
}
else {
text += lang.get("All");
}
text += ": " + chatManager->getText() + "_";
if(game != NULL) {
fontColor = game->getGui()->getDisplay()->getColor();
}
else {
// white shadowed is default ( in the menu for example )
fontColor=Vec4f(1.f, 1.f, 1.f, 0.0f);
}
renderTextShadow(
text,
chatManager->getFont(),
fontColor,
chatManager->getXPos(), chatManager->getYPos());
//textRenderer->begin(CoreData::getInstance().getConsoleFont());
//textRenderer->render(text, 300, 150);
//textRenderer->end();
}
else
{
if (chatManager->getInMenu()) {
string text = ">> "+lang.get("PressEnterToChat")+" <<";
fontColor = Vec4f(0.5f, 0.5f, 0.5f, 0.5f);
renderTextShadow(text, chatManager->getFont(), fontColor,
chatManager->getXPos(), chatManager->getYPos());
}
}
}
void Renderer::renderResourceStatus() {
const Metrics &metrics= Metrics::getInstance();
const World *world= game->getWorld();
const Faction *thisFaction= world->getFaction(world->getThisFactionIndex());
const Vec4f fontColor=game->getGui()->getDisplay()->getColor();
assertGl();
glPushAttrib(GL_ENABLE_BIT);
int j= 0;
for(int i= 0; i<world->getTechTree()->getResourceTypeCount(); ++i){
const ResourceType *rt= world->getTechTree()->getResourceType(i);
const Resource *r= thisFaction->getResource(rt);
//if any unit produces the resource
bool showResource= false;
for(int k=0; k<thisFaction->getType()->getUnitTypeCount(); ++k){
const UnitType *ut= thisFaction->getType()->getUnitType(k);
if(ut->getCost(rt)!=NULL){
showResource= true;
break;
}
}
//draw resource status
if(showResource){
string str= intToStr(r->getAmount());
glEnable(GL_TEXTURE_2D);
glColor3f(1.f, 1.f, 1.f);
renderQuad(j*100+200, metrics.getVirtualH()-30, 16, 16, rt->getImage());
if(rt->getClass() != rcStatic)
{
str+= "/" + intToStr(thisFaction->getStoreAmount(rt));
}
if(rt->getClass()==rcConsumable){
str+= "(";
if(r->getBalance()>0){
str+= "+";
}
str+= intToStr(r->getBalance()) + ")";
}
glDisable(GL_TEXTURE_2D);
renderTextShadow(
str, CoreData::getInstance().getDisplayFontSmall(),
fontColor,
j*100+220, metrics.getVirtualH()-30, false);
++j;
}
}
glPopAttrib();
assertGl();
}
void Renderer::renderSelectionQuad() {
const Gui *gui= game->getGui();
const SelectionQuad *sq= gui->getSelectionQuad();
Vec2i down= sq->getPosDown();
Vec2i up= sq->getPosUp();
if(gui->isSelecting()) {
glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT);
glColor3f(0,1,0);
glBegin(GL_LINE_LOOP);
glVertex2i(down.x, down.y);
glVertex2i(up.x, down.y);
glVertex2i(up.x, up.y);
glVertex2i(down.x, up.y);
glEnd();
glPopAttrib();
}
}
Vec2i computeCenteredPos(const string &text, const Font2D *font, int x, int y) {
if(font == NULL) {
throw runtime_error("font == NULL");
}
const Metrics &metrics= Metrics::getInstance();
const FontMetrics *fontMetrics= font->getMetrics();
if(fontMetrics == NULL) {
throw runtime_error("fontMetrics == NULL");
}
int virtualX = (fontMetrics->getTextWidth(text) > 0 ? static_cast<int>(fontMetrics->getTextWidth(text)/2.f) : 5);
int virtualY = (fontMetrics->getHeight() > 0 ? static_cast<int>(fontMetrics->getHeight()/2.f) : 5);
Vec2i textPos(
x-metrics.toVirtualX(virtualX),
y-metrics.toVirtualY(virtualY));
return textPos;
}
void Renderer::renderText(const string &text, const Font2D *font, float alpha, int x, int y, bool centered){
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
glEnable(GL_BLEND);
glColor4fv(Vec4f(1.f, 1.f, 1.f, alpha).ptr());
Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y);
textRenderer->begin(font);
textRenderer->render(text, pos.x, pos.y);
textRenderer->end();
glPopAttrib();
}
void Renderer::renderText(const string &text, const Font2D *font, const Vec3f &color, int x, int y, bool centered){
glPushAttrib(GL_CURRENT_BIT);
glColor3fv(color.ptr());
Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y);
textRenderer->begin(font);
textRenderer->render(text, pos.x, pos.y);
textRenderer->end();
glPopAttrib();
}
void Renderer::renderText(const string &text, const Font2D *font, const Vec4f &color, int x, int y, bool centered){
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
glEnable(GL_BLEND);
glColor4fv(color.ptr());
Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y);
textRenderer->begin(font);
textRenderer->render(text, pos.x, pos.y);
textRenderer->end();
glPopAttrib();
}
void Renderer::renderTextShadow(const string &text, const Font2D *font,const Vec4f &color, int x, int y, bool centered){
if(font == NULL) {
throw runtime_error("font == NULL");
}
glPushAttrib(GL_CURRENT_BIT);
Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y);
textRenderer->begin(font);
if(color.w<0.5) {
glColor3f(0.0f, 0.0f, 0.0f);
textRenderer->render(text, pos.x-1.0f, pos.y-1.0f);
}
glColor3f(color.x,color.y,color.z);
textRenderer->render(text, pos.x, pos.y);
textRenderer->end();
glPopAttrib();
}
// ============= COMPONENTS =============================
void Renderer::renderLabel(const GraphicLabel *label) {
Vec4f *colorWithAlpha = NULL;
renderLabel(label,colorWithAlpha);
}
void Renderer::renderLabel(const GraphicLabel *label,const Vec3f *color) {
if(color != NULL) {
Vec4f colorWithAlpha = Vec4f(*color);
colorWithAlpha.w = GraphicComponent::getFade();
renderLabel(label,&colorWithAlpha);
}
else {
Vec4f *colorWithAlpha = NULL;
renderLabel(label,colorWithAlpha);
}
}
void Renderer::renderLabel(const GraphicLabel *label,const Vec4f *color) {
if(label->getVisible() == false) {
return;
}
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_BLEND);
Vec2i textPos;
int x= label->getX();
int y= label->getY();
int h= label->getH();
int w= label->getW();
if(label->getCentered()){
textPos= Vec2i(x+w/2, y+h/2);
}
else{
textPos= Vec2i(x, y+h/4);
}
if(color != NULL) {
renderText(label->getText(), label->getFont(), (*color), textPos.x, textPos.y, label->getCentered());
}
else {
renderText(label->getText(), label->getFont(), GraphicComponent::getFade(), textPos.x, textPos.y, label->getCentered());
}
glPopAttrib();
}
void Renderer::renderButton(const GraphicButton *button) {
if(button->getVisible() == false) {
return;
}
int x= button->getX();
int y= button->getY();
int h= button->getH();
int w= button->getW();
const Vec3f disabledTextColor= Vec3f(0.25f,0.25f,0.25f);
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
//background
CoreData &coreData= CoreData::getInstance();
Texture2D *backTexture= w>3*h/2? coreData.getButtonBigTexture(): coreData.getButtonSmallTexture();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(backTexture)->getHandle());
//button
Vec4f fontColor;
//if(game!=NULL){
// fontColor=game->getGui()->getDisplay()->getColor();
// fontColor.w = GraphicComponent::getFade();
//}
//else {
// white shadowed is default ( in the menu for example )
fontColor=Vec4f(1.f, 1.f, 1.f, GraphicComponent::getFade());
//}
//Vec4f color= Vec4f(1.f, 1.f, 1.f, GraphicComponent::getFade());
Vec4f color= fontColor;
glColor4fv(color.ptr());
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.f, 0.f);
glVertex2f(x, y);
glTexCoord2f(0.f, 1.f);
glVertex2f(x, y+h);
glTexCoord2f(1.f, 0.f);
glVertex2f(x+w, y);
glTexCoord2f(1.f, 1.f);
glVertex2f(x+w, y+h);
glEnd();
glDisable(GL_TEXTURE_2D);
//lighting
float anim= GraphicComponent::getAnim();
if(anim>0.5f) anim= 1.f-anim;
if(button->getLighted() && button->getEditable()){
const int lightSize= 0;
const Vec4f color1= Vec4f(color.x, color.y, color.z, 0.1f+anim*0.5f);
const Vec4f color2= Vec4f(color.x, color.y, color.z, 0.3f+anim);
glBegin(GL_TRIANGLE_FAN);
glColor4fv(color2.ptr());
glVertex2f(x+w/2, y+h/2);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y-lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y-lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y-lightSize);
glEnd();
}
Vec2i textPos= Vec2i(x+w/2, y+h/2);
if(button->getEditable()){
renderText(
button->getText(), button->getFont(), color,
x+w/2, y+h/2, true);
}
else {
renderText(
button->getText(), button->getFont(),disabledTextColor,
x+w/2, y+h/2, true);
}
glPopAttrib();
}
void Renderer::renderCheckBox(const GraphicCheckBox *box) {
if(box->getVisible() == false) {
return;
}
int x= box->getX();
int y= box->getY();
int h= box->getH();
int w= box->getW();
const Vec3f disabledTextColor= Vec3f(0.25f,0.25f,0.25f);
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
//background
CoreData &coreData= CoreData::getInstance();
Texture2D *backTexture= box->getValue()? coreData.getCheckedCheckBoxTexture(): coreData.getCheckBoxTexture();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(backTexture)->getHandle());
//box
Vec4f fontColor;
//if(game!=NULL){
// fontColor=game->getGui()->getDisplay()->getColor();
// fontColor.w = GraphicComponent::getFade();
//}
//else {
// white shadowed is default ( in the menu for example )
fontColor=Vec4f(1.f, 1.f, 1.f, GraphicComponent::getFade());
//}
//Vec4f color= Vec4f(1.f, 1.f, 1.f, GraphicComponent::getFade());
Vec4f color= fontColor;
glColor4fv(color.ptr());
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.f, 0.f);
glVertex2f(x, y);
glTexCoord2f(0.f, 1.f);
glVertex2f(x, y+h);
glTexCoord2f(1.f, 0.f);
glVertex2f(x+w, y);
glTexCoord2f(1.f, 1.f);
glVertex2f(x+w, y+h);
glEnd();
glDisable(GL_TEXTURE_2D);
//lighting
float anim= GraphicComponent::getAnim();
if(anim>0.5f) anim= 1.f-anim;
if(box->getLighted() && box->getEditable()){
const int lightSize= 0;
const Vec4f color1= Vec4f(color.x, color.y, color.z, 0.1f+anim*0.5f);
const Vec4f color2= Vec4f(color.x, color.y, color.z, 0.3f+anim);
glBegin(GL_TRIANGLE_FAN);
glColor4fv(color2.ptr());
glVertex2f(x+w/2, y+h/2);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y-lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y-lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y-lightSize);
glEnd();
}
glPopAttrib();
}
void Renderer::renderLine(const GraphicLine *line) {
if(line->getVisible() == false) {
return;
}
int x= line->getX();
int y= line->getY();
int h= line->getH();
int w= line->getW();
const Vec3f disabledTextColor= Vec3f(0.25f,0.25f,0.25f);
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
//background
CoreData &coreData= CoreData::getInstance();
Texture2D *backTexture= line->getHorizontal()? coreData.getHorizontalLineTexture(): coreData.getVerticalLineTexture();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(backTexture)->getHandle());
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.f, 0.f);
glVertex2f(x, y);
glTexCoord2f(0.f, 1.f);
glVertex2f(x, y+h);
glTexCoord2f(1.f, 0.f);
glVertex2f(x+w, y);
glTexCoord2f(1.f, 1.f);
glVertex2f(x+w, y+h);
glEnd();
glDisable(GL_TEXTURE_2D);
glPopAttrib();
}
void Renderer::renderScrollBar(const GraphicScrollBar *sb) {
if(sb->getVisible() == false) {
return;
}
int x= sb->getX();
int y= sb->getY();
int h= sb->getH();
int w= sb->getW();
const Vec3f disabledTextColor= Vec3f(0.25f,0.25f,0.25f);
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
/////////////////////
//background
////////////////////
CoreData &coreData= CoreData::getInstance();
Texture2D *backTexture= coreData.getHorizontalLineTexture();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(backTexture)->getHandle());
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.f, 0.f);
glVertex2f(x, y);
glTexCoord2f(0.f, 1.f);
glVertex2f(x, y+h);
glTexCoord2f(1.f, 0.f);
glVertex2f(x+w, y);
glTexCoord2f(1.f, 1.f);
glVertex2f(x+w, y+h);
glEnd();
////////////////////
// selectBlock
////////////////////
x= sb->getX();
y= sb->getY();
h= sb->getH();
w= sb->getW();
if( sb->getHorizontal()) {
x=x+sb->getVisibleCompPosStart();
w=sb->getVisibleCompPosEnd()-sb->getVisibleCompPosStart();
}
else {
y=y+sb->getVisibleCompPosStart();
h=sb->getVisibleCompPosEnd()-sb->getVisibleCompPosStart();
}
Texture2D *selectTexture= coreData.getButtonBigTexture();
glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(selectTexture)->getHandle());
//button
Vec4f fontColor;
//if(game!=NULL){
// fontColor=game->getGui()->getDisplay()->getColor();
// fontColor.w = GraphicComponent::getFade();
//}
//else {
// white shadowed is default ( in the menu for example )
fontColor=Vec4f(1.f, 1.f, 1.f, GraphicComponent::getFade());
//}
//Vec4f color= Vec4f(1.f, 1.f, 1.f, GraphicComponent::getFade());
Vec4f color= fontColor;
glColor4fv(color.ptr());
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.f, 0.f);
glVertex2f(x, y);
glTexCoord2f(0.f, 1.f);
glVertex2f(x, y+h);
glTexCoord2f(1.f, 0.f);
glVertex2f(x+w, y);
glTexCoord2f(1.f, 1.f);
glVertex2f(x+w, y+h);
glEnd();
glDisable(GL_TEXTURE_2D);
//lighting
float anim= GraphicComponent::getAnim();
if(anim>0.5f) anim= 1.f-anim;
if(sb->getLighted() && sb->getEditable()){
const int lightSize= 0;
const Vec4f color1= Vec4f(color.x, color.y, color.z, 0.1f+anim*0.5f);
const Vec4f color2= Vec4f(color.x, color.y, color.z, 0.3f+anim);
glBegin(GL_TRIANGLE_FAN);
glColor4fv(color2.ptr());
glVertex2f(x+w/2, y+h/2);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y-lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y-lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x+w+lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y+h+lightSize);
glColor4fv(color1.ptr());
glVertex2f(x-lightSize, y-lightSize);
glEnd();
}
glPopAttrib();
}
void Renderer::renderListBox(const GraphicListBox *listBox) {
if(listBox->getVisible() == false) {
return;
}
renderButton(listBox->getButton1());
renderButton(listBox->getButton2());
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_BLEND);
GraphicLabel label;
label.init(listBox->getX(), listBox->getY(), listBox->getW(), listBox->getH(), true);
label.setText(listBox->getText());
label.setFont(listBox->getFont());
renderLabel(&label);
glPopAttrib();
}
void Renderer::renderMessageBox(const GraphicMessageBox *messageBox) {
if(messageBox->getVisible() == false) {
return;
}
//background
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
glEnable(GL_BLEND);
glColor4f(0.0f, 0.0f, 0.0f, 0.5f) ;
glBegin(GL_TRIANGLE_STRIP);
glVertex2i(messageBox->getX(), messageBox->getY()+9*messageBox->getH()/10);
glVertex2i(messageBox->getX(), messageBox->getY());
glVertex2i(messageBox->getX() + messageBox->getW(), messageBox->getY() + 9*messageBox->getH()/10);
glVertex2i(messageBox->getX() + messageBox->getW(), messageBox->getY());
glEnd();
glColor4f(0.0f, 0.0f, 0.0f, 0.8f) ;
glBegin(GL_TRIANGLE_STRIP);
glVertex2i(messageBox->getX(), messageBox->getY()+messageBox->getH());
glVertex2i(messageBox->getX(), messageBox->getY()+9*messageBox->getH()/10);
glVertex2i(messageBox->getX() + messageBox->getW(), messageBox->getY() + messageBox->getH());
glVertex2i(messageBox->getX() + messageBox->getW(), messageBox->getY()+9*messageBox->getH()/10);
glEnd();
glBegin(GL_LINE_LOOP);
glColor4f(0.5f, 0.5f, 0.5f, 0.25f) ;
glVertex2i(messageBox->getX(), messageBox->getY());
glColor4f(0.0f, 0.0f, 0.0f, 0.25f) ;
glVertex2i(messageBox->getX()+ messageBox->getW(), messageBox->getY());
glColor4f(0.5f, 0.5f, 0.5f, 0.25f) ;
glVertex2i(messageBox->getX()+ messageBox->getW(), messageBox->getY() + messageBox->getH());
glColor4f(0.25f, 0.25f, 0.25f, 0.25f) ;
glVertex2i(messageBox->getX(), messageBox->getY() + messageBox->getH());
glEnd();
glBegin(GL_LINE_STRIP);
glColor4f(1.0f, 1.0f, 1.0f, 0.25f) ;
glVertex2i(messageBox->getX(), messageBox->getY() + 90*messageBox->getH()/100);
glColor4f(0.5f, 0.5f, 0.5f, 0.25f) ;
glVertex2i(messageBox->getX()+ messageBox->getW(), messageBox->getY() + 90*messageBox->getH()/100);
glEnd();
glPopAttrib();
//buttons
renderButton(messageBox->getButton1());
if(messageBox->getButtonCount()==2){
renderButton(messageBox->getButton2());
}
Vec4f fontColor;
//if(game!=NULL){
// fontColor=game->getGui()->getDisplay()->getColor();
//}
//else {
// white shadowed is default ( in the menu for example )
fontColor=Vec4f(1.f, 1.f, 1.f, 1.0f);
//}
//text
renderTextShadow(
messageBox->getText(), messageBox->getFont(), fontColor,
messageBox->getX()+15, messageBox->getY()+7*messageBox->getH()/10,
false );
renderTextShadow(
messageBox->getHeader(), messageBox->getFont(),fontColor,
messageBox->getX()+15, messageBox->getY()+93*messageBox->getH()/100,
false );
}
// ==================== complex rendering ====================
#if defined(ENABLE_VBO_CODE)
VisibleQuadContainerVBOCache Renderer::SetupSurfaceVBO(Vec2i &pos, SurfaceCell *cell, Vec2f surfCoord) {
const World *world= game->getWorld();
const Map *map= world->getMap();
const Rect2i mapBounds(0, 0, map->getSurfaceW()-1, map->getSurfaceH()-1);
float coordStep= world->getTileset()->getSurfaceAtlas()->getCoordStep();
if(cell == NULL) {
throw runtime_error("cell == NULL");
}
VisibleQuadContainerVBOCache item1;
//printf("In [%s::%s Line: %d] setting up a VBO...\n",__FILE__,__FUNCTION__,__LINE__);
assertGl();
// Generate And Bind The Vertex Buffer
glGenBuffersARB( 1, &item1.m_nVBOVertices ); // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, item1.m_nVBOVertices ); // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(Vec3f) * 1, cell->getVertex().ptr(), GL_STATIC_DRAW_ARB );
glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
assertGl();
// Generate And Bind The Texture Coordinate Buffer
glGenBuffersARB( 1, &item1.m_nVBOFowTexCoords ); // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, item1.m_nVBOFowTexCoords ); // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(Vec2f) * 1, cell->getFowTexCoord().ptr(), GL_STATIC_DRAW_ARB );
glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
assertGl();
// Generate And Bind The Texture Coordinate Buffer
glGenBuffersARB( 1, &item1.m_nVBOSurfaceTexCoords ); // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, item1.m_nVBOSurfaceTexCoords ); // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(Vec2f) * 1, surfCoord.ptr(), GL_STATIC_DRAW_ARB );
glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
assertGl();
// Generate And Bind The Normal Buffer
glGenBuffersARB( 1, &item1.m_nVBONormals ); // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, item1.m_nVBONormals ); // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(Vec3f) * 1, cell->getNormal().ptr(), GL_STATIC_DRAW_ARB );
glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
item1.hasBuiltVBOs = true;
/*
// Generate And Bind The Index Buffer
glGenBuffersARB( 1, &m_nVBOIndexes ); // Get A Valid Name
glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nVBOIndexes ); // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(uint32)*indexCount, indices, GL_STATIC_DRAW_ARB );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
*/
// Our Copy Of The Data Is No Longer Necessary, It Is Safe In The Graphics Card
//delete [] vertices; vertices = NULL;
//delete [] texCoords; texCoords = NULL;
//delete [] normals; normals = NULL;
//delete [] indices; indices = NULL;
return item1;
}
vector<VisibleQuadContainerVBOCache> & Renderer::GetSurfaceVBOs(Vec2i &pos) {
std::map<Vec2i,std::vector<VisibleQuadContainerVBOCache> >::iterator iterFind = mapSurfaceVBOCache.find(pos);
if(iterFind == mapSurfaceVBOCache.end()) {
const World *world= game->getWorld();
const Map *map= world->getMap();
const Rect2i mapBounds(0, 0, map->getSurfaceW()-1, map->getSurfaceH()-1);
float coordStep= world->getTileset()->getSurfaceAtlas()->getCoordStep();
SurfaceCell *tc00= map->getSurfaceCell(pos.x, pos.y);
SurfaceCell *tc10= map->getSurfaceCell(pos.x+1, pos.y);
SurfaceCell *tc01= map->getSurfaceCell(pos.x, pos.y+1);
SurfaceCell *tc11= map->getSurfaceCell(pos.x+1, pos.y+1);
std::vector<VisibleQuadContainerVBOCache> vboCache;
assertGl();
VisibleQuadContainerVBOCache item1 = SetupSurfaceVBO(pos, tc01, Vec2f(pos.x, pos.y+1));
vboCache.push_back(item1);
assertGl();
VisibleQuadContainerVBOCache item2 = SetupSurfaceVBO(pos, tc00, Vec2f(pos.x, pos.y));
vboCache.push_back(item2);
assertGl();
VisibleQuadContainerVBOCache item3 = SetupSurfaceVBO(pos, tc11, Vec2f(pos.x+1, pos.y+1));
vboCache.push_back(item3);
assertGl();
VisibleQuadContainerVBOCache item4 = SetupSurfaceVBO(pos, tc10, Vec2f(pos.x+1, pos.y));
vboCache.push_back(item4);
mapSurfaceVBOCache[pos] = vboCache;
}
return mapSurfaceVBOCache[pos];
}
void Renderer::ReleaseSurfaceVBOs() {
for(std::map<Vec2i,std::vector<VisibleQuadContainerVBOCache> >::iterator iterFind = mapSurfaceVBOCache.begin();
iterFind != mapSurfaceVBOCache.end(); ++iterFind) {
std::vector<VisibleQuadContainerVBOCache> &vboCache = iterFind->second;
for(int i = 0; i < vboCache.size(); ++i) {
assertGl();
VisibleQuadContainerVBOCache &item = vboCache[i];
if(item.hasBuiltVBOs == true) {
glDeleteBuffersARB( 1, &item.m_nVBOVertices ); // Get A Valid Name
glDeleteBuffersARB( 1, &item.m_nVBOFowTexCoords ); // Get A Valid Name
glDeleteBuffersARB( 1, &item.m_nVBOSurfaceTexCoords ); // Get A Valid Name
glDeleteBuffersARB( 1, &item.m_nVBONormals ); // Get A Valid Name
//glDeleteBuffersARB( 1, &item.m_nVBOIndexes ); // Get A Valid Name
}
}
}
mapSurfaceVBOCache.clear();
}
#endif
class SurfaceData {
public:
SurfaceData(){};
int textureHandle;
vector<Vec2f> texCoords;
vector<Vec2f> texCoordsSurface;
vector<Vec3f> vertices;
vector<Vec3f> normals;
};
void Renderer::renderSurface(const int renderFps) {
IF_DEBUG_EDITION(
if (getDebugRenderer().willRenderSurface()) {
getDebugRenderer().renderSurface(visibleQuad / Map::cellScale);
} else {
)
int lastTex=-1;
int currTex=-1;
const World *world= game->getWorld();
const Map *map= world->getMap();
const Rect2i mapBounds(0, 0, map->getSurfaceW()-1, map->getSurfaceH()-1);
float coordStep= world->getTileset()->getSurfaceAtlas()->getCoordStep();
assertGl();
const Texture2D *fowTex= world->getMinimap()->getFowTexture();
glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT);
glEnable(GL_BLEND);
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_ALPHA_TEST);
glEnable(GL_CULL_FACE);
//fog of war tex unit
glActiveTexture(fowTexUnit);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(fowTex)->getHandle());
glTexSubImage2D(
GL_TEXTURE_2D, 0, 0, 0,
fowTex->getPixmapConst()->getW(), fowTex->getPixmapConst()->getH(),
GL_ALPHA, GL_UNSIGNED_BYTE, fowTex->getPixmapConst()->getPixels());
if(shadowsOffDueToMinRender == false) {
//shadow texture
if(shadows == sProjected || shadows == sShadowMapping) {
glActiveTexture(shadowTexUnit);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
enableProjectiveTexturing();
}
}
glActiveTexture(baseTexUnit);
VisibleQuadContainerCache &qCache = getQuadCache();
if(qCache.visibleScaledCellList.size() > 0) {
#if defined(ENABLE_VBO_CODE)
int lastSurfaceDataIndex = -1;
std::vector<SurfaceData> surface;
//surface.reserve(qCache.visibleScaledCellList.size());
for(int visibleIndex = 0;
visibleIndex < qCache.visibleScaledCellList.size(); ++visibleIndex) {
Vec2i &pos = qCache.visibleScaledCellList[visibleIndex];
SurfaceCell *tc00= map->getSurfaceCell(pos.x, pos.y);
SurfaceCell *tc10= map->getSurfaceCell(pos.x+1, pos.y);
SurfaceCell *tc01= map->getSurfaceCell(pos.x, pos.y+1);
SurfaceCell *tc11= map->getSurfaceCell(pos.x+1, pos.y+1);
if(tc00 == NULL) {
throw runtime_error("tc00 == NULL");
}
if(tc10 == NULL) {
throw runtime_error("tc10 == NULL");
}
if(tc01 == NULL) {
throw runtime_error("tc01 == NULL");
}
if(tc11 == NULL) {
throw runtime_error("tc11 == NULL");
}
triangleCount+= 2;
pointCount+= 4;
//set texture
if(tc00->getSurfaceTexture() == NULL) {
throw runtime_error("tc00->getSurfaceTexture() == NULL");
}
vector<VisibleQuadContainerVBOCache> &vboCache = GetSurfaceVBOs(pos);
int surfaceDataIndex = -1;
currTex= static_cast<const Texture2DGl*>(tc00->getSurfaceTexture())->getHandle();
if(currTex != lastTex) {
lastTex = currTex;
}
else {
surfaceDataIndex = lastSurfaceDataIndex;
}
if(surfaceDataIndex < 0) {
SurfaceData newData;
newData.textureHandle = currTex;
surface.push_back(newData);
surfaceDataIndex = surface.size()-1;
//surface[surfaceDataIndex].texCoords.reserve(100);
//surface[surfaceDataIndex].texCoordsSurface.reserve(100);
//surface[surfaceDataIndex].vertices.reserve(100);
//surface[surfaceDataIndex].normals.reserve(100);
}
lastSurfaceDataIndex = surfaceDataIndex;
const Vec2f &surfCoord= tc00->getSurfTexCoord();
//int dataIndex = surface[surfaceDataIndex].texCoords.size();
surface[surfaceDataIndex].texCoords.push_back(tc01->getFowTexCoord());
surface[surfaceDataIndex].texCoordsSurface.push_back(Vec2f(surfCoord.x, surfCoord.y + coordStep));
surface[surfaceDataIndex].vertices.push_back(tc01->getVertex());
surface[surfaceDataIndex].normals.push_back(tc01->getNormal());
surface[surfaceDataIndex].texCoords.push_back(tc00->getFowTexCoord());
surface[surfaceDataIndex].texCoordsSurface.push_back(Vec2f(surfCoord.x, surfCoord.y));
surface[surfaceDataIndex].vertices.push_back(tc00->getVertex());
surface[surfaceDataIndex].normals.push_back(tc00->getNormal());
surface[surfaceDataIndex].texCoords.push_back(tc11->getFowTexCoord());
surface[surfaceDataIndex].texCoordsSurface.push_back(Vec2f(surfCoord.x+coordStep, surfCoord.y+coordStep));
surface[surfaceDataIndex].vertices.push_back(tc11->getVertex());
surface[surfaceDataIndex].normals.push_back(tc11->getNormal());
surface[surfaceDataIndex].texCoords.push_back(tc10->getFowTexCoord());
surface[surfaceDataIndex].texCoordsSurface.push_back(Vec2f(surfCoord.x+coordStep, surfCoord.y));
surface[surfaceDataIndex].vertices.push_back(tc10->getVertex());
surface[surfaceDataIndex].normals.push_back(tc10->getNormal());
}
//printf("\nsurface.size() = %d vs qCache.visibleScaledCellList.size() = %d \n",surface.size(),qCache.visibleScaledCellList.size());
for(int i = 0; i < surface.size(); ++i) {
SurfaceData &data = surface[i];
Vec2f *texCoords = &data.texCoords[0];
Vec2f *texCoordsSurface = &data.texCoordsSurface[0];
Vec3f *vertices = &data.vertices[0];
Vec3f *normals = &data.normals[0];
glClientActiveTexture(fowTexUnit);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0,texCoords);
glBindTexture(GL_TEXTURE_2D, data.textureHandle);
glClientActiveTexture(baseTexUnit);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texCoordsSurface);
assertGl();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
assertGl();
glVertexPointer(3, GL_FLOAT, 0, vertices);
glNormalPointer(GL_FLOAT, 0, normals);
glDrawArrays(GL_TRIANGLE_STRIP, 0, data.vertices.size());
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//assertGl();
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
//assertGl();
}
#else
bool legacyRendering = true;
if(legacyRendering) {
//printf("\LEGACY qCache.visibleScaledCellList.size() = %d \n",qCache.visibleScaledCellList.size());
for(int visibleIndex = 0;
visibleIndex < qCache.visibleScaledCellList.size(); ++visibleIndex) {
Vec2i &pos = qCache.visibleScaledCellList[visibleIndex];
SurfaceCell *tc00= map->getSurfaceCell(pos.x, pos.y);
SurfaceCell *tc10= map->getSurfaceCell(pos.x+1, pos.y);
SurfaceCell *tc01= map->getSurfaceCell(pos.x, pos.y+1);
SurfaceCell *tc11= map->getSurfaceCell(pos.x+1, pos.y+1);
if(tc00 == NULL) {
throw runtime_error("tc00 == NULL");
}
if(tc10 == NULL) {
throw runtime_error("tc10 == NULL");
}
if(tc01 == NULL) {
throw runtime_error("tc01 == NULL");
}
if(tc11 == NULL) {
throw runtime_error("tc11 == NULL");
}
triangleCount+= 2;
pointCount+= 4;
//set texture
if(tc00->getSurfaceTexture() == NULL) {
throw runtime_error("tc00->getSurfaceTexture() == NULL");
}
currTex= static_cast<const Texture2DGl*>(tc00->getSurfaceTexture())->getHandle();
if(currTex != lastTex) {
lastTex = currTex;
glBindTexture(GL_TEXTURE_2D, lastTex);
}
const Vec2f &surfCoord= tc00->getSurfTexCoord();
glBegin(GL_TRIANGLE_STRIP);
//draw quad using immediate mode
glMultiTexCoord2fv(fowTexUnit, tc01->getFowTexCoord().ptr());
glMultiTexCoord2f(baseTexUnit, surfCoord.x, surfCoord.y + coordStep);
glNormal3fv(tc01->getNormal().ptr());
glVertex3fv(tc01->getVertex().ptr());
glMultiTexCoord2fv(fowTexUnit, tc00->getFowTexCoord().ptr());
glMultiTexCoord2f(baseTexUnit, surfCoord.x, surfCoord.y);
glNormal3fv(tc00->getNormal().ptr());
glVertex3fv(tc00->getVertex().ptr());
glMultiTexCoord2fv(fowTexUnit, tc11->getFowTexCoord().ptr());
glMultiTexCoord2f(baseTexUnit, surfCoord.x+coordStep, surfCoord.y+coordStep);
glNormal3fv(tc11->getNormal().ptr());
glVertex3fv(tc11->getVertex().ptr());
glMultiTexCoord2fv(fowTexUnit, tc10->getFowTexCoord().ptr());
glMultiTexCoord2f(baseTexUnit, surfCoord.x + coordStep, surfCoord.y);
glNormal3fv(tc10->getNormal().ptr());
glVertex3fv(tc10->getVertex().ptr());
glEnd();
}
}
else {
int lastSurfaceDataIndex = -1;
std::vector<SurfaceData> surface;
//surface.reserve(qCache.visibleScaledCellList.size());
for(int visibleIndex = 0;
visibleIndex < qCache.visibleScaledCellList.size(); ++visibleIndex) {
Vec2i &pos = qCache.visibleScaledCellList[visibleIndex];
SurfaceCell *tc00= map->getSurfaceCell(pos.x, pos.y);
SurfaceCell *tc10= map->getSurfaceCell(pos.x+1, pos.y);
SurfaceCell *tc01= map->getSurfaceCell(pos.x, pos.y+1);
SurfaceCell *tc11= map->getSurfaceCell(pos.x+1, pos.y+1);
if(tc00 == NULL) {
throw runtime_error("tc00 == NULL");
}
if(tc10 == NULL) {
throw runtime_error("tc10 == NULL");
}
if(tc01 == NULL) {
throw runtime_error("tc01 == NULL");
}
if(tc11 == NULL) {
throw runtime_error("tc11 == NULL");
}
triangleCount+= 2;
pointCount+= 4;
//set texture
if(tc00->getSurfaceTexture() == NULL) {
throw runtime_error("tc00->getSurfaceTexture() == NULL");
}
int surfaceDataIndex = -1;
currTex= static_cast<const Texture2DGl*>(tc00->getSurfaceTexture())->getHandle();
if(currTex != lastTex) {
lastTex = currTex;
}
else {
surfaceDataIndex = lastSurfaceDataIndex;
}
if(surfaceDataIndex < 0) {
SurfaceData newData;
newData.textureHandle = currTex;
surface.push_back(newData);
surfaceDataIndex = surface.size()-1;
//surface[surfaceDataIndex].texCoords.reserve(100);
//surface[surfaceDataIndex].texCoordsSurface.reserve(100);
//surface[surfaceDataIndex].vertices.reserve(100);
//surface[surfaceDataIndex].normals.reserve(100);
}
lastSurfaceDataIndex = surfaceDataIndex;
const Vec2f &surfCoord= tc00->getSurfTexCoord();
//int dataIndex = surface[surfaceDataIndex].texCoords.size();
surface[surfaceDataIndex].texCoords.push_back(tc01->getFowTexCoord());
surface[surfaceDataIndex].texCoordsSurface.push_back(Vec2f(surfCoord.x, surfCoord.y + coordStep));
surface[surfaceDataIndex].vertices.push_back(tc01->getVertex());
surface[surfaceDataIndex].normals.push_back(tc01->getNormal());
surface[surfaceDataIndex].texCoords.push_back(tc00->getFowTexCoord());
surface[surfaceDataIndex].texCoordsSurface.push_back(Vec2f(surfCoord.x, surfCoord.y));
surface[surfaceDataIndex].vertices.push_back(tc00->getVertex());
surface[surfaceDataIndex].normals.push_back(tc00->getNormal());
surface[surfaceDataIndex].texCoords.push_back(tc11->getFowTexCoord());
surface[surfaceDataIndex].texCoordsSurface.push_back(Vec2f(surfCoord.x+coordStep, surfCoord.y+coordStep));
surface[surfaceDataIndex].vertices.push_back(tc11->getVertex());
surface[surfaceDataIndex].normals.push_back(tc11->getNormal());
surface[surfaceDataIndex].texCoords.push_back(tc10->getFowTexCoord());
surface[surfaceDataIndex].texCoordsSurface.push_back(Vec2f(surfCoord.x+coordStep, surfCoord.y));
surface[surfaceDataIndex].vertices.push_back(tc10->getVertex());
surface[surfaceDataIndex].normals.push_back(tc10->getNormal());
}
//printf("\nsurface.size() = %d vs qCache.visibleScaledCellList.size() = %d \n",surface.size(),qCache.visibleScaledCellList.size());
for(int i = 0; i < surface.size(); ++i) {
SurfaceData &data = surface[i];
Vec2f *texCoords = &data.texCoords[0];
Vec2f *texCoordsSurface = &data.texCoordsSurface[0];
Vec3f *vertices = &data.vertices[0];
Vec3f *normals = &data.normals[0];
glClientActiveTexture(fowTexUnit);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0,texCoords);
glBindTexture(GL_TEXTURE_2D, data.textureHandle);
glClientActiveTexture(baseTexUnit);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texCoordsSurface);
assertGl();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
assertGl();
glVertexPointer(3, GL_FLOAT, 0, vertices);
glNormalPointer(GL_FLOAT, 0, normals);
glDrawArrays(GL_TRIANGLE_STRIP, 0, data.vertices.size());
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//assertGl();
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
//assertGl();
}
}
#endif
}
//Restore
static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(false);
glPopAttrib();
//assert
glGetError(); //remove when first mtex problem solved
assertGl();
IF_DEBUG_EDITION(
} // end else, if not renderering debug textures instead of regular terrain
getDebugRenderer().renderEffects(visibleQuad / Map::cellScale);
)
}
void Renderer::renderObjects(const int renderFps) {
const World *world= game->getWorld();
const Map *map= world->getMap();
assertGl();
const Texture2D *fowTex= NULL;
Vec3f baseFogColor;
bool modelRenderStarted = false;
VisibleQuadContainerCache &qCache = getQuadCache();
for(int visibleIndex = 0;
visibleIndex < qCache.visibleObjectList.size(); ++visibleIndex) {
Object *o = qCache.visibleObjectList[visibleIndex];
Model *objModel= o->getModelPtr();
const Vec3f &v= o->getConstPos();
if(modelRenderStarted == false) {
modelRenderStarted = true;
fowTex= world->getMinimap()->getFowTexture();
baseFogColor= world->getTileset()->getFogColor() * computeLightColor(world->getTimeFlow()->getTime());
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_FOG_BIT | GL_LIGHTING_BIT | GL_TEXTURE_BIT);
if(!shadowsOffDueToMinRender &&
shadows == sShadowMapping) {
glActiveTexture(shadowTexUnit);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
enableProjectiveTexturing();
}
glActiveTexture(baseTexUnit);
glEnable(GL_COLOR_MATERIAL);
glAlphaFunc(GL_GREATER, 0.5f);
modelRenderer->begin(true, true, false);
}
//ambient and diffuse color is taken from cell color
const Pixmap2D *fowTexPixmap = fowTex->getPixmapConst();
float fowFactor= fowTexPixmap->getPixelf(o->getMapPos().x / Map::cellScale, o->getMapPos().y / Map::cellScale);
Vec4f color= Vec4f(Vec3f(fowFactor), 1.f);
glColor4fv(color.ptr());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (color * ambFactor).ptr());
glFogfv(GL_FOG_COLOR, (baseFogColor * fowFactor).ptr());
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(v.x, v.y, v.z);
glRotatef(o->getRotation(), 0.f, 1.f, 0.f);
objModel->updateInterpolationData(0.f, true);
modelRenderer->render(objModel);
triangleCount+= objModel->getTriangleCount();
pointCount+= objModel->getVertexCount();
glPopMatrix();
}
if(modelRenderStarted == true) {
modelRenderer->end();
glPopAttrib();
}
//restore
static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
assertGl();
}
void Renderer::renderWater() {
bool closed= false;
const World *world= game->getWorld();
const Map *map= world->getMap();
float waterAnim= world->getWaterEffects()->getAmin();
//assert
assertGl();
glPushAttrib(GL_TEXTURE_BIT | GL_ENABLE_BIT | GL_CURRENT_BIT);
//water texture nit
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
if(textures3D){
Texture3D *waterTex= world->getTileset()->getWaterTex();
if(waterTex == NULL) {
throw runtime_error("waterTex == NULL");
}
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D, static_cast<Texture3DGl*>(waterTex)->getHandle());
}
else{
glEnable(GL_COLOR_MATERIAL);
glColor4f(0.5f, 0.5f, 1.0f, 0.5f);
glBindTexture(GL_TEXTURE_3D, 0);
}
assertGl();
//fog of War texture Unit
const Texture2D *fowTex= world->getMinimap()->getFowTexture();
glActiveTexture(fowTexUnit);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(fowTex)->getHandle());
glActiveTexture(baseTexUnit);
assertGl();
Rect2i boundingRect= visibleQuad.computeBoundingRect();
Rect2i scaledRect= boundingRect/Map::cellScale;
scaledRect.clamp(0, 0, map->getSurfaceW()-1, map->getSurfaceH()-1);
float waterLevel= world->getMap()->getWaterLevel();
for(int j=scaledRect.p[0].y; j<scaledRect.p[1].y; ++j){
glBegin(GL_TRIANGLE_STRIP);
for(int i=scaledRect.p[0].x; i<=scaledRect.p[1].x; ++i){
SurfaceCell *tc0= map->getSurfaceCell(i, j);
SurfaceCell *tc1= map->getSurfaceCell(i, j+1);
int thisTeamIndex= world->getThisTeamIndex();
bool cellExplored = world->showWorldForPlayer(world->getThisFactionIndex());
if(cellExplored == false) {
cellExplored = (tc0->isExplored(thisTeamIndex) || tc1->isExplored(thisTeamIndex));
}
if(tc0->getNearSubmerged() && cellExplored == true) {
glNormal3f(0.f, 1.f, 0.f);
closed= false;
triangleCount+= 2;
pointCount+= 2;
//vertex 1
glMaterialfv(
GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
computeWaterColor(waterLevel, tc1->getHeight()).ptr());
glMultiTexCoord2fv(GL_TEXTURE1, tc1->getFowTexCoord().ptr());
glTexCoord3f(i, 1.f, waterAnim);
glVertex3f(
static_cast<float>(i)*Map::mapScale,
waterLevel,
static_cast<float>(j+1)*Map::mapScale);
//vertex 2
glMaterialfv(
GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
computeWaterColor(waterLevel, tc0->getHeight()).ptr());
glMultiTexCoord2fv(GL_TEXTURE1, tc0->getFowTexCoord().ptr());
glTexCoord3f(i, 0.f, waterAnim);
glVertex3f(
static_cast<float>(i)*Map::mapScale,
waterLevel,
static_cast<float>(j)*Map::mapScale);
}
else{
if(!closed){
pointCount+= 2;
//vertex 1
glMaterialfv(
GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
computeWaterColor(waterLevel, tc1->getHeight()).ptr());
glMultiTexCoord2fv(GL_TEXTURE1, tc1->getFowTexCoord().ptr());
glTexCoord3f(i, 1.f, waterAnim);
glVertex3f(
static_cast<float>(i)*Map::mapScale,
waterLevel,
static_cast<float>(j+1)*Map::mapScale);
//vertex 2
glMaterialfv(
GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
computeWaterColor(waterLevel, tc0->getHeight()).ptr());
glMultiTexCoord2fv(GL_TEXTURE1, tc0->getFowTexCoord().ptr());
glTexCoord3f(i, 0.f, waterAnim);
glVertex3f(
static_cast<float>(i)*Map::mapScale,
waterLevel,
static_cast<float>(j)*Map::mapScale);
glEnd();
glBegin(GL_TRIANGLE_STRIP);
closed= true;
}
}
}
glEnd();
}
//restore
glPopAttrib();
assertGl();
}
void Renderer::renderUnits(const int renderFps) {
Unit *unit=NULL;
const World *world= game->getWorld();
MeshCallbackTeamColor meshCallbackTeamColor;
//assert
assertGl();
visibleFrameUnitList.clear();
bool modelRenderStarted = false;
VisibleQuadContainerCache &qCache = getQuadCache();
if(qCache.visibleQuadUnitList.size() > 0) {
for(int visibleUnitIndex = 0;
visibleUnitIndex < qCache.visibleQuadUnitList.size(); ++visibleUnitIndex) {
Unit *unit = qCache.visibleQuadUnitList[visibleUnitIndex];
meshCallbackTeamColor.setTeamTexture(unit->getFaction()->getTexture());
if(modelRenderStarted == false) {
modelRenderStarted = true;
glPushAttrib(GL_ENABLE_BIT | GL_FOG_BIT | GL_LIGHTING_BIT | GL_TEXTURE_BIT);
glEnable(GL_COLOR_MATERIAL);
if(!shadowsOffDueToMinRender) {
if(shadows == sShadowMapping) {
glActiveTexture(shadowTexUnit);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
enableProjectiveTexturing();
}
}
glActiveTexture(baseTexUnit);
modelRenderer->begin(true, true, true, &meshCallbackTeamColor);
}
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
//translate
Vec3f currVec= unit->getCurrVectorFlat();
glTranslatef(currVec.x, currVec.y, currVec.z);
//rotate
glRotatef(unit->getRotation(), 0.f, 1.f, 0.f);
glRotatef(unit->getVerticalRotation(), 1.f, 0.f, 0.f);
//dead alpha
float alpha= 1.0f;
const SkillType *st= unit->getCurrSkill();
if(st->getClass() == scDie && static_cast<const DieSkillType*>(st)->getFade()) {
alpha= 1.0f-unit->getAnimProgress();
glDisable(GL_COLOR_MATERIAL);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Vec4f(1.0f, 1.0f, 1.0f, alpha).ptr());
}
else {
glEnable(GL_COLOR_MATERIAL);
glAlphaFunc(GL_GREATER, 0.4f);
}
//render
Model *model= unit->getCurrentModelPtr();
model->updateInterpolationData(unit->getAnimProgress(), unit->isAlive());
modelRenderer->render(model);
triangleCount+= model->getTriangleCount();
pointCount+= model->getVertexCount();
glPopMatrix();
unit->setVisible(true);
unit->setScreenPos(computeScreenPosition(unit->getCurrVectorFlat()));
visibleFrameUnitList.push_back(unit);
//if(allowRenderUnitTitles == true) {
// Add to the pending render unit title list
//renderUnitTitleList.push_back(std::pair<Unit *,Vec3f>(unit,computeScreenPosition(unit->getCurrVectorFlat())) );
//}
}
if(modelRenderStarted == true) {
modelRenderer->end();
glPopAttrib();
}
}
//restore
static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
// reset alpha
glAlphaFunc(GL_GREATER, 0.0f);
//assert
assertGl();
}
void Renderer::renderSelectionEffects() {
const World *world= game->getWorld();
const Map *map= world->getMap();
const Selection *selection= game->getGui()->getSelection();
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDepthFunc(GL_ALWAYS);
glDisable(GL_STENCIL_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glLineWidth(2.f);
//units
for(int i=0; i<selection->getCount(); ++i){
const Unit *unit= selection->getUnit(i);
//translate
Vec3f currVec= unit->getCurrVectorFlat();
currVec.y+= 0.3f;
//selection circle
if(world->getThisFactionIndex() == unit->getFactionIndex()) {
if( showDebugUI == true && unit->getCommandSize() > 0 &&
dynamic_cast<const BuildCommandType *>(unit->getCurrCommand()->getCommandType()) != NULL) {
glColor4f(unit->getHpRatio(), unit->getHpRatio(), unit->getHpRatio(), 0.3f);
}
else {
glColor4f(0, unit->getHpRatio(), 0, 0.3f);
}
}
else if ( world->getThisTeamIndex() == unit->getTeam()) {
glColor4f(unit->getHpRatio(), unit->getHpRatio(), 0, 0.3f);
}
else{
glColor4f(unit->getHpRatio(), 0, 0, 0.3f);
}
renderSelectionCircle(currVec, unit->getType()->getSize(), selectionCircleRadius);
//magic circle
if(world->getThisFactionIndex() == unit->getFactionIndex() && unit->getType()->getMaxEp() > 0) {
glColor4f(unit->getEpRatio()/2.f, unit->getEpRatio(), unit->getEpRatio(), 0.5f);
renderSelectionCircle(currVec, unit->getType()->getSize(), magicCircleRadius);
}
}
//target arrow
if(selection->getCount() == 1) {
const Unit *unit= selection->getUnit(0);
//comand arrow
if(focusArrows && unit->anyCommand()) {
const CommandType *ct= unit->getCurrCommand()->getCommandType();
if(ct->getClicks() != cOne){
//arrow color
Vec3f arrowColor;
switch(ct->getClass()) {
case ccMove:
arrowColor= Vec3f(0.f, 1.f, 0.f);
break;
case ccAttack:
case ccAttackStopped:
arrowColor= Vec3f(1.f, 0.f, 0.f);
break;
default:
arrowColor= Vec3f(1.f, 1.f, 0.f);
}
//arrow target
Vec3f arrowTarget;
Command *c= unit->getCurrCommand();
if(c->getUnit() != NULL) {
arrowTarget= c->getUnit()->getCurrVectorFlat();
}
else {
Vec2i pos= c->getPos();
arrowTarget= Vec3f(pos.x, map->getCell(pos)->getHeight(), pos.y);
}
renderArrow(unit->getCurrVectorFlat(), arrowTarget, arrowColor, 0.3f);
}
}
//meeting point arrow
if(unit->getType()->getMeetingPoint()) {
Vec2i pos= unit->getMeetingPos();
Vec3f arrowTarget= Vec3f(pos.x, map->getCell(pos)->getHeight(), pos.y);
renderArrow(unit->getCurrVectorFlat(), arrowTarget, Vec3f(0.f, 0.f, 1.f), 0.3f);
}
}
//render selection hightlights
for(int i=0; i < world->getFactionCount(); ++i) {
for(int j=0; j < world->getFaction(i)->getUnitCount(); ++j) {
const Unit *unit= world->getFaction(i)->getUnit(j);
if(unit->isHighlighted()) {
float highlight= unit->getHightlight();
if(game->getWorld()->getThisFactionIndex() == unit->getFactionIndex()) {
glColor4f(0.f, 1.f, 0.f, highlight);
}
else{
glColor4f(1.f, 0.f, 0.f, highlight);
}
Vec3f v= unit->getCurrVectorFlat();
v.y+= 0.3f;
renderSelectionCircle(v, unit->getType()->getSize(), selectionCircleRadius);
}
}
}
glPopAttrib();
}
void Renderer::renderWaterEffects(){
const World *world= game->getWorld();
const WaterEffects *we= world->getWaterEffects();
const Map *map= world->getMap();
const CoreData &coreData= CoreData::getInstance();
float height= map->getWaterLevel()+0.001f;
assertGl();
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDepthMask(GL_FALSE);
glDepthFunc(GL_LEQUAL);
glEnable(GL_COLOR_MATERIAL);
glNormal3f(0.f, 1.f, 0.f);
//splashes
glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(coreData.getWaterSplashTexture())->getHandle());
for(int i=0; i<we->getWaterSplashCount(); ++i){
const WaterSplash *ws= we->getWaterSplash(i);
//render only if enabled
if(ws->getEnabled()){
//render only if visible
Vec2i intPos= Vec2i(static_cast<int>(ws->getPos().x), static_cast<int>(ws->getPos().y));
const Vec2i &mapPos = Map::toSurfCoords(intPos);
if(map->getSurfaceCell(mapPos)->isVisible(world->getThisTeamIndex())){
float scale= ws->getAnim()*ws->getSize();
glColor4f(1.f, 1.f, 1.f, 1.f-ws->getAnim());
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.f, 1.f);
glVertex3f(ws->getPos().x-scale, height, ws->getPos().y+scale);
glTexCoord2f(0.f, 0.f);
glVertex3f(ws->getPos().x-scale, height, ws->getPos().y-scale);
glTexCoord2f(1.f, 1.f);
glVertex3f(ws->getPos().x+scale, height, ws->getPos().y+scale);
glTexCoord2f(1.f, 0.f);
glVertex3f(ws->getPos().x+scale, height, ws->getPos().y-scale);
glEnd();
}
}
}
glPopAttrib();
assertGl();
}
void Renderer::renderMinimap(){
const World *world= game->getWorld();
const Minimap *minimap= world->getMinimap();
const GameCamera *gameCamera= game->getGameCamera();
const Pixmap2D *pixmap= minimap->getTexture()->getPixmapConst();
const Metrics &metrics= Metrics::getInstance();
const WaterEffects *attackEffects= world->getAttackEffects();
int mx= metrics.getMinimapX();
int my= metrics.getMinimapY();
int mw= metrics.getMinimapW();
int mh= metrics.getMinimapH();
Vec2f zoom= Vec2f(
static_cast<float>(mw)/ pixmap->getW(),
static_cast<float>(mh)/ pixmap->getH());
assertGl();
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_TEXTURE_BIT);
//draw map
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glActiveTexture(fowTexUnit);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(minimap->getFowTexture())->getHandle());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
glActiveTexture(baseTexUnit);
glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(minimap->getTexture())->getHandle());
glColor4f(0.5f, 0.5f, 0.5f, 0.1f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 1.0f);
glMultiTexCoord2f(fowTexUnit, 0.0f, 1.0f);
glVertex2i(mx, my);
glTexCoord2f(0.0f, 0.0f);
glMultiTexCoord2f(fowTexUnit, 0.0f, 0.0f);
glVertex2i(mx, my+mh);
glTexCoord2f(1.0f, 1.0f);
glMultiTexCoord2f(fowTexUnit, 1.0f, 1.0f);
glVertex2i(mx+mw, my);
glTexCoord2f(1.0f, 0.0f);
glMultiTexCoord2f(fowTexUnit, 1.0f, 0.0f);
glVertex2i(mx+mw, my+mh);
glEnd();
glDisable(GL_BLEND);
glActiveTexture(fowTexUnit);
glDisable(GL_TEXTURE_2D);
glActiveTexture(baseTexUnit);
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
// draw attack alarm
for(int i=0; i<attackEffects->getWaterSplashCount(); ++i){
const WaterSplash *ws= attackEffects->getWaterSplash(i);
float scale= (1/ws->getAnim()*ws->getSize())*5;
glColor4f(1.f, 1.f, 0.f, 1.f-ws->getAnim());
float alpha=(1.f-ws->getAnim())*0.01f;
Vec2f pos= ws->getPos()/Map::cellScale;
float attackX=mx +pos.x*zoom.x;
float attackY=my +mh -pos.y*zoom.y;
if(ws->getEnabled()){
// glBegin(GL_QUADS);
// glVertex2f(attackX-scale, attackY-scale);
// glVertex2f(attackX-scale, attackY+scale);
// glVertex2f(attackX+scale, attackY+scale);
// glVertex2f(attackX+scale, attackY-scale);
// glEnd();
glBegin(GL_TRIANGLES);
glColor4f(1.f, 1.f, 0.f, alpha);
glVertex2f(attackX-scale, attackY-scale);
glVertex2f(attackX-scale, attackY+scale);
glColor4f(1.f, 1.f, 0.f, 0.8f);
glVertex2f(attackX, attackY);
glEnd();
glBegin(GL_TRIANGLES);
glColor4f(1.f, 1.f, 0.f, alpha);
glVertex2f(attackX-scale, attackY+scale);
glVertex2f(attackX+scale, attackY+scale);
glColor4f(1.f, 1.f, 0.f, 0.8f);
glVertex2f(attackX, attackY);
glEnd();
glBegin(GL_TRIANGLES);
glColor4f(1.f, 1.f, 0.f, alpha);
glVertex2f(attackX+scale, attackY+scale);
glVertex2f(attackX+scale, attackY-scale);
glColor4f(1.f, 1.f, 0.f, 0.8f);
glVertex2f(attackX, attackY);
glEnd();
glBegin(GL_TRIANGLES);
glColor4f(1.f, 1.f, 0.f, alpha);
glVertex2f(attackX+scale, attackY-scale);
glVertex2f(attackX-scale, attackY-scale);
glColor4f(1.f, 1.f, 0.f, 0.8f);
glVertex2f(attackX, attackY);
glEnd();
}
}
glDisable(GL_BLEND);
//draw units
VisibleQuadContainerCache &qCache = getQuadCache();
if(qCache.visibleUnitList.size() > 0) {
for(int visibleIndex = 0;
visibleIndex < qCache.visibleUnitList.size(); ++visibleIndex) {
Unit *unit = qCache.visibleUnitList[visibleIndex];
if (!unit->isAlive()) {
continue;
}
Vec2i pos= unit->getPos() / Map::cellScale;
int size= unit->getType()->getSize();
Vec3f color= unit->getFaction()->getTexture()->getPixmapConst()->getPixel3f(0, 0);
glColor3fv(color.ptr());
glBegin(GL_QUADS);
glVertex2f(mx + pos.x*zoom.x, my + mh - (pos.y*zoom.y));
glVertex2f(mx + (pos.x+1)*zoom.x+size, my + mh - (pos.y*zoom.y));
glVertex2f(mx + (pos.x+1)*zoom.x+size, my + mh - ((pos.y+size)*zoom.y));
glVertex2f(mx + pos.x*zoom.x, my + mh - ((pos.y+size)*zoom.y));
glEnd();
}
}
//draw camera
float wRatio= static_cast<float>(metrics.getMinimapW()) / world->getMap()->getW();
float hRatio= static_cast<float>(metrics.getMinimapH()) / world->getMap()->getH();
int x= static_cast<int>(gameCamera->getPos().x * wRatio);
int y= static_cast<int>(gameCamera->getPos().z * hRatio);
float ang= degToRad(gameCamera->getHAng());
glEnable(GL_BLEND);
int x1 = 0;
int y1 = 0;
#ifdef USE_STREFLOP
x1 = mx + x + static_cast<int>(20*streflop::sin(ang-pi/5));
y1 = my + mh - (y-static_cast<int>(20*streflop::cos(ang-pi/5)));
#else
x1 = mx + x + static_cast<int>(20*sin(ang-pi/5));
y1 = my + mh - (y-static_cast<int>(20*cos(ang-pi/5)));
#endif
int x2 = 0;
int y2 = 0;
#ifdef USE_STREFLOP
x2 = mx + x + static_cast<int>(20*streflop::sin(ang+pi/5));
y2 = my + mh - (y-static_cast<int>(20*streflop::cos(ang+pi/5)));
#else
x2 = mx + x + static_cast<int>(20*sin(ang+pi/5));
y2 = my + mh - (y-static_cast<int>(20*cos(ang+pi/5)));
#endif
glColor4f(1.f, 1.f, 1.f, 1.f);
glBegin(GL_TRIANGLES);
glVertex2i(mx+x, my+mh-y);
glColor4f(1.f, 1.f, 1.f, 0.0f);
glVertex2i(x1,y1);
glColor4f(1.f, 1.f, 1.f, 0.0f);
glVertex2i(x2,y2);
glEnd();
glPopAttrib();
assertGl();
}
void Renderer::renderDisplay(){
CoreData &coreData= CoreData::getInstance();
const Metrics &metrics= Metrics::getInstance();
const Display *display= game->getGui()->getDisplay();
glPushAttrib(GL_ENABLE_BIT);
//infoString
renderTextShadow(
display->getInfoText().c_str(),
coreData.getDisplayFont(),
display->getColor(),
metrics.getDisplayX(),
metrics.getDisplayY()+Display::infoStringY);
//title
renderTextShadow(
display->getTitle().c_str(),
coreData.getDisplayFont(),
display->getColor(),
metrics.getDisplayX()+40,
metrics.getDisplayY() + metrics.getDisplayH() - 20);
glColor3f(0.0f, 0.0f, 0.0f);
//text
renderTextShadow(
display->getText().c_str(),
coreData.getDisplayFont(),
display->getColor(),
metrics.getDisplayX() -1,
metrics.getDisplayY() + metrics.getDisplayH() - 56);
//progress Bar
if(display->getProgressBar()!=-1){
renderProgressBar(
display->getProgressBar(),
metrics.getDisplayX(),
metrics.getDisplayY() + metrics.getDisplayH()-50,
coreData.getDisplayFontSmall());
}
//up images
glEnable(GL_TEXTURE_2D);
glColor3f(1.f, 1.f, 1.f);
for(int i=0; i<Display::upCellCount; ++i){
if(display->getUpImage(i)!=NULL){
renderQuad(
metrics.getDisplayX()+display->computeUpX(i),
metrics.getDisplayY()+display->computeUpY(i),
Display::imageSize, Display::imageSize, display->getUpImage(i));
}
}
//down images
for(int i=0; i<Display::downCellCount; ++i){
if(display->getDownImage(i)!=NULL){
if(display->getDownLighted(i)){
glColor3f(1.f, 1.f, 1.f);
}
else{
glColor3f(0.3f, 0.3f, 0.3f);
}
int x= metrics.getDisplayX()+display->computeDownX(i);
int y= metrics.getDisplayY()+display->computeDownY(i);
int size= Display::imageSize;
if(display->getDownSelectedPos()==i){
x-= 3;
y-= 3;
size+= 6;
}
renderQuad(x, y, size, size, display->getDownImage(i));
}
}
//selection
int downPos= display->getDownSelectedPos();
if(downPos!=Display::invalidPos){
const Texture2D *texture= display->getDownImage(downPos);
if(texture!=NULL){
int x= metrics.getDisplayX()+display->computeDownX(downPos)-3;
int y= metrics.getDisplayY()+display->computeDownY(downPos)-3;
int size= Display::imageSize+6;
renderQuad(x, y, size, size, display->getDownImage(downPos));
}
}
glPopAttrib();
}
void Renderer::renderMenuBackground(const MenuBackground *menuBackground){
assertGl();
const Vec3f &cameraPosition= menuBackground->getCamera()->getConstPosition();
glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
//clear
Vec4f fogColor= Vec4f(0.4f, 0.4f, 0.4f, 1.f) * menuBackground->getFade();
glClearColor(fogColor.x, fogColor.y, fogColor.z, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFogfv(GL_FOG_COLOR, fogColor.ptr());
//light
Vec4f lightPos= Vec4f(10.f, 10.f, 10.f, 1.f)* menuBackground->getFade();
Vec4f diffLight= Vec4f(0.9f, 0.9f, 0.9f, 1.f)* menuBackground->getFade();
Vec4f ambLight= Vec4f(0.3f, 0.3f, 0.3f, 1.f)* menuBackground->getFade();
Vec4f specLight= Vec4f(0.1f, 0.1f, 0.1f, 1.f)* menuBackground->getFade();
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos.ptr());
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffLight.ptr());
glLightfv(GL_LIGHT0, GL_AMBIENT, ambLight.ptr());
glLightfv(GL_LIGHT0, GL_SPECULAR, specLight.ptr());
//main model
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5f);
modelRenderer->begin(true, true, true);
modelRenderer->render(menuBackground->getMainModelPtr());
modelRenderer->end();
glDisable(GL_ALPHA_TEST);
//characters
float dist= menuBackground->getAboutPosition().dist(cameraPosition);
float minDist= 3.f;
if(dist < minDist) {
glAlphaFunc(GL_GREATER, 0.0f);
float alpha= clamp((minDist-dist) / minDist, 0.f, 1.f);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Vec4f(1.0f, 1.0f, 1.0f, alpha).ptr());
modelRenderer->begin(true, true, false);
for(int i=0; i < MenuBackground::characterCount; ++i) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(i*2.f-4.f, -1.4f, -7.5f);
menuBackground->getCharacterModelPtr(i)->updateInterpolationData(menuBackground->getAnim(), true);
modelRenderer->render(menuBackground->getCharacterModelPtr(i));
glPopMatrix();
}
modelRenderer->end();
}
//water
if(menuBackground->getWater()) {
//water surface
const int waterTesselation= 10;
const int waterSize= 250;
const int waterQuadSize= 2*waterSize/waterTesselation;
const float waterHeight= menuBackground->getWaterHeight();
glEnable(GL_BLEND);
glNormal3f(0.f, 1.f, 0.f);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Vec4f(1.f, 1.f, 1.f, 1.f).ptr());
GLuint waterHandle= static_cast<Texture2DGl*>(menuBackground->getWaterTexture())->getHandle();
glBindTexture(GL_TEXTURE_2D, waterHandle);
for(int i=1; i < waterTesselation; ++i) {
glBegin(GL_TRIANGLE_STRIP);
for(int j=1; j < waterTesselation; ++j) {
glTexCoord2i(1, 2 % j);
glVertex3f(-waterSize+i*waterQuadSize, waterHeight, -waterSize+j*waterQuadSize);
glTexCoord2i(0, 2 % j);
glVertex3f(-waterSize+(i+1)*waterQuadSize, waterHeight, -waterSize+j*waterQuadSize);
}
glEnd();
}
glDisable(GL_BLEND);
//raindrops
if(menuBackground->getRain()) {
const float maxRaindropAlpha= 0.5f;
glEnable(GL_BLEND);
glDisable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
glDepthMask(GL_FALSE);
//splashes
CoreData &coreData= CoreData::getInstance();
glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(coreData.getWaterSplashTexture())->getHandle());
for(int i=0; i< MenuBackground::raindropCount; ++i) {
Vec2f pos= menuBackground->getRaindropPos(i);
float scale= menuBackground->getRaindropState(i);
float alpha= maxRaindropAlpha-scale*maxRaindropAlpha;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glColor4f(1.f, 1.f, 1.f, alpha);
glTranslatef(pos.x, waterHeight+0.01f, pos.y);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.f, 1.f);
glVertex3f(-scale, 0, scale);
glTexCoord2f(0.f, 0.f);
glVertex3f(-scale, 0, -scale);
glTexCoord2f(1.f, 1.f);
glVertex3f(scale, 0, scale);
glTexCoord2f(1.f, 0.f);
glVertex3f(scale, 0, -scale);
glEnd();
glPopMatrix();
}
}
}
glPopAttrib();
assertGl();
}
// ==================== computing ====================
bool Renderer::computePosition(const Vec2i &screenPos, Vec2i &worldPos){
assertGl();
const Map* map= game->getWorld()->getMap();
const Metrics &metrics= Metrics::getInstance();
float depth= 0.0f;
GLdouble modelviewMatrix[16];
GLdouble projectionMatrix[16];
GLint viewport[4]= {0, 0, metrics.getScreenW(), metrics.getScreenH()};
GLdouble worldX;
GLdouble worldY;
GLdouble worldZ;
GLint screenX= (screenPos.x * metrics.getScreenW() / metrics.getVirtualW());
GLint screenY= (screenPos.y * metrics.getScreenH() / metrics.getVirtualH());
//get the depth in the cursor pixel
glReadPixels(screenX, screenY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
//load matrices
loadProjectionMatrix();
loadGameCameraMatrix();
//get matrices
glGetDoublev(GL_MODELVIEW_MATRIX, modelviewMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
//get the world coordinates
gluUnProject(
screenX, screenY, depth,
modelviewMatrix, projectionMatrix, viewport,
&worldX, &worldY, &worldZ);
//conver coords to int
worldPos= Vec2i(static_cast<int>(worldX+0.5f), static_cast<int>(worldZ+0.5f));
//clamp coords to map size
return map->isInside(worldPos);
}
// This method takes world co-ordinates and translates them to screen co-ords
Vec3f Renderer::computeScreenPosition(const Vec3f &worldPos) {
if(worldToScreenPosCache.find(worldPos) != worldToScreenPosCache.end()) {
return worldToScreenPosCache[worldPos];
}
assertGl();
const Metrics &metrics= Metrics::getInstance();
GLint viewport[]= {0, 0, metrics.getVirtualW(), metrics.getVirtualH()};
GLdouble worldX = worldPos.x;
GLdouble worldY = worldPos.y;
GLdouble worldZ = worldPos.z;
//load matrices
loadProjectionMatrix();
loadGameCameraMatrix();
//get matrices
GLdouble modelviewMatrix[16];
glGetDoublev(GL_MODELVIEW_MATRIX, modelviewMatrix);
GLdouble projectionMatrix[16];
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
//get the screen coordinates
GLdouble screenX;
GLdouble screenY;
GLdouble screenZ;
gluProject(worldX, worldY, worldZ,
modelviewMatrix, projectionMatrix, viewport,
&screenX, &screenY, &screenZ);
Vec3f screenPos(screenX,screenY,screenZ);
worldToScreenPosCache[worldPos]=screenPos;
return screenPos;
}
void Renderer::computeSelected( Selection::UnitContainer &units,
const Vec2i &posDown, const Vec2i &posUp) {
//declarations
GLuint selectBuffer[Gui::maxSelBuff];
const Metrics &metrics= Metrics::getInstance();
//compute center and dimensions of selection rectangle
int x= (posDown.x+posUp.x) / 2;
int y= (posDown.y+posUp.y) / 2;
int w= abs(posDown.x-posUp.x);
int h= abs(posDown.y-posUp.y);
if(w<1) w=1;
if(h<1) h=1;
//setup matrices
glSelectBuffer(Gui::maxSelBuff, selectBuffer);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
GLint view[]= {0, 0, metrics.getVirtualW(), metrics.getVirtualH()};
glRenderMode(GL_SELECT);
glLoadIdentity();
gluPickMatrix(x, y, w, h, view);
gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, perspFarPlane);
loadGameCameraMatrix();
//render units to find which ones should be selected
renderUnitsFast();
//pop matrices
glMatrixMode(GL_PROJECTION);
glPopMatrix();
//select units by checking the selected buffer
int selCount= glRenderMode(GL_RENDER);
if(selCount > 0) {
VisibleQuadContainerCache &qCache = getQuadCache();
for(int i=1; i <= selCount; ++i) {
int visibleUnitIndex= selectBuffer[i*4-1];
Unit *unit = qCache.visibleQuadUnitList[visibleUnitIndex];
if(unit != NULL && unit->isAlive()) {
units.push_back(unit);
}
}
}
}
// ==================== shadows ====================
void Renderer::renderShadowsToTexture(const int renderFps){
if(!shadowsOffDueToMinRender &&
(shadows == sProjected || shadows == sShadowMapping)) {
shadowMapFrame= (shadowMapFrame + 1) % (shadowFrameSkip + 1);
if(shadowMapFrame == 0){
assertGl();
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT | GL_POLYGON_BIT);
if(shadows==sShadowMapping){
glClear(GL_DEPTH_BUFFER_BIT);
}
else{
float color= 1.0f-shadowAlpha;
glColor3f(color, color, color);
glClearColor(1.f, 1.f, 1.f, 1.f);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
}
//clear color buffer
//
//set viewport, we leave one texel always in white to avoid problems
glViewport(1, 1, shadowTextureSize-2, shadowTextureSize-2);
if(nearestLightPos.w==0.f){
//directional light
//light pos
assert(game != NULL);
assert(game->getWorld() != NULL);
const TimeFlow *tf= game->getWorld()->getTimeFlow();
assert(tf != NULL);
float ang= tf->isDay()? computeSunAngle(tf->getTime()): computeMoonAngle(tf->getTime());
ang= radToDeg(ang);
//push and set projection
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
if(game->getGameCamera()->getState()==GameCamera::sGame){
//glOrtho(-35, 5, -15, 15, -1000, 1000);
//glOrtho(-30, 30, -20, 20, -1000, 1000);
glOrtho(-30, 5, -20, 20, -1000, 1000);
}
else{
glOrtho(-30, 30, -20, 20, -1000, 1000);
}
//push and set modelview
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glRotatef(15, 0, 1, 0);
glRotatef(ang, 1, 0, 0);
glRotatef(90, 0, 1, 0);
const Vec3f &pos= game->getGameCamera()->getPos();
glTranslatef(static_cast<int>(-pos.x), 0, static_cast<int>(-pos.z));
}
else{
//non directional light
//push projection
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(perspFov, 1.f, perspNearPlane, perspFarPlane);
//const Metrics &metrics= Metrics::getInstance();
//gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, perspFarPlane);
//push modelview
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glRotatef(-90, -1, 0, 0);
glTranslatef(-nearestLightPos.x, -nearestLightPos.y-2, -nearestLightPos.z);
}
if(shadows == sShadowMapping) {
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0f, 0.001f);
}
//render 3d
renderUnitsFast(true);
renderObjectsFast();
//read color buffer
glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowTextureSize, shadowTextureSize);
//get elemental matrices
static Matrix4f matrix1;
static bool matrix1Populate = true;
if(matrix1Populate == true) {
matrix1Populate = false;
matrix1[0]= 0.5f; matrix1[4]= 0.f; matrix1[8]= 0.f; matrix1[12]= 0.5f;
matrix1[1]= 0.f; matrix1[5]= 0.5f; matrix1[9]= 0.f; matrix1[13]= 0.5f;
matrix1[2]= 0.f; matrix1[6]= 0.f; matrix1[10]= 0.5f; matrix1[14]= 0.5f;
matrix1[3]= 0.f; matrix1[7]= 0.f; matrix1[11]= 0.f; matrix1[15]= 1.f;
}
Matrix4f matrix2;
glGetFloatv(GL_PROJECTION_MATRIX, matrix2.ptr());
Matrix4f matrix3;
glGetFloatv(GL_MODELVIEW_MATRIX, matrix3.ptr());
//pop both matrices
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
//compute texture matrix
glLoadMatrixf(matrix1.ptr());
glMultMatrixf(matrix2.ptr());
glMultMatrixf(matrix3.ptr());
glGetFloatv(GL_TRANSPOSE_PROJECTION_MATRIX_ARB, shadowMapMatrix.ptr());
//pop
glPopMatrix();
glPopAttrib();
assertGl();
}
}
}
// ==================== gl wrap ====================
string Renderer::getGlInfo(){
string infoStr;
Lang &lang= Lang::getInstance();
infoStr+= lang.get("OpenGlInfo")+":\n";
infoStr+= " "+lang.get("OpenGlVersion")+": ";
infoStr+= string((getGlVersion() != NULL ? getGlVersion() : "?"))+"\n";
infoStr+= " "+lang.get("OpenGlRenderer")+": ";
infoStr+= string((getGlVersion() != NULL ? getGlVersion() : "?"))+"\n";
infoStr+= " "+lang.get("OpenGlVendor")+": ";
infoStr+= string((getGlVendor() != NULL ? getGlVendor() : "?"))+"\n";
infoStr+= " "+lang.get("OpenGlMaxLights")+": ";
infoStr+= intToStr(getGlMaxLights())+"\n";
infoStr+= " "+lang.get("OpenGlMaxTextureSize")+": ";
infoStr+= intToStr(getGlMaxTextureSize())+"\n";
infoStr+= " "+lang.get("OpenGlMaxTextureUnits")+": ";
infoStr+= intToStr(getGlMaxTextureUnits())+"\n";
infoStr+= " "+lang.get("OpenGlModelviewStack")+": ";
infoStr+= intToStr(getGlModelviewMatrixStackDepth())+"\n";
infoStr+= " "+lang.get("OpenGlProjectionStack")+": ";
infoStr+= intToStr(getGlProjectionMatrixStackDepth())+"\n";
return infoStr;
}
string Renderer::getGlMoreInfo(){
string infoStr;
Lang &lang= Lang::getInstance();
//gl extensions
infoStr+= lang.get("OpenGlExtensions")+":\n ";
string extensions= getGlExtensions();
int charCount= 0;
for(int i=0; i<extensions.size(); ++i){
infoStr+= extensions[i];
if(charCount>120 && extensions[i]==' '){
infoStr+= "\n ";
charCount= 0;
}
++charCount;
}
//platform extensions
infoStr+= "\n\n";
infoStr+= lang.get("OpenGlPlatformExtensions")+":\n ";
charCount= 0;
string platformExtensions= getGlPlatformExtensions();
for(int i=0; i<platformExtensions.size(); ++i){
infoStr+= platformExtensions[i];
if(charCount>120 && platformExtensions[i]==' '){
infoStr+= "\n ";
charCount= 0;
}
++charCount;
}
return infoStr;
}
void Renderer::autoConfig(){
Config &config= Config::getInstance();
bool nvidiaCard= toLower(getGlVendor()).find("nvidia")!=string::npos;
bool atiCard= toLower(getGlVendor()).find("ati")!=string::npos;
//bool shadowExtensions = isGlExtensionSupported("GL_ARB_shadow") && isGlExtensionSupported("GL_ARB_shadow_ambient");
bool shadowExtensions = isGlExtensionSupported("GL_ARB_shadow");
//3D textures
config.setBool("Textures3D", isGlExtensionSupported("GL_EXT_texture3D"));
//shadows
string shadows;
if(getGlMaxTextureUnits()>=3){
if(nvidiaCard && shadowExtensions){
shadows= shadowsToStr(sShadowMapping);
}
else{
shadows= shadowsToStr(sProjected);
}
}
else{
shadows=shadowsToStr(sDisabled);
}
config.setString("Shadows", shadows);
//lights
config.setInt("MaxLights", atiCard? 1: 4);
//filter
config.setString("Filter", "Bilinear");
}
void Renderer::clearBuffers(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Renderer::clearZBuffer(){
glClear(GL_DEPTH_BUFFER_BIT);
}
void Renderer::loadConfig() {
Config &config= Config::getInstance();
//cache most used config params
maxLights= config.getInt("MaxLights");
photoMode= config.getBool("PhotoMode");
focusArrows= config.getBool("FocusArrows");
textures3D= config.getBool("Textures3D");
//load shadows
shadows= strToShadows(config.getString("Shadows"));
if(shadows==sProjected || shadows==sShadowMapping){
shadowTextureSize= config.getInt("ShadowTextureSize");
shadowFrameSkip= config.getInt("ShadowFrameSkip");
shadowAlpha= config.getFloat("ShadowAlpha");
}
//load filter settings
Texture2D::Filter textureFilter= strToTextureFilter(config.getString("Filter"));
int maxAnisotropy= config.getInt("FilterMaxAnisotropy");
for(int i=0; i<rsCount; ++i){
textureManager[i]->setFilter(textureFilter);
textureManager[i]->setMaxAnisotropy(maxAnisotropy);
}
}
Texture2D *Renderer::saveScreenToTexture(int x, int y, int width, int height) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
Config &config= Config::getInstance();
Texture2D::Filter textureFilter = strToTextureFilter(config.getString("Filter"));
int maxAnisotropy = config.getInt("FilterMaxAnisotropy");
Texture2D *texture = GraphicsInterface::getInstance().getFactory()->newTexture2D();
//texture->setFormat(Texture::fRgba);
texture->setForceCompressionDisabled(true);
texture->setMipmap(false);
//Pixmap2D *pixmapScreenShot = new Pixmap2D(width, height, 3);
Pixmap2D *pixmapScreenShot = texture->getPixmap();
pixmapScreenShot->init(width, height, 3);
//const Metrics &sm= Metrics::getInstance();
//pixmapScreenShot->init(sm.getScreenW(), sm.getScreenH(), 3);
texture->init(textureFilter,maxAnisotropy);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//glFinish();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glReadPixels(x, y, pixmapScreenShot->getW(), pixmapScreenShot->getH(),
GL_RGB, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
return texture;
}
void Renderer::saveScreen(const string &path) {
const Metrics &sm= Metrics::getInstance();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//Pixmap2D pixmap(sm.getScreenW(), sm.getScreenH(), 3);
Pixmap2D *pixmapScreenShot = new Pixmap2D(sm.getScreenW(), sm.getScreenH(), 3);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glFinish();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glReadPixels(0, 0, pixmapScreenShot->getW(), pixmapScreenShot->getH(),
GL_RGB, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
// Signal the threads queue to add a screenshot save request
MutexSafeWrapper safeMutex(&saveScreenShotThreadAccessor);
saveScreenQueue.push_back(make_pair(path,pixmapScreenShot));
safeMutex.ReleaseLock();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
unsigned int Renderer::getSaveScreenQueueSize() {
MutexSafeWrapper safeMutex(&saveScreenShotThreadAccessor);
int queueSize = saveScreenQueue.size();
safeMutex.ReleaseLock();
return queueSize;
}
// ==================== PRIVATE ====================
float Renderer::computeSunAngle(float time) {
float dayTime= TimeFlow::dusk-TimeFlow::dawn;
float fTime= (time-TimeFlow::dawn)/dayTime;
return clamp(fTime*pi, pi/8.f, 7.f*pi/8.f);
}
float Renderer::computeMoonAngle(float time) {
float nightTime= 24-(TimeFlow::dusk-TimeFlow::dawn);
if(time<TimeFlow::dawn){
time+= 24.f;
}
float fTime= (time-TimeFlow::dusk)/nightTime;
return clamp((1.0f-fTime)*pi, pi/8.f, 7.f*pi/8.f);
}
Vec4f Renderer::computeSunPos(float time) {
float ang= computeSunAngle(time);
#ifdef USE_STREFLOP
return Vec4f(-streflop::cos(ang)*sunDist, streflop::sin(ang)*sunDist, 0.f, 0.f);
#else
return Vec4f(-cos(ang)*sunDist, sin(ang)*sunDist, 0.f, 0.f);
#endif
}
Vec4f Renderer::computeMoonPos(float time) {
float ang= computeMoonAngle(time);
#ifdef USE_STREFLOP
return Vec4f(-streflop::cos(ang)*moonDist, streflop::sin(ang)*moonDist, 0.f, 0.f);
#else
return Vec4f(-cos(ang)*moonDist, sin(ang)*moonDist, 0.f, 0.f);
#endif
}
Vec3f Renderer::computeLightColor(float time) {
const Tileset *tileset= game->getWorld()->getTileset();
Vec3f color;
const float transition= 2;
const float dayStart= TimeFlow::dawn;
const float dayEnd= TimeFlow::dusk-transition;
const float nightStart= TimeFlow::dusk;
const float nightEnd= TimeFlow::dawn-transition;
if(time>dayStart && time<dayEnd) {
color= tileset->getSunLightColor();
}
else if(time>nightStart || time<nightEnd) {
color= tileset->getMoonLightColor();
}
else if(time>=dayEnd && time<=nightStart) {
color= tileset->getSunLightColor().lerp((time-dayEnd)/transition, tileset->getMoonLightColor());
}
else if(time>=nightEnd && time<=dayStart) {
color= tileset->getMoonLightColor().lerp((time-nightEnd)/transition, tileset->getSunLightColor());
}
else {
assert(false);
color= tileset->getSunLightColor();
}
return color;
}
Vec4f Renderer::computeWaterColor(float waterLevel, float cellHeight) {
const float waterFactor= 1.5f;
return Vec4f(1.f, 1.f, 1.f, clamp((waterLevel-cellHeight)*waterFactor, 0.f, 1.f));
}
// ==================== fast render ====================
//render units for selection purposes
void Renderer::renderUnitsFast(bool renderingShadows) {
assert(game != NULL);
const World *world= game->getWorld();
assert(world != NULL);
assertGl();
bool modelRenderStarted = false;
VisibleQuadContainerCache &qCache = getQuadCache();
if(qCache.visibleQuadUnitList.size() > 0) {
for(int visibleUnitIndex = 0;
visibleUnitIndex < qCache.visibleQuadUnitList.size(); ++visibleUnitIndex) {
Unit *unit = qCache.visibleQuadUnitList[visibleUnitIndex];
if(modelRenderStarted == false) {
modelRenderStarted = true;
//glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT);
glDisable(GL_LIGHTING);
if (renderingShadows == false) {
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_TEXTURE_2D);
}
else {
glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT);
glEnable(GL_TEXTURE_2D);
glAlphaFunc(GL_GREATER, 0.4f);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
//set color to the texture alpha
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
//set alpha to the texture alpha
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
}
modelRenderer->begin(false, renderingShadows, false);
glInitNames();
}
glPushName(visibleUnitIndex);
glMatrixMode(GL_MODELVIEW);
//debuxar modelo
glPushMatrix();
//translate
Vec3f currVec= unit->getCurrVectorFlat();
glTranslatef(currVec.x, currVec.y, currVec.z);
//rotate
glRotatef(unit->getRotation(), 0.f, 1.f, 0.f);
//render
Model *model= unit->getCurrentModelPtr();
model->updateInterpolationVertices(unit->getAnimProgress(), unit->isAlive());
modelRenderer->render(model);
glPopMatrix();
glPopName();
}
if(modelRenderStarted == true) {
modelRenderer->end();
glPopAttrib();
}
}
assertGl();
}
//render objects for selection purposes
void Renderer::renderObjectsFast() {
const World *world= game->getWorld();
const Map *map= world->getMap();
assertGl();
bool modelRenderStarted = false;
VisibleQuadContainerCache &qCache = getQuadCache();
if(qCache.visibleObjectList.size() > 0) {
for(int visibleIndex = 0;
visibleIndex < qCache.visibleObjectList.size(); ++visibleIndex) {
Object *o = qCache.visibleObjectList[visibleIndex];
Model *objModel= o->getModelPtr();
const Vec3f &v= o->getConstPos();
if(modelRenderStarted == false) {
modelRenderStarted = true;
glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT);
glDisable(GL_LIGHTING);
glAlphaFunc(GL_GREATER, 0.5f);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
//set color to the texture alpha
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
//set alpha to the texture alpha
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
modelRenderer->begin(false, true, false);
}
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(v.x, v.y, v.z);
glRotatef(o->getRotation(), 0.f, 1.f, 0.f);
modelRenderer->render(objModel);
glPopMatrix();
}
if(modelRenderStarted == true) {
modelRenderer->end();
glPopAttrib();
}
}
assertGl();
}
// ==================== gl caps ====================
void Renderer::checkGlCaps() {
//opengl 1.3
if(!isGlVersionSupported(1, 3, 0)) {
string message;
message += "Your system supports OpenGL version \"";
message += getGlVersion() + string("\"\n");
message += "MegaGlest needs at least version 1.3 to work\n";
message += "You may solve this problem by installing your latest video card drivers";
throw runtime_error(message.c_str());
}
//opengl 1.4 or extension
if(!isGlVersionSupported(1, 4, 0)){
checkExtension("GL_ARB_texture_env_crossbar", "MegaGlest");
}
}
void Renderer::checkGlOptionalCaps() {
//shadows
if(shadows == sProjected || shadows == sShadowMapping) {
if(getGlMaxTextureUnits() < 3) {
throw runtime_error("Your system doesn't support 3 texture units, required for shadows");
}
}
//shadow mapping
if(shadows == sShadowMapping) {
checkExtension("GL_ARB_shadow", "Shadow Mapping");
//checkExtension("GL_ARB_shadow_ambient", "Shadow Mapping");
//checkExtension("GL_ARB_depth_texture", "Shadow Mapping");
}
}
void Renderer::checkExtension(const string &extension, const string &msg) {
if(!isGlExtensionSupported(extension.c_str())) {
string str= "OpenGL extension not supported: " + extension + ", required for " + msg;
throw runtime_error(str);
}
}
// ==================== init 3d lists ====================
void Renderer::init3dList() {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
const Metrics &metrics= Metrics::getInstance();
assertGl();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
list3d= glGenLists(1);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glNewList(list3d, GL_COMPILE_AND_EXECUTE);
//need to execute, because if not gluPerspective takes no effect and gluLoadMatrix is wrong
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//misc
glViewport(0, 0, metrics.getScreenW(), metrics.getScreenH());
glClearColor(fowColor.x, fowColor.y, fowColor.z, fowColor.w);
glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);
loadProjectionMatrix();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//texture state
glActiveTexture(shadowTexUnit);
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glActiveTexture(fowTexUnit);
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glActiveTexture(baseTexUnit);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//material state
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, defSpecularColor.ptr());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, defAmbientColor.ptr());
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, defDiffuseColor.ptr());
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glColor4fv(defColor.ptr());
//blend state
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//alpha test state
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.f);
//depth test state
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//lighting state
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//matrix mode
glMatrixMode(GL_MODELVIEW);
//stencil test
glDisable(GL_STENCIL_TEST);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//fog
const Tileset *tileset= NULL;
if(game != NULL && game->getWorld() != NULL) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
tileset = game->getWorld()->getTileset();
}
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
if(tileset != NULL && tileset->getFog()) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glEnable(GL_FOG);
if(tileset->getFogMode()==fmExp) {
glFogi(GL_FOG_MODE, GL_EXP);
}
else {
glFogi(GL_FOG_MODE, GL_EXP2);
}
glFogf(GL_FOG_DENSITY, tileset->getFogDensity());
glFogfv(GL_FOG_COLOR, tileset->getFogColor().ptr());
}
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glEndList();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//assert
assertGl();
}
void Renderer::init2dList() {
const Metrics &metrics= Metrics::getInstance();
//this list sets the state for the 2d rendering
list2d= glGenLists(1);
glNewList(list2d, GL_COMPILE);
//projection
glViewport(0, 0, metrics.getScreenW(), metrics.getScreenH());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, metrics.getVirtualW(), 0, metrics.getVirtualH(), 0, 1);
//modelview
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//disable everything
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_FOG);
glDisable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glActiveTexture(baseTexUnit);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_TEXTURE_2D);
//blend func
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//color
glColor4f(1.f, 1.f, 1.f, 1.f);
glEndList();
assertGl();
}
void Renderer::init3dListMenu(const MainMenu *mm) {
assertGl();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
const Metrics &metrics= Metrics::getInstance();
const MenuBackground *mb= mm->getConstMenuBackground();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
list3dMenu= glGenLists(1);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glNewList(list3dMenu, GL_COMPILE);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//misc
glViewport(0, 0, metrics.getScreenW(), metrics.getScreenH());
glClearColor(0.4f, 0.4f, 0.4f, 1.f);
glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, 1000);
//texture state
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
//material state
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, defSpecularColor.ptr());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, defAmbientColor.ptr());
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, defDiffuseColor.ptr());
glColor4fv(defColor.ptr());
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
//blend state
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//alpha test state
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.f);
//depth test state
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
//lighting state
glEnable(GL_LIGHTING);
//matrix mode
glMatrixMode(GL_MODELVIEW);
//stencil test
glDisable(GL_STENCIL_TEST);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//fog
if(mb != NULL && mb->getFog()){
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glEnable(GL_FOG);
glFogi(GL_FOG_MODE, GL_EXP2);
glFogf(GL_FOG_DENSITY, mb->getFogDensity());
}
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
glEndList();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//assert
assertGl();
}
// ==================== misc ====================
void Renderer::loadProjectionMatrix() {
GLdouble clipping;
const Metrics &metrics= Metrics::getInstance();
assertGl();
clipping= photoMode ? perspFarPlane*100 : perspFarPlane;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, clipping);
assertGl();
}
void Renderer::enableProjectiveTexturing() {
glTexGenfv(GL_S, GL_EYE_PLANE, &shadowMapMatrix[0]);
glTexGenfv(GL_T, GL_EYE_PLANE, &shadowMapMatrix[4]);
glTexGenfv(GL_R, GL_EYE_PLANE, &shadowMapMatrix[8]);
glTexGenfv(GL_Q, GL_EYE_PLANE, &shadowMapMatrix[12]);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
}
// ==================== private aux drawing ====================
void Renderer::renderSelectionCircle(Vec3f v, int size, float radius) {
GLUquadricObj *disc;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(v.x, v.y, v.z);
glRotatef(90.f, 1.f, 0.f, 0.f);
disc= gluNewQuadric();
gluQuadricDrawStyle(disc, GLU_FILL);
gluCylinder(disc, radius*(size-0.2f), radius*size, 0.2f, 30, 1);
gluDeleteQuadric(disc);
glPopMatrix();
}
void Renderer::renderArrow(const Vec3f &pos1, const Vec3f &pos2,
const Vec3f &color, float width) {
const int tesselation= 3;
const float arrowEndSize= 0.4f;
const float maxlen= 25;
const float blendDelay= 5.f;
Vec3f dir= Vec3f(pos2-pos1);
float len= dir.length();
if(len>maxlen) {
return;
}
float alphaFactor= clamp((maxlen-len)/blendDelay, 0.f, 1.f);
dir.normalize();
Vec3f normal= dir.cross(Vec3f(0, 1, 0));
Vec3f pos2Left= pos2 + normal*(width-0.05f) - dir*arrowEndSize*width;
Vec3f pos2Right= pos2 - normal*(width-0.05f) - dir*arrowEndSize*width;
Vec3f pos1Left= pos1 + normal*(width+0.05f);
Vec3f pos1Right= pos1 - normal*(width+0.05f);
//arrow body
glBegin(GL_TRIANGLE_STRIP);
for(int i=0; i<=tesselation; ++i) {
float t= static_cast<float>(i)/tesselation;
Vec3f a= pos1Left.lerp(t, pos2Left);
Vec3f b= pos1Right.lerp(t, pos2Right);
Vec4f c= Vec4f(color, t*0.25f*alphaFactor);
glColor4fv(c.ptr());
glVertex3fv(a.ptr());
glVertex3fv(b.ptr());
}
glEnd();
//arrow end
glBegin(GL_TRIANGLES);
glVertex3fv((pos2Left + normal*(arrowEndSize-0.1f)).ptr());
glVertex3fv((pos2Right - normal*(arrowEndSize-0.1f)).ptr());
glVertex3fv((pos2 + dir*(arrowEndSize-0.1f)).ptr());
glEnd();
}
void Renderer::renderProgressBar(int size, int x, int y, Font2D *font, int customWidth, string prefixLabel) {
int currentSize = size;
int maxSize = maxProgressBar;
string renderText = intToStr(static_cast<int>(size)) + "%";
if(customWidth > 0) {
if(size > 0) {
currentSize = (int)((double)customWidth * ((double)size / 100.0));
}
maxSize = customWidth;
}
if(prefixLabel != "") {
renderText = prefixLabel + renderText;
}
//bar
glBegin(GL_QUADS);
glColor4fv(progressBarFront2.ptr());
glVertex2i(x, y);
glVertex2i(x, y+10);
glColor4fv(progressBarFront1.ptr());
glVertex2i(x + currentSize, y+10);
glVertex2i(x + currentSize, y);
glEnd();
//transp bar
glEnable(GL_BLEND);
glBegin(GL_QUADS);
glColor4fv(progressBarBack2.ptr());
glVertex2i(x + currentSize, y);
glVertex2i(x + currentSize, y+10);
glColor4fv(progressBarBack1.ptr());
glVertex2i(x + maxSize, y+10);
glVertex2i(x + maxSize, y);
glEnd();
glDisable(GL_BLEND);
//text
glColor3fv(defColor.ptr());
textRenderer->begin(font);
textRenderer->render(renderText.c_str(), x + maxSize / 2, y, true);
textRenderer->end();
}
void Renderer::renderTile(const Vec2i &pos) {
const Map *map= game->getWorld()->getMap();
Vec2i scaledPos= pos * Map::cellScale;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(-0.5f, 0.f, -0.5f);
glInitNames();
for(int i=0; i < Map::cellScale; ++i) {
for(int j=0; j < Map::cellScale; ++j) {
Vec2i renderPos= scaledPos + Vec2i(i, j);
glPushName(renderPos.y);
glPushName(renderPos.x);
glDisable(GL_CULL_FACE);
float h1 = map->getCell(renderPos.x, renderPos.y)->getHeight();
float h2 = map->getCell(renderPos.x, renderPos.y+1)->getHeight();
float h3 = map->getCell(renderPos.x+1, renderPos.y)->getHeight();
float h4 = map->getCell(renderPos.x+1, renderPos.y+1)->getHeight();
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(
static_cast<float>(renderPos.x),
h1,
static_cast<float>(renderPos.y));
glVertex3f(
static_cast<float>(renderPos.x),
h2,
static_cast<float>(renderPos.y+1));
glVertex3f(
static_cast<float>(renderPos.x+1),
h3,
static_cast<float>(renderPos.y));
glVertex3f(
static_cast<float>(renderPos.x+1),
h4,
static_cast<float>(renderPos.y+1));
glEnd();
glPopName();
glPopName();
}
}
glPopMatrix();
}
void Renderer::renderQuad(int x, int y, int w, int h, const Texture2D *texture) {
if(w < 0) {
w = texture->getPixmapConst()->getW();
}
if(h < 0) {
h = texture->getPixmapConst()->getH();
}
glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(texture)->getHandle());
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2i(0, 1);
glVertex2i(x, y+h);
glTexCoord2i(0, 0);
glVertex2i(x, y);
glTexCoord2i(1, 1);
glVertex2i(x+w, y+h);
glTexCoord2i(1, 0);
glVertex2i(x+w, y);
glEnd();
}
Renderer::Shadows Renderer::strToShadows(const string &s){
if(s=="Projected"){
return sProjected;
}
else if(s=="ShadowMapping"){
return sShadowMapping;
}
return sDisabled;
}
string Renderer::shadowsToStr(Shadows shadows){
switch(shadows){
case sDisabled:
return "Disabled";
case sProjected:
return "Projected";
case sShadowMapping:
return "ShadowMapping";
default:
assert(false);
return "";
}
}
Texture2D::Filter Renderer::strToTextureFilter(const string &s){
if(s=="Bilinear"){
return Texture2D::fBilinear;
}
else if(s=="Trilinear"){
return Texture2D::fTrilinear;
}
throw runtime_error("Error converting from string to FilterType, found: "+s);
}
void Renderer::setAllowRenderUnitTitles(bool value) {
allowRenderUnitTitles = value;
//if(allowRenderUnitTitles == false) {
//renderUnitTitleList.clear();
//}
}
// This method renders titles for units
void Renderer::renderUnitTitles(Font2D *font, Vec3f color) {
std::map<int,bool> unitRenderedList;
if(visibleFrameUnitList.size() > 0) {
for(int idx = 0; idx < visibleFrameUnitList.size(); idx++) {
const Unit *unit = visibleFrameUnitList[idx];
if(unit != NULL && unit->getCurrentUnitTitle() != "") {
//get the screen coordinates
Vec3f screenPos = unit->getScreenPos();
renderText(unit->getCurrentUnitTitle(), font, color, fabs(screenPos.x) + 5, fabs(screenPos.y) + 5, false);
//SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] screenPos.x = %f, screenPos.y = %f, screenPos.z = %f\n",__FILE__,__FUNCTION__,__LINE__,screenPos.x,screenPos.y,screenPos.z);
unitRenderedList[unit->getId()] = true;
}
else {
string str = unit->getFullName() + " - " + intToStr(unit->getId());
Vec3f screenPos = unit->getScreenPos();
renderText(str, font, color, fabs(screenPos.x) + 5, fabs(screenPos.y) + 5, false);
}
}
visibleFrameUnitList.clear();
}
/*
if(renderUnitTitleList.size() > 0) {
for(int idx = 0; idx < renderUnitTitleList.size(); idx++) {
std::pair<Unit *,Vec3f> &unitInfo = renderUnitTitleList[idx];
Unit *unit = unitInfo.first;
const World *world= game->getWorld();
Unit *validUnit = world->findUnitById(unit->getId());
if(validUnit != NULL && unitRenderedList.find(validUnit->getId()) == unitRenderedList.end()) {
string str = validUnit->getFullName() + " - " + intToStr(validUnit->getId());
//get the screen coordinates
Vec3f &screenPos = unitInfo.second;
renderText(str, font, color, fabs(screenPos.x) + 5, fabs(screenPos.y) + 5, false);
//SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] screenPos.x = %f, screenPos.y = %f, screenPos.z = %f\n",__FILE__,__FUNCTION__,__LINE__,screenPos.x,screenPos.y,screenPos.z);
}
}
renderUnitTitleList.clear();
}
*/
}
void Renderer::setQuadCacheDirty(bool value) {
quadCache.cacheIsDirty = value;
}
void Renderer::removeObjectFromQuadCache(const Object *o) {
VisibleQuadContainerCache &qCache = getQuadCache();
for(int visibleIndex = 0;
visibleIndex < qCache.visibleObjectList.size(); ++visibleIndex) {
Object *currentObj = qCache.visibleObjectList[visibleIndex];
if(currentObj == o) {
qCache.visibleObjectList.erase(qCache.visibleObjectList.begin() + visibleIndex);
break;
}
}
}
void Renderer::removeUnitFromQuadCache(const Unit *unit) {
VisibleQuadContainerCache &qCache = getQuadCache();
for(int visibleIndex = 0;
visibleIndex < qCache.visibleQuadUnitList.size(); ++visibleIndex) {
Unit *currentUnit = qCache.visibleQuadUnitList[visibleIndex];
if(currentUnit == unit) {
qCache.visibleQuadUnitList.erase(qCache.visibleQuadUnitList.begin() + visibleIndex);
break;
}
}
for(int visibleIndex = 0;
visibleIndex < qCache.visibleUnitList.size(); ++visibleIndex) {
Unit *currentUnit = qCache.visibleUnitList[visibleIndex];
if(currentUnit == unit) {
qCache.visibleUnitList.erase(qCache.visibleUnitList.begin() + visibleIndex);
break;
}
}
}
VisibleQuadContainerCache & Renderer::getQuadCache( bool updateOnDirtyFrame,
bool forceNew) {
//forceNew = true;
if(game != NULL && game->getWorld() != NULL) {
const World *world= game->getWorld();
if(quadCache.cacheIsDirty == true) {
forceNew = true;
}
if(forceNew == true ||
(updateOnDirtyFrame == true &&
(world->getFrameCount() != quadCache.cacheFrame ||
visibleQuad != quadCache.lastVisibleQuad))) {
// Dump cached info
//if(forceNew == true || visibleQuad != quadCache.lastVisibleQuad) {
//quadCache.clearCacheData();
//}
//else {
quadCache.clearVolatileCacheData();
//}
// Unit calculations
for(int i = 0; i < world->getFactionCount(); ++i) {
const Faction *faction = world->getFaction(i);
for(int j = 0; j < faction->getUnitCount(); ++j) {
Unit *unit= faction->getUnit(j);
bool insideQuad = visibleQuad.isInside(unit->getPos());
bool renderInMap = world->toRenderUnit(unit);
if(insideQuad == true && renderInMap == true) {
quadCache.visibleQuadUnitList.push_back(unit);
}
else {
unit->setVisible(false);
// Currently don't need this list
//quadCache.inVisibleUnitList.push_back(unit);
}
if(renderInMap == true) {
quadCache.visibleUnitList.push_back(unit);
}
}
}
if(forceNew == true || visibleQuad != quadCache.lastVisibleQuad) {
// Object calculations
const Map *map= world->getMap();
quadCache.clearNonVolatileCacheData();
PosQuadIterator pqi(visibleQuad, Map::cellScale);
while(pqi.next()) {
const Vec2i &pos= pqi.getPos();
if(map->isInside(pos)) {
const Vec2i &mapPos = Map::toSurfCoords(pos);
//quadCache.visibleCellList.push_back(mapPos);
SurfaceCell *sc = map->getSurfaceCell(mapPos);
Object *o = sc->getObject();
bool cellExplored = world->showWorldForPlayer(world->getThisFactionIndex());
if(cellExplored == false) {
cellExplored = sc->isExplored(world->getThisTeamIndex());
}
bool isExplored = (cellExplored == true && o != NULL);
//bool isVisible = (sc->isVisible(world->getThisTeamIndex()) && o != NULL);
bool isVisible = true;
if(isExplored == true && isVisible == true) {
quadCache.visibleObjectList.push_back(o);
}
}
}
const Rect2i mapBounds(0, 0, map->getSurfaceW()-1, map->getSurfaceH()-1);
Quad2i scaledQuad = visibleQuad / Map::cellScale;
PosQuadIterator pqis(scaledQuad);
while(pqis.next()) {
const Vec2i &pos= pqis.getPos();
if(mapBounds.isInside(pos)) {
quadCache.visibleScaledCellList.push_back(pos);
}
}
}
quadCache.cacheFrame = world->getFrameCount();
quadCache.cacheIsDirty = false;
quadCache.lastVisibleQuad = visibleQuad;
}
}
return quadCache;
}
void Renderer::renderMapPreview( const MapPreview *map, bool renderAll,
int screenPosX, int screenPosY,
Texture2D **renderToTexture) {
float alt=0;
float showWater=0;
int renderMapHeight=64;
int renderMapWidth=64;
float cellSize=2;
float playerCrossSize=2;
float clientW=renderMapWidth*cellSize;
float clientH=renderMapHeight*cellSize;;
const Metrics &metrics= Metrics::getInstance();
// stretch small maps to 128x128
if(map->getW() < map->getH()) {
cellSize = cellSize * renderMapHeight / map->getH();
}
else {
cellSize = cellSize * renderMapWidth / map->getW();
}
assertGl();
/*
if(renderToTexture != NULL) {
Config &config= Config::getInstance();
Texture2D::Filter textureFilter = strToTextureFilter(config.getString("Filter"));
int maxAnisotropy = config.getInt("FilterMaxAnisotropy");
*renderToTexture = GraphicsInterface::getInstance().getFactory()->newTexture2D();
Texture2DGl *texture = static_cast<Texture2DGl *>(*renderToTexture);
//texture->setFormat(Texture::fAlpha);
texture->setMipmap(false);
Pixmap2D *pixmapScreenShot = texture->getPixmap();
pixmapScreenShot->init(metrics.getVirtualW(), metrics.getVirtualH(), 3);
//pixmapScreenShot->init(map->getW(),map->getH(),3);
//pixmapScreenShot->init(200, 360, 3);
texture->setForceCompressionDisabled(true);
texture->init(textureFilter,maxAnisotropy);
//texture->initFrameBuffer();
//texture->attachFrameBufferToTexture();
//texture->initRenderBuffer();
//texture->attachRenderBuffer();
texture->setup_FBO_RBO();
if(texture->checkFrameBufferStatus() == false) {
//printf("******************** WARNING CANNOT Attach to FBO!\n");
texture->end();
delete texture;
*renderToTexture=NULL;
}
}
*/
glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);
//glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
//glViewport(screenPosX, screenPosY, metrics.getVirtualW(),metrics.getVirtualH());
// glOrtho(0, clientW, 0, clientH, -1, 1);
//glOrtho(screenPosX, screenPosX+clientW, screenPosY+clientH, screenPosY, 0, 1);
glOrtho(0, metrics.getVirtualW(), 0, metrics.getVirtualH(), 0, 1);
//gluOrtho2D (0, metrics.getVirtualW(), 0, metrics.getVirtualH());
//glEnable( GL_SCISSOR_TEST );
//glScissor(screenPosX, screenPosY,metrics.getVirtualW(), metrics.getVirtualH());
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(static_cast<float>(screenPosX),static_cast<float>(screenPosY)-clientH,0.0f);
//glEnable( GL_SCISSOR_TEST );
//glScissor(screenPosX, screenPosY,screenPosX-clientW, screenPosY-clientH);
//int newX = screenPosX - (metrics.getVirtualW() / 2);
//int newY = screenPosY - (metrics.getVirtualH() / 2);
//int newX = 0;
//int newY = 0;
//glTranslatef(static_cast<float>(newX),static_cast<float>(newY),0.0f);
glPushAttrib(GL_CURRENT_BIT);
//glTranslatef(static_cast<float>(x), static_cast<float>(y), 0.0f);
glLineWidth(1);
//glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0, 0, 0);
for (int j = 0; j < map->getH(); j++) {
for (int i = 0; i < map->getW(); i++) {
//surface
alt = map->getHeight(i, j) / 20.f;
showWater = map->getWaterLevel()/ 20.f - alt;
showWater = (showWater > 0)? showWater:0;
Vec3f surfColor;
switch (map->getSurface(i, j)) {
case st_Grass:
surfColor = Vec3f(0.0, 0.8f * alt, 0.f + showWater);
break;
case st_Secondary_Grass:
surfColor = Vec3f(0.4f * alt, 0.6f * alt, 0.f + showWater);
break;
case st_Road:
surfColor = Vec3f(0.6f * alt, 0.3f * alt, 0.f + showWater);
break;
case st_Stone:
surfColor = Vec3f(0.7f * alt, 0.7f * alt, 0.7f * alt + showWater);
break;
case st_Ground:
surfColor = Vec3f(0.7f * alt, 0.5f * alt, 0.3f * alt + showWater);
break;
}
glColor3fv(surfColor.ptr());
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(i * cellSize, clientH - j * cellSize - cellSize);
glVertex2f(i * cellSize, clientH - j * cellSize);
glVertex2f(i * cellSize + cellSize, clientH - j * cellSize - cellSize);
glVertex2f(i * cellSize + cellSize, clientH - j * cellSize);
glEnd();
//objects
if(renderAll == true) {
switch (map->getObject(i, j)) {
case 0:
glColor3f(0.f, 0.f, 0.f);
break;
case 1:
glColor3f(1.f, 0.f, 0.f);
break;
case 2:
glColor3f(1.f, 1.f, 1.f);
break;
case 3:
glColor3f(0.5f, 0.5f, 1.f);
break;
case 4:
glColor3f(0.f, 0.f, 1.f);
break;
case 5:
glColor3f(0.5f, 0.5f, 0.5f);
break;
case 6:
glColor3f(1.f, 0.8f, 0.5f);
break;
case 7:
glColor3f(0.f, 1.f, 1.f);
break;
case 8:
glColor3f(0.7f, 0.1f, 0.3f);
break;
case 9:
glColor3f(0.5f, 1.f, 0.1f);
break;
case 10:
glColor3f(1.f, 0.2f, 0.8f);
break;// we don't render unvisible blocking objects
}
if ( renderAll && (map->getObject(i, j) != 0) && (map->getObject(i, j) != 10) ) {
glPointSize(cellSize / 2.f);
glBegin(GL_POINTS);
glVertex2f(i * cellSize + cellSize / 2.f, clientH - j * cellSize - cellSize / 2.f);
glEnd();
}
}
// bool found = false;
//height lines
// if (!found) {
//left
if (i > 0 && map->getHeight(i - 1, j) > map->getHeight(i, j)) {
glColor3fv((surfColor*0.5f).ptr());
glBegin(GL_LINES);
glVertex2f(i * cellSize, clientH - (j + 1) * cellSize);
glVertex2f(i * cellSize, clientH - j * cellSize);
glEnd();
}
//down
if (j > 0 && map->getHeight(i, j - 1) > map->getHeight(i, j)) {
glColor3fv((surfColor*0.5f).ptr());
glBegin(GL_LINES);
glVertex2f(i * cellSize, clientH - j * cellSize);
glVertex2f((i + 1) * cellSize, clientH - j * cellSize);
glEnd();
}
//left
if (i > 0 && map->getHeight(i - 1, j) < map->getHeight(i, j)) {
glColor3fv((surfColor*2.f).ptr());
glBegin(GL_LINES);
glVertex2f(i * cellSize, clientH - (j + 1) * cellSize);
glVertex2f(i * cellSize, clientH - j * cellSize);
glEnd();
}
if (j > 0 && map->getHeight(i, j - 1) < map->getHeight(i, j)) {
glColor3fv((surfColor*2.f).ptr());
glBegin(GL_LINES);
glVertex2f(i * cellSize, clientH - j * cellSize);
glVertex2f((i + 1) * cellSize, clientH - j * cellSize);
glEnd();
}
// }
//resources
if(renderAll == true) {
switch (map->getResource(i, j)) {
case 1: glColor3f(1.f, 1.f, 0.f); break;
case 2: glColor3f(0.5f, 0.5f, 0.5f); break;
case 3: glColor3f(1.f, 0.f, 0.f); break;
case 4: glColor3f(0.f, 0.f, 1.f); break;
case 5: glColor3f(0.5f, 0.5f, 1.f); break;
}
if (renderAll && map->getResource(i, j) != 0) {
glBegin(GL_LINES);
glVertex2f(i * cellSize, clientH - j * cellSize - cellSize);
glVertex2f(i * cellSize + cellSize, clientH - j * cellSize);
glVertex2f(i * cellSize, clientH - j * cellSize);
glVertex2f(i * cellSize + cellSize, clientH - j * cellSize - cellSize);
glEnd();
}
}
}
}
//start locations
glLineWidth(3);
// force playerCrossSize to be at least of size 4
if(cellSize < 4) {
playerCrossSize = 4;
}
else {
playerCrossSize = cellSize;
}
for (int i = 0; i < map->getMaxFactions(); i++) {
switch (i) {
case 0: glColor3f(1.f, 0.f, 0.f); break;
case 1: glColor3f(0.f, 0.f, 1.f); break;
case 2: glColor3f(0.f, 1.f, 0.f); break;
case 3: glColor3f(1.f, 1.f, 0.f); break;
case 4: glColor3f(1.f, 1.f, 1.f); break;
case 5: glColor3f(0.f, 1.f, 0.8f); break;
case 6: glColor3f(1.f, 0.5f, 0.f); break;
case 7: glColor3f(1.f, 0.5f, 1.f); break;
}
glBegin(GL_LINES);
glVertex2f((map->getStartLocationX(i) - 1) * cellSize, clientH - (map->getStartLocationY(i) - 1) * cellSize);
glVertex2f((map->getStartLocationX(i) + 1) * cellSize + playerCrossSize, clientH - (map->getStartLocationY(i) + 1) * cellSize - playerCrossSize);
glVertex2f((map->getStartLocationX(i) - 1) * cellSize, clientH - (map->getStartLocationY(i) + 1) * cellSize - playerCrossSize);
glVertex2f((map->getStartLocationX(i) + 1) * cellSize + playerCrossSize, clientH - (map->getStartLocationY(i) - 1) * cellSize);
glEnd();
}
glPopMatrix();
glPopAttrib();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
//glDisable( GL_SCISSOR_TEST );
//glViewport(0, 0, 0, 0);
if(renderToTexture != NULL) {
// *renderToTexture = saveScreenToTexture(screenPosX, screenPosY, metrics.getVirtualW(), metrics.getVirtualH());
// *renderToTexture = saveScreenToTexture(0, 0, metrics.getVirtualW(), metrics.getVirtualH());
/*
Texture2DGl *texture = static_cast<Texture2DGl *>(*renderToTexture);
if(texture != NULL) {
// *renderToTexture = saveScreenToTexture(screenPosX, screenPosY, clientW, clientH);
texture->dettachFrameBufferFromTexture();
// Signal the threads queue to add a screenshot save request
// MutexSafeWrapper safeMutex(&saveScreenShotThreadAccessor);
// saveScreenQueue.push_back(make_pair("bob.png",texture->getPixmap()));
// *renderToTexture=NULL;
// safeMutex.ReleaseLock();
// texture->teardown_FBO_RBO();
}
*/
}
assertGl();
}
// setLastRenderFps and calculate shadowsOffDueToMinRender
void Renderer::setLastRenderFps(int value) {
lastRenderFps = value;
smoothedRenderFps=(MIN_FPS_NORMAL_RENDERING*smoothedRenderFps+lastRenderFps)/(MIN_FPS_NORMAL_RENDERING+1.0f);
if(smoothedRenderFps>=MIN_FPS_NORMAL_RENDERING_TOP_THRESHOLD){
shadowsOffDueToMinRender=false;
}
if(smoothedRenderFps<=MIN_FPS_NORMAL_RENDERING){
shadowsOffDueToMinRender=true;
}
}
uint64 Renderer::getCurrentPixelByteCount(ResourceScope rs) const {
uint64 result = 0;
for(int i = (rs == rsCount ? 0 : rs); i < rsCount; ++i) {
const Shared::Graphics::TextureContainer &textures = textureManager[i]->getTextures();
for(int j = 0; j < textures.size(); ++j) {
const Texture *texture = textures[j];
result += texture->getPixelByteCount();
}
if(rs != rsCount) {
break;
}
}
return result;
}
}}//end namespace