2007-01-15 12:09:25 -08:00
|
|
|
/*
|
|
|
|
This file is part of Warzone 2100.
|
|
|
|
Copyright (C) 1999-2004 Eidos Interactive
|
|
|
|
Copyright (C) 2005-2007 Warzone Resurrection Project
|
|
|
|
|
|
|
|
Warzone 2100 is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Warzone 2100 is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Warzone 2100; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
2007-07-31 13:16:38 -07:00
|
|
|
|
2008-02-16 05:12:58 -08:00
|
|
|
/**
|
|
|
|
* @file texture.c
|
|
|
|
* This is where we do texture atlas generation.
|
|
|
|
*/
|
2008-03-16 05:39:08 -07:00
|
|
|
#include "lib/framework/frame.h"
|
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
|
2006-11-06 06:40:07 -08:00
|
|
|
#include <string.h>
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2008-03-16 05:39:08 -07:00
|
|
|
#include <physfs.h>
|
|
|
|
#include <SDL_opengl.h>
|
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <opengl/glu.h>
|
|
|
|
#else
|
|
|
|
#include <GL/glu.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "lib/framework/file.h"
|
|
|
|
|
2006-05-27 09:37:17 -07:00
|
|
|
#include "lib/ivis_common/pietypes.h"
|
|
|
|
#include "lib/ivis_common/piestate.h"
|
2006-07-22 16:35:48 -07:00
|
|
|
#include "lib/ivis_common/tex.h"
|
2006-05-27 09:37:17 -07:00
|
|
|
#include "lib/ivis_common/piepalette.h"
|
2007-07-31 13:16:38 -07:00
|
|
|
#include "lib/ivis_opengl/screen.h"
|
2008-03-16 05:39:08 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
#include "display3ddef.h"
|
|
|
|
#include "texture.h"
|
|
|
|
#include "radar.h"
|
|
|
|
|
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
#define MIPMAP_LEVELS 4
|
|
|
|
#define MIPMAP_MIN 16
|
2008-03-20 09:01:28 -07:00
|
|
|
#define MIPMAP_NORMAL 64
|
2007-07-31 13:16:38 -07:00
|
|
|
#define MIPMAP_MAX 128
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2006-09-01 14:01:17 -07:00
|
|
|
/* Texture page and coordinates for each tile */
|
2007-06-18 07:25:06 -07:00
|
|
|
TILE_TEX_INFO tileTexInfo[MAX_TILES];
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
static int firstPage; // the last used page before we start adding terrain textures
|
2007-12-01 09:07:03 -08:00
|
|
|
int terrainPage; // texture ID of the terrain page
|
2008-03-20 09:01:28 -07:00
|
|
|
static int mipmap_max, mipmap_levels, mipmap_user_requested = MIPMAP_NORMAL;
|
2007-12-05 13:56:12 -08:00
|
|
|
|
|
|
|
void setTextureSize(int texSize)
|
|
|
|
{
|
|
|
|
if (texSize < 16 || texSize % 16 != 0)
|
|
|
|
{
|
|
|
|
debug(LOG_ERROR, "Attempted to set bad texture size %d! Ignored.", texSize);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mipmap_user_requested = texSize;
|
2007-12-06 10:26:16 -08:00
|
|
|
debug(LOG_3D, "texture size set to %d", texSize);
|
2007-12-05 13:56:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int getTextureSize()
|
|
|
|
{
|
|
|
|
return mipmap_user_requested;
|
|
|
|
}
|
2007-07-31 13:16:38 -07:00
|
|
|
|
|
|
|
// Generate a new texture page both in the texture page table, and on the graphics card
|
|
|
|
static int newPage(const char *name, int level, int width, int height, int count)
|
|
|
|
{
|
|
|
|
int texPage = firstPage + ((count + 1) / TILES_IN_PAGE);
|
|
|
|
|
2007-08-21 05:59:05 -07:00
|
|
|
// debug(LOG_TEXTURE, "newPage: texPage=%d firstPage=%d %s %d (%d,%d) (count %d + 1) / %d _TEX_INDEX=%u",
|
2007-07-31 13:16:38 -07:00
|
|
|
// texPage, firstPage, name, level, width, height, count, TILES_IN_PAGE, _TEX_INDEX);
|
|
|
|
if (texPage == _TEX_INDEX)
|
|
|
|
{
|
|
|
|
// We need to create a new texture page; create it and increase texture table to store it
|
|
|
|
glGenTextures(1, (GLuint *) &_TEX_PAGE[texPage].id);
|
|
|
|
_TEX_INDEX++;
|
|
|
|
}
|
2007-12-01 09:07:03 -08:00
|
|
|
terrainPage = texPage;
|
2007-07-31 13:16:38 -07:00
|
|
|
|
|
|
|
ASSERT(_TEX_INDEX > texPage, "newPage: Index too low (%d > %d)", _TEX_INDEX, texPage);
|
|
|
|
ASSERT(_TEX_INDEX < iV_TEX_MAX, "Too many texture pages used");
|
|
|
|
|
2007-10-27 08:47:17 -07:00
|
|
|
strlcpy(_TEX_PAGE[texPage].name, name, sizeof(_TEX_PAGE[texPage].name));
|
2007-07-31 13:16:38 -07:00
|
|
|
|
|
|
|
pie_SetTexturePage(texPage);
|
2007-12-05 13:56:12 -08:00
|
|
|
|
|
|
|
// Specify first and last mipmap level to be used
|
2007-07-31 13:16:38 -07:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
2007-12-05 13:56:12 -08:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmap_levels - 1);
|
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
// debug(LOG_TEXTURE, "newPage: glTexImage2D(page=%d, level=%d) opengl id=%u", texPage, level, _TEX_PAGE[texPage].id);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, level, wz_texture_compression, width, height, 0,
|
|
|
|
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
2007-10-16 14:23:39 -07:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
2007-10-16 13:56:29 -07:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
2007-07-31 13:16:38 -07:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
|
2007-10-16 14:23:39 -07:00
|
|
|
// Use anisotropic filtering, if available, but only max 4.0 to reduce processor burden
|
|
|
|
if (check_extension("GL_EXT_texture_filter_anisotropic"))
|
|
|
|
{
|
|
|
|
GLfloat max;
|
|
|
|
|
|
|
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max);
|
|
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, MIN(4.0f, max));
|
|
|
|
}
|
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
return texPage;
|
|
|
|
}
|
|
|
|
|
2007-07-27 07:58:17 -07:00
|
|
|
void texLoad(const char *fileName)
|
2007-07-27 05:10:31 -07:00
|
|
|
{
|
2007-08-21 05:59:05 -07:00
|
|
|
char fullPath[PATH_MAX], partialPath[PATH_MAX], *buffer;
|
2007-07-31 06:02:31 -07:00
|
|
|
unsigned int i, j, k, size;
|
2007-07-31 13:16:38 -07:00
|
|
|
int texPage;
|
2007-12-05 13:56:12 -08:00
|
|
|
GLint glval;
|
2007-07-27 05:10:31 -07:00
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
firstPage = _TEX_INDEX;
|
2007-07-27 05:10:31 -07:00
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
ASSERT(_TEX_INDEX < iV_TEX_MAX, "Too many texture pages used");
|
|
|
|
ASSERT(MIPMAP_MAX == TILE_WIDTH && MIPMAP_MAX == TILE_HEIGHT, "Bad tile sizes");
|
2007-07-31 06:02:31 -07:00
|
|
|
|
2007-12-06 10:26:16 -08:00
|
|
|
// reset defaults
|
|
|
|
mipmap_max = MIPMAP_MAX;
|
|
|
|
mipmap_levels = MIPMAP_LEVELS;
|
|
|
|
|
2007-12-05 13:56:12 -08:00
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glval);
|
2008-03-16 05:39:08 -07:00
|
|
|
|
2007-12-05 13:56:12 -08:00
|
|
|
while (glval < mipmap_max * TILES_IN_PAGE_COLUMN)
|
|
|
|
{
|
|
|
|
mipmap_max /= 2;
|
|
|
|
mipmap_levels--;
|
|
|
|
debug(LOG_ERROR, "Max supported texture size %dx%d is too low - reducing texture detail to %dx%d.",
|
|
|
|
(int)glval, (int)glval, mipmap_max, mipmap_max);
|
|
|
|
ASSERT(mipmap_levels > 0, "Supported texture size %d is too low to load any mipmap levels!",
|
|
|
|
(int)glval);
|
|
|
|
if (mipmap_levels == 0)
|
|
|
|
{
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (mipmap_user_requested < mipmap_max)
|
|
|
|
{
|
|
|
|
mipmap_max /= 2;
|
|
|
|
mipmap_levels--;
|
2007-12-06 10:26:16 -08:00
|
|
|
debug(LOG_3D, "Downgrading texture quality to %d due to user setting %d", mipmap_max, mipmap_user_requested);
|
2007-12-05 13:56:12 -08:00
|
|
|
}
|
|
|
|
mipmap_user_requested = mipmap_max; // reduce to lowest possible
|
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
/* Get and set radar colours */
|
2007-07-31 06:02:31 -07:00
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
sprintf(fullPath, "%s.radar", fileName);
|
2007-07-31 06:02:31 -07:00
|
|
|
if (!loadFile(fullPath, &buffer, &size))
|
|
|
|
{
|
|
|
|
debug(LOG_ERROR, "texLoad: Could not find radar colours at %s", fullPath);
|
|
|
|
abort(); // cannot recover; we could possibly generate a random palette?
|
|
|
|
}
|
|
|
|
i = 0; // tile
|
|
|
|
k = 0; // number of values read
|
|
|
|
j = 0; // place in buffer
|
|
|
|
do {
|
2007-08-03 01:52:25 -07:00
|
|
|
unsigned int r, g, b;
|
2007-08-02 15:34:33 -07:00
|
|
|
int cnt = 0;
|
2007-07-31 06:02:31 -07:00
|
|
|
|
2007-08-03 01:52:25 -07:00
|
|
|
k = sscanf(buffer + j, "%2x%2x%2x%n", &r, &g, &b, &cnt);
|
2007-07-31 06:02:31 -07:00
|
|
|
j += cnt;
|
|
|
|
if (k >= 3)
|
|
|
|
{
|
|
|
|
radarColour(i, r, g, b);
|
|
|
|
}
|
|
|
|
i++; // next tile
|
2007-08-02 15:34:33 -07:00
|
|
|
} while (k >= 3 && j + 6 < size);
|
2007-07-31 06:02:31 -07:00
|
|
|
free(buffer);
|
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
/* Now load the actual tiles */
|
2006-05-27 09:37:17 -07:00
|
|
|
|
2007-12-05 13:56:12 -08:00
|
|
|
i = mipmap_max; // i is used to keep track of the tile dimensions
|
|
|
|
for (j = 0; j < mipmap_levels; j++)
|
2007-07-31 13:16:38 -07:00
|
|
|
{
|
|
|
|
int xOffset = 0, yOffset = 0; // offsets into the texture atlas
|
2007-09-29 09:00:31 -07:00
|
|
|
int xSize = 1;
|
|
|
|
int ySize = 1;
|
2007-09-30 03:14:05 -07:00
|
|
|
const int xLimit = TILES_IN_PAGE_COLUMN * i;
|
|
|
|
const int yLimit = TILES_IN_PAGE_ROW * i;
|
2007-09-29 09:00:31 -07:00
|
|
|
|
|
|
|
// pad width and height into ^2 values
|
2007-09-30 03:14:05 -07:00
|
|
|
while (xLimit > (xSize *= 2));
|
|
|
|
while (yLimit > (ySize *= 2));
|
2006-05-27 09:37:17 -07:00
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
// Generate the empty texture buffer in VRAM
|
|
|
|
texPage = newPage(fileName, j, xSize, ySize, 0);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-08-16 06:45:48 -07:00
|
|
|
sprintf(partialPath, "%s-%d", fileName, i);
|
2006-05-27 09:37:17 -07:00
|
|
|
|
2007-07-31 13:16:38 -07:00
|
|
|
// Load until we cannot find anymore of them
|
|
|
|
for (k = 0; k < MAX_TILES; k++)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2008-02-07 09:02:25 -08:00
|
|
|
iV_Image tile;
|
2007-07-31 13:16:38 -07:00
|
|
|
|
2007-08-25 15:33:14 -07:00
|
|
|
sprintf(fullPath, "%s/tile-%02d.png", partialPath, k);
|
2007-07-31 13:16:38 -07:00
|
|
|
if (PHYSFS_exists(fullPath)) // avoid dire warning
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-07-31 13:16:38 -07:00
|
|
|
BOOL retval = iV_loadImage_PNG(fullPath, &tile);
|
|
|
|
ASSERT(retval, "texLoad: Could not load %s", fullPath);
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
2007-07-31 13:16:38 -07:00
|
|
|
else
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-07-31 13:16:38 -07:00
|
|
|
// no more textures in this set
|
|
|
|
ASSERT(k > 0, "texLoad: Could not find %s", fullPath);
|
|
|
|
break;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
2007-07-31 13:16:38 -07:00
|
|
|
// Insert into texture page
|
2007-08-21 05:59:05 -07:00
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, j, xOffset, yOffset, tile.width, tile.height,
|
2007-07-31 13:16:38 -07:00
|
|
|
GL_RGBA, GL_UNSIGNED_BYTE, tile.bmp);
|
|
|
|
free(tile.bmp);
|
2007-12-05 13:56:12 -08:00
|
|
|
if (i == mipmap_max) // dealing with main texture page; so register coordinates
|
2007-09-29 09:00:31 -07:00
|
|
|
{
|
2007-12-05 10:54:17 -08:00
|
|
|
tileTexInfo[k].uOffset = (float)xOffset / (float)xSize;
|
|
|
|
tileTexInfo[k].vOffset = (float)yOffset / (float)ySize;
|
2007-09-29 09:00:31 -07:00
|
|
|
tileTexInfo[k].texPage = texPage;
|
2007-09-29 11:48:58 -07:00
|
|
|
debug(LOG_TEXTURE, " texLoad: Registering k=%d i=%d u=%f v=%f xoff=%d yoff=%d xsize=%d ysize=%d tex=%d (%s)",
|
2007-09-29 09:00:31 -07:00
|
|
|
k, i, tileTexInfo[k].uOffset, tileTexInfo[k].vOffset, xOffset, yOffset, xSize, ySize, texPage, fullPath);
|
|
|
|
}
|
2007-07-31 13:16:38 -07:00
|
|
|
xOffset += i; // i is width of tile
|
2007-09-30 03:14:05 -07:00
|
|
|
if (xOffset + i > xLimit)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-07-31 13:16:38 -07:00
|
|
|
yOffset += i; // i is also height of tile
|
|
|
|
xOffset = 0;
|
|
|
|
}
|
2007-09-30 03:14:05 -07:00
|
|
|
if (yOffset + i > yLimit)
|
2007-07-31 13:16:38 -07:00
|
|
|
{
|
|
|
|
/* Change to next texture page */
|
|
|
|
xOffset = 0;
|
|
|
|
yOffset = 0;
|
2007-08-21 05:59:05 -07:00
|
|
|
debug(LOG_TEXTURE, "texLoad: Extra page added at %d for %s, was page %d, opengl id %u",
|
2007-07-31 13:16:38 -07:00
|
|
|
k, partialPath, texPage, _TEX_PAGE[texPage].id);
|
|
|
|
texPage = newPage(fileName, j, xSize, ySize, k);
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
}
|
2007-08-21 05:59:05 -07:00
|
|
|
debug(LOG_TEXTURE, "texLoad: Found %d textures for %s mipmap level %d, added to page %d, opengl id %u",
|
2007-07-31 13:16:38 -07:00
|
|
|
k, partialPath, i, texPage, _TEX_PAGE[texPage].id);
|
|
|
|
i /= 2; // halve the dimensions for the next series; OpenGL mipmaps start with largest at level zero
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
}
|