1 // ==============================================================
2 // This file is part of Glest (www.glest.org)
3 //
4 // Copyright (C) 2001-2008 Marti�o Figueroa
5 //
6 // You can redistribute this code and/or modify it under
7 // the terms of the GNU General Public License as published
8 // by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version
10 // ==============================================================
11
12 #include "renderer.h"
13
14 #include "texture_gl.h"
15 #include "main_menu.h"
16 #include "config.h"
17 #include "components.h"
18 #include "time_flow.h"
19 #include "graphics_interface.h"
20 #include "object.h"
21 #include "core_data.h"
22 #include "game.h"
23 #include "metrics.h"
24 #include "opengl.h"
25 #include "faction.h"
26 #include "factory_repository.h"
27 #include "leak_dumper.h"
28
29 using namespace Shared::Graphics;
30 using namespace Shared::Graphics::Gl;
31 using namespace Shared::Util;
32
33 namespace Glest { namespace Game{
34
35 // =====================================================
36 // class MeshCallbackTeamColor
37 // =====================================================
38
39 class MeshCallbackTeamColor: public MeshCallback{
40 private:
41 const Texture *teamTexture;
42
43 public:
setTeamTexture(const Texture * teamTexture)44 void setTeamTexture(const Texture *teamTexture) {this->teamTexture= teamTexture;}
45 virtual void execute(const Mesh *mesh);
46 };
47
execute(const Mesh * mesh)48 void MeshCallbackTeamColor::execute(const Mesh *mesh){
49
50 //team color
51 if(mesh->getCustomTexture() && teamTexture!=NULL){
52 //texture 0
53 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
54
55 //set color to interpolation
56 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
57
58 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
59 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
60
61 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1);
62 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
63
64 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE);
65 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
66
67 //set alpha to 1
68 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
69 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
70 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
71
72 //texture 1
73 glActiveTexture(GL_TEXTURE1);
74 glMultiTexCoord2f(GL_TEXTURE1, 0.f, 0.f);
75 glEnable(GL_TEXTURE_2D);
76
77 glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(teamTexture)->getHandle());
78 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
79
80 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
81
82 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
83 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
84
85 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
86 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
87
88 //set alpha to 1
89 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
90 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
91 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
92
93 glActiveTexture(GL_TEXTURE0);
94 }
95 else{
96 glActiveTexture(GL_TEXTURE1);
97 glDisable(GL_TEXTURE_2D);
98 glActiveTexture(GL_TEXTURE0);
99 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
100 }
101 }
102
103 // ===========================================================
104 // class Renderer
105 // ===========================================================
106
107 // ===================== PUBLIC ========================
108
109 const int Renderer::maxProgressBar= 100;
110 const Vec4f Renderer::progressBarBack1= Vec4f(0.7f, 0.7f, 0.7f, 0.7f);
111 const Vec4f Renderer::progressBarBack2= Vec4f(0.7f, 0.7f, 0.7f, 1.f);
112 const Vec4f Renderer::progressBarFront1= Vec4f(0.f, 0.5f, 0.f, 1.f);
113 const Vec4f Renderer::progressBarFront2= Vec4f(0.f, 0.1f, 0.f, 1.f);
114
115 const float Renderer::sunDist= 10e6;
116 const float Renderer::moonDist= 10e6;
117 const float Renderer::lightAmbFactor= 0.4f;
118
119 const int Renderer::maxMouse2dAnim= 100;
120
121 const GLenum Renderer::baseTexUnit= GL_TEXTURE0;
122 const GLenum Renderer::fowTexUnit= GL_TEXTURE1;
123 const GLenum Renderer::shadowTexUnit= GL_TEXTURE2;
124
125 const float Renderer::selectionCircleRadius= 0.7f;
126 const float Renderer::magicCircleRadius= 1.f;
127
128 //perspective values
129 const float Renderer::perspFov= 60.f;
130 const float Renderer::perspNearPlane= 1.f;
131 const float Renderer::perspFarPlane= 50.f;
132
133 const float Renderer::ambFactor= 0.7f;
134 const Vec4f Renderer::fowColor= Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
135 const Vec4f Renderer::defSpecularColor= Vec4f(0.8f, 0.8f, 0.8f, 1.f);
136 const Vec4f Renderer::defDiffuseColor= Vec4f(1.f, 1.f, 1.f, 1.f);
137 const Vec4f Renderer::defAmbientColor= Vec4f(1.f * ambFactor, 1.f * ambFactor, 1.f * ambFactor, 1.f);
138 const Vec4f Renderer::defColor= Vec4f(1.f, 1.f, 1.f, 1.f);
139
140 const float Renderer::maxLightDist= 50.f;
141
142 // ==================== constructor and destructor ====================
143
Renderer()144 Renderer::Renderer(){
145 GraphicsInterface &gi= GraphicsInterface::getInstance();
146 FactoryRepository &fr= FactoryRepository::getInstance();
147 Config &config= Config::getInstance();
148
149 gi.setFactory(fr.getGraphicsFactory(config.getString("FactoryGraphics")));
150 GraphicsFactory *graphicsFactory= GraphicsInterface::getInstance().getFactory();
151
152 modelRenderer= graphicsFactory->newModelRenderer();
153 textRenderer= graphicsFactory->newTextRenderer2D();
154 particleRenderer= graphicsFactory->newParticleRenderer();
155
156 //resources
157 for(int i=0; i<rsCount; ++i){
158 modelManager[i]= graphicsFactory->newModelManager();
159 textureManager[i]= graphicsFactory->newTextureManager();
160 modelManager[i]->setTextureManager(textureManager[i]);
161 particleManager[i]= graphicsFactory->newParticleManager();
162 fontManager[i]= graphicsFactory->newFontManager();
163 }
164 }
165
~Renderer()166 Renderer::~Renderer(){
167 delete modelRenderer;
168 delete textRenderer;
169 delete particleRenderer;
170
171 //resources
172 for(int i=0; i<rsCount; ++i){
173 delete modelManager[i];
174 delete textureManager[i];
175 delete particleManager[i];
176 delete fontManager[i];
177 }
178 }
179
getInstance()180 Renderer &Renderer::getInstance(){
181 static Renderer renderer;
182 return renderer;
183 }
184
185
186 // ==================== init ====================
187
init()188 void Renderer::init(){
189
190 Config &config= Config::getInstance();
191
192 loadConfig();
193
194 if(config.getBool("CheckGlCaps")){
195 checkGlCaps();
196 }
197
198 if(config.getBool("FirstTime")){
199 config.setBool("FirstTime", false);
200 autoConfig();
201 config.save();
202 }
203
204 modelManager[rsGlobal]->init();
205 textureManager[rsGlobal]->init();
206 fontManager[rsGlobal]->init();
207
208 init2dList();
209 }
210
initGame(Game * game)211 void Renderer::initGame(Game *game){
212 this->game= game;
213
214 //check gl caps
215 checkGlOptionalCaps();
216
217 //vars
218 shadowMapFrame= 0;
219 waterAnim= 0;
220
221 //shadows
222 if(shadows==sProjected || shadows==sShadowMapping){
223 static_cast<ModelRendererGl*>(modelRenderer)->setSecondaryTexCoordUnit(2);
224
225 glGenTextures(1, &shadowMapHandle);
226 glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
227
228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
232
233 if(shadows==sShadowMapping){
234
235 //shadow mapping
236 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
239 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 1.0f-shadowAlpha);
240
241 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32,
242 shadowTextureSize, shadowTextureSize,
243 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
244 }
245 else{
246
247 //projected
248 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
249 shadowTextureSize, shadowTextureSize,
250 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
251 }
252
253 shadowMapFrame= -1;
254 }
255
256 //texture init
257 modelManager[rsGame]->init();
258 textureManager[rsGame]->init();
259 fontManager[rsGame]->init();
260
261 init3dList();
262 }
263
initMenu(MainMenu * mm)264 void Renderer::initMenu(MainMenu *mm){
265 modelManager[rsMenu]->init();
266 textureManager[rsMenu]->init();
267 fontManager[rsMenu]->init();
268 //modelRenderer->setCustomTexture(CoreData::getInstance().getCustomTexture());
269
270 init3dListMenu(mm);
271 }
272
reset3d()273 void Renderer::reset3d(){
274 assertGl();
275 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
276 glCallList(list3d);
277 pointCount= 0;
278 triangleCount= 0;
279 assertGl();
280 }
281
reset2d()282 void Renderer::reset2d(){
283 assertGl();
284 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
285 glCallList(list2d);
286 assertGl();
287 }
288
reset3dMenu()289 void Renderer::reset3dMenu(){
290 assertGl();
291 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
292 glCallList(list3dMenu);
293 assertGl();
294 }
295
296 // ==================== end ====================
297
end()298 void Renderer::end(){
299
300 //delete resources
301 modelManager[rsGlobal]->end();
302 textureManager[rsGlobal]->end();
303 fontManager[rsGlobal]->end();
304 particleManager[rsGlobal]->end();
305
306 //delete 2d list
307 glDeleteLists(list2d, 1);
308 }
309
endGame()310 void Renderer::endGame(){
311 game= NULL;
312
313 //delete resources
314 modelManager[rsGame]->end();
315 textureManager[rsGame]->end();
316 fontManager[rsGame]->end();
317 particleManager[rsGame]->end();
318
319 if(shadows==sProjected || shadows==sShadowMapping){
320 glDeleteTextures(1, &shadowMapHandle);
321 }
322
323 glDeleteLists(list3d, 1);
324 }
325
endMenu()326 void Renderer::endMenu(){
327 //delete resources
328 modelManager[rsMenu]->end();
329 textureManager[rsMenu]->end();
330 fontManager[rsMenu]->end();
331 particleManager[rsMenu]->end();
332
333 glDeleteLists(list3dMenu, 1);
334 }
335
reloadResources()336 void Renderer::reloadResources(){
337 for(int i=0; i<rsCount; ++i){
338 modelManager[i]->end();
339 textureManager[i]->end();
340 fontManager[i]->end();
341 }
342 for(int i=0; i<rsCount; ++i){
343 modelManager[i]->init();
344 textureManager[i]->init();
345 fontManager[i]->init();
346 }
347 }
348
349
350 // ==================== engine interface ====================
351
newModel(ResourceScope rs)352 Model *Renderer::newModel(ResourceScope rs){
353 return modelManager[rs]->newModel();
354 }
355
newTexture2D(ResourceScope rs)356 Texture2D *Renderer::newTexture2D(ResourceScope rs){
357 return textureManager[rs]->newTexture2D();
358 }
359
newTexture3D(ResourceScope rs)360 Texture3D *Renderer::newTexture3D(ResourceScope rs){
361 return textureManager[rs]->newTexture3D();
362 }
363
newFont(ResourceScope rs)364 Font2D *Renderer::newFont(ResourceScope rs){
365 return fontManager[rs]->newFont2D();
366 }
367
manageParticleSystem(ParticleSystem * particleSystem,ResourceScope rs)368 void Renderer::manageParticleSystem(ParticleSystem *particleSystem, ResourceScope rs){
369 particleManager[rs]->manage(particleSystem);
370 }
371
updateParticleManager(ResourceScope rs)372 void Renderer::updateParticleManager(ResourceScope rs){
373 particleManager[rs]->update();
374 }
375
renderParticleManager(ResourceScope rs)376 void Renderer::renderParticleManager(ResourceScope rs){
377 glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
378 glDepthFunc(GL_LESS);
379 particleRenderer->renderManager(particleManager[rs], modelRenderer);
380 glPopAttrib();
381 }
382
swapBuffers()383 void Renderer::swapBuffers(){
384 glFlush();
385 GraphicsInterface::getInstance().getCurrentContext()->swapBuffers();
386 }
387
388 // ==================== lighting ====================
389
390 //places all the opengl lights
setupLighting()391 void Renderer::setupLighting(){
392
393 int lightCount= 0;
394 const World *world= game->getWorld();
395 const GameCamera *gameCamera= game->getGameCamera();
396 const TimeFlow *timeFlow= world->getTimeFlow();
397 float time= timeFlow->getTime();
398
399 assertGl();
400
401 //sun/moon light
402 Vec3f lightColor= computeLightColor(time);
403 Vec3f fogColor= world->getTileset()->getFogColor();
404 Vec4f lightPos= timeFlow->isDay()? computeSunPos(time): computeMoonPos(time);
405 nearestLightPos= lightPos;
406
407 glLightfv(GL_LIGHT0, GL_POSITION, lightPos.ptr());
408 glLightfv(GL_LIGHT0, GL_AMBIENT, Vec4f(lightColor*lightAmbFactor, 1.f).ptr());
409 glLightfv(GL_LIGHT0, GL_DIFFUSE, Vec4f(lightColor, 1.f).ptr());
410 glLightfv(GL_LIGHT0, GL_SPECULAR, Vec4f(0.0f, 0.0f, 0.f, 1.f).ptr());
411
412 glFogfv(GL_FOG_COLOR, Vec4f(fogColor*lightColor, 1.f).ptr());
413
414 lightCount++;
415
416 //disable all secondary lights
417 for(int i= 1; i<maxLights; ++i){
418 glDisable(GL_LIGHT0 + i);
419 }
420
421 //unit lights (not projectiles)
422 if(timeFlow->isTotalNight()){
423 for(int i=0; i<world->getFactionCount() && lightCount<maxLights; ++i){
424 for(int j=0; j<world->getFaction(i)->getUnitCount() && lightCount<maxLights; ++j){
425 Unit *unit= world->getFaction(i)->getUnit(j);
426 if(world->toRenderUnit(unit) &&
427 unit->getCurrVector().dist(gameCamera->getPos())<maxLightDist &&
428 unit->getType()->getLight() && unit->isOperative()){
429
430 Vec4f pos= Vec4f(unit->getCurrVector());
431 pos.y+=4.f;
432
433 GLenum lightEnum= GL_LIGHT0 + lightCount;
434
435 glEnable(lightEnum);
436 glLightfv(lightEnum, GL_POSITION, pos.ptr());
437 glLightfv(lightEnum, GL_AMBIENT, Vec4f(unit->getType()->getLightColor()).ptr());
438 glLightfv(lightEnum, GL_DIFFUSE, Vec4f(unit->getType()->getLightColor()).ptr());
439 glLightfv(lightEnum, GL_SPECULAR, Vec4f(unit->getType()->getLightColor()*0.3f).ptr());
440 glLightf(lightEnum, GL_QUADRATIC_ATTENUATION, 0.05f);
441
442 ++lightCount;
443
444 const GameCamera *gameCamera= game->getGameCamera();
445
446 if(Vec3f(pos).dist(gameCamera->getPos())<Vec3f(nearestLightPos).dist(gameCamera->getPos())){
447 nearestLightPos= pos;
448 }
449 }
450 }
451 }
452 }
453
454 assertGl();
455 }
456
loadGameCameraMatrix()457 void Renderer::loadGameCameraMatrix(){
458 const GameCamera *gameCamera= game->getGameCamera();
459
460 glMatrixMode(GL_MODELVIEW);
461 glLoadIdentity();
462 glRotatef(gameCamera->getVAng(), -1, 0, 0);
463 glRotatef(gameCamera->getHAng(), 0, 1, 0);
464 glTranslatef(-gameCamera->getPos().x, -gameCamera->getPos().y, -gameCamera->getPos().z);
465 }
466
loadCameraMatrix(const Camera * camera)467 void Renderer::loadCameraMatrix(const Camera *camera){
468 Vec3f position= camera->getPosition();
469 Quaternion orientation= camera->getOrientation().conjugate();
470
471 glMatrixMode(GL_MODELVIEW);
472 glLoadIdentity();
473 glMultMatrixf(orientation.toMatrix4().ptr());
474 glTranslatef(-position.x, -position.y, -position.z);
475 }
476
computeVisibleQuad()477 void Renderer::computeVisibleQuad(){
478 const GameCamera *gameCamera= game->getGameCamera();
479 visibleQuad= gameCamera->computeVisibleQuad();
480 }
481
482 // =======================================
483 // basic rendering
484 // =======================================
485
renderMouse2d(int x,int y,int anim,float fade)486 void Renderer::renderMouse2d(int x, int y, int anim, float fade){
487 float color1, color2;
488
489 float fadeFactor= fade+1.f;
490
491 anim= anim*2-maxMouse2dAnim;
492
493 color2= (abs(anim*fadeFactor)/static_cast<float>(maxMouse2dAnim))/2.f+0.4f;
494 color1= (abs(anim*fadeFactor)/static_cast<float>(maxMouse2dAnim))/2.f+0.8f;
495
496 glPushAttrib(GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT);
497 glEnable(GL_BLEND);
498
499 //inside
500 glColor4f(0.4f*fadeFactor, 0.2f*fadeFactor, 0.2f*fadeFactor, 0.5f*fadeFactor);
501 glBegin(GL_TRIANGLES);
502 glVertex2i(x, y);
503 glVertex2i(x+20, y-10);
504 glVertex2i(x+10, y-20);
505 glEnd();
506
507 //biorder
508 glLineWidth(2);
509 glBegin(GL_LINE_LOOP);
510 glColor4f(1.f, 0.2f, 0, color1);
511 glVertex2i(x, y);
512 glColor4f(1.f, 0.4f, 0, color2);
513 glVertex2i(x+20, y-10);
514 glColor4f(1.f, 0.4f, 0, color2);
515 glVertex2i(x+10, y-20);
516 glEnd();
517 glPopAttrib();
518 }
519
renderMouse3d()520 void Renderer::renderMouse3d(){
521
522 const Gui *gui= game->getGui();
523 const Mouse3d *mouse3d= gui->getMouse3d();
524 const Map *map= game->getWorld()->getMap();
525
526 GLUquadricObj *cilQuadric;
527 Vec4f color;
528
529 assertGl();
530
531 if((mouse3d->isEnabled() || gui->isPlacingBuilding()) && gui->isValidPosObjWorld()){
532
533 glMatrixMode(GL_MODELVIEW);
534 glPushMatrix();
535 glPushAttrib(GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
536 glEnable(GL_BLEND);
537 glDisable(GL_STENCIL_TEST);
538 glDepthFunc(GL_LESS);
539 glEnable(GL_COLOR_MATERIAL);
540 glDepthMask(GL_FALSE);
541
542 Vec2i pos= gui->getPosObjWorld();
543 Vec3f pos3f= Vec3f(pos.x, map->getCell(pos)->getHeight(), pos.y);
544
545 if(gui->isPlacingBuilding()){
546
547 const UnitType *building= gui->getBuilding();
548
549 //selection building emplacement
550 float offset= building->getSize()/2.f-0.5f;
551 glTranslatef(pos3f.x+offset, pos3f.y, pos3f.z+offset);
552
553 //choose color
554 if(map->isFreeCells(pos, building->getSize(), fLand)){
555 color= Vec4f(1.f, 1.f, 1.f, 0.5f);
556 }
557 else{
558 color= Vec4f(1.f, 0.f, 0.f, 0.5f);
559 }
560
561 modelRenderer->begin(true, true, false);
562 glColor4fv(color.ptr());
563 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color.ptr());
564 const Model *buildingModel= building->getFirstStOfClass(scStop)->getAnimation();
565 buildingModel->updateInterpolationData(0.f, false);
566 modelRenderer->render(buildingModel);
567 glDisable(GL_COLOR_MATERIAL);
568 modelRenderer->end();
569
570 }
571 else{
572 //standard mouse
573 glDisable(GL_TEXTURE_2D);
574 glDisable(GL_CULL_FACE);
575 color= Vec4f(1.f, 0.f, 0.f, 1.f-mouse3d->getFade());
576 glColor4fv(color.ptr());
577 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color.ptr());
578
579 glTranslatef(pos3f.x, pos3f.y+2.f, pos3f.z);
580 glRotatef(90.f, 1.f, 0.f, 0.f);
581 glRotatef(static_cast<float>(mouse3d->getRot()), 0.f, 0.f, 1.f);
582
583 cilQuadric= gluNewQuadric();
584 gluQuadricDrawStyle(cilQuadric, GLU_FILL);
585 gluCylinder(cilQuadric, 0.5f, 0.f, 2.f, 4, 1);
586 gluCylinder(cilQuadric, 0.5f, 0.f, 0.f, 4, 1);
587 glTranslatef(0.f, 0.f, 1.f);
588 gluCylinder(cilQuadric, 0.7f, 0.f, 1.f, 4, 1);
589 gluCylinder(cilQuadric, 0.7f, 0.f, 0.f, 4, 1);
590 gluDeleteQuadric(cilQuadric);
591 }
592
593 glPopAttrib();
594 glPopMatrix();
595 }
596
597 }
598
renderBackground(const Texture2D * texture)599 void Renderer::renderBackground(const Texture2D *texture){
600
601 const Metrics &metrics= Metrics::getInstance();
602
603 assertGl();
604
605 glPushAttrib(GL_ENABLE_BIT);
606
607 glDisable(GL_LIGHTING);
608 glEnable(GL_TEXTURE_2D);
609
610 renderQuad(0, 0, metrics.getVirtualW(), metrics.getVirtualH(), texture);
611
612 glPopAttrib();
613
614 assertGl();
615 }
616
renderTextureQuad(int x,int y,int w,int h,const Texture2D * texture,float alpha)617 void Renderer::renderTextureQuad(int x, int y, int w, int h, const Texture2D *texture, float alpha){
618 assertGl();
619
620 glPushAttrib(GL_ENABLE_BIT);
621
622 glDisable(GL_LIGHTING);
623 glEnable(GL_TEXTURE_2D);
624 glEnable(GL_BLEND);
625
626 glColor4f(1.f, 1.f, 1.f, alpha);
627 renderQuad(x, y, w, h, texture);
628
629 glPopAttrib();
630
631 assertGl();
632 }
633
renderConsole(const Console * console)634 void Renderer::renderConsole(const Console *console){
635 glPushAttrib(GL_ENABLE_BIT);
636 glEnable(GL_BLEND);
637
638 for(int i=0; i<console->getLineCount(); ++i){
639 renderTextShadow(
640 console->getLine(i),
641 CoreData::getInstance().getConsoleFont(),
642 20, i*20+20);
643 }
644
645 glPopAttrib();
646 }
647
renderChatManager(const ChatManager * chatManager)648 void Renderer::renderChatManager(const ChatManager *chatManager){
649 Lang &lang= Lang::getInstance();
650
651 if(chatManager->getEditEnabled()){
652 string text;
653
654 if(chatManager->getTeamMode()){
655 text+= lang.get("Team");
656 }
657 else
658 {
659 text+= lang.get("All");
660 }
661 text+= ": " + chatManager->getText() + "_";
662
663 textRenderer->begin(CoreData::getInstance().getConsoleFont());
664 textRenderer->render(text, 300, 150);
665 textRenderer->end();
666 }
667 }
668
renderResourceStatus()669 void Renderer::renderResourceStatus(){
670
671 const Metrics &metrics= Metrics::getInstance();
672 const World *world= game->getWorld();
673 const Faction *thisFaction= world->getFaction(world->getThisFactionIndex());
674
675 assertGl();
676
677 glPushAttrib(GL_ENABLE_BIT);
678
679 int j= 0;
680 for(int i= 0; i<world->getTechTree()->getResourceTypeCount(); ++i){
681 const ResourceType *rt= world->getTechTree()->getResourceType(i);
682 const Resource *r= thisFaction->getResource(rt);
683
684 //if any unit produces the resource
685 bool showResource= false;
686 for(int k=0; k<thisFaction->getType()->getUnitTypeCount(); ++k){
687 const UnitType *ut= thisFaction->getType()->getUnitType(k);
688 if(ut->getCost(rt)!=NULL){
689 showResource= true;
690 break;
691 }
692 }
693
694 //draw resource status
695 if(showResource){
696
697 string str= intToStr(r->getAmount());
698
699 glEnable(GL_TEXTURE_2D);
700 renderQuad(j*100+200, metrics.getVirtualH()-30, 16, 16, rt->getImage());
701
702 if(rt->getClass()!=rcStatic){
703 str+= "/" + intToStr(thisFaction->getStoreAmount(rt));
704 }
705 if(rt->getClass()==rcConsumable){
706 str+= "(";
707 if(r->getBalance()>0){
708 str+= "+";
709 }
710 str+= intToStr(r->getBalance()) + ")";
711 }
712
713 glDisable(GL_TEXTURE_2D);
714
715 renderTextShadow(
716 str, CoreData::getInstance().getMenuFontSmall(),
717 j*100+220, metrics.getVirtualH()-30, false);
718 ++j;
719 }
720
721 }
722
723 glPopAttrib();
724
725 assertGl();
726 }
727
renderSelectionQuad()728 void Renderer::renderSelectionQuad(){
729
730 const Gui *gui= game->getGui();
731 const SelectionQuad *sq= gui->getSelectionQuad();
732
733 Vec2i down= sq->getPosDown();
734 Vec2i up= sq->getPosUp();
735
736 if(gui->isSelecting()){
737 glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT);
738 glColor3f(0,1,0);
739 glBegin(GL_LINE_LOOP);
740 glVertex2i(down.x, down.y);
741 glVertex2i(up.x, down.y);
742 glVertex2i(up.x, up.y);
743 glVertex2i(down.x, up.y);
744 glEnd();
745 glPopAttrib();
746 }
747 }
748
computeCenteredPos(const string & text,const Font2D * font,int x,int y)749 Vec2i computeCenteredPos(const string &text, const Font2D *font, int x, int y){
750 Vec2i textPos;
751
752 const Metrics &metrics= Metrics::getInstance();
753 const FontMetrics *fontMetrics= font->getMetrics();
754
755 textPos= Vec2i(
756 x-metrics.toVirtualX(static_cast<int>(fontMetrics->getTextWidth(text)/2.f)),
757 y-metrics.toVirtualY(static_cast<int>(fontMetrics->getHeight()/2.f)));
758
759 return textPos;
760 }
761
renderText(const string & text,const Font2D * font,float alpha,int x,int y,bool centered)762 void Renderer::renderText(const string &text, const Font2D *font, float alpha, int x, int y, bool centered){
763 glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
764 glEnable(GL_BLEND);
765 glColor4fv(Vec4f(1.f, 1.f, 1.f, alpha).ptr());
766
767 Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y);
768
769 textRenderer->begin(font);
770 textRenderer->render(text, pos.x, pos.y);
771 textRenderer->end();
772
773 glPopAttrib();
774 }
775
renderText(const string & text,const Font2D * font,const Vec3f & color,int x,int y,bool centered)776 void Renderer::renderText(const string &text, const Font2D *font, const Vec3f &color, int x, int y, bool centered){
777 glPushAttrib(GL_CURRENT_BIT);
778 glColor3fv(color.ptr());
779
780 Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y);
781
782 textRenderer->begin(font);
783 textRenderer->render(text, pos.x, pos.y);
784 textRenderer->end();
785
786 glPopAttrib();
787 }
788
renderTextShadow(const string & text,const Font2D * font,int x,int y,bool centered)789 void Renderer::renderTextShadow(const string &text, const Font2D *font, int x, int y, bool centered){
790 glPushAttrib(GL_CURRENT_BIT);
791
792 Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y);
793
794 textRenderer->begin(font);
795 glColor3f(0.0f, 0.0f, 0.0f);
796 textRenderer->render(text, pos.x-1.0f, pos.y-1.0f);
797 glColor3f(1.0f, 1.0f, 1.0f);
798 textRenderer->render(text, pos.x, pos.y);
799 textRenderer->end();
800
801 glPopAttrib();
802 }
803
804 // ============= COMPONENTS =============================
805
renderLabel(const GraphicLabel * label)806 void Renderer::renderLabel(const GraphicLabel *label){
807
808 glPushAttrib(GL_ENABLE_BIT);
809 glEnable(GL_BLEND);
810
811 Vec2i textPos;
812 int x= label->getX();
813 int y= label->getY();
814 int h= label->getH();
815 int w= label->getW();
816
817 if(label->getCentered()){
818 textPos= Vec2i(x+w/2, y+h/2);
819 }
820 else{
821 textPos= Vec2i(x, y+h/4);
822 }
823
824 renderText(label->getText(), label->getFont(), GraphicComponent::getFade(), textPos.x, textPos.y, label->getCentered());
825
826 glPopAttrib();
827 }
828
renderButton(const GraphicButton * button)829 void Renderer::renderButton(const GraphicButton *button){
830
831 int x= button->getX();
832 int y= button->getY();
833 int h= button->getH();
834 int w= button->getW();
835
836 glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
837
838 //background
839 CoreData &coreData= CoreData::getInstance();
840 Texture2D *backTexture= w>3*h/2? coreData.getButtonBigTexture(): coreData.getButtonSmallTexture();
841
842 glEnable(GL_TEXTURE_2D);
843 glEnable(GL_BLEND);
844
845 glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(backTexture)->getHandle());
846
847 //button
848 Vec4f color= Vec4f(1.f, 1.f, 1.f, GraphicComponent::getFade());
849 glColor4fv(color.ptr());
850
851 glBegin(GL_TRIANGLE_STRIP);
852 glTexCoord2f(0.f, 0.f);
853 glVertex2f(x, y);
854
855 glTexCoord2f(0.f, 1.f);
856 glVertex2f(x, y+h);
857
858 glTexCoord2f(1.f, 0.f);
859 glVertex2f(x+w, y);
860
861 glTexCoord2f(1.f, 1.f);
862 glVertex2f(x+w, y+h);
863
864 glEnd();
865
866 glDisable(GL_TEXTURE_2D);
867
868 //lighting
869 float anim= GraphicComponent::getAnim();
870 if(anim>0.5f) anim= 1.f-anim;
871
872 if(button->getLighted()){
873 const int lightSize= 0;
874 const Vec4f color1= Vec4f(1.f, 1.f, 1.f, 0.1f+anim*0.5f);
875 const Vec4f color2= Vec4f(1.f, 1.f, 1.f, 0.3f+anim);
876
877 glBegin(GL_TRIANGLE_FAN);
878
879 glColor4fv(color2.ptr());
880 glVertex2f(x+w/2, y+h/2);
881
882 glColor4fv(color1.ptr());
883 glVertex2f(x-lightSize, y-lightSize);
884
885 glColor4fv(color1.ptr());
886 glVertex2f(x+w+lightSize, y-lightSize);
887
888 glColor4fv(color1.ptr());
889 glVertex2f(x+w+lightSize, y+h+lightSize);
890
891 glColor4fv(color1.ptr());
892 glVertex2f(x+w+lightSize, y+h+lightSize);
893
894 glColor4fv(color1.ptr());
895 glVertex2f(x-lightSize, y+h+lightSize);
896
897 glColor4fv(color1.ptr());
898 glVertex2f(x-lightSize, y-lightSize);
899
900 glEnd();
901 }
902
903 Vec2i textPos= Vec2i(x+w/2, y+h/2);
904
905 renderText(
906 button->getText(), button->getFont(), GraphicButton::getFade(),
907 x+w/2, y+h/2, true);
908
909 glPopAttrib();
910 }
911
renderListBox(const GraphicListBox * listBox)912 void Renderer::renderListBox(const GraphicListBox *listBox){
913
914 renderButton(listBox->getButton1());
915 renderButton(listBox->getButton2());
916
917 glPushAttrib(GL_ENABLE_BIT);
918 glEnable(GL_BLEND);
919
920 GraphicLabel label;
921 label.init(listBox->getX(), listBox->getY(), listBox->getW(), listBox->getH(), true);
922 label.setText(listBox->getText());
923 label.setFont(listBox->getFont());
924 renderLabel(&label);
925
926 glPopAttrib();
927 }
928
renderMessageBox(const GraphicMessageBox * messageBox)929 void Renderer::renderMessageBox(const GraphicMessageBox *messageBox){
930
931 //background
932 glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
933 glEnable(GL_BLEND);
934
935 glColor4f(0.0f, 0.0f, 0.0f, 0.5f) ;
936 glBegin(GL_TRIANGLE_STRIP);
937 glVertex2i(messageBox->getX(), messageBox->getY()+9*messageBox->getH()/10);
938 glVertex2i(messageBox->getX(), messageBox->getY());
939 glVertex2i(messageBox->getX() + messageBox->getW(), messageBox->getY() + 9*messageBox->getH()/10);
940 glVertex2i(messageBox->getX() + messageBox->getW(), messageBox->getY());
941 glEnd();
942
943 glColor4f(0.0f, 0.0f, 0.0f, 0.8f) ;
944 glBegin(GL_TRIANGLE_STRIP);
945 glVertex2i(messageBox->getX(), messageBox->getY()+messageBox->getH());
946 glVertex2i(messageBox->getX(), messageBox->getY()+9*messageBox->getH()/10);
947 glVertex2i(messageBox->getX() + messageBox->getW(), messageBox->getY() + messageBox->getH());
948 glVertex2i(messageBox->getX() + messageBox->getW(), messageBox->getY()+9*messageBox->getH()/10);
949 glEnd();
950
951 glBegin(GL_LINE_LOOP);
952 glColor4f(0.5f, 0.5f, 0.5f, 0.25f) ;
953 glVertex2i(messageBox->getX(), messageBox->getY());
954
955 glColor4f(0.0f, 0.0f, 0.0f, 0.25f) ;
956 glVertex2i(messageBox->getX()+ messageBox->getW(), messageBox->getY());
957
958 glColor4f(0.5f, 0.5f, 0.5f, 0.25f) ;
959 glVertex2i(messageBox->getX()+ messageBox->getW(), messageBox->getY() + messageBox->getH());
960
961 glColor4f(0.25f, 0.25f, 0.25f, 0.25f) ;
962 glVertex2i(messageBox->getX(), messageBox->getY() + messageBox->getH());
963 glEnd();
964
965 glBegin(GL_LINE_STRIP);
966 glColor4f(1.0f, 1.0f, 1.0f, 0.25f) ;
967 glVertex2i(messageBox->getX(), messageBox->getY() + 90*messageBox->getH()/100);
968
969 glColor4f(0.5f, 0.5f, 0.5f, 0.25f) ;
970 glVertex2i(messageBox->getX()+ messageBox->getW(), messageBox->getY() + 90*messageBox->getH()/100);
971 glEnd();
972
973 glPopAttrib();
974
975 //buttons
976 renderButton(messageBox->getButton1());
977 if(messageBox->getButtonCount()==2){
978 renderButton(messageBox->getButton2());
979 }
980
981 //text
982 renderText(
983 messageBox->getText(), messageBox->getFont(), Vec3f(1.0f, 1.0f, 1.0f),
984 messageBox->getX()+15, messageBox->getY()+7*messageBox->getH()/10,
985 false );
986
987 renderText(
988 messageBox->getHeader(), messageBox->getFont(),Vec3f(1.0f, 1.0f, 1.0f),
989 messageBox->getX()+15, messageBox->getY()+93*messageBox->getH()/100,
990 false );
991 }
992
993 // ==================== complex rendering ====================
994
renderSurface()995 void Renderer::renderSurface(){
996
997 int lastTex=-1;
998 int currTex;
999 const World *world= game->getWorld();
1000 const Map *map= world->getMap();
1001 const Rect2i mapBounds(0, 0, map->getSurfaceW()-1, map->getSurfaceH()-1);
1002 float coordStep= world->getTileset()->getSurfaceAtlas()->getCoordStep();
1003
1004 assertGl();
1005
1006 const Texture2D *fowTex= world->getMinimap()->getFowTexture();
1007
1008 glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT);
1009
1010 glEnable(GL_BLEND);
1011 glEnable(GL_COLOR_MATERIAL);
1012 glDisable(GL_ALPHA_TEST);
1013
1014 //fog of war tex unit
1015 glActiveTexture(fowTexUnit);
1016 glEnable(GL_TEXTURE_2D);
1017 glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(fowTex)->getHandle());
1018 glTexSubImage2D(
1019 GL_TEXTURE_2D, 0, 0, 0,
1020 fowTex->getPixmap()->getW(), fowTex->getPixmap()->getH(),
1021 GL_ALPHA, GL_UNSIGNED_BYTE, fowTex->getPixmap()->getPixels());
1022
1023 //shadow texture
1024 if(shadows==sProjected || shadows==sShadowMapping){
1025 glActiveTexture(shadowTexUnit);
1026 glEnable(GL_TEXTURE_2D);
1027
1028 glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
1029
1030 static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
1031 enableProjectiveTexturing();
1032 }
1033
1034 glActiveTexture(baseTexUnit);
1035
1036 Quad2i scaledQuad= visibleQuad/Map::cellScale;
1037
1038 PosQuadIterator pqi(map, scaledQuad);
1039 while(pqi.next()){
1040
1041 const Vec2i &pos= pqi.getPos();
1042
1043 if(mapBounds.isInside(pos)){
1044
1045 SurfaceCell *tc00= map->getSurfaceCell(pos.x, pos.y);
1046 SurfaceCell *tc10= map->getSurfaceCell(pos.x+1, pos.y);
1047 SurfaceCell *tc01= map->getSurfaceCell(pos.x, pos.y+1);
1048 SurfaceCell *tc11= map->getSurfaceCell(pos.x+1, pos.y+1);
1049
1050 triangleCount+= 2;
1051 pointCount+= 4;
1052
1053 //set texture
1054 currTex= static_cast<const Texture2DGl*>(tc00->getSurfaceTexture())->getHandle();
1055 if(currTex!=lastTex){
1056 lastTex=currTex;
1057 glBindTexture(GL_TEXTURE_2D, lastTex);
1058 }
1059
1060 Vec2f surfCoord= tc00->getSurfTexCoord();
1061
1062 glBegin(GL_TRIANGLE_STRIP);
1063
1064 //draw quad using immediate mode
1065 glMultiTexCoord2fv(fowTexUnit, tc01->getFowTexCoord().ptr());
1066 glMultiTexCoord2f(baseTexUnit, surfCoord.x, surfCoord.y+coordStep);
1067 glNormal3fv(tc01->getNormal().ptr());
1068 glVertex3fv(tc01->getVertex().ptr());
1069
1070 glMultiTexCoord2fv(fowTexUnit, tc00->getFowTexCoord().ptr());
1071 glMultiTexCoord2f(baseTexUnit, surfCoord.x, surfCoord.y);
1072 glNormal3fv(tc00->getNormal().ptr());
1073 glVertex3fv(tc00->getVertex().ptr());
1074
1075 glMultiTexCoord2fv(fowTexUnit, tc11->getFowTexCoord().ptr());
1076 glMultiTexCoord2f(baseTexUnit, surfCoord.x+coordStep, surfCoord.y+coordStep);
1077 glNormal3fv(tc11->getNormal().ptr());
1078 glVertex3fv(tc11->getVertex().ptr());
1079
1080 glMultiTexCoord2fv(fowTexUnit, tc10->getFowTexCoord().ptr());
1081 glMultiTexCoord2f(baseTexUnit, surfCoord.x+coordStep, surfCoord.y);
1082 glNormal3fv(tc10->getNormal().ptr());
1083 glVertex3fv(tc10->getVertex().ptr());
1084
1085 glEnd();
1086 }
1087 }
1088 glEnd();
1089
1090 //Restore
1091 static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(false);
1092 glPopAttrib();
1093
1094 //assert
1095 glGetError(); //remove when first mtex problem solved
1096 assertGl();
1097 }
1098
renderObjects()1099 void Renderer::renderObjects(){
1100 const World *world= game->getWorld();
1101 const Map *map= world->getMap();
1102
1103 assertGl();
1104 const Texture2D *fowTex= world->getMinimap()->getFowTexture();
1105 Vec3f baseFogColor= world->getTileset()->getFogColor()*computeLightColor(world->getTimeFlow()->getTime());
1106
1107 glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_FOG_BIT | GL_LIGHTING_BIT | GL_TEXTURE_BIT);
1108
1109 if(shadows==sShadowMapping){
1110 glActiveTexture(shadowTexUnit);
1111 glEnable(GL_TEXTURE_2D);
1112
1113 glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
1114
1115 static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
1116 enableProjectiveTexturing();
1117 }
1118
1119 glActiveTexture(baseTexUnit);
1120
1121 glEnable(GL_COLOR_MATERIAL);
1122 glAlphaFunc(GL_GREATER, 0.5f);
1123
1124 modelRenderer->begin(true, true, false);
1125 int thisTeamIndex= world->getThisTeamIndex();
1126
1127 PosQuadIterator pqi(map, visibleQuad, Map::cellScale);
1128 while(pqi.next()){
1129 const Vec2i pos= pqi.getPos();
1130
1131 if(map->isInside(pos)){
1132
1133 SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(pos));
1134 Object *o= sc->getObject();
1135 if(sc->isExplored(thisTeamIndex) && o!=NULL){
1136
1137 const Model *objModel= sc->getObject()->getModel();
1138 Vec3f v= o->getPos();
1139
1140 //ambient and diffuse color is taken from cell color
1141 float fowFactor= fowTex->getPixmap()->getPixelf(pos.x/Map::cellScale, pos.y/Map::cellScale);
1142 Vec4f color= Vec4f(Vec3f(fowFactor), 1.f);
1143 glColor4fv(color.ptr());
1144 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (color*ambFactor).ptr());
1145 glFogfv(GL_FOG_COLOR, (baseFogColor*fowFactor).ptr());
1146
1147 glMatrixMode(GL_MODELVIEW);
1148 glPushMatrix();
1149 glTranslatef(v.x, v.y, v.z);
1150 glRotatef(o->getRotation(), 0.f, 1.f, 0.f);
1151
1152 objModel->updateInterpolationData(0.f, true);
1153 modelRenderer->render(objModel);
1154
1155 triangleCount+= objModel->getTriangleCount();
1156 pointCount+= objModel->getVertexCount();
1157
1158 glPopMatrix();
1159
1160 }
1161 }
1162 }
1163
1164 modelRenderer->end();
1165
1166 //restore
1167 static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
1168 glPopAttrib();
1169 }
1170
renderWater()1171 void Renderer::renderWater(){
1172
1173 bool closed= false;
1174 const World *world= game->getWorld();
1175 const Map *map= world->getMap();
1176
1177 float waterAnim= world->getWaterEffects()->getAmin();
1178
1179 //assert
1180 assertGl();
1181
1182 glPushAttrib(GL_TEXTURE_BIT | GL_ENABLE_BIT | GL_CURRENT_BIT);
1183
1184 //water texture nit
1185 glDisable(GL_TEXTURE_2D);
1186
1187 glEnable(GL_BLEND);
1188 if(textures3D){
1189 Texture3D *waterTex= world->getTileset()->getWaterTex();
1190 glEnable(GL_TEXTURE_3D);
1191 glBindTexture(GL_TEXTURE_3D, static_cast<Texture3DGl*>(waterTex)->getHandle());
1192 }
1193 else{
1194 glEnable(GL_COLOR_MATERIAL);
1195 glColor4f(0.5f, 0.5f, 1.0f, 0.5f);
1196 glBindTexture(GL_TEXTURE_3D, 0);
1197 }
1198
1199 assertGl();
1200
1201 //fog of War texture Unit
1202 const Texture2D *fowTex= world->getMinimap()->getFowTexture();
1203 glActiveTexture(fowTexUnit);
1204 glEnable(GL_TEXTURE_2D);
1205 glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(fowTex)->getHandle());
1206 glActiveTexture(baseTexUnit);
1207
1208 assertGl();
1209
1210 Rect2i boundingRect= visibleQuad.computeBoundingRect();
1211 Rect2i scaledRect= boundingRect/Map::cellScale;
1212 scaledRect.clamp(0, 0, map->getSurfaceW()-1, map->getSurfaceH()-1);
1213
1214 float waterLevel= world->getMap()->getWaterLevel();
1215 for(int j=scaledRect.p[0].y; j<scaledRect.p[1].y; ++j){
1216 glBegin(GL_TRIANGLE_STRIP);
1217
1218 for(int i=scaledRect.p[0].x; i<=scaledRect.p[1].x; ++i){
1219
1220 SurfaceCell *tc0= map->getSurfaceCell(i, j);
1221 SurfaceCell *tc1= map->getSurfaceCell(i, j+1);
1222
1223 int thisTeamIndex= world->getThisTeamIndex();
1224 if(tc0->getNearSubmerged() && (tc0->isExplored(thisTeamIndex) || tc1->isExplored(thisTeamIndex))){
1225 glNormal3f(0.f, 1.f, 0.f);
1226 closed= false;
1227
1228 triangleCount+= 2;
1229 pointCount+= 2;
1230
1231 //vertex 1
1232 glMaterialfv(
1233 GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
1234 computeWaterColor(waterLevel, tc1->getHeight()).ptr());
1235 glMultiTexCoord2fv(GL_TEXTURE1, tc1->getFowTexCoord().ptr());
1236 glTexCoord3f(i, 1.f, waterAnim);
1237 glVertex3f(
1238 static_cast<float>(i)*Map::mapScale,
1239 waterLevel,
1240 static_cast<float>(j+1)*Map::mapScale);
1241
1242 //vertex 2
1243 glMaterialfv(
1244 GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
1245 computeWaterColor(waterLevel, tc0->getHeight()).ptr());
1246 glMultiTexCoord2fv(GL_TEXTURE1, tc0->getFowTexCoord().ptr());
1247 glTexCoord3f(i, 0.f, waterAnim);
1248 glVertex3f(
1249 static_cast<float>(i)*Map::mapScale,
1250 waterLevel,
1251 static_cast<float>(j)*Map::mapScale);
1252
1253 }
1254 else{
1255 if(!closed){
1256
1257 pointCount+= 2;
1258
1259 //vertex 1
1260 glMaterialfv(
1261 GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
1262 computeWaterColor(waterLevel, tc1->getHeight()).ptr());
1263 glMultiTexCoord2fv(GL_TEXTURE1, tc1->getFowTexCoord().ptr());
1264 glTexCoord3f(i, 1.f, waterAnim);
1265 glVertex3f(
1266 static_cast<float>(i)*Map::mapScale,
1267 waterLevel,
1268 static_cast<float>(j+1)*Map::mapScale);
1269
1270 //vertex 2
1271 glMaterialfv(
1272 GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
1273 computeWaterColor(waterLevel, tc0->getHeight()).ptr());
1274 glMultiTexCoord2fv(GL_TEXTURE1, tc0->getFowTexCoord().ptr());
1275 glTexCoord3f(i, 0.f, waterAnim);
1276 glVertex3f(
1277 static_cast<float>(i)*Map::mapScale,
1278 waterLevel,
1279 static_cast<float>(j)*Map::mapScale);
1280
1281 glEnd();
1282 glBegin(GL_TRIANGLE_STRIP);
1283 closed= true;
1284 }
1285 }
1286 }
1287 glEnd();
1288 }
1289
1290 //restore
1291 glPopAttrib();
1292
1293 assertGl();
1294 }
1295
renderUnits()1296 void Renderer::renderUnits(){
1297 Unit *unit;
1298 const World *world= game->getWorld();
1299 MeshCallbackTeamColor meshCallbackTeamColor;
1300
1301 //assert
1302 assertGl();
1303
1304 glPushAttrib(GL_ENABLE_BIT | GL_FOG_BIT | GL_LIGHTING_BIT | GL_TEXTURE_BIT);
1305 glEnable(GL_COLOR_MATERIAL);
1306
1307 if(shadows==sShadowMapping){
1308 glActiveTexture(shadowTexUnit);
1309 glEnable(GL_TEXTURE_2D);
1310
1311 glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
1312
1313 static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
1314 enableProjectiveTexturing();
1315 }
1316 glActiveTexture(baseTexUnit);
1317
1318 modelRenderer->begin(true, true, true, &meshCallbackTeamColor);
1319
1320 for(int i=0; i<world->getFactionCount(); ++i){
1321 meshCallbackTeamColor.setTeamTexture(world->getFaction(i)->getTexture());
1322 for(int j=0; j<world->getFaction(i)->getUnitCount(); ++j){
1323 unit= world->getFaction(i)->getUnit(j);
1324 if(world->toRenderUnit(unit, visibleQuad)) {
1325
1326 glMatrixMode(GL_MODELVIEW);
1327 glPushMatrix();
1328
1329 //translate
1330 Vec3f currVec= unit->getCurrVectorFlat();
1331 glTranslatef(currVec.x, currVec.y, currVec.z);
1332
1333 //rotate
1334 glRotatef(unit->getRotation(), 0.f, 1.f, 0.f);
1335 glRotatef(unit->getVerticalRotation(), 1.f, 0.f, 0.f);
1336
1337 //dead alpha
1338 float alpha= 1.0f;
1339 const SkillType *st= unit->getCurrSkill();
1340 if(st->getClass()==scDie && static_cast<const DieSkillType*>(st)->getFade()){
1341 alpha= 1.0f-unit->getAnimProgress();
1342 glDisable(GL_COLOR_MATERIAL);
1343 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Vec4f(1.0f, 1.0f, 1.0f, alpha).ptr());
1344 }
1345 else{
1346 glEnable(GL_COLOR_MATERIAL);
1347 }
1348
1349 //render
1350 const Model *model= unit->getCurrentModel();
1351 model->updateInterpolationData(unit->getAnimProgress(), unit->isAlive());
1352 modelRenderer->render(model);
1353
1354 triangleCount+= model->getTriangleCount();
1355 pointCount+= model->getVertexCount();
1356
1357 glPopMatrix();
1358 }
1359 }
1360 }
1361 modelRenderer->end();
1362
1363 //restore
1364 static_cast<ModelRendererGl*>(modelRenderer)->setDuplicateTexCoords(true);
1365 glPopAttrib();
1366
1367 //assert
1368 assertGl();
1369 }
1370
renderSelectionEffects()1371 void Renderer::renderSelectionEffects(){
1372
1373 const World *world= game->getWorld();
1374 const Map *map= world->getMap();
1375 const Selection *selection= game->getGui()->getSelection();
1376
1377 glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
1378 glDisable(GL_LIGHTING);
1379 glDisable(GL_TEXTURE_2D);
1380 glDepthFunc(GL_ALWAYS);
1381 glDisable(GL_STENCIL_TEST);
1382 glDisable(GL_CULL_FACE);
1383 glEnable(GL_BLEND);
1384 glLineWidth(2.f);
1385
1386 //units
1387 for(int i=0; i<selection->getCount(); ++i){
1388
1389 const Unit *unit= selection->getUnit(i);
1390
1391 //translate
1392 Vec3f currVec= unit->getCurrVectorFlat();
1393 currVec.y+= 0.3f;
1394
1395 //selection circle
1396 if(world->getThisFactionIndex()==unit->getFactionIndex()){
1397 glColor4f(0, unit->getHpRatio(), 0, 0.3f);
1398 }
1399 else{
1400 glColor4f(unit->getHpRatio(), 0, 0, 0.3f);
1401 }
1402 renderSelectionCircle(currVec, unit->getType()->getSize(), selectionCircleRadius);
1403
1404 //magic circle
1405 if(world->getThisFactionIndex()==unit->getFactionIndex() && unit->getType()->getMaxEp()>0){
1406 glColor4f(unit->getEpRatio()/2.f, unit->getEpRatio(), unit->getEpRatio(), 0.5f);
1407 renderSelectionCircle(currVec, unit->getType()->getSize(), magicCircleRadius);
1408 }
1409 }
1410
1411 //target arrow
1412 if(selection->getCount()==1){
1413 const Unit *unit= selection->getUnit(0);
1414
1415 //comand arrow
1416 if(focusArrows && unit->anyCommand()){
1417 const CommandType *ct= unit->getCurrCommand()->getCommandType();
1418 if(ct->getClicks()!=cOne){
1419
1420 //arrow color
1421 Vec3f arrowColor;
1422 switch(ct->getClass()){
1423 case ccMove:
1424 arrowColor= Vec3f(0.f, 1.f, 0.f);
1425 break;
1426 case ccAttack:
1427 case ccAttackStopped:
1428 arrowColor= Vec3f(1.f, 0.f, 0.f);
1429 break;
1430 default:
1431 arrowColor= Vec3f(1.f, 1.f, 0.f);
1432 }
1433
1434 //arrow target
1435 Vec3f arrowTarget;
1436 Command *c= unit->getCurrCommand();
1437 if(c->getUnit()!=NULL){
1438 arrowTarget= c->getUnit()->getCurrVectorFlat();
1439 }
1440 else{
1441 Vec2i pos= c->getPos();
1442 arrowTarget= Vec3f(pos.x, map->getCell(pos)->getHeight(), pos.y);
1443 }
1444
1445 renderArrow(unit->getCurrVectorFlat(), arrowTarget, arrowColor, 0.3f);
1446 }
1447 }
1448
1449 //meeting point arrow
1450 if(unit->getType()->getMeetingPoint()){
1451 Vec2i pos= unit->getMeetingPos();
1452 Vec3f arrowTarget= Vec3f(pos.x, map->getCell(pos)->getHeight(), pos.y);
1453 renderArrow(unit->getCurrVectorFlat(), arrowTarget, Vec3f(0.f, 0.f, 1.f), 0.3f);
1454 }
1455
1456 }
1457
1458 //render selection hightlights
1459 for(int i=0; i<world->getFactionCount(); ++i){
1460 for(int j=0; j<world->getFaction(i)->getUnitCount(); ++j){
1461 const Unit *unit= world->getFaction(i)->getUnit(j);
1462
1463 if(unit->isHighlighted()){
1464 float highlight= unit->getHightlight();
1465 if(game->getWorld()->getThisFactionIndex()==unit->getFactionIndex()){
1466 glColor4f(0.f, 1.f, 0.f, highlight);
1467 }
1468 else{
1469 glColor4f(1.f, 0.f, 0.f, highlight);
1470 }
1471
1472 Vec3f v= unit->getCurrVectorFlat();
1473 v.y+= 0.3f;
1474 renderSelectionCircle(v, unit->getType()->getSize(), selectionCircleRadius);
1475 }
1476 }
1477 }
1478
1479 glPopAttrib();
1480 }
1481
renderWaterEffects()1482 void Renderer::renderWaterEffects(){
1483 const World *world= game->getWorld();
1484 const WaterEffects *we= world->getWaterEffects();
1485 const Map *map= world->getMap();
1486 const CoreData &coreData= CoreData::getInstance();
1487 float height= map->getWaterLevel()+0.001f;
1488
1489 assertGl();
1490
1491 glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
1492 glEnable(GL_BLEND);
1493 glDisable(GL_ALPHA_TEST);
1494 glDepthMask(GL_FALSE);
1495 glDepthFunc(GL_LEQUAL);
1496 glEnable(GL_COLOR_MATERIAL);
1497
1498 glNormal3f(0.f, 1.f, 0.f);
1499
1500 //splashes
1501 glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(coreData.getWaterSplashTexture())->getHandle());
1502 for(int i=0; i<we->getWaterSplashCount(); ++i){
1503 const WaterSplash *ws= we->getWaterSplash(i);
1504
1505 //render only if enabled
1506 if(ws->getEnabled()){
1507
1508 //render only if visible
1509 Vec2i intPos= Vec2i(static_cast<int>(ws->getPos().x), static_cast<int>(ws->getPos().y));
1510 if(map->getSurfaceCell(Map::toSurfCoords(intPos))->isVisible(world->getThisTeamIndex())){
1511
1512 float scale= ws->getAnim();
1513
1514 glColor4f(1.f, 1.f, 1.f, 1.f-ws->getAnim());
1515 glBegin(GL_TRIANGLE_STRIP);
1516 glTexCoord2f(0.f, 1.f);
1517 glVertex3f(ws->getPos().x-scale, height, ws->getPos().y+scale);
1518 glTexCoord2f(0.f, 0.f);
1519 glVertex3f(ws->getPos().x-scale, height, ws->getPos().y-scale);
1520 glTexCoord2f(1.f, 1.f);
1521 glVertex3f(ws->getPos().x+scale, height, ws->getPos().y+scale);
1522 glTexCoord2f(1.f, 0.f);
1523 glVertex3f(ws->getPos().x+scale, height, ws->getPos().y-scale);
1524 glEnd();
1525 }
1526 }
1527 }
1528
1529 glPopAttrib();
1530
1531 assertGl();
1532 }
1533
renderMinimap()1534 void Renderer::renderMinimap(){
1535 const World *world= game->getWorld();
1536 const Minimap *minimap= world->getMinimap();
1537 const GameCamera *gameCamera= game->getGameCamera();
1538 const Pixmap2D *pixmap= minimap->getTexture()->getPixmap();
1539 const Metrics &metrics= Metrics::getInstance();
1540
1541 int mx= metrics.getMinimapX();
1542 int my= metrics.getMinimapY();
1543 int mw= metrics.getMinimapW();
1544 int mh= metrics.getMinimapH();
1545
1546 Vec2f zoom= Vec2f(
1547 static_cast<float>(mw)/ pixmap->getW(),
1548 static_cast<float>(mh)/ pixmap->getH());
1549
1550 assertGl();
1551
1552 glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_TEXTURE_BIT);
1553
1554 //draw map
1555 glEnable(GL_TEXTURE_2D);
1556 glEnable(GL_BLEND);
1557
1558 glActiveTexture(fowTexUnit);
1559 glEnable(GL_TEXTURE_2D);
1560 glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(minimap->getFowTexture())->getHandle());
1561 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1562
1563 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
1564 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1565 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
1566 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE);
1567
1568 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
1569 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
1570 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
1571
1572 glActiveTexture(baseTexUnit);
1573 glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(minimap->getTexture())->getHandle());
1574
1575 glColor4f(0.5f, 0.5f, 0.5f, 0.1f);
1576 glBegin(GL_TRIANGLE_STRIP);
1577 glTexCoord2f(0.0f, 1.0f);
1578 glMultiTexCoord2f(fowTexUnit, 0.0f, 1.0f);
1579 glVertex2i(mx, my);
1580 glTexCoord2f(0.0f, 0.0f);
1581 glMultiTexCoord2f(fowTexUnit, 0.0f, 0.0f);
1582 glVertex2i(mx, my+mh);
1583 glTexCoord2f(1.0f, 1.0f);
1584 glMultiTexCoord2f(fowTexUnit, 1.0f, 1.0f);
1585 glVertex2i(mx+mw, my);
1586 glTexCoord2f(1.0f, 0.0f);
1587 glMultiTexCoord2f(fowTexUnit, 1.0f, 0.0f);
1588 glVertex2i(mx+mw, my+mh);
1589 glEnd();
1590
1591 glDisable(GL_BLEND);
1592
1593 glActiveTexture(fowTexUnit);
1594 glDisable(GL_TEXTURE_2D);
1595 glActiveTexture(baseTexUnit);
1596 glDisable(GL_TEXTURE_2D);
1597
1598 //draw units
1599 glBegin(GL_QUADS);
1600 for(int i=0; i<world->getFactionCount(); ++i){
1601 for(int j=0; j<world->getFaction(i)->getUnitCount(); ++j){
1602 Unit *unit= world->getFaction(i)->getUnit(j);
1603 if(world->toRenderUnit(unit)){
1604 Vec2i pos= unit->getPos()/Map::cellScale;
1605 int size= unit->getType()->getSize();
1606 Vec3f color= world->getFaction(i)->getTexture()->getPixmap()->getPixel3f(0, 0);
1607 glColor3fv(color.ptr());
1608 glVertex2f(mx + pos.x*zoom.x, my + mh - (pos.y*zoom.y));
1609 glVertex2f(mx + (pos.x+1)*zoom.x+size, my + mh - (pos.y*zoom.y));
1610 glVertex2f(mx + (pos.x+1)*zoom.x+size, my + mh - ((pos.y+size)*zoom.y));
1611 glVertex2f(mx + pos.x*zoom.x, my + mh - ((pos.y+size)*zoom.y));
1612 }
1613 }
1614 }
1615 glEnd();
1616
1617 //draw camera
1618 float wRatio= static_cast<float>(metrics.getMinimapW()) / world->getMap()->getW();
1619 float hRatio= static_cast<float>(metrics.getMinimapH()) / world->getMap()->getH();
1620
1621 int x= static_cast<int>(gameCamera->getPos().x * wRatio);
1622 int y= static_cast<int>(gameCamera->getPos().z * hRatio);
1623
1624 float ang= degToRad(gameCamera->getHAng());
1625
1626 glEnable(GL_BLEND);
1627
1628 glBegin(GL_TRIANGLES);
1629 glColor4f(1.f, 1.f, 1.f, 1.f);
1630 glVertex2i(mx+x, my+mh-y);
1631
1632 glColor4f(1.f, 1.f, 1.f, 0.0f);
1633 glVertex2i(
1634 mx + x + static_cast<int>(20*sin(ang-pi/5)),
1635 my + mh - (y-static_cast<int>(20*cos(ang-pi/5))));
1636
1637 glColor4f(1.f, 1.f, 1.f, 0.0f);
1638 glVertex2i(
1639 mx + x + static_cast<int>(20*sin(ang+pi/5)),
1640 my + mh - (y-static_cast<int>(20*cos(ang+pi/5))));
1641
1642 glEnd();
1643 glPopAttrib();
1644
1645 assertGl();
1646 }
1647
renderDisplay()1648 void Renderer::renderDisplay(){
1649
1650 CoreData &coreData= CoreData::getInstance();
1651 const Metrics &metrics= Metrics::getInstance();
1652 const Display *display= game->getGui()->getDisplay();
1653
1654 glPushAttrib(GL_ENABLE_BIT);
1655
1656 //infoString
1657 renderTextShadow(
1658 display->getInfoText().c_str(),
1659 coreData.getDisplayFont(),
1660 metrics.getDisplayX(),
1661 metrics.getDisplayY()+Display::infoStringY);
1662
1663 //title
1664 renderTextShadow(
1665 display->getTitle().c_str(),
1666 coreData.getDisplayFont(),
1667 metrics.getDisplayX()+40,
1668 metrics.getDisplayY() + metrics.getDisplayH() - 20);
1669
1670 glColor3f(0.0f, 0.0f, 0.0f);
1671
1672 //text
1673 renderTextShadow(
1674 display->getText().c_str(),
1675 coreData.getDisplayFont(),
1676 metrics.getDisplayX() -1,
1677 metrics.getDisplayY() + metrics.getDisplayH() - 56);
1678
1679 //progress Bar
1680 if(display->getProgressBar()!=-1){
1681 renderProgressBar(
1682 display->getProgressBar(),
1683 metrics.getDisplayX(),
1684 metrics.getDisplayY() + metrics.getDisplayH()-50,
1685 coreData.getMenuFontSmall());
1686 }
1687
1688 //up images
1689 glEnable(GL_TEXTURE_2D);
1690
1691 glColor3f(1.f, 1.f, 1.f);
1692 for(int i=0; i<Display::upCellCount; ++i){
1693 if(display->getUpImage(i)!=NULL){
1694 renderQuad(
1695 metrics.getDisplayX()+display->computeUpX(i),
1696 metrics.getDisplayY()+display->computeUpY(i),
1697 Display::imageSize, Display::imageSize, display->getUpImage(i));
1698 }
1699 }
1700
1701 //down images
1702 for(int i=0; i<Display::downCellCount; ++i){
1703 if(display->getDownImage(i)!=NULL){
1704 if(display->getDownLighted(i)){
1705 glColor3f(1.f, 1.f, 1.f);
1706 }
1707 else{
1708 glColor3f(0.3f, 0.3f, 0.3f);
1709 }
1710
1711 int x= metrics.getDisplayX()+display->computeDownX(i);
1712 int y= metrics.getDisplayY()+display->computeDownY(i);
1713 int size= Display::imageSize;
1714
1715 if(display->getDownSelectedPos()==i){
1716 x-= 3;
1717 y-= 3;
1718 size+= 6;
1719 }
1720
1721 renderQuad(x, y, size, size, display->getDownImage(i));
1722 }
1723 }
1724
1725 //selection
1726 int downPos= display->getDownSelectedPos();
1727 if(downPos!=Display::invalidPos){
1728 const Texture2D *texture= display->getDownImage(downPos);
1729 if(texture!=NULL){
1730 int x= metrics.getDisplayX()+display->computeDownX(downPos)-3;
1731 int y= metrics.getDisplayY()+display->computeDownY(downPos)-3;
1732 int size= Display::imageSize+6;
1733 renderQuad(x, y, size, size, display->getDownImage(downPos));
1734 }
1735 }
1736
1737 glPopAttrib();
1738 }
1739
renderMenuBackground(const MenuBackground * menuBackground)1740 void Renderer::renderMenuBackground(const MenuBackground *menuBackground){
1741
1742 assertGl();
1743
1744 Vec3f cameraPosition= menuBackground->getCamera()->getPosition();
1745
1746 glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
1747
1748 //clear
1749 Vec4f fogColor= Vec4f(0.4f, 0.4f, 0.4f, 1.f) * menuBackground->getFade();
1750 glClearColor(fogColor.x, fogColor.y, fogColor.z, 1.f);
1751 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1752 glFogfv(GL_FOG_COLOR, fogColor.ptr());
1753
1754 //light
1755 Vec4f lightPos= Vec4f(10.f, 10.f, 10.f, 1.f)* menuBackground->getFade();
1756 Vec4f diffLight= Vec4f(0.9f, 0.9f, 0.9f, 1.f)* menuBackground->getFade();
1757 Vec4f ambLight= Vec4f(0.3f, 0.3f, 0.3f, 1.f)* menuBackground->getFade();
1758 Vec4f specLight= Vec4f(0.1f, 0.1f, 0.1f, 1.f)* menuBackground->getFade();
1759
1760 glEnable(GL_LIGHT0);
1761 glLightfv(GL_LIGHT0, GL_POSITION, lightPos.ptr());
1762 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffLight.ptr());
1763 glLightfv(GL_LIGHT0, GL_AMBIENT, ambLight.ptr());
1764 glLightfv(GL_LIGHT0, GL_SPECULAR, specLight.ptr());
1765
1766 //main model
1767 glEnable(GL_ALPHA_TEST);
1768 glAlphaFunc(GL_GREATER, 0.5f);
1769 modelRenderer->begin(true, true, true);
1770 modelRenderer->render(menuBackground->getMainModel());
1771 modelRenderer->end();
1772 glDisable(GL_ALPHA_TEST);
1773
1774 //characters
1775 float dist= menuBackground->getAboutPosition().dist(cameraPosition);
1776 float minDist= 3.f;
1777 if(dist<minDist){
1778
1779 glAlphaFunc(GL_GREATER, 0.0f);
1780 float alpha= clamp((minDist-dist)/minDist, 0.f, 1.f);
1781 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Vec4f(1.0f, 1.0f, 1.0f, alpha).ptr());
1782 modelRenderer->begin(true, true, false);
1783
1784 for(int i=0; i<MenuBackground::characterCount; ++i){
1785 glMatrixMode(GL_MODELVIEW);
1786 glPushMatrix();
1787 glLoadIdentity();
1788 glTranslatef(i*2.f-4.f, -1.4f, -7.5f);
1789 menuBackground->getCharacterModel(i)->updateInterpolationData(menuBackground->getAnim(), true);
1790 modelRenderer->render(menuBackground->getCharacterModel(i));
1791 glPopMatrix();
1792 }
1793 modelRenderer->end();
1794 }
1795
1796 //water
1797 if(menuBackground->getWater()){
1798
1799 //water surface
1800 const int waterTesselation= 10;
1801 const int waterSize= 250;
1802 const int waterQuadSize= 2*waterSize/waterTesselation;
1803 const float waterHeight= menuBackground->getWaterHeight();
1804
1805 glEnable(GL_BLEND);
1806
1807 glNormal3f(0.f, 1.f, 0.f);
1808 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Vec4f(1.f, 1.f, 1.f, 1.f).ptr());
1809 GLuint waterHandle= static_cast<Texture2DGl*>(menuBackground->getWaterTexture())->getHandle();
1810 glBindTexture(GL_TEXTURE_2D, waterHandle);
1811 for(int i=1; i<waterTesselation; ++i){
1812 glBegin(GL_TRIANGLE_STRIP);
1813 for(int j=1; j<waterTesselation; ++j){
1814 glTexCoord2i(1, 2 % j);
1815 glVertex3f(-waterSize+i*waterQuadSize, waterHeight, -waterSize+j*waterQuadSize);
1816 glTexCoord2i(0, 2 % j);
1817 glVertex3f(-waterSize+(i+1)*waterQuadSize, waterHeight, -waterSize+j*waterQuadSize);
1818 }
1819 glEnd();
1820 }
1821 glDisable(GL_BLEND);
1822
1823 //raindrops
1824 if(menuBackground->getRain()){
1825 const float maxRaindropAlpha= 0.5f;
1826
1827 glEnable(GL_BLEND);
1828 glDisable(GL_LIGHTING);
1829 glDisable(GL_ALPHA_TEST);
1830 glDepthMask(GL_FALSE);
1831
1832 //splashes
1833 CoreData &coreData= CoreData::getInstance();
1834 glBindTexture(GL_TEXTURE_2D, static_cast<Texture2DGl*>(coreData.getWaterSplashTexture())->getHandle());
1835 for(int i=0; i<MenuBackground::raindropCount; ++i){
1836
1837 Vec2f pos= menuBackground->getRaindropPos(i);
1838 float scale= menuBackground->getRaindropState(i);
1839 float alpha= maxRaindropAlpha-scale*maxRaindropAlpha;
1840
1841 glMatrixMode(GL_MODELVIEW);
1842 glPushMatrix();
1843
1844 glColor4f(1.f, 1.f, 1.f, alpha);
1845 glTranslatef(pos.x, waterHeight+0.01f, pos.y);
1846
1847 glBegin(GL_TRIANGLE_STRIP);
1848 glTexCoord2f(0.f, 1.f);
1849 glVertex3f(-scale, 0, scale);
1850 glTexCoord2f(0.f, 0.f);
1851 glVertex3f(-scale, 0, -scale);
1852 glTexCoord2f(1.f, 1.f);
1853 glVertex3f(scale, 0, scale);
1854 glTexCoord2f(1.f, 0.f);
1855 glVertex3f(scale, 0, -scale);
1856 glEnd();
1857
1858 glPopMatrix();
1859 }
1860 }
1861 }
1862
1863 glPopAttrib();
1864
1865 assertGl();
1866 }
1867
1868 // ==================== computing ====================
1869
computePosition(const Vec2i & screenPos,Vec2i & worldPos)1870 bool Renderer::computePosition(const Vec2i &screenPos, Vec2i &worldPos){
1871
1872 assertGl();
1873 const Map* map= game->getWorld()->getMap();
1874 const Metrics &metrics= Metrics::getInstance();
1875 float depth= 0.0f;
1876 GLdouble modelviewMatrix[16];
1877 GLdouble projectionMatrix[16];
1878 GLint viewport[4]= {0, 0, metrics.getScreenW(), metrics.getScreenH()};
1879 GLdouble worldX;
1880 GLdouble worldY;
1881 GLdouble worldZ;
1882 GLint screenX= (screenPos.x * metrics.getScreenW() / metrics.getVirtualW());
1883 GLint screenY= (screenPos.y * metrics.getScreenH() / metrics.getVirtualH());
1884
1885 //get the depth in the cursor pixel
1886 glReadPixels(screenX, screenY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
1887
1888 //load matrices
1889 loadProjectionMatrix();
1890 loadGameCameraMatrix();
1891
1892 //get matrices
1893 glGetDoublev(GL_MODELVIEW_MATRIX, modelviewMatrix);
1894 glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
1895
1896 //get the world coordinates
1897 gluUnProject(
1898 screenX, screenY, depth,
1899 modelviewMatrix, projectionMatrix, viewport,
1900 &worldX, &worldY, &worldZ);
1901
1902 //conver coords to int
1903 worldPos= Vec2i(static_cast<int>(worldX+0.5f), static_cast<int>(worldZ+0.5f));
1904
1905 //clamp coords to map size
1906 return map->isInside(worldPos);
1907 }
1908
computeSelected(Selection::UnitContainer & units,const Vec2i & posDown,const Vec2i & posUp)1909 void Renderer::computeSelected(Selection::UnitContainer &units, const Vec2i &posDown, const Vec2i &posUp){
1910
1911 //declarations
1912 GLuint selectBuffer[Gui::maxSelBuff];
1913 const Metrics &metrics= Metrics::getInstance();
1914
1915 //compute center and dimensions of selection rectangle
1916 int x= (posDown.x+posUp.x) / 2;
1917 int y= (posDown.y+posUp.y) / 2;
1918 int w= abs(posDown.x-posUp.x);
1919 int h= abs(posDown.y-posUp.y);
1920 if(w<1) w=1;
1921 if(h<1) h=1;
1922
1923 //setup matrices
1924 glSelectBuffer(Gui::maxSelBuff, selectBuffer);
1925 glMatrixMode(GL_PROJECTION);
1926 glPushMatrix();
1927 GLint view[]= {0, 0, metrics.getVirtualW(), metrics.getVirtualH()};
1928 glRenderMode(GL_SELECT);
1929 glLoadIdentity();
1930 gluPickMatrix(x, y, w, h, view);
1931 gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, perspFarPlane);
1932 loadGameCameraMatrix();
1933
1934 //render units
1935 renderUnitsFast();
1936
1937 //pop matrices
1938 glMatrixMode(GL_PROJECTION);
1939 glPopMatrix();
1940
1941 //select units
1942 int selCount= glRenderMode(GL_RENDER);
1943 for(int i=1; i<=selCount; ++i){
1944 int factionIndex= selectBuffer[i*5-2];
1945 int unitIndex= selectBuffer[i*5-1];
1946 const World *world= game->getWorld();
1947 if(factionIndex<world->getFactionCount() && unitIndex<world->getFaction(factionIndex)->getUnitCount()){
1948 Unit *unit= world->getFaction(factionIndex)->getUnit(unitIndex);
1949 if(unit->isAlive()){
1950 units.push_back(unit);
1951 }
1952 }
1953 }
1954 }
1955
1956
1957 // ==================== shadows ====================
1958
renderShadowsToTexture()1959 void Renderer::renderShadowsToTexture(){
1960
1961 if(shadows==sProjected || shadows==sShadowMapping){
1962
1963 shadowMapFrame= (shadowMapFrame + 1) % (shadowFrameSkip + 1);
1964
1965 if(shadowMapFrame==0){
1966
1967 assertGl();
1968
1969 glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT | GL_POLYGON_BIT);
1970
1971 if(shadows==sShadowMapping){
1972 glClear(GL_DEPTH_BUFFER_BIT);
1973 }
1974 else{
1975 float color= 1.0f-shadowAlpha;
1976 glColor3f(color, color, color);
1977 glClearColor(1.f, 1.f, 1.f, 1.f);
1978 glDisable(GL_DEPTH_TEST);
1979 glClear(GL_COLOR_BUFFER_BIT);
1980 }
1981
1982 //clear color buffer
1983 //
1984 //set viewport, we leave one texel always in white to avoid problems
1985 glViewport(1, 1, shadowTextureSize-2, shadowTextureSize-2);
1986
1987 if(nearestLightPos.w==0.f){
1988 //directional light
1989
1990 //light pos
1991 const TimeFlow *tf= game->getWorld()->getTimeFlow();
1992 float ang= tf->isDay()? computeSunAngle(tf->getTime()): computeMoonAngle(tf->getTime());
1993 ang= radToDeg(ang);
1994
1995 //push and set projection
1996 glMatrixMode(GL_PROJECTION);
1997 glPushMatrix();
1998 glLoadIdentity();
1999 if(game->getGameCamera()->getState()==GameCamera::sGame){
2000 glOrtho(-35, 5, -15, 15, -1000, 1000);
2001 }
2002 else{
2003 glOrtho(-30, 30, -20, 20, -1000, 1000);
2004 }
2005
2006 //push and set modelview
2007 glMatrixMode(GL_MODELVIEW);
2008 glPushMatrix();
2009 glLoadIdentity();
2010
2011 glRotatef(15, 0, 1, 0);
2012
2013 glRotatef(ang, 1, 0, 0);
2014 glRotatef(90, 0, 1, 0);
2015 Vec3f pos= game->getGameCamera()->getPos();
2016
2017 glTranslatef(static_cast<int>(-pos.x), 0, static_cast<int>(-pos.z));
2018
2019 }
2020 else{
2021 //non directional light
2022
2023 //push projection
2024 glMatrixMode(GL_PROJECTION);
2025 glPushMatrix();
2026 glLoadIdentity();
2027 gluPerspective(150, 1.f, perspNearPlane, perspFarPlane);
2028
2029 //push modelview
2030 glMatrixMode(GL_MODELVIEW);
2031 glPushMatrix();
2032 glLoadIdentity();
2033 glRotatef(-90, -1, 0, 0);
2034 glTranslatef(-nearestLightPos.x, -nearestLightPos.y-2, -nearestLightPos.z);
2035 }
2036
2037 if(shadows==sShadowMapping){
2038 glEnable(GL_POLYGON_OFFSET_FILL);
2039 glPolygonOffset(1.0f, 0.001f);
2040 }
2041
2042 //render 3d
2043 renderUnitsFast();
2044 renderObjectsFast();
2045
2046 //read color buffer
2047 glBindTexture(GL_TEXTURE_2D, shadowMapHandle);
2048 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowTextureSize, shadowTextureSize);
2049
2050 //get elemental matrices
2051 Matrix4f matrix1;
2052 matrix1[0]= 0.5f; matrix1[4]= 0.f; matrix1[8]= 0.f; matrix1[12]= 0.5f;
2053 matrix1[1]= 0.f; matrix1[5]= 0.5f; matrix1[9]= 0.f; matrix1[13]= 0.5f;
2054 matrix1[2]= 0.f; matrix1[6]= 0.f; matrix1[10]= 0.5f; matrix1[14]= 0.5f;
2055 matrix1[3]= 0.f; matrix1[7]= 0.f; matrix1[11]= 0.f; matrix1[15]= 1.f;
2056
2057 Matrix4f matrix2;
2058 glGetFloatv(GL_PROJECTION_MATRIX, matrix2.ptr());
2059
2060 Matrix4f matrix3;
2061 glGetFloatv(GL_MODELVIEW_MATRIX, matrix3.ptr());
2062
2063 //pop both matrices
2064 glPopMatrix();
2065 glMatrixMode(GL_PROJECTION);
2066 glPopMatrix();
2067
2068 glMatrixMode(GL_PROJECTION);
2069 glPushMatrix();
2070
2071 //compute texture matrix
2072 glLoadMatrixf(matrix1.ptr());
2073 glMultMatrixf(matrix2.ptr());
2074 glMultMatrixf(matrix3.ptr());
2075 glGetFloatv(GL_TRANSPOSE_PROJECTION_MATRIX_ARB, shadowMapMatrix.ptr());
2076
2077 //pop
2078 glPopMatrix();
2079
2080 glPopAttrib();
2081
2082 assertGl();
2083 }
2084 }
2085 }
2086
2087
2088 // ==================== gl wrap ====================
2089
getGlInfo()2090 string Renderer::getGlInfo(){
2091 string infoStr;
2092 Lang &lang= Lang::getInstance();
2093
2094 infoStr+= lang.get("OpenGlInfo")+":\n";
2095 infoStr+= " "+lang.get("OpenGlVersion")+": ";
2096 infoStr+= string(getGlVersion())+"\n";
2097 infoStr+= " "+lang.get("OpenGlRenderer")+": ";
2098 infoStr+= string(getGlRenderer())+"\n";
2099 infoStr+= " "+lang.get("OpenGlVendor")+": ";
2100 infoStr+= string(getGlVendor())+"\n";
2101 infoStr+= " "+lang.get("OpenGlMaxLights")+": ";
2102 infoStr+= intToStr(getGlMaxLights())+"\n";
2103 infoStr+= " "+lang.get("OpenGlMaxTextureSize")+": ";
2104 infoStr+= intToStr(getGlMaxTextureSize())+"\n";
2105 infoStr+= " "+lang.get("OpenGlMaxTextureUnits")+": ";
2106 infoStr+= intToStr(getGlMaxTextureUnits())+"\n";
2107 infoStr+= " "+lang.get("OpenGlModelviewStack")+": ";
2108 infoStr+= intToStr(getGlModelviewMatrixStackDepth())+"\n";
2109 infoStr+= " "+lang.get("OpenGlProjectionStack")+": ";
2110 infoStr+= intToStr(getGlProjectionMatrixStackDepth())+"\n";
2111
2112 return infoStr;
2113 }
2114
getGlMoreInfo()2115 string Renderer::getGlMoreInfo(){
2116 string infoStr;
2117 Lang &lang= Lang::getInstance();
2118
2119 //gl extensions
2120 infoStr+= lang.get("OpenGlExtensions")+":\n ";
2121
2122 string extensions= getGlExtensions();
2123 int charCount= 0;
2124 for(int i=0; i<extensions.size(); ++i){
2125 infoStr+= extensions[i];
2126 if(charCount>120 && extensions[i]==' '){
2127 infoStr+= "\n ";
2128 charCount= 0;
2129 }
2130 ++charCount;
2131 }
2132
2133 //platform extensions
2134 infoStr+= "\n\n";
2135 infoStr+= lang.get("OpenGlPlatformExtensions")+":\n ";
2136
2137 charCount= 0;
2138 string platformExtensions= getGlPlatformExtensions();
2139 for(int i=0; i<platformExtensions.size(); ++i){
2140 infoStr+= platformExtensions[i];
2141 if(charCount>120 && platformExtensions[i]==' '){
2142 infoStr+= "\n ";
2143 charCount= 0;
2144 }
2145 ++charCount;
2146 }
2147
2148 return infoStr;
2149 }
2150
autoConfig()2151 void Renderer::autoConfig(){
2152
2153 Config &config= Config::getInstance();
2154 bool nvidiaCard= toLower(getGlVendor()).find("nvidia")!=string::npos;
2155 bool atiCard= toLower(getGlVendor()).find("ati")!=string::npos;
2156 bool shadowExtensions = isGlExtensionSupported("GL_ARB_shadow") && isGlExtensionSupported("GL_ARB_shadow_ambient");
2157
2158 //3D textures
2159 config.setBool("Textures3D", isGlExtensionSupported("GL_EXT_texture3D"));
2160
2161 //shadows
2162 string shadows;
2163 if(getGlMaxTextureUnits()>=3){
2164 if(nvidiaCard && shadowExtensions){
2165 shadows= shadowsToStr(sShadowMapping);
2166 }
2167 else{
2168 shadows= shadowsToStr(sProjected);
2169 }
2170 }
2171 else{
2172 shadows=shadowsToStr(sDisabled);
2173 }
2174 config.setString("Shadows", shadows);
2175
2176 //lights
2177 config.setInt("MaxLights", atiCard? 1: 4);
2178
2179 //filter
2180 config.setString("Filter", "Bilinear");
2181 }
2182
clearBuffers()2183 void Renderer::clearBuffers(){
2184 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2185 }
2186
clearZBuffer()2187 void Renderer::clearZBuffer(){
2188 glClear(GL_DEPTH_BUFFER_BIT);
2189 }
2190
loadConfig()2191 void Renderer::loadConfig(){
2192 Config &config= Config::getInstance();
2193
2194 //cache most used config params
2195 maxLights= config.getInt("MaxLights");
2196 photoMode= config.getBool("PhotoMode");
2197 focusArrows= config.getBool("FocusArrows");
2198 textures3D= config.getBool("Textures3D");
2199
2200 //load shadows
2201 shadows= strToShadows(config.getString("Shadows"));
2202 if(shadows==sProjected || shadows==sShadowMapping){
2203 shadowTextureSize= config.getInt("ShadowTextureSize");
2204 shadowFrameSkip= config.getInt("ShadowFrameSkip");
2205 shadowAlpha= config.getFloat("ShadowAlpha");
2206 }
2207
2208 //load filter settings
2209 Texture2D::Filter textureFilter= strToTextureFilter(config.getString("Filter"));
2210 int maxAnisotropy= config.getInt("FilterMaxAnisotropy");
2211 for(int i=0; i<rsCount; ++i){
2212 textureManager[i]->setFilter(textureFilter);
2213 textureManager[i]->setMaxAnisotropy(maxAnisotropy);
2214 }
2215 }
2216
saveScreen(const string & path)2217 void Renderer::saveScreen(const string &path){
2218
2219 const Metrics &sm= Metrics::getInstance();
2220
2221 Pixmap2D pixmap(sm.getScreenW(), sm.getScreenH(), 3);
2222
2223 glReadPixels(0, 0, pixmap.getW(), pixmap.getH(), GL_RGB, GL_UNSIGNED_BYTE, pixmap.getPixels());
2224 pixmap.saveTga(path);
2225 }
2226
2227 // ==================== PRIVATE ====================
2228
computeSunAngle(float time)2229 float Renderer::computeSunAngle(float time){
2230
2231 float dayTime= TimeFlow::dusk-TimeFlow::dawn;
2232 float fTime= (time-TimeFlow::dawn)/dayTime;
2233 return clamp(fTime*pi, pi/8.f, 7.f*pi/8.f);
2234 }
2235
computeMoonAngle(float time)2236 float Renderer::computeMoonAngle(float time){
2237 float nightTime= 24-(TimeFlow::dusk-TimeFlow::dawn);
2238
2239 if(time<TimeFlow::dawn){
2240 time+= 24.f;
2241 }
2242
2243 float fTime= (time-TimeFlow::dusk)/nightTime;
2244 return clamp((1.0f-fTime)*pi, pi/8.f, 7.f*pi/8.f);
2245 }
2246
computeSunPos(float time)2247 Vec4f Renderer::computeSunPos(float time){
2248 float ang= computeSunAngle(time);
2249 return Vec4f(-cos(ang)*sunDist, sin(ang)*sunDist, 0.f, 0.f);
2250 }
2251
computeMoonPos(float time)2252 Vec4f Renderer::computeMoonPos(float time){
2253 float ang= computeMoonAngle(time);
2254 return Vec4f(-cos(ang)*moonDist, sin(ang)*moonDist, 0.f, 0.f);
2255 }
2256
computeLightColor(float time)2257 Vec3f Renderer::computeLightColor(float time){
2258 const Tileset *tileset= game->getWorld()->getTileset();
2259 Vec3f color;
2260
2261 const float transition= 2;
2262 const float dayStart= TimeFlow::dawn;
2263 const float dayEnd= TimeFlow::dusk-transition;
2264 const float nightStart= TimeFlow::dusk;
2265 const float nightEnd= TimeFlow::dawn-transition;
2266
2267 if(time>dayStart && time<dayEnd){
2268 color= tileset->getSunLightColor();
2269 }
2270 else if(time>nightStart || time<nightEnd){
2271 color= tileset->getMoonLightColor();
2272 }
2273 else if(time>=dayEnd && time<=nightStart){
2274 color= tileset->getSunLightColor().lerp((time-dayEnd)/transition, tileset->getMoonLightColor());
2275 }
2276 else if(time>=nightEnd && time<=dayStart){
2277 color= tileset->getMoonLightColor().lerp((time-nightEnd)/transition, tileset->getSunLightColor());
2278 }
2279 else{
2280 assert(false);
2281 color= tileset->getSunLightColor();
2282 }
2283 return color;
2284 }
2285
computeWaterColor(float waterLevel,float cellHeight)2286 Vec4f Renderer::computeWaterColor(float waterLevel, float cellHeight){
2287 const float waterFactor= 1.5f;
2288 return Vec4f(1.f, 1.f, 1.f, clamp((waterLevel-cellHeight)*waterFactor, 0.f, 1.f));
2289 }
2290
2291 // ==================== fast render ====================
2292
2293 //render units for selection purposes
renderUnitsFast()2294 void Renderer::renderUnitsFast(){
2295 const World *world= game->getWorld();
2296
2297 assertGl();
2298
2299 glPushAttrib(GL_ENABLE_BIT);
2300 glDisable(GL_TEXTURE_2D);
2301 glDisable(GL_LIGHTING);
2302
2303 modelRenderer->begin(false, false, false);
2304 glInitNames();
2305 for(int i=0; i<world->getFactionCount(); ++i){
2306 glPushName(i);
2307 for(int j=0; j<world->getFaction(i)->getUnitCount(); ++j){
2308 glPushName(j);
2309 Unit *unit= world->getFaction(i)->getUnit(j);
2310 if(world->toRenderUnit(unit, visibleQuad)) {
2311 glMatrixMode(GL_MODELVIEW);
2312
2313 //debuxar modelo
2314 glPushMatrix();
2315
2316 //translate
2317 Vec3f currVec= unit->getCurrVectorFlat();
2318 glTranslatef(currVec.x, currVec.y, currVec.z);
2319
2320 //rotate
2321 glRotatef(unit->getRotation(), 0.f, 1.f, 0.f);
2322
2323 //render
2324 const Model *model= unit->getCurrentModel();
2325 model->updateInterpolationVertices(unit->getAnimProgress(), unit->isAlive());
2326 modelRenderer->render(model);
2327
2328 glPopMatrix();
2329
2330 }
2331 glPopName();
2332 }
2333 glPopName();
2334 }
2335 modelRenderer->end();
2336
2337 glPopAttrib();
2338 }
2339
2340 //render objects for selection purposes
renderObjectsFast()2341 void Renderer::renderObjectsFast(){
2342 const World *world= game->getWorld();
2343 const Map *map= world->getMap();
2344
2345 assertGl();
2346
2347 glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT);
2348 glDisable(GL_LIGHTING);
2349
2350 glAlphaFunc(GL_GREATER, 0.5f);
2351
2352 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
2353
2354 //set color to the texture alpha
2355 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
2356 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
2357 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
2358
2359 //set alpha to the texture alpha
2360 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
2361 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
2362 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
2363
2364 modelRenderer->begin(false, true, false);
2365 int thisTeamIndex= world->getThisTeamIndex();
2366
2367 PosQuadIterator pqi(map, visibleQuad, Map::cellScale);
2368 while(pqi.next()){
2369 const Vec2i pos= pqi.getPos();
2370
2371 if(map->isInside(pos)){
2372
2373 SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(pos));
2374 Object *o= sc->getObject();
2375 if(sc->isExplored(thisTeamIndex) && o!=NULL){
2376
2377 const Model *objModel= sc->getObject()->getModel();
2378 Vec3f v= o->getPos();
2379
2380 glMatrixMode(GL_MODELVIEW);
2381 glPushMatrix();
2382 glTranslatef(v.x, v.y, v.z);
2383 glRotatef(o->getRotation(), 0.f, 1.f, 0.f);
2384
2385 modelRenderer->render(objModel);
2386
2387 glPopMatrix();
2388
2389 }
2390 }
2391 }
2392
2393 modelRenderer->end();
2394
2395 glPopAttrib();
2396
2397 assertGl();
2398 }
2399
2400 // ==================== gl caps ====================
2401
checkGlCaps()2402 void Renderer::checkGlCaps(){
2403
2404 //opengl 1.3
2405 if(!isGlVersionSupported(1, 3, 0)){
2406 string message;
2407
2408 message += "Your system supports OpenGL version \"";
2409 message += getGlVersion() + string("\"\n");
2410 message += "Glest needs at least version 1.3 to work\n";
2411 message += "You may solve this problem by installing your latest video card drivers";
2412
2413 throw runtime_error(message.c_str());
2414 }
2415
2416 //opengl 1.4 or extension
2417 if(!isGlVersionSupported(1, 4, 0)){
2418 checkExtension("GL_ARB_texture_env_crossbar", "Glest");
2419 }
2420 }
2421
checkGlOptionalCaps()2422 void Renderer::checkGlOptionalCaps(){
2423
2424 //shadows
2425 if(shadows==sProjected || shadows==sShadowMapping){
2426 if(getGlMaxTextureUnits()<3){
2427 throw runtime_error("Your system doesn't support 3 texture units, required for shadows");
2428 }
2429 }
2430
2431 //shadow mapping
2432 if(shadows==sShadowMapping){
2433 checkExtension("GL_ARB_shadow", "Shadow Mapping");
2434 checkExtension("GL_ARB_shadow_ambient", "Shadow Mapping");
2435 }
2436 }
2437
checkExtension(const string & extension,const string & msg)2438 void Renderer::checkExtension(const string &extension, const string &msg){
2439 if(!isGlExtensionSupported(extension.c_str())){
2440 string str= "OpenGL extension not supported: " + extension + ", required for " + msg;
2441 throw runtime_error(str);
2442 }
2443 }
2444
2445 // ==================== init 3d lists ====================
2446
init3dList()2447 void Renderer::init3dList(){
2448
2449 const Metrics &metrics= Metrics::getInstance();
2450
2451 assertGl();
2452
2453 list3d= glGenLists(1);
2454 glNewList(list3d, GL_COMPILE_AND_EXECUTE);
2455 //need to execute, because if not gluPerspective takes no effect and gluLoadMatrix is wrong
2456
2457 //misc
2458 glViewport(0, 0, metrics.getScreenW(), metrics.getScreenH());
2459 glClearColor(fowColor.x, fowColor.y, fowColor.z, fowColor.w);
2460 glFrontFace(GL_CW);
2461 glEnable(GL_CULL_FACE);
2462 loadProjectionMatrix();
2463
2464 //texture state
2465 glActiveTexture(shadowTexUnit);
2466 glDisable(GL_TEXTURE_2D);
2467 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2468
2469 glActiveTexture(fowTexUnit);
2470 glDisable(GL_TEXTURE_2D);
2471 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2472
2473 glActiveTexture(baseTexUnit);
2474 glEnable(GL_TEXTURE_2D);
2475 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2476
2477 //material state
2478 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, defSpecularColor.ptr());
2479 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, defAmbientColor.ptr());
2480 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, defDiffuseColor.ptr());
2481 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
2482 glColor4fv(defColor.ptr());
2483
2484 //blend state
2485 glDisable(GL_BLEND);
2486 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2487
2488 //alpha test state
2489 glEnable(GL_ALPHA_TEST);
2490 glAlphaFunc(GL_GREATER, 0.f);
2491
2492 //depth test state
2493 glEnable(GL_DEPTH_TEST);
2494 glDepthMask(GL_TRUE);
2495 glDepthFunc(GL_LESS);
2496
2497 //lighting state
2498 glEnable(GL_LIGHTING);
2499 glEnable(GL_LIGHT0);
2500
2501 //matrix mode
2502 glMatrixMode(GL_MODELVIEW);
2503
2504 //stencil test
2505 glDisable(GL_STENCIL_TEST);
2506
2507 //fog
2508 const Tileset *tileset= game->getWorld()->getTileset();
2509 if(tileset->getFog()){
2510 glEnable(GL_FOG);
2511 if(tileset->getFogMode()==fmExp){
2512 glFogi(GL_FOG_MODE, GL_EXP);
2513 }
2514 else{
2515 glFogi(GL_FOG_MODE, GL_EXP2);
2516 }
2517
2518 glFogf(GL_FOG_DENSITY, tileset->getFogDensity());
2519 glFogfv(GL_FOG_COLOR, tileset->getFogColor().ptr());
2520 }
2521
2522 glEndList();
2523
2524 //assert
2525 assertGl();
2526
2527 }
2528
init2dList()2529 void Renderer::init2dList(){
2530
2531 const Metrics &metrics= Metrics::getInstance();
2532
2533 //this list sets the state for the 2d rendering
2534 list2d= glGenLists(1);
2535 glNewList(list2d, GL_COMPILE);
2536
2537 //projection
2538 glViewport(0, 0, metrics.getScreenW(), metrics.getScreenH());
2539 glMatrixMode(GL_PROJECTION);
2540 glLoadIdentity();
2541 glOrtho(0, metrics.getVirtualW(), 0, metrics.getVirtualH(), 0, 1);
2542
2543 //modelview
2544 glMatrixMode(GL_MODELVIEW);
2545 glLoadIdentity();
2546
2547 //disable everything
2548 glDisable(GL_BLEND);
2549 glDisable(GL_LIGHTING);
2550 glDisable(GL_ALPHA_TEST);
2551 glDisable(GL_DEPTH_TEST);
2552 glDisable(GL_STENCIL_TEST);
2553 glDisable(GL_FOG);
2554 glDisable(GL_CULL_FACE);
2555 glFrontFace(GL_CCW);
2556 glActiveTexture(baseTexUnit);
2557 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2558 glDisable(GL_TEXTURE_2D);
2559
2560 //blend func
2561 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2562
2563 //color
2564 glColor4f(1.f, 1.f, 1.f, 1.f);
2565
2566 glEndList();
2567
2568 assertGl();
2569 }
2570
init3dListMenu(MainMenu * mm)2571 void Renderer::init3dListMenu(MainMenu *mm){
2572 assertGl();
2573
2574 const Metrics &metrics= Metrics::getInstance();
2575 const MenuBackground *mb= mm->getMenuBackground();
2576
2577 list3dMenu= glGenLists(1);
2578 glNewList(list3dMenu, GL_COMPILE);
2579
2580 //misc
2581 glViewport(0, 0, metrics.getScreenW(), metrics.getScreenH());
2582 glClearColor(0.4f, 0.4f, 0.4f, 1.f);
2583 glFrontFace(GL_CW);
2584 glEnable(GL_CULL_FACE);
2585 glMatrixMode(GL_PROJECTION);
2586 glLoadIdentity();
2587 gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, 1000);
2588
2589 //texture state
2590 glEnable(GL_TEXTURE_2D);
2591 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2592
2593 //material state
2594 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, defSpecularColor.ptr());
2595 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, defAmbientColor.ptr());
2596 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, defDiffuseColor.ptr());
2597 glColor4fv(defColor.ptr());
2598 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
2599
2600 //blend state
2601 glDisable(GL_BLEND);
2602 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2603
2604 //alpha test state
2605 glEnable(GL_ALPHA_TEST);
2606 glAlphaFunc(GL_GREATER, 0.f);
2607
2608 //depth test state
2609 glEnable(GL_DEPTH_TEST);
2610 glDepthMask(GL_TRUE);
2611 glDepthFunc(GL_LESS);
2612
2613 //lighting state
2614 glEnable(GL_LIGHTING);
2615
2616 //matrix mode
2617 glMatrixMode(GL_MODELVIEW);
2618
2619 //stencil test
2620 glDisable(GL_STENCIL_TEST);
2621
2622 //fog
2623 if(mb->getFog()){
2624 glEnable(GL_FOG);
2625 glFogi(GL_FOG_MODE, GL_EXP2);
2626 glFogf(GL_FOG_DENSITY, mb->getFogDensity());
2627 }
2628
2629 glEndList();
2630
2631 //assert
2632 assertGl();
2633 }
2634
2635
2636 // ==================== misc ====================
2637
loadProjectionMatrix()2638 void Renderer::loadProjectionMatrix(){
2639 GLdouble clipping;
2640 const Metrics &metrics= Metrics::getInstance();
2641
2642 assertGl();
2643
2644 clipping= photoMode ? perspFarPlane*100 : perspFarPlane;
2645
2646 glMatrixMode(GL_PROJECTION);
2647 glLoadIdentity();
2648 gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, clipping);
2649
2650 assertGl();
2651 }
2652
enableProjectiveTexturing()2653 void Renderer::enableProjectiveTexturing(){
2654 glTexGenfv(GL_S, GL_EYE_PLANE, &shadowMapMatrix[0]);
2655 glTexGenfv(GL_T, GL_EYE_PLANE, &shadowMapMatrix[4]);
2656 glTexGenfv(GL_R, GL_EYE_PLANE, &shadowMapMatrix[8]);
2657 glTexGenfv(GL_Q, GL_EYE_PLANE, &shadowMapMatrix[12]);
2658 glEnable(GL_TEXTURE_GEN_S);
2659 glEnable(GL_TEXTURE_GEN_T);
2660 glEnable(GL_TEXTURE_GEN_R);
2661 glEnable(GL_TEXTURE_GEN_Q);
2662 }
2663
2664 // ==================== private aux drawing ====================
2665
renderSelectionCircle(Vec3f v,int size,float radius)2666 void Renderer::renderSelectionCircle(Vec3f v, int size, float radius){
2667 GLUquadricObj *disc;
2668
2669 glMatrixMode(GL_MODELVIEW);
2670 glPushMatrix();
2671
2672 glTranslatef(v.x, v.y, v.z);
2673 glRotatef(90.f, 1.f, 0.f, 0.f);
2674 disc= gluNewQuadric();
2675 gluQuadricDrawStyle(disc, GLU_FILL);
2676 gluCylinder(disc, radius*(size-0.2f), radius*size, 0.2f, 30, 1);
2677 gluDeleteQuadric(disc);
2678
2679 glPopMatrix();
2680 }
2681
renderArrow(const Vec3f & pos1,const Vec3f & pos2,const Vec3f & color,float width)2682 void Renderer::renderArrow(const Vec3f &pos1, const Vec3f &pos2, const Vec3f &color, float width){
2683 const int tesselation= 3;
2684 const float arrowEndSize= 0.4f;
2685 const float maxlen= 25;
2686 const float blendDelay= 5.f;
2687
2688 Vec3f dir= Vec3f(pos2-pos1);
2689 float len= dir.length();
2690
2691 if(len>maxlen){
2692 return;
2693 }
2694 float alphaFactor= clamp((maxlen-len)/blendDelay, 0.f, 1.f);
2695
2696 dir.normalize();
2697 Vec3f normal= dir.cross(Vec3f(0, 1, 0));
2698
2699 Vec3f pos2Left= pos2 + normal*(width-0.05f) - dir*arrowEndSize*width;
2700 Vec3f pos2Right= pos2 - normal*(width-0.05f) - dir*arrowEndSize*width;
2701 Vec3f pos1Left= pos1 + normal*(width+0.05f);
2702 Vec3f pos1Right= pos1 - normal*(width+0.05f);
2703
2704 //arrow body
2705 glBegin(GL_TRIANGLE_STRIP);
2706 for(int i=0; i<=tesselation; ++i){
2707 float t= static_cast<float>(i)/tesselation;
2708 Vec3f a= pos1Left.lerp(t, pos2Left);
2709 Vec3f b= pos1Right.lerp(t, pos2Right);
2710 Vec4f c= Vec4f(color, t*0.25f*alphaFactor);
2711
2712 glColor4fv(c.ptr());
2713 glVertex3fv(a.ptr());
2714 glVertex3fv(b.ptr());
2715 }
2716 glEnd();
2717
2718 //arrow end
2719 glBegin(GL_TRIANGLES);
2720 glVertex3fv((pos2Left + normal*(arrowEndSize-0.1f)).ptr());
2721 glVertex3fv((pos2Right - normal*(arrowEndSize-0.1f)).ptr());
2722 glVertex3fv((pos2 + dir*(arrowEndSize-0.1f)).ptr());
2723 glEnd();
2724 }
2725
renderProgressBar(int size,int x,int y,Font2D * font)2726 void Renderer::renderProgressBar(int size, int x, int y, Font2D *font){
2727
2728 //bar
2729 glBegin(GL_QUADS);
2730 glColor4fv(progressBarFront2.ptr());
2731 glVertex2i(x, y);
2732 glVertex2i(x, y+10);
2733 glColor4fv(progressBarFront1.ptr());
2734 glVertex2i(x+size, y+10);
2735 glVertex2i(x+size, y);
2736 glEnd();
2737
2738 //transp bar
2739 glEnable(GL_BLEND);
2740 glBegin(GL_QUADS);
2741 glColor4fv(progressBarBack2.ptr());
2742 glVertex2i(x+size, y);
2743 glVertex2i(x+size, y+10);
2744 glColor4fv(progressBarBack1.ptr());
2745 glVertex2i(x+maxProgressBar, y+10);
2746 glVertex2i(x+maxProgressBar, y);
2747 glEnd();
2748 glDisable(GL_BLEND);
2749
2750 //text
2751 glColor3fv(defColor.ptr());
2752 textRenderer->begin(font);
2753 textRenderer->render(intToStr(static_cast<int>(size))+"%", x+maxProgressBar/2, y, true);
2754 textRenderer->end();
2755 }
2756
2757
renderTile(const Vec2i & pos)2758 void Renderer::renderTile(const Vec2i &pos){
2759
2760 const Map *map= game->getWorld()->getMap();
2761 Vec2i scaledPos= pos * Map::cellScale;
2762
2763 glMatrixMode(GL_MODELVIEW);
2764 glPushMatrix();
2765 glTranslatef(-0.5f, 0.f, -0.5f);
2766
2767 glInitNames();
2768 for(int i=0; i<Map::cellScale; ++i){
2769 for(int j=0; j<Map::cellScale; ++j){
2770
2771 Vec2i renderPos= scaledPos + Vec2i(i, j);
2772
2773 glPushName(renderPos.y);
2774 glPushName(renderPos.x);
2775
2776 glDisable(GL_CULL_FACE);
2777
2778 glBegin(GL_TRIANGLE_STRIP);
2779 glVertex3f(
2780 static_cast<float>(renderPos.x),
2781 map->getCell(renderPos.x, renderPos.y)->getHeight(),
2782 static_cast<float>(renderPos.y));
2783 glVertex3f(
2784 static_cast<float>(renderPos.x),
2785 map->getCell(renderPos.x, renderPos.y+1)->getHeight(),
2786 static_cast<float>(renderPos.y+1));
2787 glVertex3f(
2788 static_cast<float>(renderPos.x+1),
2789 map->getCell(renderPos.x+1, renderPos.y)->getHeight(),
2790 static_cast<float>(renderPos.y));
2791 glVertex3f(
2792 static_cast<float>(renderPos.x+1),
2793 map->getCell(renderPos.x+1, renderPos.y+1)->getHeight(),
2794 static_cast<float>(renderPos.y+1));
2795 glEnd();
2796
2797 glPopName();
2798 glPopName();
2799 }
2800 }
2801
2802 glPopMatrix();
2803 }
2804
renderQuad(int x,int y,int w,int h,const Texture2D * texture)2805 void Renderer::renderQuad(int x, int y, int w, int h, const Texture2D *texture){
2806 glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(texture)->getHandle());
2807 glBegin(GL_TRIANGLE_STRIP);
2808 glTexCoord2i(0, 1);
2809 glVertex2i(x, y+h);
2810 glTexCoord2i(0, 0);
2811 glVertex2i(x, y);
2812 glTexCoord2i(1, 1);
2813 glVertex2i(x+w, y+h);
2814 glTexCoord2i(1, 0);
2815 glVertex2i(x+w, y);
2816 glEnd();
2817 }
2818
strToShadows(const string & s)2819 Renderer::Shadows Renderer::strToShadows(const string &s){
2820 if(s=="Projected"){
2821 return sProjected;
2822 }
2823 else if(s=="ShadowMapping"){
2824 return sShadowMapping;
2825 }
2826 return sDisabled;
2827 }
2828
shadowsToStr(Shadows shadows)2829 string Renderer::shadowsToStr(Shadows shadows){
2830 switch(shadows){
2831 case sDisabled:
2832 return "Disabled";
2833 case sProjected:
2834 return "Projected";
2835 case sShadowMapping:
2836 return "ShadowMapping";
2837 default:
2838 assert(false);
2839 return "";
2840 }
2841 }
2842
strToTextureFilter(const string & s)2843 Texture2D::Filter Renderer::strToTextureFilter(const string &s){
2844 if(s=="Bilinear"){
2845 return Texture2D::fBilinear;
2846 }
2847 else if(s=="Trilinear"){
2848 return Texture2D::fTrilinear;
2849 }
2850
2851 throw runtime_error("Error converting from string to FilterType, found: "+s);
2852 }
2853
2854 }}//end namespace
2855