TexturePeeker

This commit is contained in:
David Rose 2008-08-27 01:38:08 +00:00
parent bcc7ed59a8
commit 515c6cd83a
7 changed files with 726 additions and 1 deletions

View File

@ -55,6 +55,7 @@
sliderTable.I sliderTable.h \
texture.I texture.h \
textureContext.I textureContext.h \
texturePeeker.I texturePeeker.h \
texturePool.I texturePool.h \
texturePoolFilter.I texturePoolFilter.h \
textureStage.I textureStage.h \
@ -116,7 +117,9 @@
simpleAllocator.cxx \
simpleLru.cxx \
sliderTable.cxx \
texture.cxx textureContext.cxx texturePool.cxx \
texture.cxx textureContext.cxx \
texturePeeker.cxx \
texturePool.cxx \
texturePoolFilter.cxx \
textureStage.cxx \
transformBlend.cxx \
@ -181,6 +184,7 @@
sliderTable.I sliderTable.h \
texture.I texture.h \
textureContext.I textureContext.h \
texturePeeker.I texturePeeker.h \
texturePool.I texturePool.h \
texturePoolFilter.I texturePoolFilter.h \
textureStage.I textureStage.h \

View File

@ -14,6 +14,7 @@
#include "sliderTable.cxx"
#include "texture.cxx"
#include "textureContext.cxx"
#include "texturePeeker.cxx"
#include "texturePool.cxx"
#include "texturePoolFilter.cxx"
#include "textureStage.cxx"

View File

