/*
 * server/Lightmap.cc:
 *
 * Copyright (C) 2000 John Watson, jwatson@tempusmud.com
 * 
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */

#include "Lightmap.h"
#include "../util/Persist.h"

#include <iostream>

Lightmap::Lightmap() {
        use_size[0] = use_size[1] = size[0] = size[1] = 0;
        rgb_pixels = static_pixels = 0;
        clientLightmap = 0;
        flags = 0;
}

Lightmap::~Lightmap() {
        if ( rgb_pixels )
                delete[] rgb_pixels;
        if ( static_pixels )
                delete[] static_pixels;
}

void Lightmap::load( class istream & is ) {

        size[0]   = Persist::readShort( is );
        size[1]   = Persist::readShort( is );

        use_size[0]   = Persist::readShort( is );
        use_size[1]   = Persist::readShort( is );
        
        int numpix = size[0] * size[1] * 3;

        static_pixels = new unsigned char[ numpix ];
        is.read( static_pixels, numpix );

        rgb_pixels = new unsigned char[ numpix ];
        memcpy( rgb_pixels, static_pixels, numpix );
        
}

void Lightmap::writeLightmap( class ostream & os ) {
        Persist::writeShort( os, size[0] );
        Persist::writeShort( os, size[1] );

        Persist::writeShort( os, use_size[0] );
        Persist::writeShort( os, use_size[1] );

        int numpix = size[0] * size[1] * 3;

        os.write( static_pixels, numpix );
        
}

/**
 * sets the size to the next-largest power-of-two, max 256
 */
void Lightmap::setSize( int x, int y ) {
        
        if ( x > 4096 || y > 4096 ) {
                cout << " WARNING LIGHTMAP IS TOO LARGE" << endl;
        }
        
        use_size[0] = size[0] = x / TEX_RES;
        use_size[1] = size[1] = y / TEX_RES;
        
        //
        // use the next-largest power-of-two
        //
        
        static int powers[9] = {
                256, 128, 64, 32, 16, 8, 4, 2, 1
        };

        bool found = false;

        for ( int i = 0; i < 8; ++i ) {
                if ( size[0] > powers[ i + 1 ] ) {
                        size[0] = powers[ i ];
                        found = true;
                        break;
                }
        }
                
        if ( ! found )
                size[0] = 1;

        found = false;

        for ( int i = 0; i < 8; ++i ) {
                if ( size[1] > powers[ i + 1 ] ) {
                        size[1] = powers[ i ];
                        found = true;
                        break;
                }
        }

        if ( ! found )
                size[1] = 1;
        
        /*
         * square lightmap code

        if ( size[1] > size[0] )
                size[0] = size[1];
        else if ( size[0] > size[1] )
                size[1] = size[0];

        */
}

void Lightmap::clear( unsigned char r, unsigned char g, unsigned char b ) {

        if ( static_pixels == 0 )
                return;
        
        unsigned char * p = static_pixels;
        int numpix = size[0] * size[1];

        for ( int i = 0; i < numpix; ++i ) {
                *(p++) = r;
                *(p++) = g;
                *(p++) = b;
        }
}

void Lightmap::clampEdges( unsigned char * pix ) {
        
        //
        // clamp along the t edge
        //
        
        const int row_len = size[0] * 3; // length of a row in bytes
        
        if ( use_size[1] < size[1] ) {
                
                unsigned char * src = pix + ( use_size[1]-1 ) * row_len;
                
                for ( int s = 0; s < use_size[0]; ++s, src += 3 ) {
                        
                        unsigned char *dst = src;
                        
                        for ( int t = use_size[1]; t < size[1]; ++t ) {
                                
                                dst += row_len;
                                
                                dst[0] = src[0];
                                dst[1] = src[1];
                                dst[2] = src[2];
                        }
                }
        }

        //
        // clamp along the s edge
        //

        if ( use_size[0] < size[0] ) {
                
                unsigned char * src = pix + ( use_size[0] - 1 ) * 3;
                
                for ( int t = 0; t < size[1]; ++t, src += row_len ) {
                        unsigned char *dst = src + 3;
                        
                        for ( int s = use_size[0]; s < size[0]; ++s ) {
                                *(dst++) = src[0];
                                *(dst++) = src[1];
                                *(dst++) = src[2];
                        }
                        
                }
        }
}
