mirror of https://github.com/skeeto/pixelcity.git
842 lines
24 KiB
C++
842 lines
24 KiB
C++
/*-----------------------------------------------------------------------------
|
|
|
|
Render.cpp
|
|
|
|
2009 Shamus Young
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
This is the core of the gl rendering functions. This contains the main
|
|
rendering function RenderUpdate (), which initiates the various
|
|
other renders in the other modules.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
#define RENDER_DISTANCE 1280
|
|
#define MAX_TEXT 256
|
|
#define YOUFAIL(message) {WinPopup (message);return;}
|
|
#define HELP_SIZE sizeof(help)
|
|
#define COLOR_CYCLE_TIME 10000 //milliseconds
|
|
#define COLOR_CYCLE (COLOR_CYCLE_TIME / 4)
|
|
#define FONT_COUNT (sizeof (fonts) / sizeof (struct glFont))
|
|
#define FONT_SIZE (LOGO_PIXELS - LOGO_PIXELS / 8)
|
|
#define BLOOM_SCALING 0.07f
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <stdarg.h>
|
|
#include <math.h>
|
|
|
|
#include <gl\gl.h>
|
|
#include <gl\glu.h>
|
|
|
|
#include "gltypes.h"
|
|
#include "entity.h"
|
|
#include "car.h"
|
|
#include "camera.h"
|
|
#include "ini.h"
|
|
#include "light.h"
|
|
#include "macro.h"
|
|
#include "math.h"
|
|
#include "render.h"
|
|
#include "sky.h"
|
|
#include "texture.h"
|
|
#include "world.h"
|
|
#include "win.h"
|
|
|
|
static PIXELFORMATDESCRIPTOR pfd =
|
|
{
|
|
sizeof(PIXELFORMATDESCRIPTOR),
|
|
1, // Version Number
|
|
PFD_DRAW_TO_WINDOW | // Format Must Support Window
|
|
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
|
|
PFD_DOUBLEBUFFER, // Must Support Double Buffering
|
|
PFD_TYPE_RGBA, // Request An RGBA Format
|
|
32, // Select Our glRgbaDepth
|
|
0, 0, 0, 0, 0, 0, // glRgbaBits Ignored
|
|
0, // No Alpha Buffer
|
|
0, // Shift Bit Ignored
|
|
0, // Accumulation Buffers
|
|
0, 0, 0, 0, // Accumulation Bits Ignored
|
|
16, // Z-Buffer (Depth Buffer) bits
|
|
0, // Stencil Buffers
|
|
1, // Auxiliary Buffers
|
|
PFD_MAIN_PLANE, // Main Drawing Layer
|
|
0, // Reserved
|
|
0, 0, 0 // Layer Masks Ignored
|
|
};
|
|
|
|
static char help[] =
|
|
"ESC - Exit!\n"
|
|
"F1 - Show this help screen\n"
|
|
"R - Rebuild city\n"
|
|
"L - Toggle 'letterbox' mode\n"
|
|
"F - Show Framecounter\n"
|
|
"W - Toggle Wireframe\n"
|
|
"E - Change full-scene effects\n"
|
|
"T - Toggle Textures\n"
|
|
"G - Toggle Fog\n"
|
|
;
|
|
|
|
struct glFont
|
|
{
|
|
char* name;
|
|
unsigned base_char;
|
|
} fonts[] =
|
|
{
|
|
"Courier New", 0,
|
|
"Arial", 0,
|
|
"Times New Roman", 0,
|
|
"Arial Black", 0,
|
|
"Impact", 0,
|
|
"Agency FB", 0,
|
|
"Book Antiqua", 0,
|
|
};
|
|
|
|
#if SCREENSAVER
|
|
enum
|
|
{
|
|
EFFECT_NONE,
|
|
EFFECT_BLOOM,
|
|
EFFECT_BLOOM_RADIAL,
|
|
EFFECT_COLOR_CYCLE,
|
|
EFFECT_GLASS_CITY,
|
|
EFFECT_COUNT,
|
|
EFFECT_DEBUG,
|
|
EFFECT_DEBUG_OVERBLOOM,
|
|
};
|
|
#else
|
|
enum
|
|
{
|
|
EFFECT_NONE,
|
|
EFFECT_BLOOM,
|
|
EFFECT_COUNT,
|
|
EFFECT_DEBUG_OVERBLOOM,
|
|
EFFECT_DEBUG,
|
|
EFFECT_BLOOM_RADIAL,
|
|
EFFECT_COLOR_CYCLE,
|
|
EFFECT_GLASS_CITY,
|
|
};
|
|
#endif
|
|
|
|
static HDC hDC;
|
|
static HGLRC hRC;
|
|
static float render_aspect;
|
|
static float fog_distance;
|
|
static int render_width;
|
|
static int render_height;
|
|
static bool letterbox;
|
|
static int letterbox_offset;
|
|
static int effect;
|
|
static unsigned next_fps;
|
|
static unsigned current_fps;
|
|
static unsigned frames;
|
|
static bool show_wireframe;
|
|
static bool flat;
|
|
static bool show_fps;
|
|
static bool show_fog;
|
|
static bool show_help;
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
Draw a clock-ish progress.. widget... thing. It's cute.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
static void do_progress (float center_x, float center_y, float radius, float opacity, float progress)
|
|
{
|
|
|
|
int i;
|
|
int end_angle;
|
|
float inner, outer;
|
|
float angle;
|
|
float s, c;
|
|
float gap;
|
|
|
|
//Outer Ring
|
|
gap = radius * 0.05f;
|
|
outer = radius;
|
|
inner = radius - gap * 2;
|
|
glColor4f (1,1,1, opacity);
|
|
glBegin (GL_QUAD_STRIP);
|
|
for (i = 0; i <= 360; i+= 15) {
|
|
angle = (float)i * DEGREES_TO_RADIANS;
|
|
s = sinf (angle);
|
|
c = -cosf (angle);
|
|
glVertex2f (center_x + s * outer, center_y + c * outer);
|
|
glVertex2f (center_x + s * inner, center_y + c * inner);
|
|
}
|
|
glEnd ();
|
|
//Progress indicator
|
|
glColor4f (1,1,1, opacity);
|
|
end_angle = (int)(360 * progress);
|
|
outer = radius - gap * 3;
|
|
glBegin (GL_TRIANGLE_FAN);
|
|
glVertex2f (center_x, center_y);
|
|
for (i = 0; i <= end_angle; i+= 3) {
|
|
angle = (float)i * DEGREES_TO_RADIANS;
|
|
s = sinf (angle);
|
|
c = -cosf (angle);
|
|
glVertex2f (center_x + s * outer, center_y + c * outer);
|
|
}
|
|
glEnd ();
|
|
//Tic lines
|
|
glLineWidth (2.0f);
|
|
outer = radius - gap * 1;
|
|
inner = radius - gap * 2;
|
|
glColor4f (0,0,0, opacity);
|
|
glBegin (GL_LINES);
|
|
for (i = 0; i <= 360; i+= 15) {
|
|
angle = (float)i * DEGREES_TO_RADIANS;
|
|
s = sinf (angle);
|
|
c = -cosf (angle);
|
|
glVertex2f (center_x + s * outer, center_y + c * outer);
|
|
glVertex2f (center_x + s * inner, center_y + c * inner);
|
|
}
|
|
glEnd ();
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
static void do_effects (int type)
|
|
{
|
|
|
|
float hue1, hue2, hue3, hue4;
|
|
GLrgba color;
|
|
float fade;
|
|
int radius;
|
|
int x, y;
|
|
int i;
|
|
int bloom_radius;
|
|
int bloom_step;
|
|
|
|
fade = WorldFade ();
|
|
bloom_radius = 15;
|
|
bloom_step = bloom_radius / 3;
|
|
if (!TextureReady ())
|
|
return;
|
|
//Now change projection modes so we can render full-screen effects
|
|
glDisable(GL_DEPTH_TEST);
|
|
glMatrixMode (GL_PROJECTION);
|
|
glPushMatrix ();
|
|
glLoadIdentity ();
|
|
glOrtho (0, render_width, render_height, 0, 0.1f, 2048);
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glPushMatrix ();
|
|
glLoadIdentity();
|
|
glTranslatef(0, 0, -1.0f);
|
|
glDisable (GL_CULL_FACE);
|
|
glDisable (GL_FOG);
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
//Render full-screen effects
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
glEnable (GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_BLOOM));
|
|
switch (type) {
|
|
case EFFECT_DEBUG:
|
|
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_LOGOS));
|
|
glDisable (GL_BLEND);
|
|
glBegin (GL_QUADS);
|
|
glColor3f (1, 1, 1);
|
|
glTexCoord2f (0, 0); glVertex2i (0, render_height / 4);
|
|
glTexCoord2f (0, 1); glVertex2i (0, 0);
|
|
glTexCoord2f (1, 1); glVertex2i (render_width / 4, 0);
|
|
glTexCoord2f (1, 0); glVertex2i (render_width / 4, render_height / 4);
|
|
|
|
glTexCoord2f (0, 0); glVertex2i (0, 512);
|
|
glTexCoord2f (0, 1); glVertex2i (0, 0);
|
|
glTexCoord2f (1, 1); glVertex2i (512, 0);
|
|
glTexCoord2f (1, 0); glVertex2i (512, 512);
|
|
glEnd ();
|
|
break;
|
|
case EFFECT_BLOOM_RADIAL:
|
|
//Psychedelic bloom
|
|
glEnable (GL_BLEND);
|
|
glBegin (GL_QUADS);
|
|
color = WorldBloomColor () * BLOOM_SCALING * 2;
|
|
glColor3fv (&color.red);
|
|
for (i = 0; i <= 100; i+=10) {
|
|
glTexCoord2f (0, 0); glVertex2i (-i, i + render_height);
|
|
glTexCoord2f (0, 1); glVertex2i (-i, -i);
|
|
glTexCoord2f (1, 1); glVertex2i (i + render_width, -i);
|
|
glTexCoord2f (1, 0); glVertex2i (i + render_width, i + render_height);
|
|
}
|
|
glEnd ();
|
|
break;
|
|
case EFFECT_COLOR_CYCLE:
|
|
//Oooh. Pretty colors. Tint the scene according to screenspace.
|
|
hue1 = (float)(GetTickCount () % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME;
|
|
hue2 = (float)((GetTickCount () + COLOR_CYCLE) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME;
|
|
hue3 = (float)((GetTickCount () + COLOR_CYCLE * 2) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME;
|
|
hue4 = (float)((GetTickCount () + COLOR_CYCLE * 3) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME;
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
glBlendFunc (GL_DST_COLOR, GL_SRC_COLOR);
|
|
glBegin (GL_QUADS);
|
|
color = glRgbaFromHsl (hue1, 1.0f, 0.6f);
|
|
glColor3fv (&color.red);
|
|
glTexCoord2f (0, 0); glVertex2i (0, render_height);
|
|
color = glRgbaFromHsl (hue2, 1.0f, 0.6f);
|
|
glColor3fv (&color.red);
|
|
glTexCoord2f (0, 1); glVertex2i (0, 0);
|
|
color = glRgbaFromHsl (hue3, 1.0f, 0.6f);
|
|
glColor3fv (&color.red);
|
|
glTexCoord2f (1, 1); glVertex2i (render_width, 0);
|
|
color = glRgbaFromHsl (hue4, 1.0f, 0.6f);
|
|
glColor3fv (&color.red);
|
|
glTexCoord2f (1, 0); glVertex2i (render_width, render_height);
|
|
glEnd ();
|
|
break;
|
|
case EFFECT_BLOOM:
|
|
//Simple bloom effect
|
|
glBegin (GL_QUADS);
|
|
color = WorldBloomColor () * BLOOM_SCALING;
|
|
glColor3fv (&color.red);
|
|
for (x = -bloom_radius; x <= bloom_radius; x += bloom_step) {
|
|
for (y = -bloom_radius; y <= bloom_radius; y += bloom_step) {
|
|
if (abs (x) == abs (y) && x)
|
|
continue;
|
|
glTexCoord2f (0, 0); glVertex2i (x, y + render_height);
|
|
glTexCoord2f (0, 1); glVertex2i (x, y);
|
|
glTexCoord2f (1, 1); glVertex2i (x + render_width, y);
|
|
glTexCoord2f (1, 0); glVertex2i (x + render_width, y + render_height);
|
|
}
|
|
}
|
|
glEnd ();
|
|
break;
|
|
case EFFECT_DEBUG_OVERBLOOM:
|
|
//This will punish that uppity GPU. Good for testing low frame rate behavior.
|
|
glBegin (GL_QUADS);
|
|
color = WorldBloomColor () * 0.01f;
|
|
glColor3fv (&color.red);
|
|
for (x = -50; x <= 50; x+=5) {
|
|
for (y = -50; y <= 50; y+=5) {
|
|
glTexCoord2f (0, 0); glVertex2i (x, y + render_height);
|
|
glTexCoord2f (0, 1); glVertex2i (x, y);
|
|
glTexCoord2f (1, 1); glVertex2i (x + render_width, y);
|
|
glTexCoord2f (1, 0); glVertex2i (x + render_width, y + render_height);
|
|
}
|
|
}
|
|
glEnd ();
|
|
break;
|
|
}
|
|
//Do the fade to / from darkness used to hide scene transitions
|
|
if (LOADING_SCREEN) {
|
|
if (fade > 0.0f) {
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable (GL_BLEND);
|
|
glDisable (GL_TEXTURE_2D);
|
|
glColor4f (0, 0, 0, fade);
|
|
glBegin (GL_QUADS);
|
|
glVertex2i (0, 0);
|
|
glVertex2i (0, render_height);
|
|
glVertex2i (render_width, render_height);
|
|
glVertex2i (render_width, 0);
|
|
glEnd ();
|
|
}
|
|
if (TextureReady () && !EntityReady () && fade != 0.0f) {
|
|
radius = render_width / 16;
|
|
do_progress ((float)render_width / 2, (float)render_height / 2, (float)radius, fade, EntityProgress ());
|
|
RenderPrint (render_width / 2 - LOGO_PIXELS, render_height / 2 + LOGO_PIXELS, 0, glRgba (0.5f), "%1.2f%%", EntityProgress () * 100.0f);
|
|
RenderPrint (1, "%s v%d.%d.%03d", APP_TITLE, VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
|
}
|
|
}
|
|
glPopMatrix ();
|
|
glMatrixMode (GL_PROJECTION);
|
|
glPopMatrix ();
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
int RenderMaxTextureSize ()
|
|
{
|
|
|
|
int mts;
|
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mts);
|
|
mts = MIN (mts, render_width);
|
|
return MIN (mts, render_height);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderPrint (int x, int y, int font, GLrgba color, const char *fmt, ...)
|
|
{
|
|
|
|
char text[MAX_TEXT];
|
|
va_list ap;
|
|
|
|
text[0] = 0;
|
|
if (fmt == NULL)
|
|
return;
|
|
va_start(ap, fmt);
|
|
vsprintf(text, fmt, ap);
|
|
va_end(ap);
|
|
glPushAttrib(GL_LIST_BIT);
|
|
glListBase(fonts[font % FONT_COUNT].base_char - 32);
|
|
glColor3fv (&color.red);
|
|
glRasterPos2i (x, y);
|
|
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderPrint (int line, const char *fmt, ...)
|
|
{
|
|
|
|
char text[MAX_TEXT];
|
|
va_list ap;
|
|
|
|
text[0] = 0;
|
|
if (fmt == NULL)
|
|
return;
|
|
va_start (ap, fmt);
|
|
vsprintf (text, fmt, ap);
|
|
va_end (ap);
|
|
glDepthMask (false);
|
|
glMatrixMode (GL_PROJECTION);
|
|
glPushMatrix ();
|
|
glLoadIdentity ();
|
|
glOrtho (0, render_width, render_height, 0, 0.1f, 2048);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glPushMatrix ();
|
|
glLoadIdentity();
|
|
glTranslatef(0, 0, -1.0f);
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable (GL_DEPTH_TEST);
|
|
RenderPrint (0, line * FONT_SIZE - 2, 0, glRgba (0.0f), text);
|
|
RenderPrint (4, line * FONT_SIZE + 2, 0, glRgba (0.0f), text);
|
|
RenderPrint (2, line * FONT_SIZE, 0, glRgba (1.0f), text);
|
|
glPopAttrib();
|
|
glPopMatrix ();
|
|
glMatrixMode (GL_PROJECTION);
|
|
glPopMatrix ();
|
|
glMatrixMode (GL_MODELVIEW);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void static do_help (void)
|
|
{
|
|
|
|
char* text;
|
|
int line;
|
|
char parse[HELP_SIZE];
|
|
int x;
|
|
|
|
strcpy (parse, help);
|
|
line = 0;
|
|
text = strtok (parse, "\n");
|
|
x = 10;
|
|
while (text) {
|
|
RenderPrint (line + 2, text);
|
|
text = strtok (NULL, "\n");
|
|
line++;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void do_fps ()
|
|
{
|
|
|
|
LIMIT_INTERVAL (1000);
|
|
current_fps = frames;
|
|
frames = 0;
|
|
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderResize (void)
|
|
{
|
|
|
|
float fovy;
|
|
|
|
render_width = WinWidth ();
|
|
render_height = WinHeight ();
|
|
if (letterbox) {
|
|
letterbox_offset = render_height / 6;
|
|
render_height = render_height - letterbox_offset * 2;
|
|
} else
|
|
letterbox_offset = 0;
|
|
//render_aspect = (float)render_height / (float)render_width;
|
|
glViewport (0, letterbox_offset, render_width, render_height);
|
|
glMatrixMode (GL_PROJECTION);
|
|
glLoadIdentity ();
|
|
render_aspect = (float)render_width / (float)render_height;
|
|
fovy = 60.0f;
|
|
if (render_aspect > 1.0f)
|
|
fovy /= render_aspect;
|
|
gluPerspective (fovy, render_aspect, 0.1f, RENDER_DISTANCE);
|
|
glMatrixMode (GL_MODELVIEW);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderTerm (void)
|
|
{
|
|
|
|
if (!hRC)
|
|
return;
|
|
wglDeleteContext (hRC);
|
|
hRC = NULL;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderInit (void)
|
|
{
|
|
|
|
HWND hWnd;
|
|
unsigned PixelFormat;
|
|
HFONT font;
|
|
HFONT oldfont;
|
|
|
|
hWnd = WinHwnd ();
|
|
if (!(hDC = GetDC (hWnd)))
|
|
YOUFAIL ("Can't Create A GL Device Context.") ;
|
|
if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd)))
|
|
YOUFAIL ("Can't Find A Suitable PixelFormat.") ;
|
|
if(!SetPixelFormat(hDC,PixelFormat,&pfd))
|
|
YOUFAIL ("Can't Set The PixelFormat.");
|
|
if (!(hRC = wglCreateContext (hDC)))
|
|
YOUFAIL ("Can't Create A GL Rendering Context.");
|
|
if(!wglMakeCurrent(hDC,hRC))
|
|
YOUFAIL ("Can't Activate The GL Rendering Context.");
|
|
//Load the fonts for printing debug info to the window.
|
|
for (int i = 0; i < FONT_COUNT; i++) {
|
|
fonts[i].base_char = glGenLists(96);
|
|
font = CreateFont (FONT_SIZE, 0, 0, 0,
|
|
FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_TT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE|DEFAULT_PITCH,
|
|
fonts[i].name);
|
|
oldfont = (HFONT)SelectObject(hDC, font);
|
|
wglUseFontBitmaps(hDC, 32, 96, fonts[i].base_char);
|
|
SelectObject(hDC, oldfont);
|
|
DeleteObject(font);
|
|
}
|
|
//If the program is running for the first time, set the defaults.
|
|
if (!IniInt ("SetDefaults")) {
|
|
IniIntSet ("SetDefaults", 1);
|
|
IniIntSet ("Effect", EFFECT_BLOOM);
|
|
IniIntSet ("ShowFog", 1);
|
|
}
|
|
//load in our settings
|
|
letterbox = IniInt ("Letterbox") != 0;
|
|
show_wireframe = IniInt ("Wireframe") != 0;
|
|
show_fps = IniInt ("ShowFPS") != 0;
|
|
show_fog = IniInt ("ShowFog") != 0;
|
|
effect = IniInt ("Effect");
|
|
flat = IniInt ("Flat") != 0;
|
|
fog_distance = WORLD_HALF;
|
|
//clear the viewport so the user isn't looking at trash while the program starts
|
|
glViewport (0, 0, WinWidth (), WinHeight ());
|
|
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
|
|
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
SwapBuffers (hDC);
|
|
RenderResize ();
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderFPSToggle ()
|
|
{
|
|
|
|
show_fps = !show_fps;
|
|
IniIntSet ("ShowFPS", show_fps ? 1 : 0);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
bool RenderFog ()
|
|
{
|
|
|
|
return show_fog;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderFogToggle ()
|
|
{
|
|
|
|
show_fog = !show_fog;
|
|
IniIntSet ("ShowFog", show_fog ? 1 : 0);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderLetterboxToggle ()
|
|
{
|
|
|
|
letterbox = !letterbox;
|
|
IniIntSet ("Letterbox", letterbox ? 1 : 0);
|
|
RenderResize ();
|
|
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderWireframeToggle ()
|
|
{
|
|
|
|
show_wireframe = !show_wireframe;
|
|
IniIntSet ("Wireframe", show_wireframe ? 1 : 0);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
bool RenderWireframe ()
|
|
{
|
|
|
|
return show_wireframe;
|
|
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderEffectCycle ()
|
|
{
|
|
|
|
effect = (effect + 1) % EFFECT_COUNT;
|
|
IniIntSet ("Effect", effect);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
bool RenderBloom ()
|
|
{
|
|
|
|
return effect == EFFECT_BLOOM || effect == EFFECT_BLOOM_RADIAL
|
|
|| effect == EFFECT_DEBUG_OVERBLOOM || effect == EFFECT_COLOR_CYCLE;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
bool RenderFlat ()
|
|
{
|
|
|
|
return flat;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderFlatToggle ()
|
|
{
|
|
|
|
flat = !flat;
|
|
IniIntSet ("Flat", flat ? 1 : 0);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderHelpToggle ()
|
|
{
|
|
|
|
show_help = !show_help;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
float RenderFogDistance ()
|
|
{
|
|
|
|
return fog_distance;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
This is used to set a gradient fog that goes from camera to some portion of
|
|
the normal fog distance. This is used for making wireframe outlines and
|
|
flat surfaces fade out after rebuild. Looks cool.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderFogFX (float scalar)
|
|
{
|
|
|
|
if (scalar >= 1.0f) {
|
|
glDisable (GL_FOG);
|
|
return;
|
|
}
|
|
glFogf (GL_FOG_START, 0.0f);
|
|
glFogf (GL_FOG_END, fog_distance * 2.0f * scalar);
|
|
glEnable (GL_FOG);
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void RenderUpdate (void)
|
|
{
|
|
|
|
GLvector pos;
|
|
GLvector angle;
|
|
GLrgba color;
|
|
int elapsed;
|
|
|
|
frames++;
|
|
do_fps ();
|
|
glViewport (0, 0, WinWidth (), WinHeight ());
|
|
glDepthMask (true);
|
|
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
if (letterbox)
|
|
glViewport (0, letterbox_offset, render_width, render_height);
|
|
if (LOADING_SCREEN && TextureReady () && !EntityReady ()) {
|
|
do_effects (EFFECT_NONE);
|
|
SwapBuffers (hDC);
|
|
return;
|
|
}
|
|
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
glShadeModel(GL_SMOOTH);
|
|
glFogi (GL_FOG_MODE, GL_LINEAR);
|
|
glDepthFunc(GL_LEQUAL);
|
|
glEnable (GL_CULL_FACE);
|
|
glCullFace (GL_BACK);
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glMatrixMode (GL_TEXTURE);
|
|
glLoadIdentity();
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
glLoadIdentity();
|
|
glLineWidth (1.0f);
|
|
pos = CameraPosition ();
|
|
angle = CameraAngle ();
|
|
glRotatef (angle.x, 1.0f, 0.0f, 0.0f);
|
|
glRotatef (angle.y, 0.0f, 1.0f, 0.0f);
|
|
glRotatef (angle.z, 0.0f, 0.0f, 1.0f);
|
|
glTranslatef (-pos.x, -pos.y, -pos.z);
|
|
glEnable (GL_TEXTURE_2D);
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
//Render all the stuff in the whole entire world.
|
|
glDisable (GL_FOG);
|
|
SkyRender ();
|
|
if (show_fog) {
|
|
glEnable (GL_FOG);
|
|
glFogf (GL_FOG_START, fog_distance - 100);
|
|
glFogf (GL_FOG_END, fog_distance);
|
|
color = glRgba (0.0f);
|
|
glFogfv (GL_FOG_COLOR, &color.red);
|
|
}
|
|
WorldRender ();
|
|
if (effect == EFFECT_GLASS_CITY) {
|
|
glDisable (GL_CULL_FACE);
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
glDepthFunc (false);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glMatrixMode (GL_TEXTURE);
|
|
glTranslatef ((pos.x + pos.z) / SEGMENTS_PER_TEXTURE, 0, 0);
|
|
glMatrixMode (GL_MODELVIEW);
|
|
} else {
|
|
glEnable (GL_CULL_FACE);
|
|
glDisable (GL_BLEND);
|
|
}
|
|
EntityRender ();
|
|
|
|
if (!LOADING_SCREEN) {
|
|
elapsed = 3000 - WorldSceneElapsed ();
|
|
if (elapsed >= 0 && elapsed <= 3000) {
|
|
RenderFogFX ((float)elapsed / 3000.0f);
|
|
glDisable (GL_TEXTURE_2D);
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
EntityRender ();
|
|
}
|
|
}
|
|
if (EntityReady ())
|
|
LightRender ();
|
|
CarRender ();
|
|
if (show_wireframe) {
|
|
glDisable (GL_TEXTURE_2D);
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
EntityRender ();
|
|
}
|
|
do_effects (effect);
|
|
//Framerate tracker
|
|
if (show_fps)
|
|
RenderPrint (1, "FPS=%d : Entities=%d : polys=%d", current_fps, EntityCount () + LightCount () + CarCount (), EntityPolyCount () + LightCount () + CarCount ());
|
|
//Show the help overlay
|
|
if (show_help)
|
|
do_help ();
|
|
SwapBuffers (hDC);
|
|
|
|
}
|