@ -37,6 +37,7 @@
#include "pStatTimer.h"
#include "pbitops.h"
#include "streamReader.h"
#include "texturePeeker.h"
#include <stddef.h>
@ -1946,6 +1947,34 @@ clear_simple_ram_image() {
++_simple_image_modified;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::peek
// Access: Published
// Description: Returns a TexturePeeker object that can be used to
// examine the individual texels stored within this
// Texture by (u, v) coordinate.
//
// If the texture has a ram image resident, that image
// is used. If it does not have a full ram image but
// does have a simple_ram_image resident, that image is
// used instead. If neither image is resident the full
// image is reloaded.
//
// Returns NULL if the texture cannot find an image to
// load, or the texture format is incompatible.
////////////////////////////////////////////////////////////////////
PT(TexturePeeker) Texture::
peek() {
ReMutexHolder holder(_lock);
PT(TexturePeeker) peeker = new TexturePeeker(this);
if (peeker->is_valid()) {
return peeker;
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::prepare
// Access: Published

View File

@ -38,6 +38,7 @@ class PreparedGraphicsObjects;
class CullTraverser;
class CullTraverserData;
class BamCacheRecord;
class TexturePeeker;
struct DDSHeader;
////////////////////////////////////////////////////////////////////
@ -337,6 +338,8 @@ PUBLISHED:
void generate_simple_ram_image();
void clear_simple_ram_image();
PT(TexturePeeker) peek();
INLINE UpdateSeq get_properties_modified() const;
INLINE UpdateSeq get_image_modified() const;
INLINE UpdateSeq get_simple_image_modified() const;
@ -670,6 +673,7 @@ private:
friend class TextureContext;
friend class PreparedGraphicsObjects;
friend class TexturePool;
friend class TexturePeeker;
};
extern EXPCL_PANDA_GOBJ ConfigVariableEnum<Texture::QualityLevel> texture_quality_level;

View File

@ -0,0 +1,64 @@
// Filename: texturePeeker.I
// Created by: drose (26Aug08)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::is_valid
// Access: Public
// Description: Returns true if the TexturePeeker was able to
// initialize itself and is ready to return texel
// colors.
////////////////////////////////////////////////////////////////////
INLINE bool TexturePeeker::
is_valid() const {
return !_image.is_null();
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_x_size
// Access: Published
// Description: Returns the width of the texture image that is
// contributing to the TexturePeeker's information.
// This may be either the Texture's full width, or its
// simple ram image's width.
////////////////////////////////////////////////////////////////////
INLINE int TexturePeeker::
get_x_size() const {
return _x_size;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_y_size
// Access: Published
// Description: Returns the height of the texture image that is
// contributing to the TexturePeeker's information.
// This may be either the Texture's full height, or its
// simple ram image's height.
////////////////////////////////////////////////////////////////////
INLINE int TexturePeeker::
get_y_size() const {
return _y_size;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_z_size
// Access: Published
// Description: Returns the depth of the texture image that is
// contributing to the TexturePeeker's information.
////////////////////////////////////////////////////////////////////
INLINE int TexturePeeker::
get_z_size() const {
return _z_size;
}

View File

@ -0,0 +1,521 @@
// Filename: texturePeeker.cxx
// Created by: drose (26Aug08)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "texturePeeker.h"
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::Constructor
// Access: Private
// Description: Use Texture::peek() to construct a TexturePeeker.
////////////////////////////////////////////////////////////////////
TexturePeeker::
TexturePeeker(Texture *tex) {
_x_size = tex->_x_size;
_y_size = tex->_y_size;
_z_size = tex->_z_size;
_component_width = tex->_component_width;
_num_components = tex->_num_components;
_format = tex->_format;
_component_type = tex->_component_type;
if (tex->_texture_type == Texture::TT_cube_map) {
// Cube map texture. We'll need to map from (u, v, w) to (u, v)
// within the appropriate page, where w indicates the page.
// TODO: handle cube maps.
return;
} else {
// Regular 1-d, 2-d, or 3-d texture. The coordinates map
// directly. Simple ram images are possible if it is a 2-d
// texture.
if (!(tex->has_ram_image() && tex->get_ram_image_compression() == Texture::CM_off) && tex->has_simple_ram_image()) {
_image = tex->_simple_ram_image._image;
_x_size = tex->_simple_x_size;
_y_size = tex->_simple_y_size;
_z_size = 1;
_component_width = 1;
_num_components = 4;
_format = Texture::F_rgba;
_component_type = Texture::T_unsigned_byte;
} else {
_image = tex->get_uncompressed_ram_image();
}
}
if (_image.is_null()) {
return;
}
_pixel_width = _component_width * _num_components;
switch (_component_type) {
case Texture::T_unsigned_byte:
_get_component = Texture::get_unsigned_byte;
break;
case Texture::T_unsigned_short:
_get_component = Texture::get_unsigned_short;
break;
case Texture::T_float:
// Not supported.
_image.clear();
return;
}
switch (_format) {
case Texture::F_depth_stencil:
case Texture::F_color_index:
// Not supported.
_image.clear();
return;
case Texture::F_red:
_get_texel = get_texel_r;
break;
case Texture::F_green:
_get_texel = get_texel_g;
break;
case Texture::F_blue:
_get_texel = get_texel_b;
break;
case Texture::F_alpha:
_get_texel = get_texel_a;
break;
case Texture::F_luminance:
_get_texel = get_texel_l;
break;
case Texture::F_luminance_alpha:
case Texture::F_luminance_alphamask:
_get_texel = get_texel_la;
break;
case Texture::F_rgb:
case Texture::F_rgb5:
case Texture::F_rgb8:
case Texture::F_rgb12:
case Texture::F_rgb332:
_get_texel = get_texel_rgb;
break;
case Texture::F_rgba:
case Texture::F_rgbm:
case Texture::F_rgba4:
case Texture::F_rgba5:
case Texture::F_rgba8:
case Texture::F_rgba12:
case Texture::F_rgba16:
case Texture::F_rgba32:
_get_texel = get_texel_rgba;
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::lookup
// Access: Published
// Description: Fills "color" with the RGBA color of the texel at
// point (u, v).
//
// The texel color is determined via nearest-point
// sampling (no filtering of adjacent pixels),
// regardless of the filter type associated with the
// texture. u, v, and w will wrap around regardless of
// the texture's wrap mode.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
lookup(Colorf &color, float u, float v) const {
int x = int((u - cfloor(u)) * (float)_x_size + 0.5f) % _x_size;
int y = int((v - cfloor(v)) * (float)_y_size + 0.5f) % _y_size;
const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
(*_get_texel)(color, p, _get_component);
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::lookup
// Access: Published
// Description: Fills "color" with the RGBA color of the texel at
// point (u, v, w).
//
// The texel color is determined via nearest-point
// sampling (no filtering of adjacent pixels),
// regardless of the filter type associated with the
// texture. u, v, and w will wrap around regardless of
// the texture's wrap mode.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
lookup(Colorf &color, float u, float v, float w) const {
int x = int((u - cfloor(u)) * (float)_x_size + 0.5f) % _x_size;
int y = int((v - cfloor(v)) * (float)_y_size + 0.5f) % _y_size;
int z = int((w - cfloor(w)) * (float)_z_size + 0.5f) % _z_size;
const unsigned char *p = _image.p() + (z * _x_size * _y_size + y * _x_size + x) * _pixel_width;
(*_get_texel)(color, p, _get_component);
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::filter_rect
// Access: Published
// Description: Fills "color" with the average RGBA color of the
// texels within the rectangle defined by the specified
// coordinate range.
//
// The texel color is linearly filtered over the entire
// region. u, v, and w will wrap around regardless of
// the texture's wrap mode.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
filter_rect(Colorf &color,
float min_u, float min_v, float max_u, float max_v) const {
int min_x, max_x;
init_rect_minmax(min_x, max_x, min_u, max_u, _x_size);
int min_y, max_y;
init_rect_minmax(min_y, max_y, min_v, max_v, _y_size);
color.set(0.0f, 0.0f, 0.0f, 0.0f);
float net = 0.0f;
accum_filter_y(color, net, 0,
min_x, max_x, min_u, max_u,
min_y, max_y, min_v, max_v,
1.0f);
if (net != 0.0f) {
color /= net;
}
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::filter_rect
// Access: Published
// Description: Fills "color" with the average RGBA color of the
// texels within the rectangle defined by the specified
// coordinate range.
//
// The texel color is linearly filtered over the entire
// region. u, v, and w will wrap around regardless of
// the texture's wrap mode.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
filter_rect(Colorf &color,
float min_u, float min_v, float min_w,
float max_u, float max_v, float max_w) const {
int min_x, max_x;
init_rect_minmax(min_x, max_x, min_u, max_u, _x_size);
int min_y, max_y;
init_rect_minmax(min_y, max_y, min_v, max_v, _y_size);
int min_z, max_z;
init_rect_minmax(min_z, max_z, min_w, max_w, _z_size);
color.set(0.0f, 0.0f, 0.0f, 0.0f);
float net = 0.0f;
accum_filter_z(color, net,
min_x, max_x, min_u, max_u,
min_y, max_y, min_v, max_v,
min_z, max_z, min_w, max_w);
if (net != 0.0f) {
color /= net;
}
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::init_rect_minmax
// Access: Private, Static
// Description: Sanity-checks min_u, max_u and computes min_x and
// min_y based on them. Also works for y and z.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
init_rect_minmax(int &min_x, int &max_x, float &min_u, float &max_u,
int x_size) {
if (min_u > max_u) {
float t = min_u;
min_u = max_u;
max_u = t;
}
if (max_u - min_u >= 1.0f) {
min_u = 0.0f;
max_u = 1.0f;
}
min_x = (int)cfloor(min_u * (float)x_size);
max_x = (int)cceil(max_u * (float)x_size);
nassertv(min_x <= max_x);
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::accum_filter_z
// Access: Private
// Description: Accumulates the range of pixels from min_z to max_z.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
accum_filter_z(Colorf &color, float &net,
int min_x, int max_x, float min_u, float max_u,
int min_y, int max_y, float min_v, float max_v,
int min_z, int max_z, float min_w, float max_w) const {
int zi = min_z;
if (min_z >= max_z - 1) {
// Within a single texel.
accum_filter_y(color, net, zi % _z_size,
min_x, max_x, min_u, max_u,
min_y, max_y, min_v, max_v,
1.0f);
} else {
// First part-texel.
float w = (min_z + 1) - min_w * _z_size;
accum_filter_y(color, net, zi % _z_size,
min_x, max_x, min_u, max_u,
min_y, max_y, min_v, max_v,
w);
int zs = max_z - 1;
// Run of full texels.
zi = min_z + 1;
while (zi < zs) {
accum_filter_y(color, net, zi % _z_size,
min_x, max_x, min_u, max_u,
min_y, max_y, min_v, max_v,
1.0f);
++zi;
}
// Last part-texel.
w = max_w * _z_size - (max_z - 1);
accum_filter_y(color, net, zi % _z_size,
min_x, max_x, min_u, max_u,
min_y, max_y, min_v, max_v,
w);
}
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::accum_filter_y
// Access: Private
// Description: Accumulates the range of pixels from min_y to max_y.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
accum_filter_y(Colorf &color, float &net, int zi,
int min_x, int max_x, float min_u, float max_u,
int min_y, int max_y, float min_v, float max_v,
float weight) const {
int yi = min_y;
if (min_y >= max_y - 1) {
// Within a single texel.
accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight);
} else {
// First part-texel.
float w = (min_y + 1) - min_v * _y_size;
accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight * w);
int ys = max_y - 1;
// Run of full texels.
yi = min_y + 1;
while (yi < ys) {
accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight);
++yi;
}
// Last part-texel.
w = max_v * _y_size - (max_y - 1);
accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight * w);
}
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::accum_filter_x
// Access: Private
// Description: Accumulates the range of pixels from min_x to max_x.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
accum_filter_x(Colorf &color, float &net, int yi, int zi,
int min_x, int max_x, float min_u, float max_u,
float weight) const {
// Compute the p corresponding to min_x.
int xi = min_x % _x_size;
const unsigned char *p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
if (min_x >= max_x - 1) {
// Within a single texel.
accum_texel(color, net, p, weight);
} else {
// First part-texel.
float w = (min_x + 1) - min_u * _x_size;
accum_texel(color, net, p, weight * w);
int xs = max_x - 1;
// Run of full texels.
xi = min_x + 1;
while (xi < xs) {
if (xi == _x_size) {
xi = 0;
p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
xs -= _x_size;
}
accum_texel(color, net, p, weight);
++xi;
}
// Last part-texel.
if (xi == _x_size) {
xi = 0;
p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
}
w = max_u * _x_size - (max_x - 1);
accum_texel(color, net, p, weight * w);
}
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::accum_texel
// Access: Private
// Description: Accumulates a single texel into the total computed by
// filter_rect().
////////////////////////////////////////////////////////////////////
void TexturePeeker::
accum_texel(Colorf &color, float &net, const unsigned char *&p, float weight) const {
Colorf c;
(*_get_texel)(c, p, _get_component);
color += c * weight;
net += weight;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_texel_r
// Access: Private, Static
// Description: Gets the color of the texel at byte p, given that the
// texture is in format F_red.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
get_texel_r(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component) {
color[0] = (*get_component)(p);
color[1] = 0.0f;
color[2] = 0.0f;
color[3] = 1.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_texel_g
// Access: Private, Static
// Description: Gets the color of the texel at byte p, given that the
// texture is in format F_green.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
get_texel_g(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component) {
color[0] = 0.0f;
color[1] = (*get_component)(p);
color[2] = 0.0f;
color[3] = 1.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_texel_b
// Access: Private, Static
// Description: Gets the color of the texel at byte p, given that the
// texture is in format F_blue.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
get_texel_b(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component) {
color[0] = 0.0f;
color[1] = 0.0f;
color[2] = (*get_component)(p);
color[3] = 1.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_texel_a
// Access: Private, Static
// Description: Gets the color of the texel at byte p, given that the
// texture is in format F_alpha.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
get_texel_a(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component) {
color[0] = 0.0f;
color[1] = 0.0f;
color[2] = 1.0f;
color[3] = (*get_component)(p);
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_texel_l
// Access: Private, Static
// Description: Gets the color of the texel at byte p, given that the
// texture is in format F_luminance.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
get_texel_l(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component) {
color[0] = (*get_component)(p);
color[1] = color[0];
color[2] = color[0];
color[3] = 1.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_texel_la
// Access: Private, Static
// Description: Gets the color of the texel at byte p, given that the
// texture is in format F_luminance_alpha or similar.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
get_texel_la(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component) {
color[0] = (*get_component)(p);
color[1] = color[0];
color[2] = color[0];
color[3] = (*get_component)(p);
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_texel_rgb
// Access: Private, Static
// Description: Gets the color of the texel at byte p, given that the
// texture is in format F_rgb or similar.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
get_texel_rgb(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component) {
color[2] = (*get_component)(p);
color[1] = (*get_component)(p);
color[0] = (*get_component)(p);
color[3] = 1.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePeeker::get_texel_rgba
// Access: Private, Static
// Description: Gets the color of the texel at byte p, given that the
// texture is in format F_rgba or similar.
////////////////////////////////////////////////////////////////////
void TexturePeeker::
get_texel_rgba(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component) {
color[2] = (*get_component)(p);
color[1] = (*get_component)(p);
color[0] = (*get_component)(p);
color[3] = (*get_component)(p);
}

View File

@ -0,0 +1,102 @@
// Filename: texturePeeker.h
// Created by: drose (26Aug08)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef TEXTUREPEEKER_H
#define TEXTUREPEEKER_H
#include "pandabase.h"
#include "referenceCount.h"
#include "texture.h"
////////////////////////////////////////////////////////////////////
// Class : TexturePeeker
// Description : An instance of this object is returned by
// Texture::peek(). This object allows quick and easy
// inspection of a texture's texels by (u, v)
// coordinates.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_GOBJ TexturePeeker : public ReferenceCount {
private:
TexturePeeker(Texture *tex);
public:
INLINE bool is_valid() const;
PUBLISHED:
INLINE int get_x_size() const;
INLINE int get_y_size() const;
INLINE int get_z_size() const;
void lookup(Colorf &color, float u, float v) const;
void lookup(Colorf &color, float u, float v, float w) const;
void filter_rect(Colorf &color,
float min_u, float min_v,
float max_u, float max_v) const;
void filter_rect(Colorf &color,
float min_u, float min_v, float min_w,
float max_u, float max_v, float max_w) const;
private:
static void init_rect_minmax(int &min_x, int &max_x,
float &min_u, float &max_u,
int x_size);
void accum_filter_z(Colorf &color, float &net,
int min_x, int max_x, float min_u, float max_u,
int min_y, int max_y, float min_v, float max_v,
int min_z, int max_z, float min_w, float max_w) const;
void accum_filter_y(Colorf &color, float &net, int zi,
int min_x, int max_x, float min_u, float max_u,
int min_y, int max_y, float min_v, float max_v,
float weight) const;
void accum_filter_x(Colorf &color, float &net, int yi, int zi,
int min_x, int max_x, float min_u, float max_u,
float weight) const;
void accum_texel(Colorf &color, float &net, const unsigned char *&p,
float weight) const;
typedef double GetComponentFunc(const unsigned char *&p);
typedef void GetTexelFunc(Colorf &color, const unsigned char *&p,
GetComponentFunc *get_component);
static void get_texel_r(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component);
static void get_texel_g(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component);
static void get_texel_b(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component);
static void get_texel_a(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component);
static void get_texel_l(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component);
static void get_texel_la(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component);
static void get_texel_rgb(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component);
static void get_texel_rgba(Colorf &color, const unsigned char *&p, GetComponentFunc *get_component);
int _x_size;
int _y_size;
int _z_size;
int _component_width;
int _num_components;
int _pixel_width;
Texture::Format _format;
Texture::ComponentType _component_type;
CPTA_uchar _image;
GetComponentFunc *_get_component;
GetTexelFunc *_get_texel;
friend class Texture;
};
#include "texturePeeker.I"
#endif