Add a utility to generate the köppen-geiger climate database image
This commit is contained in:
parent
370a412ee6
commit
9481ac4595
5 changed files with 1510 additions and 0 deletions
21
utils/climate/README
Normal file
21
utils/climate/README
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
-- Data Source:
|
||||||
|
http://koeppen-geiger.vu-wien.ac.at/present.htm
|
||||||
|
|
||||||
|
Download "code with raster file: Map_KG-Global.R"
|
||||||
|
|
||||||
|
|
||||||
|
-- Bulding:
|
||||||
|
g++ asc2a.cpp texture.cxx -o asc2a -lGL -lz -losg
|
||||||
|
|
||||||
|
|
||||||
|
-- Workflow:
|
||||||
|
1. Convert the ESRI grid to ASCII using R:
|
||||||
|
https://groups.google.com/forum/#!topic/maxent/OrTBUvqOXaE
|
||||||
|
|
||||||
|
2. Run asc2a to convert the ASCII file to a single channel rgb file:
|
||||||
|
./asc2a <infile>.asc <outfile>.rgb
|
||||||
|
|
||||||
|
3. Use your favorite image processing package to convert from rgb to png
|
||||||
|
to compress it 40x compared to the ESRI grid image and 110x compared to
|
||||||
|
the ASCII file.
|
||||||
|
|
77
utils/climate/asc2a.cpp
Normal file
77
utils/climate/asc2a.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <climits>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "texture.hxx"
|
||||||
|
|
||||||
|
#define NCOLS 4320
|
||||||
|
#define NROWS 2160
|
||||||
|
|
||||||
|
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
|
||||||
|
|
||||||
|
STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
|
||||||
|
{
|
||||||
|
char *end;
|
||||||
|
long l;
|
||||||
|
errno = 0;
|
||||||
|
l = strtol(s, &end, base);
|
||||||
|
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
|
||||||
|
std::cerr << "OVERFLOW" << std::endl;
|
||||||
|
return OVERFLOW;
|
||||||
|
}
|
||||||
|
if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
|
||||||
|
std::cerr << "UNDERFLOW" << std::endl;
|
||||||
|
return UNDERFLOW;
|
||||||
|
}
|
||||||
|
if (*s == '\0' || end == s) {
|
||||||
|
std::cerr << "INCONVERTIBLE: " << s << std::endl;
|
||||||
|
return INCONVERTIBLE;
|
||||||
|
}
|
||||||
|
i = l;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("Uage: %s <infile>.asc <outfile>.rgb\n\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *infile = argv[1];
|
||||||
|
const char *outfile = argv[2];
|
||||||
|
|
||||||
|
SGTexture texture(NCOLS, NROWS);
|
||||||
|
std::ifstream file(infile);
|
||||||
|
std::string str;
|
||||||
|
|
||||||
|
texture.prepare(NCOLS, NROWS);
|
||||||
|
texture.set_colors(1);
|
||||||
|
|
||||||
|
GLuint row = 0;
|
||||||
|
unsigned int line = 0;
|
||||||
|
while (std::getline(file, str))
|
||||||
|
{
|
||||||
|
GLuint col = 0;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
if (++line < 7) continue;
|
||||||
|
|
||||||
|
std::istringstream iss(str);
|
||||||
|
std::string token;
|
||||||
|
while (std::getline(iss, token, ' '))
|
||||||
|
{
|
||||||
|
if (str2int(num, token.c_str(), 10) == SUCCESS)
|
||||||
|
{
|
||||||
|
GLubyte val = (num == 32) ? 0 : 4*num;
|
||||||
|
texture.set_pixel(col++, NROWS-row, &val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture.write_texture(outfile);
|
||||||
|
}
|
289
utils/climate/colours.h
Normal file
289
utils/climate/colours.h
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
// colours.h -- This header file contains colour definitions in the
|
||||||
|
// same way as MS FS5 does
|
||||||
|
//
|
||||||
|
// Contributed by "Christian Mayer" <Vader@t-online.de>, started April 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Christian Mayer - Vader@t-online.de
|
||||||
|
//
|
||||||
|
// This program 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.
|
||||||
|
//
|
||||||
|
// This program 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 this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef COLOURS_H
|
||||||
|
#define COLOURS_H
|
||||||
|
|
||||||
|
unsigned char msfs_colour[256][3]=
|
||||||
|
{
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 8, 8, 8},
|
||||||
|
{ 16, 16, 16},
|
||||||
|
{ 24, 24, 24},
|
||||||
|
{ 32, 32, 32},
|
||||||
|
{ 40, 40, 40},
|
||||||
|
{ 48, 48, 48},
|
||||||
|
{ 56, 56, 56},
|
||||||
|
{ 65, 65, 65},
|
||||||
|
{ 73, 73, 73},
|
||||||
|
{ 81, 81, 81},
|
||||||
|
{ 89, 89, 89},
|
||||||
|
{ 97, 97, 97},
|
||||||
|
{105, 105, 105},
|
||||||
|
{113, 113, 113},
|
||||||
|
{121, 121, 121},
|
||||||
|
{130, 130, 130},
|
||||||
|
{138, 138, 138},
|
||||||
|
{146, 146, 146},
|
||||||
|
{154, 154, 154},
|
||||||
|
{162, 162, 162},
|
||||||
|
{170, 170, 170},
|
||||||
|
{178, 178, 178},
|
||||||
|
{186, 186, 186},
|
||||||
|
{195, 195, 195},
|
||||||
|
{203, 203, 203},
|
||||||
|
{211, 211, 211},
|
||||||
|
{219, 219, 219},
|
||||||
|
{227, 227, 227},
|
||||||
|
{235, 235, 235},
|
||||||
|
{247, 247, 247},
|
||||||
|
{255, 255, 255},
|
||||||
|
{ 21, 5, 5},
|
||||||
|
{ 42, 10, 10},
|
||||||
|
{ 63, 15, 15},
|
||||||
|
{ 84, 20, 20},
|
||||||
|
{105, 25, 25},
|
||||||
|
{126, 30, 30},
|
||||||
|
{147, 35, 35},
|
||||||
|
{168, 40, 40},
|
||||||
|
{189, 45, 45},
|
||||||
|
{210, 50, 50},
|
||||||
|
{231, 55, 55},
|
||||||
|
{252, 60, 60},
|
||||||
|
{ 5, 21, 5},
|
||||||
|
{ 10, 42, 10},
|
||||||
|
{ 15, 63, 15},
|
||||||
|
{ 20, 84, 20},
|
||||||
|
{ 25, 105, 25},
|
||||||
|
{ 30, 126, 30},
|
||||||
|
{ 35, 147, 35},
|
||||||
|
{ 40, 168, 40},
|
||||||
|
{ 45, 189, 45},
|
||||||
|
{ 50, 210, 50},
|
||||||
|
{ 55, 231, 55},
|
||||||
|
{ 60, 252, 60},
|
||||||
|
{ 0, 7, 23},
|
||||||
|
{ 0, 15, 40},
|
||||||
|
{ 0, 23, 58},
|
||||||
|
{ 0, 40, 84},
|
||||||
|
{ 0, 64, 104},
|
||||||
|
{ 0, 71, 122},
|
||||||
|
{ 0, 87, 143},
|
||||||
|
{ 0, 99, 156},
|
||||||
|
{ 0, 112, 179},
|
||||||
|
{ 0, 128, 199},
|
||||||
|
{ 0, 143, 215},
|
||||||
|
{ 0, 153, 230},
|
||||||
|
{ 28, 14, 0},
|
||||||
|
{ 56, 28, 0},
|
||||||
|
{ 84, 42, 0},
|
||||||
|
{112, 56, 0},
|
||||||
|
{140, 70, 0},
|
||||||
|
{168, 84, 0},
|
||||||
|
{196, 98, 0},
|
||||||
|
{224, 112, 0},
|
||||||
|
{252, 126, 0},
|
||||||
|
{ 28, 28, 0},
|
||||||
|
{ 56, 56, 0},
|
||||||
|
{ 84, 84, 0},
|
||||||
|
{112, 112, 0},
|
||||||
|
{140, 140, 0},
|
||||||
|
{168, 168, 0},
|
||||||
|
{196, 196, 0},
|
||||||
|
{224, 224, 0},
|
||||||
|
{252, 252, 0},
|
||||||
|
{ 25, 21, 16},
|
||||||
|
{ 50, 42, 32},
|
||||||
|
{ 75, 63, 48},
|
||||||
|
{100, 84, 64},
|
||||||
|
{125, 105, 80},
|
||||||
|
{150, 126, 96},
|
||||||
|
{175, 147, 112},
|
||||||
|
{200, 168, 128},
|
||||||
|
{225, 189, 144},
|
||||||
|
{ 28, 11, 7},
|
||||||
|
{ 56, 22, 14},
|
||||||
|
{ 84, 33, 21},
|
||||||
|
{112, 44, 28},
|
||||||
|
{140, 55, 35},
|
||||||
|
{168, 66, 42},
|
||||||
|
{196, 77, 49},
|
||||||
|
{224, 88, 56},
|
||||||
|
{252, 99, 63},
|
||||||
|
{ 17, 22, 9},
|
||||||
|
{ 34, 44, 18},
|
||||||
|
{ 51, 66, 27},
|
||||||
|
{ 68, 88, 36},
|
||||||
|
{ 85, 110, 45},
|
||||||
|
{102, 132, 54},
|
||||||
|
{119, 154, 63},
|
||||||
|
{136, 176, 72},
|
||||||
|
{153, 198, 81},
|
||||||
|
{ 0, 58, 104},
|
||||||
|
{ 0, 87, 112},
|
||||||
|
{ 43, 112, 128},
|
||||||
|
{255, 0, 0},
|
||||||
|
{ 64, 255, 64},
|
||||||
|
{ 0, 0, 192},
|
||||||
|
{ 0, 105, 105},
|
||||||
|
{255, 128, 0},
|
||||||
|
{255, 255, 0},
|
||||||
|
{ 81, 81, 81},
|
||||||
|
{121, 121, 121},
|
||||||
|
{146, 146, 146},
|
||||||
|
{170, 170, 170},
|
||||||
|
{195, 195, 195},
|
||||||
|
{227, 227, 227},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{ 0, 0, 0},
|
||||||
|
{192, 192, 255},
|
||||||
|
{200, 200, 255},
|
||||||
|
{208, 208, 255},
|
||||||
|
{216, 216, 255},
|
||||||
|
{224, 224, 255},
|
||||||
|
{232, 232, 255},
|
||||||
|
{240, 240, 255},
|
||||||
|
{248, 248, 255},
|
||||||
|
{255, 255, 255},
|
||||||
|
{255, 255, 255},
|
||||||
|
{255, 255, 255},
|
||||||
|
{255, 255, 255},
|
||||||
|
{255, 255, 255},
|
||||||
|
{255, 255, 255},
|
||||||
|
{255, 255, 255},
|
||||||
|
{255, 255, 255},
|
||||||
|
{ 16, 72, 16},
|
||||||
|
{ 32, 80, 32},
|
||||||
|
{ 48, 88, 48},
|
||||||
|
{ 64, 96, 64},
|
||||||
|
{ 80, 104, 80},
|
||||||
|
{ 96, 112, 96},
|
||||||
|
{112, 120, 112},
|
||||||
|
{120, 124, 120},
|
||||||
|
{128, 128, 128},
|
||||||
|
{128, 128, 128},
|
||||||
|
{128, 128, 128},
|
||||||
|
{128, 128, 128},
|
||||||
|
{128, 128, 128},
|
||||||
|
{128, 128, 128},
|
||||||
|
{128, 128, 128},
|
||||||
|
{128, 128, 128},
|
||||||
|
{ 33, 140, 189},
|
||||||
|
{ 57, 132, 165},
|
||||||
|
{189, 66, 66},
|
||||||
|
{156, 66, 66},
|
||||||
|
{132, 74, 74},
|
||||||
|
{ 33, 82, 107},
|
||||||
|
{214, 90, 82},
|
||||||
|
{189, 90, 82},
|
||||||
|
{165, 90, 82},
|
||||||
|
{123, 57, 49},
|
||||||
|
{ 99, 57, 49},
|
||||||
|
{107, 74, 66},
|
||||||
|
{123, 90, 82},
|
||||||
|
{181, 90, 66},
|
||||||
|
{ 74, 49, 41},
|
||||||
|
{189, 115, 90},
|
||||||
|
{140, 90, 49},
|
||||||
|
{ 33, 49, 74},
|
||||||
|
{181, 115, 49},
|
||||||
|
{ 99, 66, 33},
|
||||||
|
{165, 115, 66},
|
||||||
|
{ 49, 41, 33},
|
||||||
|
{165, 140, 115},
|
||||||
|
{189, 165, 140},
|
||||||
|
{ 57, 99, 123},
|
||||||
|
{181, 107, 24},
|
||||||
|
{206, 123, 33},
|
||||||
|
{156, 99, 33},
|
||||||
|
{148, 107, 49},
|
||||||
|
{107, 82, 49},
|
||||||
|
{ 33, 33, 57},
|
||||||
|
{ 33, 115, 165},
|
||||||
|
{214, 214, 33},
|
||||||
|
{173, 173, 33},
|
||||||
|
{198, 198, 41},
|
||||||
|
{140, 140, 33},
|
||||||
|
{115, 115, 33},
|
||||||
|
{189, 189, 57},
|
||||||
|
{156, 156, 49},
|
||||||
|
{173, 173, 57},
|
||||||
|
{123, 123, 49},
|
||||||
|
{123, 123, 66},
|
||||||
|
{ 74, 74, 49},
|
||||||
|
{123, 123, 90},
|
||||||
|
{ 41, 41, 33},
|
||||||
|
{ 90, 99, 57},
|
||||||
|
{107, 115, 74},
|
||||||
|
{123, 148, 82},
|
||||||
|
{140, 173, 99},
|
||||||
|
{132, 156, 99},
|
||||||
|
{ 49, 66, 41},
|
||||||
|
{ 99, 165, 90},
|
||||||
|
{ 74, 214, 74},
|
||||||
|
{ 57, 140, 57},
|
||||||
|
{ 74, 181, 74},
|
||||||
|
{ 90, 198, 90},
|
||||||
|
{ 57, 123, 57},
|
||||||
|
{ 49, 99, 49},
|
||||||
|
{ 90, 165, 90},
|
||||||
|
{ 82, 148, 82},
|
||||||
|
{ 74, 99, 74},
|
||||||
|
{ 57, 115, 132},
|
||||||
|
{ 33, 99, 123},
|
||||||
|
{ 74, 115, 132}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
970
utils/climate/texture.cxx
Normal file
970
utils/climate/texture.cxx
Normal file
|
@ -0,0 +1,970 @@
|
||||||
|
/*
|
||||||
|
* Texture manipulation routines
|
||||||
|
*
|
||||||
|
* Copyright (c) Mark J. Kilgard, 1997.
|
||||||
|
* Code added in april 2003 by Erik Hofman
|
||||||
|
*
|
||||||
|
* This program is freely distributable without licensing fees
|
||||||
|
* and is provided without guarantee or warrantee expressed or
|
||||||
|
* implied. This program is -not- in the public domain.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <osg/Matrixf>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "texture.hxx"
|
||||||
|
#include "colours.h"
|
||||||
|
|
||||||
|
|
||||||
|
const char *FILE_OPEN_ERROR = "Unable to open file.";
|
||||||
|
const char *WRONG_COUNT = "Unsupported number of color channels.";
|
||||||
|
const char *NO_TEXTURE = "No texture data resident.";
|
||||||
|
const char *OUT_OF_MEMORY = "Out of memory.";
|
||||||
|
|
||||||
|
|
||||||
|
SGTexture::SGTexture()
|
||||||
|
: texture_id(0),
|
||||||
|
texture_data(0),
|
||||||
|
num_colors(3),
|
||||||
|
file(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SGTexture::SGTexture(unsigned int width, unsigned int height)
|
||||||
|
: texture_id(0),
|
||||||
|
errstr("")
|
||||||
|
{
|
||||||
|
texture_data = new GLubyte[ width * height * 3 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
SGTexture::~SGTexture()
|
||||||
|
{
|
||||||
|
delete[] texture_data;
|
||||||
|
|
||||||
|
if ( texture_id != 0 ) {
|
||||||
|
free_id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::bind()
|
||||||
|
{
|
||||||
|
bool gen = false;
|
||||||
|
if (!texture_id) {
|
||||||
|
#ifdef GL_VERSION_1_1
|
||||||
|
glGenTextures(1, &texture_id);
|
||||||
|
|
||||||
|
#elif GL_EXT_texture_object
|
||||||
|
glGenTexturesEXT(1, &texture_id);
|
||||||
|
#endif
|
||||||
|
gen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GL_VERSION_1_1
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||||
|
|
||||||
|
#elif GL_EXT_texture_object
|
||||||
|
glBindTextureEXT(GL_TEXTURE_2D, texture_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (gen) {
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to resize the OpenGL window which will be used by
|
||||||
|
* the dynamic texture generating routines.
|
||||||
|
*
|
||||||
|
* @param width The width of the new window
|
||||||
|
* @param height The height of the new window
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
SGTexture::resize(unsigned int width, unsigned int height)
|
||||||
|
{
|
||||||
|
using namespace osg;
|
||||||
|
GLfloat aspect;
|
||||||
|
|
||||||
|
// Make sure that we don't get a divide by zero exception
|
||||||
|
if (height == 0)
|
||||||
|
height = 1;
|
||||||
|
|
||||||
|
// Set the viewport for the OpenGL window
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
|
||||||
|
// Calculate the aspect ratio of the window
|
||||||
|
aspect = width/height;
|
||||||
|
|
||||||
|
// Go to the projection matrix, this gets modified by the perspective
|
||||||
|
// calulations
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
|
||||||
|
// Do the perspective calculations
|
||||||
|
Matrixf proj = Matrixf::perspective(45.0, aspect, 1.0, 400.0);
|
||||||
|
glLoadMatrix(proj.ptr());
|
||||||
|
|
||||||
|
// Return to the modelview matrix
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to prepare the OpenGL state machine for dynamic
|
||||||
|
* texture generation.
|
||||||
|
*
|
||||||
|
* @param width The width of the texture
|
||||||
|
* @param height The height of the texture
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
SGTexture::prepare(unsigned int width, unsigned int height) {
|
||||||
|
|
||||||
|
texture_width = width;
|
||||||
|
texture_height = height;
|
||||||
|
|
||||||
|
// Resize the OpenGL window to the size of our dynamic texture
|
||||||
|
resize(texture_width, texture_height);
|
||||||
|
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to generate the dynamic texture.
|
||||||
|
*
|
||||||
|
* The actual texture can be accessed by calling get_texture()
|
||||||
|
*
|
||||||
|
* @param width The width of the previous OpenGL window
|
||||||
|
* @param height The height of the previous OpenGL window
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
SGTexture::finish(unsigned int width, unsigned int height) {
|
||||||
|
// If a texture hasn't been created then it gets created, and the contents
|
||||||
|
// of the frame buffer gets copied into it. If the texture has already been
|
||||||
|
// created then its contents just get updated.
|
||||||
|
bind();
|
||||||
|
if (!texture_data)
|
||||||
|
{
|
||||||
|
// Copies the contents of the frame buffer into the texture
|
||||||
|
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0,
|
||||||
|
texture_width, texture_height, 0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Copies the contents of the frame buffer into the texture
|
||||||
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
|
||||||
|
texture_width, texture_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the OpenGL window back to its previous size
|
||||||
|
resize(width, height);
|
||||||
|
|
||||||
|
// Clear the window back to black
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::read_alpha_texture(const char *name)
|
||||||
|
{
|
||||||
|
GLubyte *lptr;
|
||||||
|
SGTexture::ImageRec *image;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
delete[] texture_data;
|
||||||
|
|
||||||
|
image = ImageOpen(name);
|
||||||
|
if(!image) {
|
||||||
|
errstr = FILE_OPEN_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_width = image->xsize;
|
||||||
|
texture_height = image->ysize;
|
||||||
|
|
||||||
|
// printf("image->zsize = %d\n", image->zsize);
|
||||||
|
|
||||||
|
if (image->zsize != 1) {
|
||||||
|
ImageClose(image);
|
||||||
|
errstr = WRONG_COUNT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_data = new GLubyte[ image->xsize * image->ysize ];
|
||||||
|
num_colors = 1;
|
||||||
|
if (!texture_data) {
|
||||||
|
errstr = NO_TEXTURE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lptr = texture_data;
|
||||||
|
for(y=0; y<image->ysize; y++) {
|
||||||
|
ImageGetRow(image,lptr,y,0);
|
||||||
|
lptr += image->xsize;
|
||||||
|
}
|
||||||
|
ImageClose(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::read_rgb_texture(const char *name)
|
||||||
|
{
|
||||||
|
GLubyte *ptr;
|
||||||
|
GLubyte *rbuf, *gbuf, *bbuf;
|
||||||
|
SGTexture::ImageRec *image;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
delete[] texture_data;
|
||||||
|
|
||||||
|
image = ImageOpen(name);
|
||||||
|
if(!image) {
|
||||||
|
errstr = FILE_OPEN_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_width = image->xsize;
|
||||||
|
texture_height = image->ysize;
|
||||||
|
if (image->zsize < 1 || image->zsize > 4) {
|
||||||
|
ImageClose(image);
|
||||||
|
errstr = WRONG_COUNT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_colors = 3;
|
||||||
|
texture_data = new GLubyte[ image->xsize * image->ysize * num_colors ];
|
||||||
|
rbuf = new GLubyte[ image->xsize ];
|
||||||
|
gbuf = new GLubyte[ image->xsize ];
|
||||||
|
bbuf = new GLubyte[ image->xsize ];
|
||||||
|
if(!texture_data || !rbuf || !gbuf || !bbuf) {
|
||||||
|
delete[] texture_data;
|
||||||
|
delete[] rbuf;
|
||||||
|
delete[] gbuf;
|
||||||
|
delete[] bbuf;
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = texture_data;
|
||||||
|
for(y=0; y<image->ysize; y++) {
|
||||||
|
if(image->zsize == 4 || image->zsize == 3) {
|
||||||
|
ImageGetRow(image,rbuf,y,0);
|
||||||
|
ImageGetRow(image,gbuf,y,1);
|
||||||
|
ImageGetRow(image,bbuf,y,2);
|
||||||
|
} else {
|
||||||
|
ImageGetRow(image,rbuf,y,0);
|
||||||
|
memcpy(gbuf,rbuf,image->xsize);
|
||||||
|
memcpy(bbuf,rbuf,image->xsize);
|
||||||
|
}
|
||||||
|
rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
|
||||||
|
ptr += (image->xsize * num_colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageClose(image);
|
||||||
|
delete[] rbuf;
|
||||||
|
delete[] gbuf;
|
||||||
|
delete[] bbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::read_rgba_texture(const char *name)
|
||||||
|
{
|
||||||
|
GLubyte *ptr;
|
||||||
|
GLubyte *rbuf, *gbuf, *bbuf, *abuf;
|
||||||
|
SGTexture::ImageRec *image;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
delete[] texture_data;
|
||||||
|
|
||||||
|
image = ImageOpen(name);
|
||||||
|
if(!image) {
|
||||||
|
errstr = FILE_OPEN_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_width = image->xsize;
|
||||||
|
texture_height = image->ysize;
|
||||||
|
if (image->zsize < 1 || image->zsize > 4) {
|
||||||
|
ImageClose(image);
|
||||||
|
errstr = WRONG_COUNT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_colors = 4;
|
||||||
|
texture_data = new GLubyte[ image->xsize * image->ysize * num_colors ];
|
||||||
|
rbuf = new GLubyte[ image->xsize ];
|
||||||
|
gbuf = new GLubyte[ image->xsize ];
|
||||||
|
bbuf = new GLubyte[ image->xsize ];
|
||||||
|
abuf = new GLubyte[ image->xsize ];
|
||||||
|
if(!texture_data || !rbuf || !gbuf || !bbuf || !abuf) {
|
||||||
|
delete[] texture_data;
|
||||||
|
delete[] rbuf;
|
||||||
|
delete[] gbuf;
|
||||||
|
delete[] bbuf;
|
||||||
|
delete[] abuf;
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = texture_data;
|
||||||
|
for(y=0; y<image->ysize; y++) {
|
||||||
|
if(image->zsize == 4) {
|
||||||
|
ImageGetRow(image,rbuf,y,0);
|
||||||
|
ImageGetRow(image,gbuf,y,1);
|
||||||
|
ImageGetRow(image,bbuf,y,2);
|
||||||
|
ImageGetRow(image,abuf,y,3);
|
||||||
|
} else if(image->zsize == 3) {
|
||||||
|
ImageGetRow(image,rbuf,y,0);
|
||||||
|
ImageGetRow(image,gbuf,y,1);
|
||||||
|
ImageGetRow(image,bbuf,y,2);
|
||||||
|
memset(abuf, 255, image->xsize);
|
||||||
|
} else if(image->zsize == 2) {
|
||||||
|
ImageGetRow(image,rbuf,y,0);
|
||||||
|
memcpy(gbuf,rbuf,image->xsize);
|
||||||
|
memcpy(bbuf,rbuf,image->xsize);
|
||||||
|
ImageGetRow(image,abuf,y,1);
|
||||||
|
} else {
|
||||||
|
ImageGetRow(image,rbuf,y,0);
|
||||||
|
memcpy(gbuf,rbuf,image->xsize);
|
||||||
|
memcpy(bbuf,rbuf,image->xsize);
|
||||||
|
memset(abuf, 255, image->xsize);
|
||||||
|
}
|
||||||
|
rgbatorgba(rbuf,gbuf,bbuf,abuf,ptr,image->xsize);
|
||||||
|
ptr += (image->xsize * num_colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageClose(image);
|
||||||
|
delete[] rbuf;
|
||||||
|
delete[] gbuf;
|
||||||
|
delete[] bbuf;
|
||||||
|
delete[] abuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::read_raw_texture(const char *name)
|
||||||
|
{
|
||||||
|
GLubyte *ptr;
|
||||||
|
SGTexture::ImageRec *image;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
delete[] texture_data;
|
||||||
|
|
||||||
|
image = RawImageOpen(name);
|
||||||
|
|
||||||
|
if(!image) {
|
||||||
|
errstr = FILE_OPEN_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_width = 256;
|
||||||
|
texture_height = 256;
|
||||||
|
|
||||||
|
texture_data = new GLubyte[ 256 * 256 * 3 ];
|
||||||
|
if(!texture_data) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = texture_data;
|
||||||
|
for(y=0; y<256; y++) {
|
||||||
|
gzread(image->file, ptr, 256*3);
|
||||||
|
ptr+=256*3;
|
||||||
|
}
|
||||||
|
ImageClose(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::read_r8_texture(const char *name)
|
||||||
|
{
|
||||||
|
unsigned char c[1];
|
||||||
|
GLubyte *ptr;
|
||||||
|
SGTexture::ImageRec *image;
|
||||||
|
int xy;
|
||||||
|
|
||||||
|
delete[] texture_data;
|
||||||
|
|
||||||
|
//it wouldn't make sense to write a new function ...
|
||||||
|
image = RawImageOpen(name);
|
||||||
|
|
||||||
|
if(!image) {
|
||||||
|
errstr = FILE_OPEN_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_width = 256;
|
||||||
|
texture_height = 256;
|
||||||
|
|
||||||
|
texture_data = new GLubyte [ 256 * 256 * 3 ];
|
||||||
|
if(!texture_data) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = texture_data;
|
||||||
|
for(xy=0; xy<(256*256); xy++) {
|
||||||
|
gzread(image->file, c, 1);
|
||||||
|
|
||||||
|
//look in the table for the right colours
|
||||||
|
ptr[0]=msfs_colour[c[0]][0];
|
||||||
|
ptr[1]=msfs_colour[c[0]][1];
|
||||||
|
ptr[2]=msfs_colour[c[0]][2];
|
||||||
|
|
||||||
|
ptr+=3;
|
||||||
|
}
|
||||||
|
ImageClose(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::write_texture(const char *name) {
|
||||||
|
SGTexture::ImageRec *image = ImageWriteOpen(name);
|
||||||
|
|
||||||
|
printf("colors: %i, height: %i, width: %i\n", num_colors, texture_height, texture_width);
|
||||||
|
for (int c=0; c<num_colors; c++) {
|
||||||
|
GLubyte *ptr = texture_data + c;
|
||||||
|
for (int y=0; y<texture_height; y++) {
|
||||||
|
for (int x=0; x<texture_width; x++) {
|
||||||
|
image->tmp[x]=*ptr;
|
||||||
|
ptr = ptr + num_colors;
|
||||||
|
}
|
||||||
|
fwrite(image->tmp, 1, texture_width, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageClose(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::set_pixel(GLuint x, GLuint y, GLubyte *c)
|
||||||
|
{
|
||||||
|
if (!texture_data) {
|
||||||
|
errstr = NO_TEXTURE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int pos = (x + y*texture_width) * num_colors;
|
||||||
|
memcpy(texture_data+pos, c, num_colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLubyte *
|
||||||
|
SGTexture::get_pixel(GLuint x, GLuint y)
|
||||||
|
{
|
||||||
|
static GLubyte c[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
if (!texture_data) {
|
||||||
|
errstr = NO_TEXTURE;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int pos = (x + y*texture_width)*num_colors;
|
||||||
|
memcpy(c, texture_data + pos, num_colors);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGTexture::ImageRec *
|
||||||
|
SGTexture::ImageOpen(const char *fileName)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
int testWord;
|
||||||
|
char testByte[4];
|
||||||
|
} endianTest;
|
||||||
|
|
||||||
|
SGTexture::ImageRec *image;
|
||||||
|
int swapFlag;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
endianTest.testWord = 1;
|
||||||
|
if (endianTest.testByte[0] == 1) {
|
||||||
|
swapFlag = 1;
|
||||||
|
} else {
|
||||||
|
swapFlag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = new SGTexture::ImageRec;
|
||||||
|
memset(image, 0, sizeof(SGTexture::ImageRec));
|
||||||
|
if (image == 0) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((image->file = gzopen(fileName, "rb")) == 0) {
|
||||||
|
errstr = FILE_OPEN_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gzread(image->file, image, 12);
|
||||||
|
|
||||||
|
if (swapFlag) {
|
||||||
|
ConvertShort(&image->imagic, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
image->tmp = new GLubyte[ image->xsize * 256 ];
|
||||||
|
if (image->tmp == 0) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((image->type & 0xFF00) == 0x0100) {
|
||||||
|
x = image->ysize * image->zsize * (int) sizeof(unsigned);
|
||||||
|
image->rowStart = new unsigned[x];
|
||||||
|
image->rowSize = new int[x];
|
||||||
|
if (image->rowStart == 0 || image->rowSize == 0) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
image->rleEnd = 512 + (2 * x);
|
||||||
|
gzseek(image->file, 512, SEEK_SET);
|
||||||
|
gzread(image->file, image->rowStart, x);
|
||||||
|
gzread(image->file, image->rowSize, x);
|
||||||
|
if (swapFlag) {
|
||||||
|
ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
|
||||||
|
ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::ImageClose(SGTexture::ImageRec *image) {
|
||||||
|
if (image->file) gzclose(image->file);
|
||||||
|
if (file) fclose(file);
|
||||||
|
delete[] image->tmp;
|
||||||
|
delete[] image->rowStart;
|
||||||
|
delete[] image->rowSize;
|
||||||
|
delete image;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGTexture::ImageRec *
|
||||||
|
SGTexture::RawImageOpen(const char *fileName)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
int testWord;
|
||||||
|
char testByte[4];
|
||||||
|
} endianTest;
|
||||||
|
|
||||||
|
SGTexture::ImageRec *image;
|
||||||
|
int swapFlag;
|
||||||
|
|
||||||
|
endianTest.testWord = 1;
|
||||||
|
if (endianTest.testByte[0] == 1) {
|
||||||
|
swapFlag = 1;
|
||||||
|
} else {
|
||||||
|
swapFlag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = new SGTexture::ImageRec;
|
||||||
|
memset(image, 0, sizeof(SGTexture::ImageRec));
|
||||||
|
if (image == 0) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((image->file = gzopen(fileName, "rb")) == 0) {
|
||||||
|
errstr = FILE_OPEN_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gzread(image->file, image, 12);
|
||||||
|
|
||||||
|
if (swapFlag) {
|
||||||
|
ConvertShort(&image->imagic, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//just allocate a pseudo value as I'm too lazy to change ImageClose()...
|
||||||
|
image->tmp = new GLubyte[1];
|
||||||
|
|
||||||
|
if (image->tmp == 0) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGTexture::ImageRec *
|
||||||
|
SGTexture::ImageWriteOpen(const char *fileName)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
int testWord;
|
||||||
|
char testByte[4];
|
||||||
|
} endianTest;
|
||||||
|
ImageRec* image;
|
||||||
|
int swapFlag;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
endianTest.testWord = 1;
|
||||||
|
if (endianTest.testByte[0] == 1) {
|
||||||
|
swapFlag = 1;
|
||||||
|
} else {
|
||||||
|
swapFlag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = new SGTexture::ImageRec;
|
||||||
|
memset(image, 0, sizeof(SGTexture::ImageRec));
|
||||||
|
if (image == 0) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((file = fopen(fileName, "wb")) == 0) {
|
||||||
|
errstr = FILE_OPEN_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
image->imagic = 474;
|
||||||
|
image->type = 0x0001;
|
||||||
|
image->dim = (num_colors > 1) ? 3 : 2;
|
||||||
|
image->xsize = texture_width;
|
||||||
|
image->ysize = texture_height;
|
||||||
|
image->zsize = num_colors;
|
||||||
|
|
||||||
|
if (swapFlag) {
|
||||||
|
ConvertShort(&image->imagic, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(image, 1, 12, file);
|
||||||
|
fseek(file, 512, SEEK_SET);
|
||||||
|
|
||||||
|
image->tmp = new GLubyte[ image->xsize * 256 ];
|
||||||
|
if (image->tmp == 0) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((image->type & 0xFF00) == 0x0100) {
|
||||||
|
x = image->ysize * image->zsize * (int) sizeof(unsigned);
|
||||||
|
image->rowStart = new unsigned[x];
|
||||||
|
image->rowSize = new int[x];
|
||||||
|
if (image->rowStart == 0 || image->rowSize == 0) {
|
||||||
|
errstr = OUT_OF_MEMORY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
image->rleEnd = 512 + (2 * x);
|
||||||
|
fseek(file, 512, SEEK_SET);
|
||||||
|
fread(image->rowStart, 1, x, file);
|
||||||
|
fread(image->rowSize, 1, x, file);
|
||||||
|
if (swapFlag) {
|
||||||
|
ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
|
||||||
|
ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
|
||||||
|
GLubyte *iPtr, *oPtr, pixel;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if ((image->type & 0xFF00) == 0x0100) {
|
||||||
|
gzseek(image->file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
|
||||||
|
int size = image->rowSize[y+z*image->ysize];
|
||||||
|
gzread(image->file, image->tmp, size);
|
||||||
|
|
||||||
|
iPtr = image->tmp;
|
||||||
|
oPtr = buf;
|
||||||
|
for (GLubyte *limit = iPtr + size; iPtr < limit;) {
|
||||||
|
pixel = *iPtr++;
|
||||||
|
count = (int)(pixel & 0x7F);
|
||||||
|
if (!count) {
|
||||||
|
errstr = WRONG_COUNT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pixel & 0x80) {
|
||||||
|
while (iPtr < limit && count--) {
|
||||||
|
*oPtr++ = *iPtr++;
|
||||||
|
}
|
||||||
|
} else if (iPtr < limit) {
|
||||||
|
pixel = *iPtr++;
|
||||||
|
while (count--) {
|
||||||
|
*oPtr++ = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gzseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
|
||||||
|
SEEK_SET);
|
||||||
|
gzread(image->file, buf, image->xsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::ImagePutRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
|
||||||
|
GLubyte *iPtr, *oPtr, pixel;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if ((image->type & 0xFF00) == 0x0100) {
|
||||||
|
fseek(file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
|
||||||
|
fread( image->tmp, 1, (unsigned int)image->rowSize[y+z*image->ysize],
|
||||||
|
file);
|
||||||
|
|
||||||
|
iPtr = image->tmp;
|
||||||
|
oPtr = buf;
|
||||||
|
for (;;) {
|
||||||
|
pixel = *iPtr++;
|
||||||
|
count = (int)(pixel & 0x7F);
|
||||||
|
if (!count) {
|
||||||
|
errstr = WRONG_COUNT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pixel & 0x80) {
|
||||||
|
while (count--) {
|
||||||
|
*oPtr++ = *iPtr++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pixel = *iPtr++;
|
||||||
|
while (count--) {
|
||||||
|
*oPtr++ = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fseek(file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
|
||||||
|
SEEK_SET);
|
||||||
|
fread(buf, 1, image->xsize, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::rgbtorgb(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *l, int n) {
|
||||||
|
while(n--) {
|
||||||
|
l[0] = r[0];
|
||||||
|
l[1] = g[0];
|
||||||
|
l[2] = b[0];
|
||||||
|
l += 3; r++; g++; b++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::rgbatorgba(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *a,
|
||||||
|
GLubyte *l, int n) {
|
||||||
|
while(n--) {
|
||||||
|
l[0] = r[0];
|
||||||
|
l[1] = g[0];
|
||||||
|
l[2] = b[0];
|
||||||
|
l[3] = a[0];
|
||||||
|
l += 4; r++; g++; b++; a++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::ConvertShort(unsigned short *array, unsigned int length) {
|
||||||
|
unsigned short b1, b2;
|
||||||
|
unsigned char *ptr;
|
||||||
|
|
||||||
|
ptr = (unsigned char *)array;
|
||||||
|
while (length--) {
|
||||||
|
b1 = *ptr++;
|
||||||
|
b2 = *ptr++;
|
||||||
|
*array++ = (b1 << 8) | (b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::ConvertUint(unsigned *array, unsigned int length) {
|
||||||
|
unsigned int b1, b2, b3, b4;
|
||||||
|
unsigned char *ptr;
|
||||||
|
|
||||||
|
ptr = (unsigned char *)array;
|
||||||
|
while (length--) {
|
||||||
|
b1 = *ptr++;
|
||||||
|
b2 = *ptr++;
|
||||||
|
b3 = *ptr++;
|
||||||
|
b4 = *ptr++;
|
||||||
|
*array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::make_monochrome(float contrast, GLubyte r, GLubyte g, GLubyte b) {
|
||||||
|
|
||||||
|
if (num_colors >= 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GLubyte ap[3];
|
||||||
|
for (int y=0; y<texture_height; y++)
|
||||||
|
for (int x=0; x<texture_width; x++)
|
||||||
|
{
|
||||||
|
GLubyte *rgb = get_pixel(x,y);
|
||||||
|
GLubyte avg = (rgb[0] + rgb[1] + rgb[2]) / 3;
|
||||||
|
|
||||||
|
if (contrast != 1.0) {
|
||||||
|
float pixcol = -1.0 + (avg/128);
|
||||||
|
avg = 128 + int(128*pow(pixcol, contrast));
|
||||||
|
}
|
||||||
|
|
||||||
|
ap[0] = avg*r/255;
|
||||||
|
ap[1] = avg*g/255;
|
||||||
|
ap[2] = avg*b/255;
|
||||||
|
|
||||||
|
set_pixel(x,y,ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::make_grayscale(float contrast) {
|
||||||
|
if (num_colors < 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int colors = (num_colors == 3) ? 1 : 2;
|
||||||
|
GLubyte *map = new GLubyte[ texture_width * texture_height * colors ];
|
||||||
|
|
||||||
|
for (int y=0; y<texture_height; y++)
|
||||||
|
for (int x=0; x<texture_width; x++)
|
||||||
|
{
|
||||||
|
GLubyte *rgb = get_pixel(x,y);
|
||||||
|
GLubyte avg = (rgb[0] + rgb[1] + rgb[2]) / 3;
|
||||||
|
|
||||||
|
if (contrast != 1.0) {
|
||||||
|
float pixcol = -1.0 + (avg/128);
|
||||||
|
avg = 128 + int(128*pow(pixcol, contrast));
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = (x + y*texture_width)*colors;
|
||||||
|
map[pos] = avg;
|
||||||
|
if (colors > 1)
|
||||||
|
map[pos+1] = rgb[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] texture_data;
|
||||||
|
texture_data = map;
|
||||||
|
num_colors = colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::make_maxcolorwindow() {
|
||||||
|
GLubyte minmaxc[2] = {255, 0};
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
int max = num_colors;
|
||||||
|
if (num_colors == 2) max = 1;
|
||||||
|
if (num_colors == 4) max = 3;
|
||||||
|
while (pos < texture_width * texture_height * num_colors) {
|
||||||
|
for (int i=0; i < max; i++) {
|
||||||
|
GLubyte c = texture_data[pos+i];
|
||||||
|
if (c < minmaxc[0]) minmaxc[0] = c;
|
||||||
|
if (c > minmaxc[1]) minmaxc[1] = c;
|
||||||
|
}
|
||||||
|
pos += num_colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLubyte offs = minmaxc[0];
|
||||||
|
float factor = 255.0 / float(minmaxc[1] - minmaxc[0]);
|
||||||
|
// printf("Min: %i, Max: %i, Factor: %f\n", offs, minmaxc[1], factor);
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while (pos < texture_width * texture_height * num_colors) {
|
||||||
|
for (int i=0; i < max; i++) {
|
||||||
|
texture_data[pos+i] -= offs;
|
||||||
|
texture_data[pos+i] = int(factor * texture_data[pos+i]);
|
||||||
|
}
|
||||||
|
pos += num_colors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::make_normalmap(float brightness, float contrast) {
|
||||||
|
make_grayscale(contrast);
|
||||||
|
make_maxcolorwindow();
|
||||||
|
|
||||||
|
int colors = (num_colors == 1) ? 3 : 4;
|
||||||
|
bool alpha = (colors > 3);
|
||||||
|
int tsize = texture_width * texture_height * colors;
|
||||||
|
GLubyte *map = new GLubyte[ tsize ];
|
||||||
|
|
||||||
|
int mpos = 0, dpos = 0;
|
||||||
|
for (int y=0; y<texture_height; y++) {
|
||||||
|
int ytw = y*texture_width;
|
||||||
|
|
||||||
|
for (int x=0; x<texture_width; x++)
|
||||||
|
{
|
||||||
|
int xp1 = (x < (texture_width-1)) ? x+1 : 0;
|
||||||
|
int yp1 = (y < (texture_height-1)) ? y+1 : 0;
|
||||||
|
int posxp1 = (xp1 + ytw)*num_colors;
|
||||||
|
int posyp1 = (x + yp1*texture_width)*num_colors;
|
||||||
|
float fx,fy;
|
||||||
|
|
||||||
|
GLubyte c = texture_data[dpos];
|
||||||
|
GLubyte cx1 = texture_data[posxp1];
|
||||||
|
GLubyte cy1 = texture_data[posyp1];
|
||||||
|
|
||||||
|
if (alpha) {
|
||||||
|
GLubyte a = texture_data[dpos+1];
|
||||||
|
GLubyte ax1 = texture_data[posxp1+1];
|
||||||
|
GLubyte ay1 = texture_data[posyp1+1];
|
||||||
|
|
||||||
|
c = (c + a)/2;
|
||||||
|
cx1 = (cx1 + ax1)/2;
|
||||||
|
cy1 = (cy1 + ay1)/2;
|
||||||
|
|
||||||
|
map[mpos+3] = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx = asin((c/256.0-cx1/256.0))/1.57079633;
|
||||||
|
fy = asin((cy1/256.0-c/256.0))/1.57079633;
|
||||||
|
|
||||||
|
map[mpos+0] = (GLuint)(fx*256.0)-128;
|
||||||
|
map[mpos+1] = (GLuint)(fy*256.0)-128;
|
||||||
|
map[mpos+2] = 127+int(brightness*128); // 255-c/2;
|
||||||
|
|
||||||
|
mpos += colors;
|
||||||
|
dpos += num_colors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] texture_data;
|
||||||
|
texture_data = map;
|
||||||
|
num_colors = colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGTexture::make_bumpmap(float brightness, float contrast) {
|
||||||
|
make_grayscale(contrast);
|
||||||
|
|
||||||
|
int colors = (num_colors == 1) ? 1 : 2;
|
||||||
|
GLubyte *map = new GLubyte[ texture_width * texture_height * colors ];
|
||||||
|
|
||||||
|
for (int y=0; y<texture_height; y++)
|
||||||
|
for (int x=0; x<texture_width; x++)
|
||||||
|
{
|
||||||
|
int mpos = (x + y*texture_width)*colors;
|
||||||
|
int dpos = (x + y*texture_width)*num_colors;
|
||||||
|
|
||||||
|
int xp1 = (x < (texture_width-1)) ? x+1 : 0;
|
||||||
|
int yp1 = (y < (texture_height-1)) ? y+1 : 0;
|
||||||
|
int posxp1 = (xp1 + y*texture_width)*num_colors;
|
||||||
|
int posyp1 = (x + yp1*texture_width)*num_colors;
|
||||||
|
|
||||||
|
map[mpos] = (127 - ((texture_data[dpos]-texture_data[posxp1]) -
|
||||||
|
((texture_data[dpos]-texture_data[posyp1]))/4))/2;
|
||||||
|
if (colors > 1)
|
||||||
|
map[mpos+1] = texture_data[dpos+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] texture_data;
|
||||||
|
texture_data = map;
|
||||||
|
num_colors = colors;
|
||||||
|
}
|
||||||
|
|
153
utils/climate/texture.hxx
Normal file
153
utils/climate/texture.hxx
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* \file texture.hxx
|
||||||
|
* Texture manipulation routines
|
||||||
|
*
|
||||||
|
* Copyright (c) Mark J. Kilgard, 1997.
|
||||||
|
* Code added in april 2003 by Erik Hofman
|
||||||
|
*
|
||||||
|
* This program is freely distributable without licensing fees
|
||||||
|
* and is provided without guarantee or warrantee expressed or
|
||||||
|
* implied. This program is -not- in the public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SG_TEXTURE_HXX
|
||||||
|
#define __SG_TEXTURE_HXX 1
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <osg/GL>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include <plib/sg.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to encapsulate all the info surrounding an OpenGL texture
|
||||||
|
* and also query various info and load various file formats
|
||||||
|
*/
|
||||||
|
class SGTexture {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
GLuint texture_id;
|
||||||
|
GLubyte *texture_data;
|
||||||
|
|
||||||
|
GLsizei texture_width;
|
||||||
|
GLsizei texture_height;
|
||||||
|
GLsizei num_colors;
|
||||||
|
|
||||||
|
void resize(unsigned int width = 256, unsigned int height = 256);
|
||||||
|
|
||||||
|
const char *errstr;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
FILE *file;
|
||||||
|
typedef struct _ImageRec {
|
||||||
|
_ImageRec(void) : tmp(0), rowStart(0), rowSize(0) {}
|
||||||
|
unsigned short imagic;
|
||||||
|
unsigned short type;
|
||||||
|
unsigned short dim;
|
||||||
|
unsigned short xsize, ysize, zsize;
|
||||||
|
unsigned int min, max;
|
||||||
|
unsigned int wasteBytes;
|
||||||
|
char name[80];
|
||||||
|
unsigned long colorMap;
|
||||||
|
gzFile file;
|
||||||
|
GLubyte *tmp;
|
||||||
|
unsigned long rleEnd;
|
||||||
|
unsigned int *rowStart;
|
||||||
|
int *rowSize;
|
||||||
|
} ImageRec;
|
||||||
|
|
||||||
|
void ConvertUint(unsigned *array, unsigned int length);
|
||||||
|
void ConvertShort(unsigned short *array, unsigned int length);
|
||||||
|
void rgbtorgb(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *l, int n);
|
||||||
|
void rgbatorgba(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *a,
|
||||||
|
GLubyte *l, int n);
|
||||||
|
|
||||||
|
ImageRec *ImageOpen(const char *fileName);
|
||||||
|
ImageRec *ImageWriteOpen(const char *fileName);
|
||||||
|
ImageRec *RawImageOpen(const char *fileName);
|
||||||
|
void ImageClose(ImageRec *image);
|
||||||
|
void ImageGetRow(ImageRec *image, GLubyte *buf, int y, int z);
|
||||||
|
void ImagePutRow(ImageRec *image, GLubyte *buf, int y, int z);
|
||||||
|
|
||||||
|
inline void free_id() {
|
||||||
|
#ifdef GL_VERSION_1_1
|
||||||
|
glDeleteTextures(1, &texture_id);
|
||||||
|
#else
|
||||||
|
glDeleteTexturesEXT(1, &texture_id);
|
||||||
|
#endif
|
||||||
|
texture_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SGTexture();
|
||||||
|
SGTexture(unsigned int width, unsigned int height);
|
||||||
|
~SGTexture();
|
||||||
|
|
||||||
|
/* Copyright (c) Mark J. Kilgard, 1997. */
|
||||||
|
void read_alpha_texture(const char *name);
|
||||||
|
void read_rgb_texture(const char *name);
|
||||||
|
void read_rgba_texture(const char *name);
|
||||||
|
void read_raw_texture(const char *name);
|
||||||
|
void read_r8_texture(const char *name);
|
||||||
|
void write_texture(const char *name);
|
||||||
|
|
||||||
|
inline bool usable() { return (texture_id > 0) ? true : false; }
|
||||||
|
|
||||||
|
inline GLuint id() { return texture_id; }
|
||||||
|
inline GLubyte *texture() { return texture_data; }
|
||||||
|
inline void set_data(GLubyte *data) { texture_data = data; }
|
||||||
|
inline void set_colors(int c) { num_colors = c; }
|
||||||
|
|
||||||
|
inline int width() { return texture_width; }
|
||||||
|
inline int height() { return texture_height; }
|
||||||
|
inline int colors() { return num_colors; }
|
||||||
|
|
||||||
|
// dynamic texture functions.
|
||||||
|
// everything drawn to the OpenGL screen after prepare is
|
||||||
|
// called and before finish is called will be included
|
||||||
|
// in the new texture.
|
||||||
|
void prepare(unsigned int width = 256, unsigned int height = 256);
|
||||||
|
void finish(unsigned int width, unsigned int height);
|
||||||
|
|
||||||
|
// texture pixel manipulation functions.
|
||||||
|
void set_pixel(GLuint x, GLuint y, GLubyte *c);
|
||||||
|
GLubyte *get_pixel(GLuint x, GLuint y);
|
||||||
|
|
||||||
|
void bind();
|
||||||
|
inline void select(bool keep_data = false) {
|
||||||
|
glTexImage2D( GL_TEXTURE_2D, 0, num_colors,
|
||||||
|
texture_width, texture_height, 0,
|
||||||
|
(num_colors==1)?GL_LUMINANCE:(num_colors==3)?GL_RGB:GL_RGBA, GL_UNSIGNED_BYTE, texture_data );
|
||||||
|
|
||||||
|
if (!keep_data) {
|
||||||
|
delete[] texture_data;
|
||||||
|
texture_data = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nowhere does it say that resident textures have to be in video memory!
|
||||||
|
// NVidia's OpenGL drivers implement glAreTexturesResident() correctly,
|
||||||
|
// but the Matrox G400, for example, doesn't.
|
||||||
|
inline bool is_resident() {
|
||||||
|
GLboolean is_res;
|
||||||
|
glAreTexturesResident(1, &texture_id, &is_res);
|
||||||
|
return is_res != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *err_str() { return errstr; }
|
||||||
|
inline void clear_err_str() { errstr = ""; }
|
||||||
|
|
||||||
|
void make_maxcolorwindow();
|
||||||
|
void make_grayscale(float contrast = 1.0);
|
||||||
|
void make_monochrome(float contrast = 1.0,
|
||||||
|
GLubyte r=255, GLubyte g=255, GLubyte b=255);
|
||||||
|
void make_normalmap(float brightness = 1.0, float contrast = 1.0);
|
||||||
|
void make_bumpmap(float brightness = 1.0, float contrast = 1.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue