thug/Code/Gfx/NGPS/p_NxTexture.cpp
2016-02-14 08:39:12 +11:00

2266 lines
75 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// p_NxTexture.cpp
#include "Gfx/gfxutils.h"
#include "Gfx/Nx.h"
#include "Gfx/NGPS/p_NxTexture.h"
#include "Gfx/NGPS/PaletteGen.h"
#include "Gfx/NGPS/nx/scene.h"
#include "Gfx/NGPS/nx/sprite.h"
#include <gel/scripting/checksum.h>
#include <gel/scripting/script.h>
#include <gel/scripting/symboltable.h>
#define min(x, y) (((x) > (y))? (y): (x))
#define max(x, y) (((x) < (y))? (y): (x))
#define USE_FAST_COLOR_FIND 1
#define PRINT_TIMES 0
#define PRINT_FAST_TIMES 0
namespace Nx
{
////////////////////////////////////////////////////////////////////////////////////
// Here's a machine specific implementation of CTexture
bool CPs2Texture::s_tables_initialized = false;
uint8 CPs2Texture::s_clut8_index_to_offset_table[256];
uint8 CPs2Texture::s_clut8_offset_to_index_table[256];
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2Texture::CPs2Texture(bool loading_screen) :
m_transparent(false),
m_loading_screen(loading_screen),
mp_single_texture(NULL),
mp_group_texture(NULL),
mp_orig_temp_32bit_image(NULL),
mp_cur_temp_32bit_image(NULL),
mp_temp_32bit_single_texture(NULL)
{
m_width = m_height = m_bitdepth = m_clut_bitdepth = m_num_mipmaps = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2Texture::CPs2Texture(const CPs2Texture & src_texture) :
CTexture(src_texture)
{
Dbg_MsgAssert(src_texture.mp_group_texture == NULL, ("Can't copy a CPs2Texture that is in a texture group"));
m_width = src_texture.m_width;
m_height = src_texture.m_height;
m_bitdepth = src_texture.m_bitdepth;
m_clut_bitdepth = src_texture.m_clut_bitdepth;
m_num_mipmaps = src_texture.m_num_mipmaps;
m_transparent = src_texture.m_transparent;
m_loading_screen = src_texture.m_loading_screen;
mp_group_texture = NULL;
if (src_texture.mp_orig_temp_32bit_image)
{
mp_orig_temp_32bit_image = new uint32[m_width * m_height];
memcpy(mp_orig_temp_32bit_image, src_texture.mp_orig_temp_32bit_image, m_width * m_height * sizeof(uint32));
}
else
{
mp_orig_temp_32bit_image = NULL;
}
if (src_texture.mp_cur_temp_32bit_image)
{
mp_cur_temp_32bit_image = new uint32[m_width * m_height];
memcpy(mp_cur_temp_32bit_image, src_texture.mp_cur_temp_32bit_image, m_width * m_height * sizeof(uint32));
}
else
{
mp_cur_temp_32bit_image = NULL;
}
if (src_texture.mp_single_texture)
{
mp_single_texture = new NxPs2::SSingleTexture(*src_texture.mp_single_texture);
}
else
{
mp_single_texture = NULL;
}
if (src_texture.mp_temp_32bit_single_texture)
{
mp_temp_32bit_single_texture = new NxPs2::SSingleTexture(*src_texture.mp_temp_32bit_single_texture);
}
else
{
mp_temp_32bit_single_texture = NULL;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2Texture::~CPs2Texture()
{
// delete the actual single texture, if any
if (mp_single_texture)
{
delete mp_single_texture;
}
if (mp_orig_temp_32bit_image)
{
delete mp_orig_temp_32bit_image;
}
if (mp_cur_temp_32bit_image)
{
delete mp_cur_temp_32bit_image;
}
if (mp_temp_32bit_single_texture)
{
delete mp_temp_32bit_single_texture;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::sInitTables()
{
if (!s_tables_initialized)
{
uint i, j, idx;
idx = 0;
for(i = 0; i < 256; i+=32)
{
for(j = i; j < i+8; j++)
s_clut8_index_to_offset_table[j] = (uint8) idx++;
for(j = i+16; j < i+16+8; j++)
s_clut8_index_to_offset_table[j] = (uint8) idx++;
for(j = i+8; j < i+8+8; j++)
s_clut8_index_to_offset_table[j] = (uint8) idx++;
for(j = i+24; j < i+24+8; j++)
s_clut8_index_to_offset_table[j] = (uint8) idx++;
}
idx = 0;
for(i = 0; i < 256; i+=32)
{
for(j = i; j < i+8; j++)
s_clut8_offset_to_index_table[idx++] = (uint8) j;
for(j = i+16; j < i+16+8; j++)
s_clut8_offset_to_index_table[idx++] = (uint8) j;
for(j = i+8; j < i+8+8; j++)
s_clut8_offset_to_index_table[idx++] = (uint8) j;
for(j = i+24; j < i+24+8; j++)
s_clut8_offset_to_index_table[idx++] = (uint8) j;
}
s_tables_initialized = true;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// Private classes
//
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_load_texture(const char *p_texture_name, bool sprite, bool alloc_vram)
{
Dbg_Assert(mp_group_texture == NULL);
// call engine
mp_single_texture = new NxPs2::SSingleTexture(p_texture_name, sprite, alloc_vram, m_loading_screen);
if (mp_single_texture)
{
m_width = mp_single_texture->GetOrigWidth(); // Garrett: This is probably not what we want, but CSprite
m_height = mp_single_texture->GetOrigHeight(); // needs this. Probably will need to change CTexture.
m_bitdepth = mp_single_texture->GetBitdepth();
m_clut_bitdepth = mp_single_texture->GetClutBitdepth();
m_num_mipmaps = mp_single_texture->GetNumMipmaps();
m_transparent = mp_single_texture->IsTransparent();
}
return mp_single_texture != NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_load_texture_from_buffer(uint8* p_buffer, int buffer_size, bool sprite, bool alloc_vram)
{
Dbg_Assert(mp_group_texture == NULL);
// call engine
mp_single_texture = new NxPs2::SSingleTexture(p_buffer, buffer_size, sprite, alloc_vram, m_loading_screen);
if (mp_single_texture)
{
m_width = mp_single_texture->GetOrigWidth(); // Garrett: This is probably not what we want, but CSprite
m_height = mp_single_texture->GetOrigHeight(); // needs this. Probably will need to change CTexture.
m_bitdepth = mp_single_texture->GetBitdepth();
m_clut_bitdepth = mp_single_texture->GetClutBitdepth();
m_num_mipmaps = mp_single_texture->GetNumMipmaps();
m_transparent = mp_single_texture->IsTransparent();
}
return mp_single_texture != NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_replace_texture(CTexture *p_texture)
{
Dbg_Assert(p_texture);
Dbg_Assert(mp_group_texture);
CPs2Texture *p_ps2_texture = static_cast<CPs2Texture *>(p_texture);
Dbg_Assert(p_ps2_texture->mp_single_texture);
if ((m_width != p_ps2_texture->m_width) ||
(m_height != p_ps2_texture->m_height) ||
(m_bitdepth != p_ps2_texture->m_bitdepth) ||
(m_num_mipmaps != p_ps2_texture->m_num_mipmaps))
{
Dbg_Message("Original size (%d, %d); Replacement size (%d, %d)", m_width, m_height, p_ps2_texture->m_width, p_ps2_texture->m_height);
Dbg_Message("Original bitdepth %d; Replacement bitdepth %d", m_bitdepth, p_ps2_texture->m_bitdepth);
Dbg_Message("Original num mipmaps %d; Replacement num mipmaps %d", m_num_mipmaps, p_ps2_texture->m_num_mipmaps);
return false;
}
#if 0
if ((m_bitdepth <= 8) && (m_clut_bitdepth < p_ps2_texture->m_clut_bitdepth))
{
Dbg_Message("Original clut bitdepth %d; Replacement clut bitdepth %d", m_clut_bitdepth, p_ps2_texture->m_clut_bitdepth);
return false;
}
#endif
// Copy texture
uint8 *p_orig_tex_buffer = mp_group_texture->GetTextureBuffer();
uint8 *p_new_tex_buffer = p_ps2_texture->mp_single_texture->GetTextureBuffer();
if (mp_group_texture->HasSwizzleMip())
{
mp_group_texture->ReplaceTextureData(p_new_tex_buffer);
}
else
{
memcpy(p_orig_tex_buffer, p_new_tex_buffer, p_ps2_texture->mp_single_texture->GetTextureBufferSize());
}
// And clut (if any)
uint32 *p_orig_clut_buffer = (uint32 *) mp_group_texture->GetClutBuffer();
if (p_orig_clut_buffer)
{
uint32 *p_new_clut_buffer = (uint32 *) p_ps2_texture->mp_single_texture->GetClutBuffer();
Dbg_Assert(p_new_clut_buffer);
if (m_clut_bitdepth == p_ps2_texture->m_clut_bitdepth)
{
memcpy(p_orig_clut_buffer, p_new_clut_buffer, p_ps2_texture->mp_single_texture->GetClutBufferSize());
} else if ((m_clut_bitdepth == 32) && (p_ps2_texture->m_clut_bitdepth == 16))
{
uint16 *p_clut_16_buffer = (uint16 *) p_new_clut_buffer;
Image::RGBA new_color;
new_color.a = 0x80;
int num_colors = p_ps2_texture->mp_single_texture->GetClutBufferSize() / 2;
for (int i = 0; i < num_colors; i++)
{
// Convert from 16 to 32 bit
new_color.r = ((*(p_clut_16_buffer) >> 0) & 0x1f) << 3;
new_color.g = ((*(p_clut_16_buffer) >> 5) & 0x1f) << 3;
new_color.b = ((*(p_clut_16_buffer++) >> 10) & 0x1f) << 3;
//Dbg_Message("Replacing color #%d %x with %x", i, *p_orig_clut_buffer, *((uint32 *) &new_color));
*(p_orig_clut_buffer++) = *((uint32 *) &new_color);
}
} else if ((m_clut_bitdepth == 16) && (p_ps2_texture->m_clut_bitdepth == 32))
{
uint16 *p_clut_16_buffer = (uint16 *) p_orig_clut_buffer;
uint16 new_color;
Image::RGBA *p_full_color;
int num_colors = p_ps2_texture->mp_single_texture->GetClutBufferSize() / 4;
for (int i = 0; i < num_colors; i++)
{
p_full_color = (Image::RGBA *) p_new_clut_buffer++;
new_color = 0x8000 | (p_full_color->r >> 3) | ( (p_full_color->g >> 3) << 5 ) | ( (p_full_color->b >> 3) << 10 );
*(p_clut_16_buffer++) = new_color;
}
} else {
Dbg_Message("Can't handle this combination: clut bitdepth %d; Replacement clut bitdepth %d", m_clut_bitdepth, p_ps2_texture->m_clut_bitdepth);
return false;
}
//Dbg_Message("Original clut size %d; Replacement clut size %d", mp_group_texture->GetClutBufferSize(), p_ps2_texture->mp_single_texture->GetClutBufferSize());
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_generate_32bit_image(bool renderable, bool store_original)
{
Dbg_MsgAssert(!mp_cur_temp_32bit_image, ("Can't generate temp 32-bit image: one already exists"));
// For now, just coded up the 8-bit image with 32-bit clut
Dbg_Assert(m_bitdepth == 8);
Dbg_MsgAssert(m_clut_bitdepth == 32, ("Clut bitdepth is only %d, not 32", m_clut_bitdepth));
Dbg_Assert(mp_single_texture);
Dbg_Assert(s_tables_initialized);
// Allocate buffer
mp_cur_temp_32bit_image = new uint32[m_width * m_height];
uint32 *p_pixel_buffer = mp_cur_temp_32bit_image;
// Get source buffers
uint8 *p_orig_tex_buffer = mp_single_texture->GetTextureBuffer();
// And clut (if any)
uint32 *p_orig_clut_buffer = (uint32 *) mp_single_texture->GetClutBuffer();
// Move texture buffer to start (and flip y)
p_orig_tex_buffer += (m_height - 1) * m_width;
for (uint h = 0; h < m_height; h++)
{
for (uint w = 0; w < m_width; w++)
{
// Copies from 8-bit to 32-bit
*p_pixel_buffer++ = p_orig_clut_buffer[ s_clut8_index_to_offset(p_orig_tex_buffer[w]) ];
}
p_orig_tex_buffer -= m_width; // Negative because were flipping the lines
}
// Copy to original buffer
if (store_original)
{
mp_orig_temp_32bit_image = new uint32[m_width * m_height];
memcpy(mp_orig_temp_32bit_image, mp_cur_temp_32bit_image, m_width * m_height * sizeof(uint32));
}
// Allocate a SSingleTexture
if (renderable)
{
mp_temp_32bit_single_texture = new NxPs2::SSingleTexture((uint8 *) mp_cur_temp_32bit_image, m_width, m_height, 32,
m_clut_bitdepth, m_num_mipmaps, true, true, m_loading_screen);
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_put_32bit_image_into_texture(bool new_palette)
{
Dbg_MsgAssert(mp_cur_temp_32bit_image, ("No temp 32-bit image"));
// For now, just coded up the 8-bit image with 32-bit clut
Dbg_Assert(m_bitdepth == 8);
Dbg_Assert(m_clut_bitdepth == 32);
Dbg_Assert(mp_single_texture);
Dbg_Assert(s_tables_initialized);
// Generate a new palette
if (new_palette)
{
GeneratePalette((Image::RGBA *) mp_single_texture->GetClutBuffer(), (uint8 *) mp_cur_temp_32bit_image, m_width, m_height, 32, 1 << m_bitdepth);
}
// Get buffers
uint8 *p_tex_buffer = mp_single_texture->GetTextureBuffer();
uint32 *p_pixel_buffer = mp_cur_temp_32bit_image;
// Move texture buffer to start (and flip y)
p_tex_buffer += (m_height - 1) * m_width;
#if USE_FAST_COLOR_FIND
#if PRINT_FAST_TIMES
uint32 start_time = Tmr::GetTimeInUSeconds();
#endif // PRINT_FAST_TIMES
setup_fast_clut_color_find(false);
#if PRINT_FAST_TIMES
uint32 end_time = Tmr::GetTimeInUSeconds();
Dbg_Message("plat_put_32bit_image_into_texture fast setup time %d us", end_time - start_time);
#endif // PRINT_FAST_TIMES
#endif // USE_FAST_COLOR_FIND
for (uint h = 0; h < m_height; h++)
{
for (uint w = 0; w < m_width; w++)
{
// Copies from 32-bit to 8-bit
#if USE_FAST_COLOR_FIND
p_tex_buffer[w] = s_clut8_offset_to_index( fast_find_closest_clut_color( *((Image::RGBA *) p_pixel_buffer++) ) );
#else
p_tex_buffer[w] = s_clut8_offset_to_index( find_closest_clut_color( *((Image::RGBA *) p_pixel_buffer++) ) );
#endif // USE_FAST_COLOR_FIND
}
p_tex_buffer -= m_width; // Negative because were flipping the lines
}
#if USE_FAST_COLOR_FIND
cleanup_fast_clut_color_find();
#if PRINT_FAST_TIMES
end_time = Tmr::GetTimeInUSeconds();
Dbg_Message("plat_put_32bit_image_into_texture fast total time %d us", end_time - start_time);
#endif // PRINT_FAST_TIMES
#endif // USE_FAST_COLOR_FIND
// Delete buffers
delete [] mp_cur_temp_32bit_image;
mp_cur_temp_32bit_image = NULL;
if (mp_orig_temp_32bit_image)
{
delete [] mp_orig_temp_32bit_image;
mp_orig_temp_32bit_image = NULL;
}
if (mp_temp_32bit_single_texture)
{
delete mp_temp_32bit_single_texture;
mp_temp_32bit_single_texture = NULL;
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::s_get_nearest_pixels_from_32bit_texture(Image::RGBA p_nearest[][2], uint32 *p_buffer,
uint16 x_pos, uint16 y_pos, uint16 width, uint16 height)
{
int next_x = (x_pos >= (width - 1)) ? 0 : 1; // Clamp x if at end
bool clamp_y = (y_pos >= (height - 1)); // And same for y
p_buffer += (y_pos * width) + x_pos;
// First row
p_nearest[0][0] = *((Image::RGBA *) p_buffer);
p_nearest[0][1] = *((Image::RGBA *) &p_buffer[next_x]);
if (!clamp_y)
{
p_buffer += width;
}
// Second row
p_nearest[1][0] = *((Image::RGBA *) p_buffer);
p_nearest[1][1] = *((Image::RGBA *) &p_buffer[next_x]);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::s_get_region(uint8 *p_buffer, uint16 x_pos, uint16 y_pos, uint16 tex_width, uint16 tex_height,
uint8 *p_region, uint16 region_width, uint16 region_height, uint16 bitdepth)
{
int bytes_per_pixel = bitdepth / 8;
int copy_bytes;
int width_in_bytes;
int stride_in_bytes;
// Clamp region values
int clamp_region_width = min(region_width, tex_width - x_pos);
int clamp_region_height = min(region_height, tex_height - y_pos);
Dbg_Assert(clamp_region_width >= 0);
Dbg_Assert(clamp_region_height >= 0);
// Move texture buffer to start
if (bytes_per_pixel)
{
p_buffer += ((y_pos * tex_width) + x_pos) * bytes_per_pixel;
copy_bytes = clamp_region_width * bytes_per_pixel;
width_in_bytes = region_width * bytes_per_pixel;
stride_in_bytes = tex_width * bytes_per_pixel;
}
else // 4-bit
{
p_buffer += ((y_pos * tex_width) + x_pos) / 2;
copy_bytes = clamp_region_width / 2;
width_in_bytes = region_width / 2;
stride_in_bytes = tex_width / 2;
}
//Dbg_Message("s_get_region(): xpos %d, ypos %d, tex_width %d, tex_height %d, region_width %d, region_height %d, width_in_bytes %d, stride_in_bytes %d, bitdepth %d",
// x_pos, y_pos, tex_width, tex_height, region_width, region_height, width_in_bytes, stride_in_bytes, bitdepth);
for (int h = 0; h < clamp_region_height; h++)
{
// Copy each line
memcpy(p_region, p_buffer, copy_bytes);
p_region += width_in_bytes;
p_buffer += stride_in_bytes;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::s_put_region(uint8 *p_buffer, uint16 x_pos, uint16 y_pos, uint16 tex_width, uint16 tex_height,
uint8 *p_region, uint16 region_width, uint16 region_height, uint16 bitdepth)
{
int bytes_per_pixel = bitdepth / 8;
int copy_bytes;
int width_in_bytes;
int stride_in_bytes;
// Clamp region values
int clamp_region_width = min(region_width, tex_width - x_pos);
int clamp_region_height = min(region_height, tex_height - y_pos);
Dbg_Assert(clamp_region_width >= 0);
Dbg_Assert(clamp_region_height >= 0);
// Move texture buffer to start
if (bytes_per_pixel)
{
p_buffer += ((y_pos * tex_width) + x_pos) * bytes_per_pixel;
copy_bytes = clamp_region_width * bytes_per_pixel;
width_in_bytes = region_width * bytes_per_pixel;
stride_in_bytes = tex_width * bytes_per_pixel;
}
else // 4-bit
{
p_buffer += ((y_pos * tex_width) + x_pos) / 2;
copy_bytes = clamp_region_width / 2;
width_in_bytes = region_width / 2;
stride_in_bytes = tex_width / 2;
}
//Dbg_Message("s_put_region(): xpos %d, ypos %d, tex_width %d, tex_height %d, region_width %d, region_height %d, width_in_bytes %d, stride_in_bytes %d, bitdepth %d",
// x_pos, y_pos, tex_width, tex_height, region_width, region_height, width_in_bytes, stride_in_bytes, bitdepth);
for (int h = 0; h < clamp_region_height; h++)
{
// Copy each line
memcpy(p_buffer, p_region, copy_bytes);
p_region += width_in_bytes;
p_buffer += stride_in_bytes;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::s_scale_texture(uint8 *p_buffer, uint16 width, uint16 height,
uint8 *p_result_buffer, uint16 new_width, uint16 new_height, uint16 bitdepth)
{
Dbg_MsgAssert(bitdepth > 8, ("Can't scale a paletted texture. Convert to unpaletted first."));
Dbg_Assert(bitdepth == 32); // We'll worry about 16 and 24 bit later.
#if PRINT_TIMES
static uint32 total_time = 0;
uint32 start_time = Tmr::GetTimeInUSeconds();
#endif
float orig_coord[2] = { 0.0f, 0.0f };
float delta_dim[2];
float delta_coord[2] = { 0.0f, 0.0f };
uint16 orig_index[2] = { 0, 0 };
Image::RGBA closest_pixels[2][2];
float pixel_portion[2][2];
Image::RGBA combined_pixel;
delta_dim[X] = (float) width / (float) new_width;
delta_dim[Y] = (float) height / (float) new_height;
for (int h = 0; h < new_height; h++)
{
orig_index[Y] = (uint16) orig_coord[Y]; // Get integer version
delta_coord[Y] = orig_coord[Y] - orig_index[Y]; // And now get fractional part
for (int w = 0; w < new_width; w++)
{
orig_index[X] = (uint16) orig_coord[X]; // Get integer version
delta_coord[X] = orig_coord[X] - orig_index[X]; // And now get fractional part
// Calculate the pixel portions
pixel_portion[0][0] = (1.0f - delta_coord[X]) * (1.0f - delta_coord[Y]);
pixel_portion[0][1] = (delta_coord[X]) * (1.0f - delta_coord[Y]);
pixel_portion[1][0] = (1.0f - delta_coord[X]) * (delta_coord[Y]);
pixel_portion[1][1] = (delta_coord[X]) * (delta_coord[Y]);
Dbg_MsgAssert((orig_index[X] + 0) < width, ("X coord out of range: %d", orig_index[X]));
Dbg_MsgAssert((orig_index[Y] + 0) < height, ("Y coord out of range: %d", orig_index[Y]));
// Get the 4 nearest pixels
s_get_nearest_pixels_from_32bit_texture(closest_pixels, (uint32 *) p_buffer, orig_index[X], orig_index[Y], width, height);
// Calculate each color
combined_pixel.r = (uint8) ((pixel_portion[0][0] * (float) closest_pixels[0][0].r) +
(pixel_portion[0][1] * (float) closest_pixels[0][1].r) +
(pixel_portion[1][0] * (float) closest_pixels[1][0].r) +
(pixel_portion[1][1] * (float) closest_pixels[1][1].r));
combined_pixel.g = (uint8) ((pixel_portion[0][0] * (float) closest_pixels[0][0].g) +
(pixel_portion[0][1] * (float) closest_pixels[0][1].g) +
(pixel_portion[1][0] * (float) closest_pixels[1][0].g) +
(pixel_portion[1][1] * (float) closest_pixels[1][1].g));
combined_pixel.b = (uint8) ((pixel_portion[0][0] * (float) closest_pixels[0][0].b) +
(pixel_portion[0][1] * (float) closest_pixels[0][1].b) +
(pixel_portion[1][0] * (float) closest_pixels[1][0].b) +
(pixel_portion[1][1] * (float) closest_pixels[1][1].b));
combined_pixel.a = (uint8) ((pixel_portion[0][0] * (float) closest_pixels[0][0].a) +
(pixel_portion[0][1] * (float) closest_pixels[0][1].a) +
(pixel_portion[1][0] * (float) closest_pixels[1][0].a) +
(pixel_portion[1][1] * (float) closest_pixels[1][1].a));
// And copy
*((uint32 *) p_result_buffer)++ = *((uint32 *) &(combined_pixel));
// Advance to next coord
orig_coord[X] += delta_dim[X];
}
orig_coord[X] = 0.0f;
orig_coord[Y] += delta_dim[Y];
}
#if PRINT_TIMES
uint32 end_time = Tmr::GetTimeInUSeconds();
total_time += end_time - start_time;
Dbg_Message("scale_texture Update time %d us; Total Time %d", end_time - start_time, total_time);
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::s_combine_adjacent_borders(uint8 *p_first_rect, uint8 *p_second_rect, uint16 first_width,
uint16 first_height, uint16 second_stride, float first_portion,
int split_axis, uint16 bitdepth)
{
Dbg_MsgAssert(bitdepth > 8, ("Can't adjust the border of a paletted texture. Convert to unpaletted first."));
Dbg_Assert(bitdepth == 32); // We'll worry about 16 and 24 bit later.
Image::RGBA *p_rect_pixel[2] = { (Image::RGBA *) p_first_rect, (Image::RGBA *) p_second_rect };
float second_portion = 1.0f - first_portion;
int num_pixels, inc_pixels;
// Init
if (split_axis == X)
{
num_pixels = first_width;
inc_pixels = 1;
}
else
{
Dbg_Assert(first_width == second_stride);
num_pixels = first_height;
inc_pixels = second_stride;
}
// Combine the pixels
for (int pidx = 0; pidx < num_pixels; pidx++)
{
p_rect_pixel[1]->r = (uint8) ( (first_portion * (float) p_rect_pixel[0]->r) + (second_portion * (float) p_rect_pixel[1]->r) );
p_rect_pixel[1]->g = (uint8) ( (first_portion * (float) p_rect_pixel[0]->g) + (second_portion * (float) p_rect_pixel[1]->g) );
p_rect_pixel[1]->b = (uint8) ( (first_portion * (float) p_rect_pixel[0]->b) + (second_portion * (float) p_rect_pixel[1]->b) );
p_rect_pixel[1]->a = (uint8) ( (first_portion * (float) p_rect_pixel[0]->a) + (second_portion * (float) p_rect_pixel[1]->a) );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static const int ALPHA_WEIGHT = 2; // how much more weight to give to alpha
uint8 CPs2Texture::find_closest_clut_color(Image::RGBA rgba)
{
// For now, just coded up the 8-bit image with 32-bit clut
Dbg_Assert(m_bitdepth == 8);
Dbg_Assert(m_clut_bitdepth == 32);
Dbg_Assert(mp_single_texture);
int clutsize = 1 << m_bitdepth;
Image::RGBA *p_clut_buffer = (Image::RGBA *) mp_single_texture->GetClutBuffer();
Dbg_Assert(p_clut_buffer);
int delR, delG, delB, delA;
int bestDist, curDist;
uint8 bestIdx = 0;
bestDist = 0x7FFFFFFF;
for (int i = 0; i < clutsize; i++)
{
delR = (int) (p_clut_buffer)->r - (int) rgba.r;
delG = (int) (p_clut_buffer)->g - (int) rgba.g;
delB = (int) (p_clut_buffer)->b - (int) rgba.b;
delA = (int) (p_clut_buffer++)->a - (int) rgba.a;
// Calculate 4-dimensional distance between color components
curDist = (delR * delR) + (delG * delG) + (delB * delB) +
(delA * delA * ALPHA_WEIGHT);
// Choose the index with the smallest distance from src color
if (curDist < bestDist)
{
bestDist = curDist;
bestIdx = i;
}
}
return bestIdx;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
// Holds clut index array start and size
struct SClutEntries
{
uint16 m_clut_buffer_index;
uint8 m_num_clut_entries;
};
static const int s_axis_level_bits = 3; // Significant bits used to break down each color into the tree
static const int s_axis_levels = 1 << s_axis_level_bits;
static bool s_use_alpha_axis;
static uint8 *sp_clut_index_buffer = NULL;
//static int s_num_color_searches;
//static int s_num_color_compares;
// Array is of form [R][G][B][A]
static SClutEntries s_palette_octree[s_axis_levels][s_axis_levels][s_axis_levels][s_axis_levels];
void CPs2Texture::setup_fast_clut_color_find(bool use_alpha)
{
// For now, just coded up the 8-bit image with 32-bit clut
Dbg_Assert(m_bitdepth == 8);
Dbg_Assert(m_clut_bitdepth == 32);
Dbg_Assert(mp_single_texture);
Dbg_Assert(!sp_clut_index_buffer);
s_use_alpha_axis = use_alpha;
int clutsize = 1 << m_bitdepth;
int range = clutsize >> s_axis_level_bits;
int alpha_axis_levels = (s_use_alpha_axis) ? s_axis_levels : 1;
int index_buffer_size = s_axis_levels * s_axis_levels * s_axis_levels * alpha_axis_levels * (clutsize / 2); // Could be made smaller
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
sp_clut_index_buffer = new uint8[index_buffer_size];
Mem::Manager::sHandle().PopContext();
int min_level[4];
int max_level[4];
const int overlap = (range >> 1);
const int min_start = -overlap;
const int max_start = range + overlap;
const int max_alpha_start = (s_use_alpha_axis) ? max_start : clutsize;
int buffer_index = 0;
min_level[0] = min_start;
max_level[0] = max_start;
for (int r = 0; r < s_axis_levels; r++)
{
min_level[1] = min_start;
max_level[1] = max_start;
for (int g = 0; g < s_axis_levels; g++)
{
min_level[2] = min_start;
max_level[2] = max_start;
for (int b = 0; b < s_axis_levels; b++)
{
min_level[3] = min_start;
max_level[3] = max_alpha_start;
for (int a = 0; a < alpha_axis_levels; a++)
{
SClutEntries *p_palette_node = &s_palette_octree[r][g][b][a];
p_palette_node->m_clut_buffer_index = buffer_index;
p_palette_node->m_num_clut_entries = 0;
Image::RGBA *p_clut_buffer = (Image::RGBA *) mp_single_texture->GetClutBuffer();
Dbg_MsgAssert(buffer_index < (index_buffer_size - clutsize), ("Running out of index buffer space"));
for (int index = 0; index < clutsize; index++, p_clut_buffer++)
{
if ((p_clut_buffer->r >= min_level[0]) && (p_clut_buffer->r <= max_level[0]) &&
(p_clut_buffer->g >= min_level[1]) && (p_clut_buffer->g <= max_level[1]) &&
(p_clut_buffer->b >= min_level[2]) && (p_clut_buffer->b <= max_level[2]) &&
(p_clut_buffer->a >= min_level[3]) && (p_clut_buffer->a <= max_level[3]))
{
p_palette_node->m_num_clut_entries++;
sp_clut_index_buffer[buffer_index++] = index;
}
} // for index
min_level[3] += range;
max_level[3] += range;
} // for a
min_level[2] += range;
max_level[2] += range;
} // for b
min_level[1] += range;
max_level[1] += range;
} // for g
min_level[0] += range;
max_level[0] += range;
} // for r
//s_num_color_searches = 0;
//s_num_color_compares = 0;
}
uint8 CPs2Texture::fast_find_closest_clut_color(Image::RGBA rgba)
{
// For now, just coded up the 8-bit image with 32-bit clut
Dbg_Assert(m_bitdepth == 8);
Dbg_Assert(m_clut_bitdepth == 32);
Dbg_Assert(mp_single_texture);
Dbg_Assert(sp_clut_index_buffer);
int range_bits = m_bitdepth - s_axis_level_bits;
int r_index = rgba.r >> range_bits;
int g_index = rgba.g >> range_bits;
int b_index = rgba.b >> range_bits;
int a_index = (s_use_alpha_axis) ? rgba.a >> range_bits : 0;
SClutEntries *p_palette_node = &s_palette_octree[r_index][g_index][b_index][a_index];
//s_num_color_searches++;
if (p_palette_node->m_num_clut_entries == 0)
{
//s_num_color_compares += 256;
return find_closest_clut_color(rgba);
}
else
{
uint8 *p_palette_index = &sp_clut_index_buffer[p_palette_node->m_clut_buffer_index];
Image::RGBA *p_clut_buffer = (Image::RGBA *) mp_single_texture->GetClutBuffer();
Dbg_Assert(p_clut_buffer);
int delR, delG, delB, delA;
int bestDist, curDist;
uint8 bestIdx = 0;
bestDist = 0x7FFFFFFF;
for (int entry_index = 0; entry_index < p_palette_node->m_num_clut_entries; entry_index++, p_palette_index++)
{
Image::RGBA *p_clut_color = &p_clut_buffer[*p_palette_index];
delR = (int) p_clut_color->r - (int) rgba.r;
delG = (int) p_clut_color->g - (int) rgba.g;
delB = (int) p_clut_color->b - (int) rgba.b;
delA = (int) p_clut_color->a - (int) rgba.a;
// Calculate 4-dimensional distance between color components
curDist = (delR * delR) + (delG * delG) + (delB * delB) +
(delA * delA * ALPHA_WEIGHT);
// Choose the index with the smallest distance from src color
if (curDist < bestDist)
{
bestDist = curDist;
bestIdx = *p_palette_index;
}
}
//s_num_color_compares += p_palette_node->m_num_clut_entries;
return bestIdx;
}
}
void CPs2Texture::cleanup_fast_clut_color_find()
{
Dbg_Assert(sp_clut_index_buffer);
//Dbg_Message("Average color compares per search: %f", (float) s_num_color_compares / (float) s_num_color_searches);
delete [] sp_clut_index_buffer;
sp_clut_index_buffer = NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::copy_region_to_32bit_buffer(uint32 *p_pixel_buffer, uint16 x_pos, uint16 y_pos,
uint16 width, uint16 height)
{
// For now, just coded up the 8-bit image with 32-bit clut
Dbg_Assert(m_bitdepth == 8);
Dbg_MsgAssert(m_clut_bitdepth == 32, ("Clut bitdepth is only %d, not 32", m_clut_bitdepth));
Dbg_Assert(mp_single_texture);
Dbg_Assert(s_tables_initialized);
#if PRINT_TIMES
static uint32 total_time = 0;
uint32 start_time = Tmr::GetTimeInUSeconds();
#endif
if (mp_cur_temp_32bit_image)
{
// Get source buffer
uint32 *p_orig_tex_buffer = mp_cur_temp_32bit_image;
// Move texture buffer to start
p_orig_tex_buffer += (y_pos * m_width) + x_pos;
for (uint h = 0; h < height; h++)
{
memcpy(p_pixel_buffer, p_orig_tex_buffer, width * sizeof(uint32));
p_pixel_buffer += width;
p_orig_tex_buffer += m_width;
}
}
else
{
// Get source buffers
uint8 *p_orig_tex_buffer = mp_single_texture->GetTextureBuffer();
// And clut (if any)
uint32 *p_orig_clut_buffer = (uint32 *) mp_single_texture->GetClutBuffer();
// Move texture buffer to start (and flip y)
p_orig_tex_buffer += ((m_height - 1 - y_pos) * m_width) + x_pos;
for (uint h = 0; h < height; h++)
{
for (uint w = 0; w < width; w++)
{
// Copies from 8-bit to 32-bit
*p_pixel_buffer++ = p_orig_clut_buffer[ s_clut8_index_to_offset(p_orig_tex_buffer[w]) ];
}
p_orig_tex_buffer -= m_width; // Negative because were flipping the lines
}
}
#if PRINT_TIMES
uint32 end_time = Tmr::GetTimeInUSeconds();
total_time += end_time - start_time;
Dbg_Message("copy_region_to_32bit_buffer Update time %d us; Total Time %d", end_time - start_time, total_time);
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::blit_32bit_buffer_to_texture(uint32 *p_pixel_buffer, uint16 x_pos, uint16 y_pos,
uint16 width, uint16 height)
{
// For now, just coded up the 8-bit image with 32-bit clut
Dbg_Assert(m_bitdepth == 8);
Dbg_Assert(m_clut_bitdepth == 32);
Dbg_Assert(mp_single_texture);
Dbg_Assert(s_tables_initialized);
#if PRINT_TIMES
static uint32 total_time = 0;
uint32 start_time = Tmr::GetTimeInUSeconds();
#endif
if (mp_cur_temp_32bit_image)
{
// Get source buffer
uint32 *p_tex_buffer = mp_cur_temp_32bit_image;
// Move texture buffer to start
p_tex_buffer += (y_pos * m_width) + x_pos;
for (uint h = 0; h < height; h++)
{
memcpy(p_tex_buffer, p_pixel_buffer, width * sizeof(uint32));
p_pixel_buffer += width;
p_tex_buffer += m_width;
}
}
else
{
// Get source buffers
uint8 *p_tex_buffer = mp_single_texture->GetTextureBuffer();
// Move texture buffer to start (and flip y)
p_tex_buffer += ((m_height - 1 - y_pos) * m_width) + x_pos;
for (uint h = 0; h < height; h++)
{
for (uint w = 0; w < width; w++)
{
// Copies from 32-bit to 8-bit
p_tex_buffer[w] = s_clut8_offset_to_index( find_closest_clut_color( *((Image::RGBA *) p_pixel_buffer++) ) );
}
p_tex_buffer -= m_width; // Negative because were flipping the lines
}
}
#if PRINT_TIMES
uint32 end_time = Tmr::GetTimeInUSeconds();
total_time += end_time - start_time;
Dbg_Message("blit_32bit_buffer_to_texture Update time %d us; Total Time %d", end_time - start_time, total_time);
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2Texture::set_32bit_pixel_to_texture(uint32 pixel, uint16 x_pos, uint16 y_pos)
{
// For now, just coded up the 8-bit image with 32-bit clut
Dbg_Assert(m_bitdepth == 8);
Dbg_Assert(m_clut_bitdepth == 32);
Dbg_Assert(mp_single_texture);
Dbg_Assert(s_tables_initialized);
if (mp_cur_temp_32bit_image)
{
// Set pixel in buffer
mp_cur_temp_32bit_image[(y_pos * m_width) + x_pos] = pixel;
}
else
{
// Get source buffers
uint8 *p_tex_buffer = mp_single_texture->GetTextureBuffer();
// Move texture buffer to start (and flip y)
p_tex_buffer[((m_height - 1 - y_pos) * m_width) + x_pos] = s_clut8_offset_to_index( find_closest_clut_color( *((Image::RGBA *) &pixel) ) );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_offset(int x_pixels, int y_pixels, bool use_fill_color, Image::RGBA fill_color)
{
int region_start_pos[2];
int region_end_pos[2];
int region_width;
int region_height;
// Figure out X info
if (x_pixels >= 0)
{
region_start_pos[X] = 0;
region_end_pos[X] = x_pixels;
region_width = m_width - x_pixels;
}
else
{
region_start_pos[X] = -x_pixels;
region_end_pos[X] = 0;
region_width = m_width - (-x_pixels);
}
// Figure out Y info
if (y_pixels >= 0)
{
region_start_pos[Y] = 0;
region_end_pos[Y] = y_pixels;
region_height = m_height - y_pixels;
}
else
{
region_start_pos[Y] = -y_pixels;
region_end_pos[Y] = 0;
region_height = m_height - (-y_pixels);
}
// Copy texture region into temp buffers in 32-bit format
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
uint32 *p_texture_buffer = new uint32[region_width * region_height];
Mem::Manager::sHandle().PopContext();
// Get section that will be in offset texture
copy_region_to_32bit_buffer(p_texture_buffer, region_start_pos[X], region_start_pos[Y], region_width, region_height);
// And put that region back into texture
blit_32bit_buffer_to_texture(p_texture_buffer, region_end_pos[X], region_end_pos[Y], region_width, region_height);
//static uint32 total_time = 0;
//uint32 start_time = Tmr::GetTimeInUSeconds();
// Check if we have a fill color
if (use_fill_color)
{
Dbg_MsgAssert(0, ("Fill color not implemented yet"));
}
else
{
for (int h = 0, y_pos = -region_end_pos[Y]; h < m_height; h++, y_pos++)
{
int y_clamp_pos = max(y_pos, 0);
y_clamp_pos = min(y_clamp_pos, region_height - 1);
int y_buffer_index = y_clamp_pos * region_width;
for (int w = 0, x_pos = -region_end_pos[X]; w < m_width; w++, x_pos++)
{
// Check if we are within the new region
if ((x_pos >= 0) && (x_pos < region_width) &&
(y_pos >= 0) && (y_pos < region_height))
{
continue;
}
int x_clamp_pos = max(x_pos, 0);
x_clamp_pos = min(x_clamp_pos, region_width - 1);
set_32bit_pixel_to_texture(p_texture_buffer[y_buffer_index + x_clamp_pos], w, h);
}
}
}
//uint32 end_time = Tmr::GetTimeInUSeconds();
//total_time += end_time - start_time;
//Dbg_Message("offset_texture fill Update time %d us; Total Time %d", end_time - start_time, total_time);
delete [] p_texture_buffer;
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_adjust_region(uint16 x_pos, uint16 y_pos, uint16 width, uint16 height,
int split_axis, uint16 start_point, uint16 end_point)
{
// Copy original rectangle in a temp buffer in 32-bit format (needed for interpolation)
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
uint32 *p_orig_region_pixels = new uint32[width * height];
Mem::Manager::sHandle().PopContext();
copy_region_to_32bit_buffer(p_orig_region_pixels, x_pos, y_pos, width, height);
float first_rect_portion;
uint16 rect_pos[2][2];
uint16 rect_new_pos[2];
uint16 rect_orig_width[2];
uint16 rect_orig_height[2];
uint16 rect_new_width[2];
uint16 rect_new_height[2];
// Figure out first rectangle
rect_pos[0][X] = 0;
rect_pos[0][Y] = 0;
if (split_axis == X)
{
Dbg_Assert(start_point >= x_pos);
Dbg_Assert(start_point <= x_pos + width);
Dbg_Assert(end_point >= x_pos);
Dbg_Assert(end_point <= x_pos + width);
// Dimensions of first rectangle
rect_orig_width[0] = start_point - x_pos + 1;
rect_orig_height[0] = height;
rect_new_width[0] = end_point - x_pos + 1;
rect_new_height[0] = height;
// Second rectangle
rect_pos[1][X] = start_point - x_pos;
rect_pos[1][Y] = 0;
rect_new_pos[X] = end_point - x_pos;
rect_new_pos[Y] = 0;
rect_orig_width[1] = width - (start_point - x_pos);
rect_orig_height[1] = height;
rect_new_width[1] = width - (end_point - x_pos);
rect_new_height[1] = height;
// Figure out portion of first rectangle to whole region
first_rect_portion = (float) rect_new_width[0] / (float) width;
}
else
{
Dbg_Assert(start_point >= y_pos);
Dbg_Assert(start_point <= y_pos + height);
Dbg_Assert(end_point >= y_pos);
Dbg_Assert(end_point <= y_pos + height);
// Dimensions of first rectangle
rect_orig_width[0] = width;
rect_orig_height[0] = start_point - y_pos + 1;
rect_new_width[0] = width;
rect_new_height[0] = end_point - y_pos + 1;
// Second rectangle
rect_pos[1][X] = 0;
rect_pos[1][Y] = start_point - y_pos;
rect_new_pos[X] = 0;
rect_new_pos[Y] = end_point - y_pos;
rect_orig_width[1] = width;
rect_orig_height[1] = height - (start_point - y_pos);
rect_new_width[1] = width;
rect_new_height[1] = height - (end_point - y_pos);
// Figure out portion of first rectangle to whole region
first_rect_portion = (float) rect_new_height[0] / (float) height;
}
// Make room for the original and new rectangles
uint32 *p_orig_rect_pixels[2];
uint32 *p_new_rect_pixels[2];
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
p_orig_rect_pixels[0] = new uint32[rect_orig_width[0] * rect_orig_height[0]];
p_orig_rect_pixels[1] = new uint32[rect_orig_width[1] * rect_orig_height[1]];
p_new_rect_pixels[0] = new uint32[rect_new_width[0] * rect_new_height[0]];
p_new_rect_pixels[1] = new uint32[rect_new_width[1] * rect_new_height[1]];
Mem::Manager::sHandle().PopContext();
// Get the original rectangles
s_get_region((uint8 *) p_orig_region_pixels, rect_pos[0][X], rect_pos[0][Y], width, height,
(uint8 *) p_orig_rect_pixels[0], rect_orig_width[0], rect_orig_height[0], 32);
s_get_region((uint8 *) p_orig_region_pixels, rect_pos[1][X], rect_pos[1][Y], width, height,
(uint8 *) p_orig_rect_pixels[1], rect_orig_width[1], rect_orig_height[1], 32);
// Scale each rectangle
s_scale_texture((uint8 *) p_orig_rect_pixels[0], rect_orig_width[0], rect_orig_height[0],
(uint8 *) p_new_rect_pixels[0], rect_new_width[0], rect_new_height[0], 32);
s_scale_texture((uint8 *) p_orig_rect_pixels[1], rect_orig_width[1], rect_orig_height[1],
(uint8 *) p_new_rect_pixels[1], rect_new_width[1], rect_new_height[1], 32);
// Combine two adjacent side lines into 1 (and put into the second rectangle since it will overwrite the first)
s_combine_adjacent_borders((uint8 *) p_new_rect_pixels[0], (uint8 *) p_new_rect_pixels[1],
rect_new_width[0], rect_new_height[0], rect_new_width[1], first_rect_portion, split_axis, 32);
// Put new rectangles back into region
s_put_region((uint8 *) p_orig_region_pixels, rect_pos[0][X], rect_pos[0][Y], width, height,
(uint8 *) p_new_rect_pixels[0], rect_new_width[0], rect_new_height[0], 32);
s_put_region((uint8 *) p_orig_region_pixels, rect_new_pos[X], rect_new_pos[Y], width, height,
(uint8 *) p_new_rect_pixels[1], rect_new_width[1], rect_new_height[1], 32);
// And put region back into texture
blit_32bit_buffer_to_texture(p_orig_region_pixels, x_pos, y_pos, width, height);
// Free all the buffers
delete [] p_orig_rect_pixels[0];
delete [] p_orig_rect_pixels[1];
delete [] p_new_rect_pixels[0];
delete [] p_new_rect_pixels[1];
delete [] p_orig_region_pixels;
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_pull_to_edge(uint16 point, int axis, int num_pixels)
{
#if PRINT_TIMES
static uint32 total_time = 0;
uint32 start_time = Tmr::GetTimeInUSeconds();
#endif
uint32 *p_texture_buffer = NULL;
uint32 *p_scaled_texture_buffer = NULL;
uint16 rect_pos[2];
uint16 rect_orig_width;
uint16 rect_orig_height;
uint16 rect_new_width;
uint16 rect_new_height;
uint16 scaled_offset;
if (num_pixels == 0)
{
// Nothing to do
return true;
}
// Cap num_pixels on low end
if ((point + num_pixels) <= 0)
{
num_pixels = -point + 1;
}
Dbg_Assert((point + num_pixels) >= 0);
if (axis == X)
{
Dbg_Assert(point < m_width);
// Cap num_pixels on high end
if ((point + num_pixels) >= m_width)
{
num_pixels = m_width - point - 1;
}
Dbg_Assert((point + num_pixels) < m_width);
bool left = (num_pixels < 0);
if (left)
{
// Figure out orig rectangle
rect_pos[X] = 0;
rect_pos[Y] = 0;
rect_orig_width = point + 1;
rect_orig_height = m_height;
// Figure out new rectangle
rect_new_width = point + (-num_pixels) + 1;
rect_new_height = m_height;
scaled_offset = -num_pixels;
}
else
{
// Figure out orig rectangle
rect_pos[X] = point;
rect_pos[Y] = 0;
rect_orig_width = (m_width - point);
rect_orig_height = m_height;
// Figure out new rectangle
rect_new_width = (m_width - point) + num_pixels;
rect_new_height = m_height;
scaled_offset = 0;
}
}
else
{
Dbg_Assert(point < m_height);
// Cap num_pixels on high end
if ((point + num_pixels) >= m_height)
{
num_pixels = m_height - point - 1;
}
Dbg_Assert((point + num_pixels) < m_height);
bool top = (num_pixels < 0);
if (top)
{
// Figure out orig rectangle
rect_pos[X] = 0;
rect_pos[Y] = 0;
rect_orig_width = m_width;
rect_orig_height = point + 1;
// Figure out new rectangle
rect_new_width = m_width;
rect_new_height = point + (-num_pixels) + 1;
scaled_offset = -num_pixels * m_width;
}
else
{
// Figure out orig rectangle
rect_pos[X] = 0;
rect_pos[Y] = point;
rect_orig_width = m_width;
rect_orig_height = (m_height - point);
// Figure out new rectangle
rect_new_width = m_width;
rect_new_height = (m_height - point) + num_pixels;
scaled_offset = 0;
}
}
// Copy texture region into temp buffers in 32-bit format
if (Mem::Manager::sHandle().CutsceneTopDownHeap())
{
// GJ FIX 9/9/03 FOR SK5:TT13114 - "Failing to allocate
// face texture memory in cutscenes"
// if the cutscene top down heap exists, we want to use
// that first, because there won't be much on the
// top down heap during cutscenes...
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().CutsceneTopDownHeap());
}
else
{
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
}
p_texture_buffer = new uint32[rect_orig_width * rect_orig_height];
p_scaled_texture_buffer = new uint32[rect_new_width * rect_new_height];
Mem::Manager::sHandle().PopContext();
//Dbg_Message("Copying region from (%d, %d) of size (%d, %d)", rect_pos[X], rect_pos[Y], rect_orig_width, rect_orig_height);
copy_region_to_32bit_buffer(p_texture_buffer, rect_pos[X], rect_pos[Y], rect_orig_width, rect_orig_height);
// Scale the rectangle
s_scale_texture((uint8 *) p_texture_buffer, rect_orig_width, rect_orig_height,
(uint8 *) p_scaled_texture_buffer, rect_new_width, rect_new_height, 32);
//Dbg_Message("Pull: Original size (%d, %d), new size (%d, %d)", rect_orig_width, rect_orig_height, rect_new_width, rect_new_height);
// Crop the rectangle and put back into original buffer
s_put_region((uint8 *) p_texture_buffer, 0, 0, rect_orig_width, rect_orig_height,
(uint8 *) (p_scaled_texture_buffer + scaled_offset), rect_new_width, rect_new_height, 32);
// And put region back into texture
blit_32bit_buffer_to_texture(p_texture_buffer, rect_pos[X], rect_pos[Y], rect_orig_width, rect_orig_height);
// Free buffers
if (p_texture_buffer)
{
delete [] p_texture_buffer;
}
if (p_scaled_texture_buffer)
{
delete [] p_scaled_texture_buffer;
}
#if PRINT_TIMES
uint32 end_time = Tmr::GetTimeInUSeconds();
total_time += end_time - start_time;
Dbg_Message("pull_to_edge Update time %d us; Total Time %d", end_time - start_time, total_time);
#endif
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_push_to_point(uint16 point, int axis, int num_pixels, bool use_fill_color, Image::RGBA fill_color)
{
#if PRINT_TIMES
static uint32 total_time = 0;
uint32 start_time = Tmr::GetTimeInUSeconds();
#endif
uint32 *p_texture_buffer = NULL;
uint32 *p_scaled_texture_buffer = NULL;
uint16 rect_pos[2];
uint16 rect_new_offset[2];
uint16 rect_orig_width;
uint16 rect_orig_height;
uint16 rect_new_width;
uint16 rect_new_height;
if (num_pixels == 0)
{
// Nothing to do
return true;
}
//Dbg_Message("Moving %d pixels along %d axis starting at %d", num_pixels, axis, point);
// Cap num_pixels on low end
if ((point + num_pixels) <= 0)
{
num_pixels = -point + 1;
}
Dbg_Assert((point + num_pixels) >= 0);
if (axis == X)
{
Dbg_Assert(point < m_width);
// Cap num_pixels on high end
if ((point + num_pixels) >= m_width)
{
num_pixels = m_width - point - 1;
}
Dbg_Assert((point + num_pixels) < m_width);
bool left = (num_pixels < 0);
if (left)
{
// Figure out orig rectangle
rect_pos[X] = point;
rect_pos[Y] = 0;
rect_orig_width = (m_width - point);
rect_orig_height = m_height;
// Figure out new rectangle
rect_new_offset[X] = 0;
rect_new_offset[Y] = 0;
rect_new_width = (m_width - point) - (-num_pixels);
rect_new_height = m_height;
}
else
{
// Figure out orig rectangle
rect_pos[X] = 0;
rect_pos[Y] = 0;
rect_orig_width = point + 1;
rect_orig_height = m_height;
// Figure out new rectangle
rect_new_offset[X] = num_pixels;
rect_new_offset[Y] = 0;
rect_new_width = point - num_pixels + 1;
rect_new_height = m_height;
}
}
else
{
Dbg_Assert(point < m_height);
// Cap num_pixels on high end
if ((point + num_pixels) >= m_height)
{
num_pixels = m_height - point - 1;
}
Dbg_Assert((point + num_pixels) < m_height);
bool top = (num_pixels < 0);
if (top)
{
// Figure out orig rectangle
rect_pos[X] = 0;
rect_pos[Y] = point;
rect_orig_width = m_width;
rect_orig_height = (m_height - point);
// Figure out new rectangle
rect_new_offset[X] = 0;
rect_new_offset[Y] = 0;
rect_new_width = m_width;
rect_new_height = (m_height - point) - (-num_pixels);
}
else
{
// Figure out orig rectangle
rect_pos[X] = 0;
rect_pos[Y] = 0;
rect_orig_width = m_width;
rect_orig_height = point + 1;
// Figure out new rectangle
rect_new_offset[X] = 0;
rect_new_offset[Y] = num_pixels;
rect_new_width = m_width;
rect_new_height = point - num_pixels + 1;
}
}
Dbg_Assert(rect_new_width);
Dbg_Assert(rect_new_height);
// Copy texture region into temp buffers in 32-bit format
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
p_texture_buffer = new uint32[rect_orig_width * rect_orig_height];
p_scaled_texture_buffer = new uint32[rect_new_width * rect_new_height];
Mem::Manager::sHandle().PopContext();
//Dbg_Message("Copying region from (%d, %d) of size (%d, %d)", rect_pos[X], rect_pos[Y], rect_orig_width, rect_orig_height);
copy_region_to_32bit_buffer(p_texture_buffer, rect_pos[X], rect_pos[Y], rect_orig_width, rect_orig_height);
// Scale the rectangle
s_scale_texture((uint8 *) p_texture_buffer, rect_orig_width, rect_orig_height,
(uint8 *) p_scaled_texture_buffer, rect_new_width, rect_new_height, 32);
// Check if we have a fill color
if (use_fill_color)
{
int num_pixels = rect_orig_width * rect_orig_height;
// Just brute force it for now
// Garrett: This doesn't work since p_texture_buffer is only a subset of the texture
Dbg_MsgAssert(0, ("Fill color not implemented properly yet"));
for (int i = 0; i < num_pixels; i++)
{
p_texture_buffer[i] = *((uint32 *) &fill_color);
}
}
// Put smaller rectangle back into original buffer
s_put_region((uint8 *) p_texture_buffer, rect_new_offset[X], rect_new_offset[Y], rect_orig_width, rect_orig_height,
(uint8 *) p_scaled_texture_buffer, rect_new_width, rect_new_height, 32);
// And put region back into texture
blit_32bit_buffer_to_texture(p_texture_buffer, rect_pos[X], rect_pos[Y], rect_orig_width, rect_orig_height);
// Cover up old pixels
if (!use_fill_color)
{
if (axis == X)
{
bool use_left = (num_pixels > 0);
int scaled_coord = (use_left) ? 0 : rect_new_width - 1;
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
uint32 *p_strip_buffer = new uint32[m_height];
Mem::Manager::sHandle().PopContext();
for (int pidx = 0; pidx < m_height; pidx++)
{
p_strip_buffer[pidx] = p_scaled_texture_buffer[(pidx * rect_new_width) + scaled_coord];
}
int start = (use_left) ? 0 : m_width - (-num_pixels);
int end = (use_left) ? num_pixels - 1 : m_width - 1;
for (int line = start; line <= end; line++)
{
blit_32bit_buffer_to_texture(p_strip_buffer, line, 0, 1, m_height);
}
delete [] p_strip_buffer;
}
else
{
bool use_top = (num_pixels > 0);
int scaled_coord = (use_top) ? 0 : rect_new_height - 1;
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
uint32 *p_strip_buffer = new uint32[m_width];
Mem::Manager::sHandle().PopContext();
memcpy(p_strip_buffer, &(p_scaled_texture_buffer[scaled_coord * rect_new_width]), m_width * sizeof(uint32));
int start = (use_top) ? 0 : m_height - (-num_pixels);
int end = (use_top) ? num_pixels - 1 : m_height - 1;
for (int line = start; line <= end; line++)
{
blit_32bit_buffer_to_texture(p_strip_buffer, 0, line, m_width, 1);
}
delete [] p_strip_buffer;
}
}
// Free buffers
if (p_texture_buffer)
{
delete [] p_texture_buffer;
}
if (p_scaled_texture_buffer)
{
delete [] p_scaled_texture_buffer;
}
#if PRINT_TIMES
uint32 end_time = Tmr::GetTimeInUSeconds();
total_time += end_time - start_time;
Dbg_Message("push_to_point Update time %d us; Total Time %d", end_time - start_time, total_time);
#endif
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_adjust_brightness(float brightness_scale, bool force_adjust_current)
{
#if PRINT_TIMES
static uint32 total_time = 0;
uint32 start_time = Tmr::GetTimeInUSeconds();
#endif
Dbg_Assert(mp_single_texture);
Dbg_MsgAssert(mp_cur_temp_32bit_image, ("For now, AdjustBrightness() only supports 32-bit mode"));
Image::RGBA *p_src_pixels;
Image::RGBA *p_dst_pixels = (Image::RGBA *) mp_cur_temp_32bit_image;
// Figure out the source
if (mp_orig_temp_32bit_image && !force_adjust_current)
{
p_src_pixels = (Image::RGBA *) mp_orig_temp_32bit_image;
}
else
{
p_src_pixels = (Image::RGBA *) mp_cur_temp_32bit_image;
}
// Adjust each pixel
int num_pixels = m_width * m_height;
for (int i = 0; i < num_pixels; i++, p_src_pixels++, p_dst_pixels++)
{
p_dst_pixels->r = (uint8) min(p_src_pixels->r * brightness_scale, 255);
p_dst_pixels->g = (uint8) min(p_src_pixels->g * brightness_scale, 255);
p_dst_pixels->b = (uint8) min(p_src_pixels->b * brightness_scale, 255);
}
#if PRINT_TIMES
uint32 end_time = Tmr::GetTimeInUSeconds();
total_time += end_time - start_time;
Dbg_Message("adjust_brightness(%f) Update time %d us; Total Time %d", brightness_scale, end_time - start_time, total_time);
#endif
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_adjust_hsv(float h, float s, float v, bool force_adjust_current)
{
#if PRINT_TIMES
static uint32 total_time = 0;
uint32 start_time = Tmr::GetTimeInUSeconds();
#endif
Dbg_Assert(mp_single_texture);
Dbg_MsgAssert(mp_cur_temp_32bit_image, ("For now, AdjustHSV() only supports 32-bit mode"));
Dbg_MsgAssert((h >= 0.0f) && (h <= 360.0f), ("h is out of range: %f", h));
Dbg_MsgAssert(s >= 0.0f, ("s is negative: %f", s));
Dbg_MsgAssert(v >= 0.0f, ("v is negative: %f", v));
Image::RGBA *p_src_pixels;
Image::RGBA *p_dst_pixels = (Image::RGBA *) mp_cur_temp_32bit_image;
// Figure out the source
if (mp_orig_temp_32bit_image && !force_adjust_current)
{
p_src_pixels = (Image::RGBA *) mp_orig_temp_32bit_image;
}
else
{
p_src_pixels = (Image::RGBA *) mp_cur_temp_32bit_image;
}
// Adjust each pixel
float pixel_h, pixel_s, pixel_v;
float pixel_r, pixel_g, pixel_b;
int num_pixels = m_width * m_height;
for (int i = 0; i < num_pixels; i++, p_src_pixels++, p_dst_pixels++)
{
// Convert
Gfx::inlineRGBtoHSV(p_src_pixels->r / 255.0f, p_src_pixels->g / 255.0f, p_src_pixels->b / 255.0f, pixel_h, pixel_s, pixel_v);
// Adjust
pixel_h += h;
if (pixel_h > 360.0f)
{
pixel_h -= 360.0f;
}
pixel_s = Mth::Min(pixel_s * s, 1.0f);
pixel_v = Mth::Min(pixel_v * v, 1.0f);
// Convert back
Gfx::inlineHSVtoRGB(pixel_r, pixel_g, pixel_b, pixel_h, pixel_s, pixel_v);
p_dst_pixels->r = (unsigned char)( pixel_r * 255.0f + 0.5f );
p_dst_pixels->g = (unsigned char)( pixel_g * 255.0f + 0.5f );
p_dst_pixels->b = (unsigned char)( pixel_b * 255.0f + 0.5f );
}
#if PRINT_TIMES
uint32 end_time = Tmr::GetTimeInUSeconds();
total_time += end_time - start_time;
Dbg_Message("adjust_hsv(%f) Update time %d us; Total Time %d", s, end_time - start_time, total_time);
#endif
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_add_to_vram()
{
Dbg_MsgAssert(mp_single_texture, ("CPs2Texture::plat_add_to_vram() only works for sSingleTexture types"));
return mp_single_texture->AddToVRAM();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_remove_from_vram()
{
Dbg_MsgAssert(mp_single_texture, ("CPs2Texture::plat_remove_from_vram() only works for sSingleTexture types"));
return mp_single_texture->RemoveFromVRAM();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint16 CPs2Texture::plat_get_width() const
{
return m_width;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint16 CPs2Texture::plat_get_height() const
{
return m_height;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint8 CPs2Texture::plat_get_bitdepth() const
{
return m_bitdepth;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint8 CPs2Texture::plat_get_palette_bitdepth() const
{
return m_clut_bitdepth;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint8 CPs2Texture::plat_get_num_mipmaps() const
{
return m_num_mipmaps;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_is_transparent() const
{
return m_transparent;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2Texture::plat_combine_textures(CTexture *p_texture, bool palette_gen)
{
CPs2Texture *p_ps2_texture = static_cast<CPs2Texture *>(p_texture);
// Make sure both textures have same attributes
Dbg_Assert(m_width == p_ps2_texture->m_width);
Dbg_Assert(m_height == p_ps2_texture->m_height);
Dbg_Assert(m_bitdepth == p_ps2_texture->m_bitdepth);
Dbg_Assert(m_clut_bitdepth == p_ps2_texture->m_clut_bitdepth);
Dbg_Assert((m_bitdepth == 8) || (m_bitdepth == 32)); // Maybe support more later
Dbg_Assert(mp_single_texture);
Dbg_Assert(p_ps2_texture->mp_single_texture);
bool paletted = (m_bitdepth <= 8);
uint32 *p_texture1_buffer = NULL;
uint32 *p_texture2_buffer = NULL;
Image::RGBA *p_src;
Image::RGBA *p_dst;
if (paletted)
{
// Try temp 32-bit images first
p_dst = (Image::RGBA *) mp_cur_temp_32bit_image;
p_src = (Image::RGBA *) p_ps2_texture->mp_cur_temp_32bit_image;
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
// Copy original textures iton temp buffers in 32-bit format
if (!p_dst)
{
p_texture1_buffer = new uint32[m_width * m_height];
copy_region_to_32bit_buffer(p_texture1_buffer, 0, 0, m_width, m_height);
p_dst = (Image::RGBA *) p_texture1_buffer;
}
if (!p_src)
{
p_texture2_buffer = new uint32[p_ps2_texture->m_width * p_ps2_texture->m_height];
p_ps2_texture->copy_region_to_32bit_buffer(p_texture2_buffer, 0, 0, p_ps2_texture->m_width, p_ps2_texture->m_height);
p_src = (Image::RGBA *) p_texture2_buffer;
}
Mem::Manager::sHandle().PopContext();
}
else
{
p_src = (Image::RGBA *) p_ps2_texture->mp_single_texture->GetTextureBuffer();
p_dst = (Image::RGBA *) mp_single_texture->GetTextureBuffer();
}
// Do the actual alpha blend
uint8 om_src_alpha;
int size = m_width * m_height;
for (int i = 0; i < size; i++, p_src++, p_dst++)
{
om_src_alpha = 0x80 - p_src->a;
p_dst->r = (uint8) ( ( ((int) p_src->r * p_src->a) + ((int) p_dst->r * om_src_alpha) ) >> 7 /* divide by 0x80 */);
p_dst->g = (uint8) ( ( ((int) p_src->g * p_src->a) + ((int) p_dst->g * om_src_alpha) ) >> 7 /* divide by 0x80 */);
p_dst->b = (uint8) ( ( ((int) p_src->b * p_src->a) + ((int) p_dst->b * om_src_alpha) ) >> 7 /* divide by 0x80 */);
p_dst->a = max(p_src->a, p_dst->a); // Choose the highest alpha (since we don't want solid pixels to become transparent)
}
// Go back to original bitdepth if necessary
if (paletted && !mp_cur_temp_32bit_image)
{
Dbg_Assert(m_clut_bitdepth == 32);
// Generate a new palette
if (palette_gen)
{
GeneratePalette((Image::RGBA *) mp_single_texture->GetClutBuffer(), (uint8 *) p_texture1_buffer, m_width, m_height, 32, 1 << m_bitdepth);
}
// And repalettize and put back into texture
blit_32bit_buffer_to_texture(p_texture1_buffer, 0, 0, m_width, m_height);
}
// Free buffers
if (p_texture1_buffer)
{
delete [] p_texture1_buffer;
}
if (p_texture2_buffer)
{
delete [] p_texture2_buffer;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////
// Here's a machine specific implementation of CTexDict
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2TexDict::CPs2TexDict(uint32 checksum) : CTexDict(checksum)
{
// Load nothing
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2TexDict::CPs2TexDict(const char *p_tex_dict_name, bool is_level_data, uint32 texDictOffset, bool isSkin, bool forceTexDictLookup) : CTexDict(p_tex_dict_name, !is_level_data)
{
LoadTextureDictionary(p_tex_dict_name, NULL, 0, is_level_data, texDictOffset, isSkin, forceTexDictLookup); // the derived class will does this
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2TexDict::~CPs2TexDict()
{
UnloadTextureDictionary(); // the derived class does this
}
/******************************************************************/
/* */
/* */
/******************************************************************/
NxPs2::sScene * CPs2TexDict::GetEngineTextureDictionary() const
{
//printf( "Returning scene from GetEngineTextureDictionary %08x\n", (uint32)mp_tex_dict );
return mp_tex_dict;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2TexDict::add_textures_to_hash_table()
{
for (int i = 0; i < mp_tex_dict->NumTextures; i++)
{
// Make sure we don't add duplicate textures. We can have the same texture in two
// different texture groups (for sorting purposes). This will break texture
// replacement, though.
if (!GetTexture(mp_tex_dict->pTextures[i].Checksum))
{
CPs2Texture *p_texture = new CPs2Texture;
p_texture->m_checksum = mp_tex_dict->pTextures[i].Checksum;
p_texture->m_width = mp_tex_dict->pTextures[i].GetWidth();
p_texture->m_height = mp_tex_dict->pTextures[i].GetHeight();
p_texture->m_bitdepth = mp_tex_dict->pTextures[i].GetBitdepth();
p_texture->m_clut_bitdepth = mp_tex_dict->pTextures[i].GetClutBitdepth();
p_texture->m_num_mipmaps = mp_tex_dict->pTextures[i].GetNumMipmaps();
p_texture->mp_group_texture = &(mp_tex_dict->pTextures[i]);
AddTexture(p_texture);
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2TexDict::LoadTextureDictionary(const char *p_tex_dict_name, uint32* pData, int dataSize, bool is_level_data, uint32 texDictOffset, bool isSkin, bool forceTexDictLookup)
{
// set up the texture dictionary's main parameters
bool IsSkin;
bool IsInstanceable;
bool UsesPip;
if ( is_level_data )
{
// for level data
IsSkin = false;
IsInstanceable = false;
UsesPip = true;
}
else if ( !isSkin && texDictOffset==0 )
{
// for non-skinned models (unless they
// do texture replacement, such as the
// boards in the skateshop do)
IsSkin = false;
IsInstanceable = false;
UsesPip = true;
}
else
{
// for all skinned models, and for
// non-skinned models that do
// texture replacement)
IsSkin = true;
IsInstanceable = true;
UsesPip = false;
}
if ( !is_level_data && isSkin )
{
// add all skinned model textures
// to the hash table
forceTexDictLookup = true;
}
if ( p_tex_dict_name )
{
// either the filename OR the data pointer should have been specified, but not both
Dbg_MsgAssert( !pData, ( "You can't specify both a filename %s AND a data pointer", p_tex_dict_name ) )
// p_tex_dict_name is assumed to be the full path name of the texture dictionary
mp_tex_dict = NxPs2::LoadTextures(p_tex_dict_name, IsSkin, IsInstanceable, UsesPip, texDictOffset, &m_file_size );
Dbg_Assert( mp_tex_dict );
}
else
{
Dbg_MsgAssert( pData, ( "No data pointer specified" ) );
m_file_size = dataSize;
mp_tex_dict = NxPs2::LoadTextures(pData, dataSize, IsSkin, IsInstanceable, UsesPip, texDictOffset );
Dbg_Assert( mp_tex_dict );
}
// Add textures to hash table (just do it for non-level dictionaries now)
// should this go on bottom up heap?
if ( forceTexDictLookup )
{
add_textures_to_hash_table();
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2TexDict::UnloadTextureDictionary()
{
NxPs2::DeleteTextures(mp_tex_dict);
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTexture * CPs2TexDict::plat_load_texture(const char *p_texture_name, bool sprite, bool alloc_vram)
{
CPs2Texture *p_texture = new CPs2Texture;
if (!p_texture->LoadTexture(p_texture_name, sprite, alloc_vram))
{
Dbg_Error("Can't load texture %s", p_texture_name);
}
return p_texture;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTexture * CPs2TexDict::plat_load_texture_from_buffer(uint8* p_buffer, int buffer_size, uint32 texture_checksum, bool sprite, bool alloc_vram)
{
CPs2Texture *p_texture = new CPs2Texture;
if (!p_texture->LoadTextureFromBuffer(p_buffer, buffer_size, texture_checksum, sprite, alloc_vram))
{
Dbg_MsgAssert(0, ("Can't load texture from buffer %s", Script::FindChecksumName(texture_checksum)));
}
return p_texture;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTexture * CPs2TexDict::plat_reload_texture(const char *p_texture_name)
{
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2TexDict::plat_unload_texture(CTexture *p_texture)
{
delete p_texture;
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2TexDict::plat_add_texture(CTexture *p_texture)
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2TexDict::plat_remove_texture(CTexture *p_texture)
{
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTexture * CPs2TexDict::plat_copy_texture(uint32 new_texture_checksum, CTexture *p_texture)
{
CPs2Texture *p_ps2_texture = static_cast<CPs2Texture *>(p_texture);
return new CPs2Texture(*p_ps2_texture);
}
} // Namespace Nx