1
0
Fork 0

Add a utility to generate the köppen-geiger climate database image

This commit is contained in:
Erik Hofman 2020-11-03 14:39:32 +01:00
parent 370a412ee6
commit 9481ac4595
5 changed files with 1510 additions and 0 deletions

21
utils/climate/README Normal file
View 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
View 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
View 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
View 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
View 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