pixelcity/Texture.cpp

888 lines
27 KiB
C++

/*-----------------------------------------------------------------------------
Texture.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This procedurally builds all of the textures.
I apologize in advance for the apalling state of this module. It's the victim
of iterative and experimental development. It has cruft, poorly named
functions, obscure code, poorly named variables, a is poorly organized. Even
the formatting sucks in places. Its only saving grace is that it works.
-----------------------------------------------------------------------------*/
#define RANDOM_COLOR_SHIFT ((float)(RandomVal (10)) / 50.0f)
#define RANDOM_COLOR_VAL ((float)(RandomVal (256)) / 256.0f)
#define RANDOM_COLOR_LIGHT ((float)(200 + RandomVal (56)) / 256.0f)
#define SKY_BANDS (sizeof (sky_pos) / sizeof (int))
#define PREFIX_COUNT (sizeof (prefix) / sizeof (char*))
#define SUFFIX_COUNT (sizeof (suffix) / sizeof (char*))
#define NAME_COUNT (sizeof (name) / sizeof (char*))
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include "gltypes.h"
#include "building.h"
#include "camera.h"
#include "car.h"
#include "light.h"
#include "macro.h"
#include "random.h"
#include "render.h"
#include "sky.h"
#include "texture.h"
#include "world.h"
static char* prefix[] =
{
"i",
"Green ",
"Mega",
"Super ",
"Omni",
"e",
"Hyper",
"Global ",
"Vital",
"Next ",
"Pacific ",
"Metro",
"Unity ",
"G-",
"Trans",
"Infinity ",
"Superior ",
"Monolith ",
"Best ",
"Atlantic ",
"First ",
"Union ",
"National ",
};
static char* name[] =
{
"Biotic",
"Info",
"Data",
"Solar",
"Aerospace",
"Motors",
"Nano",
"Online",
"Circuits",
"Energy",
"Med",
"Robotic",
"Exports",
"Security",
"Systems",
"Financial",
"Industrial",
"Media",
"Materials",
"Foods",
"Networks",
"Shipping",
"Tools",
"Medical",
"Publishing",
"Enterprises",
"Audio",
"Health",
"Bank",
"Imports",
"Apparel",
"Petroleum",
"Studios",
};
static char* suffix[] =
{
"Corp",
" Inc.",
"Co",
"World",
".Com",
" USA",
" Ltd.",
"Net",
" Tech",
" Labs",
" Mfg.",
" UK",
" Unlimited",
" One",
};
class CTexture
{
public:
int _my_id;
unsigned _glid;
int _size;
int _half;
int _segment_size;
bool _ready;
bool _masked;
bool _mipmap;
bool _clamp;
public:
CTexture* _next;
CTexture (int id, int size, bool mipmap, bool clamp, bool masked);
void Clear () { _ready = false; }
void Rebuild ();
void DrawWindows ();
};
static CTexture* head;
static bool textures_done;
static GLrgba horizon_color;
static GLrgba cloud_color;
static bool prefix_used[PREFIX_COUNT];
static bool name_used[NAME_COUNT];
static bool suffix_used[SUFFIX_COUNT];
static int build_time;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void drawrect_simple (int left, int top, int right, int bottom, GLrgba color)
{
glColor3fv (&color.red);
glBegin (GL_QUADS);
glVertex2i (left, top);
glVertex2i (right, top);
glVertex2i (right, bottom);
glVertex2i (left, bottom);
glEnd ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void drawrect_simple (int left, int top, int right, int bottom, GLrgba color1, GLrgba color2)
{
glColor3fv (&color1.red);
glBegin (GL_TRIANGLE_FAN);
glVertex2i ((left + right) / 2, (top + bottom) / 2);
glColor3fv (&color2.red);
glVertex2i (left, top);
glVertex2i (right, top);
glVertex2i (right, bottom);
glVertex2i (left, bottom);
glVertex2i (left, top);
glEnd ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void drawrect (int left, int top, int right, int bottom, GLrgba color)
{
float average;
float hue;
int potential;
int repeats;
int height;
int i, j;
bool bright;
GLrgba color_noise;
glDisable (GL_CULL_FACE);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
glLineWidth (1.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor3fv (&color.red);
if (left == right) { //in low resolution, a "rect" might be 1 pixel wide
glBegin (GL_LINES);
glVertex2i (left, top);
glVertex2i (left, bottom);
glEnd ();
} if (top == bottom) { //in low resolution, a "rect" might be 1 pixel wide
glBegin (GL_LINES);
glVertex2i (left, top);
glVertex2i (right, top);
glEnd ();
} else { // draw one of those fancy 2-dimensional rectangles
glBegin (GL_QUADS);
glVertex2i (left, top);
glVertex2i (right, top);
glVertex2i (right, bottom);
glVertex2i (left, bottom);
glEnd ();
average = (color.red + color.blue + color.green) / 3.0f;
bright = average > 0.5f;
potential = (int)(average * 255.0f);
if (bright) {
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin (GL_POINTS);
for (i = left + 1; i < right - 1; i++) {
for (j = top + 1; j < bottom - 1; j++) {
glColor4i (255, 0, RandomVal (potential), 255);
hue = 0.2f + (float)RandomVal (100) / 300.0f + (float)RandomVal (100) / 300.0f + (float)RandomVal (100) / 300.0f;
color_noise = glRgbaFromHsl (hue, 0.3f, 0.5f);
color_noise.alpha = (float)RandomVal (potential) / 144.0f;
glColor4f (RANDOM_COLOR_VAL, RANDOM_COLOR_VAL, RANDOM_COLOR_VAL, (float)RandomVal (potential) / 144.0f);
glColor4fv (&color_noise.red);
glVertex2i (i, j);
}
}
glEnd ();
}
repeats = RandomVal (6) + 1;
height = (bottom - top) + (RandomVal (3) - 1) + (RandomVal(3) - 1);
for (i = left; i < right; i++) {
if (RandomVal (3) == 0)
repeats = RandomVal (4) + 1;
if (RandomVal (6) == 0) {
height = bottom - top;
height = RandomVal (height);
height = RandomVal (height);
height = RandomVal (height);
height = ((bottom - top) + height) / 2;
}
for (j = 0; j < 1; j++) {
glBegin (GL_LINES);
glColor4f (0, 0, 0, (float)RandomVal (256) / 256.0f);
glVertex2i (i, bottom - height);
glColor4f (0, 0, 0, (float)RandomVal (256) / 256.0f);
glVertex2i (i, bottom);
glEnd ();
}
}
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void window (int x, int y, int size, int id, GLrgba color)
{
int margin;
int half;
int i;
margin = size / 3;
half = size / 2;
//color = (color * 0.9f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT);
//glColor3fv (&color.red);
switch (id) {
case TEXTURE_BUILDING1: //filled, 1-pixel frame
drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color);
break;
case TEXTURE_BUILDING2: //vertical
drawrect (x + margin, y + 1, x + size - margin, y + size - 1, color);
break;
case TEXTURE_BUILDING3: //side-by-side pair
drawrect (x + 1, y + 1, x + half - 1, y + size - margin, color);
drawrect (x + half + 1, y + 1, x + size - 1, y + size - margin, color);
break;
case TEXTURE_BUILDING4: //windows with blinds
drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color);
i = RandomVal (size - 2);
drawrect (x + 1, y + 1, x + size - 1, y + i + 1, color * 0.3f);
break;
case TEXTURE_BUILDING5: //vert stripes
drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color);
drawrect (x + margin, y + 1, x + margin, y + size - 1, color * 0.7f);
drawrect (x + size - margin - 1, y + 1, x + size - margin - 1, y + size - 1, color * 0.3f);
break;
case TEXTURE_BUILDING6: //wide horz line
drawrect (x + 1, y + 1, x + size - 1, y + size - margin, color);
break;
case TEXTURE_BUILDING7: //4-pane
drawrect (x + 2, y + 1, x + size - 1, y + size - 1, color);
drawrect (x + 2, y + half, x + size - 1, y + half, color * 0.2f);
drawrect (x + half, y + 1, x + half, y + size - 1, color * 0.2f);
break;
case TEXTURE_BUILDING8: // Single narrow window
drawrect (x + half - 1, y + 1, x + half + 1, y + size - margin, color);
break;
case TEXTURE_BUILDING9: //horizontal
drawrect (x + 1, y + margin, x + size - 1, y + size - margin - 1, color);
break;
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void do_bloom (CTexture* t)
{
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(0, 0, t->_size , t->_size);
glCullFace (GL_BACK);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask (true);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_DEPTH_TEST);
glEnable (GL_CULL_FACE);
glCullFace (GL_BACK);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_FOG);
glFogf (GL_FOG_START, RenderFogDistance () / 2);
glFogf (GL_FOG_END, RenderFogDistance ());
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
WorldRender ();
glEnable (GL_TEXTURE_2D);
EntityRender ();
CarRender ();
LightRender ();
glBindTexture(GL_TEXTURE_2D, t->_glid);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, t->_size, t->_size, 0);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CTexture::CTexture (int id, int size, bool mipmap, bool clamp, bool masked)
{
glGenTextures (1, &_glid);
_my_id = id;
_mipmap = mipmap;
_clamp = clamp;
_masked = masked;
_size = size;
_half = size / 2;
_segment_size = size / SEGMENTS_PER_TEXTURE;
_ready = false;
_next = head;
head = this;
}
/*-----------------------------------------------------------------------------
This draws all of the windows on a building texture. lit_density controls
how many lights are on. (1 in n chance that the light is on. Higher values
mean less lit windows. run_length controls how often it will consider
changing the lit / unlit status. 1 produces a complete scatter, higher
numbers make long strings of lights.
-----------------------------------------------------------------------------*/
void CTexture::DrawWindows ()
{
int x, y;
int run;
int run_length;
int lit_density;
GLrgba color;
bool lit;
//color = glRgbaUnique (_my_id);
for (y = 0; y < SEGMENTS_PER_TEXTURE; y++) {
//Every few floors we change the behavior
if (!(y % 8)) {
run = 0;
run_length = RandomVal (9) + 2;
lit_density = 2 + RandomVal(2) + RandomVal(2);
lit = false;
}
for (x = 0; x < SEGMENTS_PER_TEXTURE; x++) {
//if this run is over reroll lit and start a new one
if (run < 1) {
run = RandomVal (run_length);
lit = RandomVal (lit_density) == 0;
//if (lit)
//color = glRgba (0.5f + (float)(RandomVal () % 128) / 256.0f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT);
}
if (lit)
color = glRgba (0.5f + (float)(RandomVal () % 128) / 256.0f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT);
else
color = glRgba ((float)(RandomVal () % 40) / 256.0f);
window (x * _segment_size, y * _segment_size, _segment_size, _my_id, color);
run--;
}
}
}
/*-----------------------------------------------------------------------------
Here is where ALL of the procedural textures are created. It's filled with
obscure logic, magic numbers, and messy code. Part of this is because
there is a lot of "art" being done here, and lots of numbers that could be
endlessly tweaked. Also because I'm lazy.
-----------------------------------------------------------------------------*/
void CTexture::Rebuild ()
{
int i, j;
int x, y;
int name_num, prefix_num, suffix_num;
float radius;
GLvector2 pos;
GLrgba color;
bool use_framebuffer;
unsigned char* bits;
unsigned start;
int lapsed;
start = GetTickCount ();
glBindTexture(GL_TEXTURE_2D, _glid);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, _size, _size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (_clamp) {
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
//Set up our viewport so that drawing into our texture will be as easy
//as possible. We make the viewport and projection simply match the given
//texture size.
glViewport(0, 0, _size , _size);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, _size, _size, 0, 0.1f, 2048);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity();
glDisable (GL_CULL_FACE);
glBindTexture(GL_TEXTURE_2D, 0);
glTranslatef(0, 0, -10.0f);
glClearColor (0, 0, 0, _masked ? 0.0f : 1.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
use_framebuffer = true;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
switch (_my_id) {
case TEXTURE_GROUND:
unsigned char icolor[4];
char cell;
//memset (buffer, 0, 1024 * 1024 * 4);
bits = new unsigned char[_size * _size * 4];
ZeroMemory (bits, sizeof (bits));
icolor[3] = 255;
for (x = 0; x < _size; x++) {
for (y = 0; y < _size; y++) {
cell = WorldCell (x, y);
memset (icolor, 0, 3);
if (cell & CLAIM_ROAD)
icolor[0] = icolor[1] = icolor[2] = 12;
if (cell == CLAIM_WALK)
icolor[0] = icolor[1] = icolor[2] = 64;
icolor[0] += (unsigned char)RandomVal (4);
icolor[1] += (unsigned char)RandomVal (4);
icolor[2] += (unsigned char)RandomVal (4);
if (1) { //use this to make the road lanes visible
if (cell & MAP_ROAD_EAST)
icolor[0] += 128;
if (cell & MAP_ROAD_WEST)
icolor[1] += 128;
if (cell & MAP_ROAD_NORTH)
icolor[2] += 128;
if (cell & MAP_ROAD_SOUTH) {
icolor[1] += 64;
icolor[2] += 64;
}
}
memcpy (&bits[(x + y * _size) * 4], &icolor[0], 4);
}
}
glBindTexture(GL_TEXTURE_2D, _glid);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, _size, _size, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits);
use_framebuffer = false;
delete bits;
break;
case TEXTURE_LATTICE:
glLineWidth (2.0f);
glColor3f (0,0,0);
glBegin (GL_LINES);
glVertex2i (0, 0); glVertex2i (_size, _size);//diagonal
glVertex2i (0, 0); glVertex2i (0, _size);//vertical
glVertex2i (0, 0); glVertex2i (_size, 0);//vertical
glEnd ();
glBegin (GL_LINE_STRIP);
glVertex2i (0, 0);
for (i = 0; i < _size; i += 9) {
if (i % 2)
glVertex2i (0, i);
else
glVertex2i (i, i);
}
for (i = 0; i < _size; i += 9) {
if (i % 2)
glVertex2i (i, 0);
else
glVertex2i (i, i);
}
glEnd ();
break;
case TEXTURE_SOFT_CIRCLE:
//Make a simple circle of light, bright in the center and fading out
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
radius = ((float)_half) - 3;
glBegin (GL_TRIANGLE_FAN);
glColor4f (1, 1, 1, 1);
glVertex2i (_half, _half);
glColor4f (0, 0, 0, 0);
for (i = 0; i <= 360; i++) {
pos.x = sinf ((float)i * DEGREES_TO_RADIANS) * radius;
pos.y = cosf ((float)i * DEGREES_TO_RADIANS) * radius;
glVertex2i (_half + (int)pos.x, _half + (int)pos.y);
}
glEnd ();
break;
case TEXTURE_LIGHT:
//
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
radius = ((float)_half) - 3;
for (j = 0; j < 2; j++) {
glBegin (GL_TRIANGLE_FAN);
glColor4f (1, 1, 1, 1);
glVertex2i (_half, _half);
if (!j)
radius = ((float)_half / 2);
else
radius = 8;
glColor4f (1, 1, 0, 0);
for (i = 0; i <= 360; i++) {
pos.x = sinf ((float)i * DEGREES_TO_RADIANS) * radius;
pos.y = cosf ((float)i * DEGREES_TO_RADIANS) * radius;
glVertex2i (_half + (int)pos.x, _half + (int)pos.y);
}
glEnd ();
}
break;
case TEXTURE_HEADLIGHT:
//Make a simple circle of light, bright in the center and fading out
radius = ((float)_half) - 20;
x = _half - 20;
y = _half;
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin (GL_TRIANGLE_FAN);
glColor4f (0.8f, 0.8f, 0.8f, 0.6f);
glVertex2i (_half - 5, y);
glColor4f (0, 0, 0, 0);
for (i = 0; i <= 360; i += 36) {
pos.x = sinf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius;
pos.y = cosf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius;
glVertex2i (x + (int)pos.x, _half + (int)pos.y);
}
glEnd ();
x = _half + 20;
glBegin (GL_TRIANGLE_FAN);
glColor4f (0.8f, 0.8f, 0.8f, 0.6f);
glVertex2i (_half + 5, y);
glColor4f (0, 0, 0, 0);
for (i = 0; i <= 360; i += 36) {
pos.x = sinf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius;
pos.y = cosf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius;
glVertex2i (x + (int)pos.x, _half + (int)pos.y);
}
glEnd ();
x = _half - 6;
drawrect_simple (x - 3, y - 2, x + 2, y + 2, glRgba (1.0f));
x = _half + 6;
drawrect_simple (x - 2, y - 2, x + 3, y + 2, glRgba (1.0f));
break;
case TEXTURE_LOGOS:
i = 0;
glDepthMask (false);
glDisable (GL_BLEND);
name_num = RandomVal (NAME_COUNT);
prefix_num = RandomVal (PREFIX_COUNT);
suffix_num = RandomVal (SUFFIX_COUNT);
glColor3f (1,1,1);
while (i < _size) {
//randomly use a prefix OR suffix, but not both. Too verbose.
/*
if (COIN_FLIP)
RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "%s%s", prefix[prefix_num], name[name_num]);
else
RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "%s%s", name[name_num], suffix[suffix_num]);
*/
RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "Pixel City");
name_num = (name_num + 1) % NAME_COUNT;
prefix_num = (prefix_num + 1) % PREFIX_COUNT;
suffix_num = (suffix_num + 1) % SUFFIX_COUNT;
i += LOGO_PIXELS;
}
break;
case TEXTURE_CLOUDS:
int width, height;
int offset;
float scale;
for (i = _size - 30; i > 5; i -= 1) {
x = RandomVal (_size);
y = i;
scale = 1.0f - ((float)y / (float)_size);
width = RandomVal (_half / 2) + (int)((float)_half * scale) / 2;
scale = 1.0f - (float)y / (float)_size;
height = (int)((float)(width) * scale);
height = MAX (height, 4);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable (GL_CULL_FACE);
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, TextureId (TEXTURE_SOFT_CIRCLE));
glDepthMask (false);
glBegin (GL_QUADS);
for (offset = -_size; offset <= _size; offset += _size) {
for (scale = 1.0f; scale > 0.0f; scale -= 0.25f) {
int width_adjust;
int height_adjust;
float inv_scale;
inv_scale = 1.0f - (scale);
if (scale < 0.4f)
color = cloud_color;
else
color = glRgba (0.0f);
color.alpha = 1.0f;
glColor4fv (&color.red);
//width_adjust = (int)((1.0f - scale) * ((float)width / 2.0f));
width_adjust = (int)((float)width / 2.0f + (int)(inv_scale * ((float)width / 2.0f)));
height_adjust = height + (int)(scale * (float)height * 0.99f);
glTexCoord2f (0, 0); glVertex2i (offset + x - width_adjust, y + height - height_adjust);
glTexCoord2f (0, 1); glVertex2i (offset + x - width_adjust, y + height);
glTexCoord2f (1, 1); glVertex2i (offset + x + width_adjust, y + height);
glTexCoord2f (1, 0); glVertex2i (offset + x + width_adjust, y + height - height_adjust);
}
}
glEnd ();
}
break;
case TEXTURE_TRIM:
int margin;
y = 0;
margin = MAX (TRIM_PIXELS / 4, 1);
for (x = 0; x < _size; x += TRIM_PIXELS)
drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f));
y += TRIM_PIXELS;
for (x = 0; x < _size; x += TRIM_PIXELS * 2)
drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f));
y += TRIM_PIXELS;
for (x = 0; x < _size; x += TRIM_PIXELS * 3)
drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f));
y += TRIM_PIXELS;
for (x = 0; x < _size; x += TRIM_PIXELS)
drawrect_simple (x + margin, y + margin * 2, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f));
break;
case TEXTURE_SKY:
glDisable (GL_BLEND);
glBegin (GL_QUAD_STRIP);
glColor3f (0,0,0);
glVertex2i (0, _half);
glVertex2i (_size, _half);
glColor3fv (&horizon_color.red);
glVertex2i (0, _size - 2);
glVertex2i (_size, _size - 2);
glEnd ();
//Draw a bunch of little faux-buildings on the horizon.
for (i = 0; i < _size; i += 5)
drawrect (i, _size - RandomVal (8) - RandomVal (8) - RandomVal (8), i + RandomVal (9), _size, glRgba (0.0f));
break;
default: //building textures
DrawWindows ();
break;
}
glPopMatrix ();
//Now blit the finished image into our texture
if (use_framebuffer) {
glBindTexture(GL_TEXTURE_2D, _glid);
glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, _size, _size, 0);
}
if (_mipmap) {
bits = (unsigned char*)malloc (_size * _size * 4);
glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, _size, _size, GL_RGBA, GL_UNSIGNED_BYTE, bits);
free (bits);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
} else
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
//cleanup and restore the viewport
RenderResize ();
_ready = true;
lapsed = GetTickCount () - start;
build_time += lapsed;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
unsigned TextureId (int id)
{
for (CTexture* t = head; t; t = t->_next) {
if (t->_my_id == id)
return t->_glid;
}
return 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
unsigned TextureRandomBuilding (int index)
{
index = abs (index) % BUILDING_COUNT;
return TextureId (TEXTURE_BUILDING1 + index);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void TextureReset (void)
{
float hue, sat;
textures_done = false;
build_time = 0;
for (CTexture* t = head; t; t = t->_next)
t->Clear ();
hue = 0.5f + (float)RandomVal (20) / 100.0f;
sat = 0.1f + (float)RandomVal (80) / 100.0f;
horizon_color = glRgbaFromHsl (hue, sat, 0.15f);
cloud_color = glRgbaFromHsl (hue, 0.15f, 0.1f);
ZeroMemory (prefix_used, sizeof (prefix_used));
ZeroMemory (name_used, sizeof (name_used));
ZeroMemory (suffix_used, sizeof (suffix_used));
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool TextureReady ()
{
return textures_done;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void TextureUpdate (void)
{
if (textures_done) {
if (!RenderBloom ())
return;
CTexture* t;
for (t = head; t; t = t->_next) {
if (t->_my_id != TEXTURE_BLOOM)
continue;
do_bloom (t);
return;
}
}
for (CTexture* t = head; t; t = t->_next) {
if (!t->_ready) {
t->Rebuild();
return;
}
}
textures_done = true;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void TextureTerm (void)
{
CTexture* t;
while (head) {
t = head->_next;
free (head);
head = t;
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void TextureInit (void)
{
new CTexture (TEXTURE_SKY, 512, true, false, false);
new CTexture (TEXTURE_CLOUDS, 256, true, false, true);
new CTexture (TEXTURE_LATTICE, 128, true, true, true);
new CTexture (TEXTURE_LIGHT, 128, false, false, true);
new CTexture (TEXTURE_SOFT_CIRCLE, 128, false, false, true);
new CTexture (TEXTURE_HEADLIGHT, 128, false, false, true);
new CTexture (TEXTURE_TRIM, TRIM_RESOLUTION, true, false, false);
if (SHOW_DEBUG_GROUND)
new CTexture (TEXTURE_GROUND, 1024, false, false, false);
new CTexture (TEXTURE_LOGOS, LOGO_RESOLUTION, true, false, true);
for (int i = TEXTURE_BUILDING1; i <= TEXTURE_BUILDING9; i++)
new CTexture (i, 512, true, false, false);
new CTexture (TEXTURE_BLOOM, 512, true, false, false);
int names = PREFIX_COUNT * NAME_COUNT + SUFFIX_COUNT * NAME_COUNT;
}