support GraphicsOutput::set_inverted()

This commit is contained in:
David Rose 2004-12-07 04:25:38 +00:00
parent 097ce080d6
commit 48e09cda31
26 changed files with 491 additions and 350 deletions

View File

@ -35,71 +35,90 @@ ConfigureFn(config_display) {
init_libdisplay();
}
// This is normally true; set it false to disable view-frustum culling
// (primarily useful for debugging).
const bool view_frustum_cull = config_display.GetBool("view-frustum-cull", true);
ConfigVariableBool view_frustum_cull
("view-frustum-cull", true,
"This is normally true; set it false to disable view-frustum culling "
"(primarily useful for debugging).");
// Set this true to show the number of unused states in the pstats
// graph for TransformState and RenderState counts. This adds a bit
// of per-frame overhead to count these things up.
const bool pstats_unused_states = config_display.GetBool("pstats-unused-states", false);
ConfigVariableBool pstats_unused_states
("pstats-unused-states", false,
"Set this true to show the number of unused states in the pstats "
"graph for TransformState and RenderState counts. This adds a bit "
"of per-frame overhead to count these things up.");
// This is the default threading model to use for new windows. Use
// empty string for single-threaded, or something like "cull/draw" for
// a 3-stage pipeline. See GraphicsEngine::set_threading_model().
// Warning! The code that uses this is currently experimental and
// incomplete, and will almost certainly crash! Do not set
// threading-model to anything other than its default of a
// single-threaded model unless you are developing Panda's threading
// system!
const string threading_model = config_display.GetString("threading-model", "");
ConfigVariableString threading_model
("threading-model", "",
"This is the default threading model to use for new windows. Use "
"empty string for single-threaded, or something like \"cull/draw\" for "
"a 3-stage pipeline. See GraphicsEngine::set_threading_model(). "
"EXPERIMENTAL and incomplete, do not use this!");
// This indicates the initial setting of the auto-flip flag. Set it
// true (the default) to cause render_frame() to flip all the windows
// before it returns (in single-threaded mode only), or false to wait
// until an explicit call to flip_frame() or the next render_frame().
const bool auto_flip = config_display.GetBool("auto-flip", true);
ConfigVariableBool auto_flip
("auto-flip", true,
"This indicates the initial setting of the auto-flip flag. Set it "
"true (the default) to cause render_frame() to flip all the windows "
"before it returns (in single-threaded mode only), or false to wait "
"until an explicit call to flip_frame() or the next render_frame().");
// Set this true to yield the timeslice at the end of the frame to be
// more polite to other applications that are trying to run.
const bool yield_timeslice = config_display.GetBool("yield-timeslice", false);
ConfigVariableBool yield_timeslice
("yield-timeslice", false,
"Set this true to yield the timeslice at the end of the frame to be "
"more polite to other applications that are trying to run.");
const string screenshot_filename = config_display.GetString("screenshot-filename", "%~p-%a-%b-%d-%H-%M-%S-%Y-%~f.%~e");
const string screenshot_extension = config_display.GetString("screenshot-extension", "jpg");
ConfigVariableString screenshot_filename
("screenshot-filename", "%~p-%a-%b-%d-%H-%M-%S-%Y-%~f.%~e",
"This specifies the filename pattern to be used to generate "
"screenshots captured via save_screenshot_default(). See "
"DisplayRegion::save_screenshot()."
);
ConfigVariableString screenshot_extension
("screenshot-extension", "jpg",
"This specifies the default filename extension (and therefore the "
"default image type) to be used for saving screenshots.");
// Set this true to cause offscreen GraphicsBuffers to be created as
// GraphicsWindows, if possible, so that their contents may be viewed
// interactively. Handy during development of multipass algorithms.
const bool show_buffers = config_display.GetBool("show-buffers", false);
ConfigVariableBool show_buffers
("show-buffers", false,
"Set this true to cause offscreen GraphicsBuffers to be created as "
"GraphicsWindows, if possible, so that their contents may be viewed "
"interactively. Handy during development of multipass algorithms.");
// Set this true to make GraphicsOutput::make_render_texture() try to
// create a parasite buffer before it tries to create an offscreen
// buffer. This may be desired if you know your graphics API does not
// support render-directly-to-texture and you want to minimize
// framebuffer memory.
const bool prefer_parasite_buffer = config_display.GetBool("prefer-parasite-buffer", true);
ConfigVariableBool prefer_parasite_buffer
("prefer-parasite-buffer", true,
"Set this true to make GraphicsOutput::make_render_texture() try to "
"create a parasite buffer before it tries to create an offscreen "
"buffer. This may be desired if you know your graphics API does not "
"support render-directly-to-texture and you want to minimize "
"framebuffer memory.");
// Set this true to make GraphicsOutput::make_render_texture() first
// try to create a single-buffered offscreen buffer, before falling
// back to a double-buffered one (or whatever kind the source window
// has). This is true by default to reduce waste of framebuffer
// memory, but you may get a performance benefit by setting it to
// false (since in that case the buffer can share a graphics context
// with the window).
const bool prefer_single_buffer = config_display.GetBool("prefer-single-buffer", true);
ConfigVariableBool prefer_single_buffer
("prefer-single-buffer", true,
"Set this true to make GraphicsOutput::make_render_texture() first "
"try to create a single-buffered offscreen buffer, before falling "
"back to a double-buffered one (or whatever kind the source window "
"has). This is true by default to reduce waste of framebuffer "
"memory, but you may get a performance benefit by setting it to "
"false (since in that case the buffer can share a graphics context "
"with the window).");
ConfigVariableBool copy_texture_inverted
("copy-texture-inverted", false,
"Set this true to indicate that the GSG in use will invert textures when "
"it performs a framebuffer-to-texture copy operation, or false to indicate "
"that it does the right thing. If this is not set, the default behavior is "
"determined by the GSG's internal logic.");
// Use the variable load-display to specify the name of the default
// graphics display library or GraphicsPipe to load. It is the name
// of a shared library (or * for all libraries named in aux-display),
// optionally followed by the name of the particular GraphicsPipe
// class to create.
// Also use the variable aux-display to name each of the graphics
// display libraries that are available on a particular platform.
// This variable may be repeated several times.
ConfigVariableBool window_inverted
("window-inverted", false,
"Set this true to create all windows with the inverted flag set, so that "
"they will render upside-down and backwards. Normally this is useful only "
"for debugging.");
////////////////////////////////////////////////////////////////////

View File

@ -21,29 +21,34 @@
#include "pandabase.h"
#include "notifyCategoryProxy.h"
#include "configVariableBool.h"
#include "configVariableString.h"
#include "configVariableList.h"
#include "dconfig.h"
#include <string>
#include "pvector.h"
ConfigureDecl(config_display, EXPCL_PANDA, EXPTP_PANDA);
NotifyCategoryDecl(display, EXPCL_PANDA, EXPTP_PANDA);
NotifyCategoryDecl(gsg, EXPCL_PANDA, EXPTP_PANDA);
extern const bool view_frustum_cull;
extern const bool pstats_unused_states;
extern ConfigVariableBool view_frustum_cull;
extern ConfigVariableBool pstats_unused_states;
extern const string threading_model;
extern const bool auto_flip;
extern const bool yield_timeslice;
extern ConfigVariableString threading_model;
extern ConfigVariableBool auto_flip;
extern ConfigVariableBool yield_timeslice;
extern const string screenshot_filename;
extern const string screenshot_extension;
extern ConfigVariableString screenshot_filename;
extern ConfigVariableString screenshot_extension;
extern const bool show_buffers;
extern ConfigVariableBool show_buffers;
extern const bool prefer_parasite_buffer;
extern const bool prefer_single_buffer;
extern ConfigVariableBool prefer_parasite_buffer;
extern ConfigVariableBool prefer_single_buffer;
extern ConfigVariableBool copy_texture_inverted;
extern ConfigVariableBool window_inverted;
extern EXPCL_PANDA void init_libdisplay();

View File

@ -50,27 +50,6 @@ get_sort() const {
return _sort;
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::do_compute_pixels
// Access: Private
// Description: The private implementation of compute_pixels, this
// assumes that we already have the lock.
////////////////////////////////////////////////////////////////////
INLINE void DisplayRegion::
do_compute_pixels(int x_size, int y_size) {
if (display_cat.is_debug()) {
display_cat.debug()
<< "DisplayRegion::do_compute_pixels(" << x_size << ", " << y_size << ")\n";
}
_pl = int((_l * x_size) + 0.5);
_pr = int((_r * x_size) + 0.5);
_pb = int((_b * y_size) + 0.5);
_pt = int((_t * y_size) + 0.5);
_pbi = int(((1.0f - _b) * y_size) + 0.5);
_pti = int(((1.0f - _t) * y_size) + 0.5);
}
INLINE ostream &operator << (ostream &out, const DisplayRegion &dr) {
dr.output(out);

View File

@ -553,3 +553,37 @@ win_display_regions_changed() {
_window->win_display_regions_changed();
}
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::do_compute_pixels
// Access: Private
// Description: The private implementation of compute_pixels, this
// assumes that we already have the lock.
////////////////////////////////////////////////////////////////////
void DisplayRegion::
do_compute_pixels(int x_size, int y_size) {
if (display_cat.is_debug()) {
display_cat.debug()
<< "DisplayRegion::do_compute_pixels(" << x_size << ", " << y_size << ")\n";
}
_pl = int((_l * x_size) + 0.5);
_pr = int((_r * x_size) + 0.5);
const GraphicsOutput *win = get_window();
nassertv(win != (GraphicsOutput *)NULL);
if (win->get_inverted()) {
// The window is inverted; compute the DisplayRegion accordingly.
_pb = int(((1.0f - _t) * y_size) + 0.5);
_pt = int(((1.0f - _b) * y_size) + 0.5);
_pbi = int((_t * y_size) + 0.5);
_pti = int((_b * y_size) + 0.5);
} else {
// The window is normal.
_pb = int((_b * y_size) + 0.5);
_pt = int((_t * y_size) + 0.5);
_pbi = int(((1.0f - _b) * y_size) + 0.5);
_pti = int(((1.0f - _t) * y_size) + 0.5);
}
}

View File

@ -99,7 +99,7 @@ PUBLISHED:
private:
void win_display_regions_changed();
INLINE void do_compute_pixels(int x_size, int y_size);
void do_compute_pixels(int x_size, int y_size);
Mutex _lock;
float _l;

View File

@ -30,6 +30,7 @@
#include "pStatClient.h"
#include "pStatCollector.h"
#include "mutexHolder.h"
#include "cullFaceAttrib.h"
#include "string_utils.h"
#if defined(WIN32)
@ -739,7 +740,7 @@ void GraphicsEngine::
cull_and_draw_together(GraphicsStateGuardian *gsg, DisplayRegion *dr) {
nassertv(gsg != (GraphicsStateGuardian *)NULL);
PT(SceneSetup) scene_setup = setup_scene(dr->get_camera(), gsg);
PT(SceneSetup) scene_setup = setup_scene(gsg, dr);
if (setup_gsg(gsg, scene_setup)) {
DisplayRegionStack old_dr = gsg->push_display_region(dr);
gsg->prepare_display_region();
@ -819,7 +820,7 @@ cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr) {
cull_result = new CullResult(gsg);
}
PT(SceneSetup) scene_setup = setup_scene(dr->get_camera(), gsg);
PT(SceneSetup) scene_setup = setup_scene(gsg, dr);
if (scene_setup != (SceneSetup *)NULL) {
BinCullHandler cull_handler(cull_result);
do_cull(&cull_handler, scene_setup, gsg);
@ -964,7 +965,14 @@ do_flip_frame() {
// reason.
////////////////////////////////////////////////////////////////////
PT(SceneSetup) GraphicsEngine::
setup_scene(const NodePath &camera, GraphicsStateGuardian *gsg) {
setup_scene(GraphicsStateGuardian *gsg, DisplayRegion *dr) {
GraphicsOutput *window = dr->get_window();
// The window pointer shouldn't be NULL, since we presumably got to
// this particular DisplayRegion by walking through a list on a
// window.
nassertr(window != (GraphicsOutput *)NULL, NULL);
NodePath camera = dr->get_camera();
if (camera.is_empty()) {
// No camera, no draw.
return NULL;
@ -1007,18 +1015,26 @@ setup_scene(const NodePath &camera, GraphicsStateGuardian *gsg) {
// The render transform is the same as the world transform, except
// it is converted into the GSG's internal coordinate system. This
// is the transform that the GSG will apply to all of its vertices.
CPT(TransformState) cs_transform = TransformState::make_identity();
CoordinateSystem external_cs = gsg->get_coordinate_system();
CoordinateSystem internal_cs = gsg->get_internal_coordinate_system();
if (internal_cs != CS_default && internal_cs != external_cs) {
cs_transform =
TransformState::make_mat(LMatrix4f::convert_mat(external_cs, internal_cs));
CPT(TransformState) cs_transform = gsg->get_cs_transform();
CPT(RenderState) initial_state = camera_node->get_initial_state();
if (window->get_inverted()) {
// If the window is to be inverted, we must set the inverted flag
// on the SceneSetup object, so that the GSG will be able to
// invert the projection matrix at the last minute.
scene_setup->set_inverted(true);
// This also means we need to globally invert the sense of polygon
// vertex ordering.
initial_state = initial_state->compose(get_invert_polygon_state());
}
scene_setup->set_scene_root(scene_root);
scene_setup->set_camera_path(camera);
scene_setup->set_camera_node(camera_node);
scene_setup->set_lens(lens);
scene_setup->set_initial_state(initial_state);
scene_setup->set_camera_transform(camera_transform);
scene_setup->set_world_transform(world_transform);
scene_setup->set_cs_transform(cs_transform);
@ -1041,7 +1057,6 @@ do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
trav.set_cull_handler(cull_handler);
trav.set_depth_offset_decals(gsg->depth_offset_decals());
trav.set_scene(scene_setup);
trav.set_camera_mask(scene_setup->get_camera_node()->get_camera_mask());
if (view_frustum_cull) {
// If we're to be performing view-frustum culling, determine the
@ -1108,22 +1123,13 @@ setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup) {
return false;
}
const Lens *lens = scene_setup->get_lens();
if (lens == (const Lens *)NULL) {
// No lens, no draw.
return false;
}
if (!gsg->set_lens(lens)) {
// The lens is inappropriate somehow.
if (!gsg->set_scene(scene_setup)) {
// The scene or lens is inappropriate somehow.
display_cat.error()
<< gsg->get_type() << " cannot render with " << lens->get_type()
<< "\n";
<< gsg->get_type() << " cannot render scene with specified lens.\n";
return false;
}
gsg->set_scene(scene_setup);
return true;
}
@ -1271,6 +1277,26 @@ terminate_threads() {
_threads.clear();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::get_invert_polygon_state
// Access: Protected, Static
// Description: Returns a RenderState for inverting the sense of
// polygon vertex ordering: if the scene graph specifies
// a clockwise ordering, this changes it to
// counterclockwise, and vice-versa.
////////////////////////////////////////////////////////////////////
const RenderState *GraphicsEngine::
get_invert_polygon_state() {
// Once someone asks for this pointer, we hold its reference count
// and never free it.
static CPT(RenderState) state = (const RenderState *)NULL;
if (state == (const RenderState *)NULL) {
state = RenderState::make(CullFaceAttrib::make_reverse());
}
return state;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::get_window_renderer
// Access: Private

View File

@ -152,8 +152,7 @@ private:
void do_flip_frame();
INLINE void close_gsg(GraphicsPipe *pipe, GraphicsStateGuardian *gsg);
PT(SceneSetup) setup_scene(const NodePath &camera,
GraphicsStateGuardian *gsg);
PT(SceneSetup) setup_scene(GraphicsStateGuardian *gsg, DisplayRegion *dr);
void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
GraphicsStateGuardian *gsg);
void do_draw(CullResult *cull_result, SceneSetup *scene_setup,
@ -167,6 +166,8 @@ private:
void do_resort_windows();
void terminate_threads();
static const RenderState *get_invert_polygon_state();
// The WindowRenderer class records the stages of the pipeline that
// each thread (including the main thread, a.k.a. "app") should
// process, and the list of windows for each stage.

View File

@ -188,6 +188,19 @@ get_one_shot() const {
return _one_shot;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::get_inverted
// Access: Published
// Description: Returns the current setting of the inverted flag.
// When this is true, the scene is rendered into the
// window upside-down, flipped like a mirror along the X
// axis. See set_inverted().
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsOutput::
get_inverted() const {
return _inverted;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::clear_delete_flag
// Access: Published

View File

@ -25,6 +25,7 @@
#include "renderBuffer.h"
#include "indirectLess.h"
#include "pStatTimer.h"
#include "configVariableBool.h"
TypeHandle GraphicsOutput::_type_handle;
@ -57,6 +58,7 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
_sort = 0;
_active = true;
_one_shot = false;
_inverted = window_inverted;
_delete_flag = false;
int mode = gsg->get_properties().get_frame_buffer_mode();
@ -69,6 +71,7 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
// which we may use internally for full-window operations like
// clear() and get_screenshot().
_default_display_region = make_display_region(0.0f, 1.0f, 0.0f, 1.0f);
_default_display_region->set_active(false);
_display_regions_stale = false;
@ -131,15 +134,17 @@ GraphicsOutput::
// Function: GraphicsOutput::detach_texture
// Access: Published
// Description: Disassociates the texture from the GraphicsOutput.
// It will no longer be filled as the frame renders, and
// it may be used (with its current contents) as a
// texture in its own right.
// The texture will no longer be filled as the frame
// renders, and it may be used (with its current
// contents) as an ordinary texture in its own right.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
detach_texture() {
MutexHolder holder(_lock);
_texture = NULL;
_copy_texture = false;
set_inverted(window_inverted);
}
////////////////////////////////////////////////////////////////////
@ -160,6 +165,9 @@ setup_copy_texture(const string &name) {
_texture->set_wrapv(Texture::WM_clamp);
_copy_texture = true;
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
set_inverted(_gsg->get_copy_texture_inverted());
}
////////////////////////////////////////////////////////////////////
@ -185,6 +193,40 @@ is_active() const {
return _active && is_valid();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::set_inverted
// Access: Published
// Description: Changes the current setting of the inverted flag.
// When this is true, the scene is rendered into the
// window upside-down and backwards, that is, inverted
// as if viewed through a mirror placed on the floor.
//
// This is primarily intended to support DirectX (and a
// few buggy OpenGL graphics drivers) that perform a
// framebuffer-to-texture copy upside-down from the
// usual OpenGL (and Panda) convention. Panda will
// automatically set this flag for offscreen buffers on
// hardware that is known to do this, to compensate when
// rendering offscreen into a texture.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
set_inverted(bool inverted) {
if (_inverted != inverted) {
_inverted = inverted;
if (_y_size != 0) {
// All of our DisplayRegions need to recompute their pixel
// positions now.
TotalDisplayRegions::iterator dri;
for (dri = _total_display_regions.begin();
dri != _total_display_regions.end();
++dri) {
(*dri)->compute_pixels(_x_size, _y_size);
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::set_sort
// Access: Published
@ -539,8 +581,9 @@ end_frame() {
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
_gsg->end_frame();
// By default, we copy the framebuffer to the texture at the end of
// the frame. GraphicsBuffer objects that are set up to render
// If _copy_texture is true, it means we should copy the framebuffer
// to the GraphicsOutput's associated texture after the frame has
// rendered. GraphicsBuffer objects that are set up to render
// directly into texture memory don't need to do this; they will set
// _copy_texture to false.
if (_copy_texture) {

View File

@ -88,6 +88,9 @@ PUBLISHED:
INLINE void set_one_shot(bool one_shot);
INLINE bool get_one_shot() const;
void set_inverted(bool inverted);
INLINE bool get_inverted() const;
INLINE void clear_delete_flag();
INLINE bool get_delete_flag() const;
@ -170,6 +173,7 @@ private:
protected:
bool _active;
bool _one_shot;
bool _inverted;
bool _delete_flag;
protected:

View File

@ -33,49 +33,41 @@ GraphicsPipeSelection *GraphicsPipeSelection::_global_ptr = NULL;
////////////////////////////////////////////////////////////////////
GraphicsPipeSelection::
GraphicsPipeSelection() {
pset<string> got_display_modules;
// We declare these variables here instead of in config_display, in
// case this constructor is running at static init time.
ConfigVariableString load_display
("load-display", "*",
"Specify the name of the default graphics display library or "
"GraphicsPipe to load. It is the name of a shared library (or * for "
"all libraries named in aux-display), optionally followed by the "
"name of the particular GraphicsPipe class to create.");
ConfigVariableList aux_display
("aux-display",
"Names each of the graphics display libraries that are available on "
"a particular platform. This variable may be repeated several "
"times. These libraries will be tried one at a time if the library "
"specified by load_display cannot be loaded.");
// First get the name of the default module from the load-display
// variable. We get this explicitly from Configrc now (instead of
// retrieving it in config_display), in case this constructor is
// running at static init time.
string load_display = config_display.GetString("load-display", "");
load_display = trim_right(load_display);
size_t space = load_display.rfind(' ');
if (space != string::npos) {
// If there's a space, it indicates the name of the GraphicsPipe
// class to prefer.
_default_pipe_name = load_display.substr(space + 1);
load_display = trim_right(load_display.substr(0, space));
}
// Everything else is the name of the .dll (or .so) file to load.
_default_display_module = load_display;
_default_display_module = load_display.get_word(0);
_default_pipe_name = load_display.get_word(1);
if (_default_display_module == "*") {
// '*' or empty string is the key for all display modules.
_default_display_module = string();
} else if (!_default_display_module.empty()) {
// Don't insert a particular display more than once.
if (got_display_modules.insert(_default_display_module).second) {
_display_modules.push_back(_default_display_module);
}
_display_modules.push_back(_default_display_module);
}
// Also get the set of modules named in the various aux-display
// Configrc variables. We'll want to know this when we call
// load_modules() later.
Config::ConfigTable::Symbol disp;
config_display.GetAll("aux-display", disp);
Config::ConfigTable::Symbol::iterator ci;
for (ci = disp.begin(); ci != disp.end(); ++ci) {
string aux_display = trim_right((*ci).Val());
// Don't insert a particular display more than once.
if (got_display_modules.insert(aux_display).second) {
_display_modules.push_back(aux_display);
int num_aux = aux_display.get_num_unique_values();
for (int i = 0; i < num_aux; i++) {
string name = aux_display.get_unique_value(i);
if (name != _default_display_module) {
_display_modules.push_back(name);
}
}

View File

@ -140,17 +140,51 @@ get_max_texture_stages() const {
return _max_texture_stages;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_copy_texture_inverted
// Access: Published
// Description: Returns true if this particular GSG has the property
// that any framebuffer-to-texture copy results in a
// texture that is upside-down and backwards from
// Panda's usual convention; that is, it copies into a
// texture from the bottom up instead of from the top
// down.
//
// If this is true, then on offscreen GraphicsBuffer
// created for the purposes of rendering into a texture
// should be created with the invert flag set true, to
// compensate. Panda will do this automatically if you
// create an offscreen buffer using
// GraphicsOutput::make_texture_buffer().
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsStateGuardian::
get_copy_texture_inverted() const {
// If this is set from a Config variable, that overrides.
if (copy_texture_inverted.has_value()) {
return copy_texture_inverted;
}
// Otherwise, use whatever behavior the GSG figured for itself.
return _copy_texture_inverted;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::set_scene
// Access: Public
// Description: Sets the SceneSetup object that indicates the initial
// camera position, etc. This must be called before
// traversal begins.
// traversal begins. Returns true if the scene is
// acceptable, false if something's wrong.
////////////////////////////////////////////////////////////////////
INLINE void GraphicsStateGuardian::
INLINE bool GraphicsStateGuardian::
set_scene(SceneSetup *scene_setup) {
_scene_setup = scene_setup;
_current_lens = scene_setup->get_lens();
if (_current_lens == (Lens *)NULL) {
return false;
}
return prepare_lens();
}
////////////////////////////////////////////////////////////////////
@ -315,10 +349,9 @@ get_current_display_region(void) const {
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_current_lens
// Access: Public
// Description: Returns the current lens being rendered with, as set
// by the last call to push_lens() (or restored by
// pop_lens()). This lens will be made active (if it is
// not already) by a call to prepare_lens().
// Description: Returns the current lens being used to render,
// according to the scene specified via the last call to
// set_scene().
////////////////////////////////////////////////////////////////////
INLINE const Lens *GraphicsStateGuardian::
get_current_lens() const {
@ -402,78 +435,6 @@ pop_frame_buffer(FrameBufferStack &node) {
node._stack_level = -1;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::push_lens
// Access: Public
// Description: Saves the current lens information and sets up a new
// lens for rendering. The return value from this
// function must eventually be passed to a matching
// pop_lens() call.
//
// The new lens will not actually be made active for
// rendering until the next call to prepare_lens().
// This is a state-changing optimization.
////////////////////////////////////////////////////////////////////
INLINE LensStack GraphicsStateGuardian::
push_lens(const Lens *lens) {
LensStack old;
old._lens = _current_lens;
old._stack_level = _lens_stack_level;
_lens_stack_level++;
_current_lens = lens;
return old;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::pop_lens
// Access: Public
// Description: Restores the lens previously in effect, before the
// matching call to push_lens().
//
// The newly-restored lens will not actually be made
// active for rendering until the next call to
// prepare_lens(). This is a state-changing
// optimization.
////////////////////////////////////////////////////////////////////
INLINE void GraphicsStateGuardian::
pop_lens(LensStack &node) {
nassertv(_lens_stack_level > 0);
_lens_stack_level--;
nassertv(node._stack_level == _lens_stack_level);
_current_lens = node._lens;
node._stack_level = -1;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::set_lens
// Access: Public
// Description: Sets a new lens for rendering without bothering to
// push or pop. This replaces the lens most recently
// pushed, if any. There is no need to call
// prepare_lens() following this call.
//
// The return value is true if the lens is acceptable,
// false if it is not.
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsStateGuardian::
set_lens(const Lens *lens) {
_current_lens = lens;
return prepare_lens();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::set_coordinate_system
// Access: Public
// Description: Changes the coordinate system in effect on this
// particular gsg. Normally, this will be the default
// coordinate system, but it might be set differently at
// runtime.
////////////////////////////////////////////////////////////////////
INLINE void GraphicsStateGuardian::
set_coordinate_system(CoordinateSystem cs) {
_coordinate_system = cs;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_coordinate_system
// Access: Public
@ -487,6 +448,38 @@ get_coordinate_system() const {
return _coordinate_system;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_internal_coordinate_system
// Access: Public
// Description: Returns the coordinate system used internally by the
// GSG, if any one particular coordinate system is used.
// The default, CS_default, indicates that the GSG can
// use any coordinate system.
//
// If this returns other than CS_default, the
// GraphicsEngine will automatically convert all
// transforms into the indicated coordinate system.
////////////////////////////////////////////////////////////////////
INLINE CoordinateSystem GraphicsStateGuardian::
get_internal_coordinate_system() const {
return _coordinate_system;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_cs_transform
// Access: Public
// Description: Returns a transform that converts from the GSG's
// external coordinate system (as returned by
// get_coordinate_system()) to its internal coordinate
// system (as returned by
// get_internal_coordinate_system()). This is used for
// rendering.
////////////////////////////////////////////////////////////////////
INLINE const TransformState *GraphicsStateGuardian::
get_cs_transform() const {
return _cs_transform;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_light
// Access: Protected

View File

@ -69,9 +69,14 @@ TypeHandle GraphicsStateGuardian::_type_handle;
// Description:
////////////////////////////////////////////////////////////////////
GraphicsStateGuardian::
GraphicsStateGuardian(const FrameBufferProperties &properties) {
_properties = properties;
_coordinate_system = get_default_coordinate_system();
GraphicsStateGuardian(const FrameBufferProperties &properties,
CoordinateSystem internal_coordinate_system) :
_internal_coordinate_system(internal_coordinate_system),
_properties(properties)
{
_coordinate_system = CS_invalid;
set_coordinate_system(get_default_coordinate_system());
_current_display_region = (DisplayRegion*)0L;
_current_lens = (Lens *)NULL;
_needs_reset = true;
@ -83,6 +88,10 @@ GraphicsStateGuardian(const FrameBufferProperties &properties) {
// supported). A derived GSG may set this differently if it
// supports multitexturing.
_max_texture_stages = 1;
// Initially, we set this to false; a GSG that knows it has this
// property should set it to true.
_copy_texture_inverted = false;
}
////////////////////////////////////////////////////////////////////
@ -287,11 +296,10 @@ clear(DrawableRegion *clearable) {
// Function: GraphicsStateGuardian::prepare_lens
// Access: Public, Virtual
// Description: Makes the current lens (whichever lens was most
// recently specified with push_lens()) active, so that
// it will transform future rendered geometry. Normally
// this is only called from the draw process, and
// usually it is called immediately after a call to
// push_lens().
// recently specified with set_scene()) active, so
// that it will transform future rendered geometry.
// Normally this is only called from the draw process,
// and usually it is called by set_scene().
//
// The return value is true if the lens is acceptable,
// false if it is not.
@ -550,21 +558,31 @@ finish_decal() {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_internal_coordinate_system
// Access: Public, Virtual
// Description: Should be overridden by derived classes to return the
// coordinate system used internally by the GSG, if any
// one particular coordinate system is used. The
// default, CS_default, indicates that the GSG can use
// any coordinate system.
// Function: GraphicsStateGuardian::set_coordinate_system
// Access: Public
// Description: Changes the coordinate system in effect on this
// particular gsg. This is also called the "external"
// coordinate system, since it is the coordinate system
// used by the scene graph, external to to GSG.
//
// If this returns other than CS_default, the
// GraphicsEngine will automatically convert all
// transforms into the indicated coordinate system.
// Normally, this will be the default coordinate system,
// but it might be set differently at runtime.
////////////////////////////////////////////////////////////////////
CoordinateSystem GraphicsStateGuardian::
get_internal_coordinate_system() const {
return CS_default;
void GraphicsStateGuardian::
set_coordinate_system(CoordinateSystem cs) {
_coordinate_system = cs;
// Changing the external coordinate system changes the cs_transform.
if (_internal_coordinate_system == CS_default ||
_internal_coordinate_system == _coordinate_system) {
_cs_transform = TransformState::make_identity();
} else {
_cs_transform =
TransformState::make_mat
(LMatrix4f::convert_mat(_coordinate_system,
_internal_coordinate_system));
}
}
////////////////////////////////////////////////////////////////////

View File

@ -66,7 +66,8 @@ class EXPCL_PANDA GraphicsStateGuardian : public GraphicsStateGuardianBase {
// Interfaces all GSGs should have
//
public:
GraphicsStateGuardian(const FrameBufferProperties &properties);
GraphicsStateGuardian(const FrameBufferProperties &properties,
CoordinateSystem internal_coordinate_system);
virtual ~GraphicsStateGuardian();
PUBLISHED:
@ -82,9 +83,10 @@ PUBLISHED:
INLINE const GraphicsThreadingModel &get_threading_model() const;
INLINE int get_max_texture_stages() const;
INLINE bool get_copy_texture_inverted() const;
public:
INLINE void set_scene(SceneSetup *scene_setup);
INLINE bool set_scene(SceneSetup *scene_setup);
INLINE SceneSetup *get_scene() const;
virtual PreparedGraphicsObjects *get_prepared_objects();
@ -148,13 +150,11 @@ public:
const DisplayRegion *dr);
INLINE void pop_frame_buffer(FrameBufferStack &node);
INLINE LensStack push_lens(const Lens *lens);
INLINE void pop_lens(LensStack &stack);
INLINE bool set_lens(const Lens *lens);
INLINE void set_coordinate_system(CoordinateSystem cs);
void set_coordinate_system(CoordinateSystem cs);
INLINE CoordinateSystem get_coordinate_system() const;
virtual CoordinateSystem get_internal_coordinate_system() const;
INLINE CoordinateSystem get_internal_coordinate_system() const;
INLINE const TransformState *get_cs_transform() const;
virtual void issue_transform(const TransformState *transform);
virtual void issue_color_scale(const ColorScaleAttrib *attrib);
@ -250,6 +250,8 @@ protected:
int _force_normals;
CoordinateSystem _coordinate_system;
CoordinateSystem _internal_coordinate_system;
CPT(TransformState) _cs_transform;
Colorf _scene_graph_color;
bool _has_scene_graph_color;
@ -277,6 +279,7 @@ protected:
PT(PreparedGraphicsObjects) _prepared_objects;
int _max_texture_stages;
bool _copy_texture_inverted;
public:
// Statistics

View File

@ -229,7 +229,7 @@ set_color_clear_value(const Colorf& value) {
////////////////////////////////////////////////////////////////////
DXGraphicsStateGuardian7::
DXGraphicsStateGuardian7(const FrameBufferProperties &properties) :
GraphicsStateGuardian(properties)
GraphicsStateGuardian(properties, CS_yup_left)
{
// allocate local buffers used during rendering
@ -776,11 +776,10 @@ prepare_display_region() {
// Function: DXGraphicsStateGuardian7::prepare_lens
// Access: Public, Virtual
// Description: Makes the current lens (whichever lens was most
// recently specified with push_lens()) active, so that
// it will transform future rendered geometry. Normally
// this is only called from the draw process, and
// usually it is called immediately after a call to
// push_lens().
// recently specified with set_scene()) active, so
// that it will transform future rendered geometry.
// Normally this is only called from the draw process,
// and usually it is called by set_scene().
//
// The return value is true if the lens is acceptable,
// false if it is not.
@ -816,6 +815,13 @@ prepare_lens() {
LMatrix4f new_projection_mat =
convert_mat * projection_mat * rescale_mat;
if (_scene_setup->get_inverted()) {
// If the scene is supposed to be inverted, then invert the
// projection matrix.
static LMatrix4f invert_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
new_projection_mat *= invert_mat;
}
HRESULT hr =
hr = _pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION,
(LPD3DMATRIX)new_projection_mat.get_data());
@ -4304,24 +4310,6 @@ depth_offset_decals() {
return dx_depth_offset_decals;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian7::get_internal_coordinate_system
// Access: Public, Virtual
// Description: Should be overridden by derived classes to return the
// coordinate system used internally by the GSG, if any
// one particular coordinate system is used. The
// default, CS_default, indicates that the GSG can use
// any coordinate system.
//
// If this returns other than CS_default, the
// GraphicsEngine will automatically convert all
// transforms into the indicated coordinate system.
////////////////////////////////////////////////////////////////////
CoordinateSystem DXGraphicsStateGuardian7::
get_internal_coordinate_system() const {
return CS_yup_left;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian7::compute_distance_to
// Access: Public, Virtual

View File

@ -133,7 +133,6 @@ public:
virtual bool depth_offset_decals();
virtual CoordinateSystem get_internal_coordinate_system() const;
INLINE float compute_distance_to(const LPoint3f &point) const;
virtual void set_color_clear_value(const Colorf& value);

View File

@ -367,7 +367,8 @@ reset_panda_gsg(void) {
////////////////////////////////////////////////////////////////////
DXGraphicsStateGuardian8::
DXGraphicsStateGuardian8(const FrameBufferProperties &properties) :
GraphicsStateGuardian(properties) {
GraphicsStateGuardian(properties, CS_yup_left)
{
reset_panda_gsg();
@ -991,11 +992,10 @@ prepare_display_region() {
// Function: DXGraphicsStateGuardian8::prepare_lens
// Access: Public, Virtual
// Description: Makes the current lens (whichever lens was most
// recently specified with push_lens()) active, so that
// it will transform future rendered geometry. Normally
// this is only called from the draw process, and
// usually it is called immediately after a call to
// push_lens().
// recently specified with set_scene()) active, so
// that it will transform future rendered geometry.
// Normally this is only called from the draw process,
// and usually it is called by set_scene().
//
// The return value is true if the lens is acceptable,
// false if it is not.
@ -1031,6 +1031,13 @@ prepare_lens() {
LMatrix4f new_projection_mat =
convert_mat * projection_mat * rescale_mat;
if (_scene_setup->get_inverted()) {
// If the scene is supposed to be inverted, then invert the
// projection matrix.
static LMatrix4f invert_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
new_projection_mat *= invert_mat;
}
HRESULT hr =
_pD3DDevice->SetTransform(D3DTS_PROJECTION,
(D3DMATRIX*)new_projection_mat.get_data());
@ -4077,24 +4084,6 @@ depth_offset_decals() {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian8::get_internal_coordinate_system
// Access: Public, Virtual
// Description: Should be overridden by derived classes to return the
// coordinate system used internally by the GSG, if any
// one particular coordinate system is used. The
// default, CS_default, indicates that the GSG can use
// any coordinate system.
//
// If this returns other than CS_default, the
// GraphicsEngine will automatically convert all
// transforms into the indicated coordinate system.
////////////////////////////////////////////////////////////////////
CoordinateSystem DXGraphicsStateGuardian8::
get_internal_coordinate_system() const {
return CS_yup_left;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian8::set_draw_buffer
// Access: Protected

View File

@ -139,7 +139,6 @@ public:
virtual bool depth_offset_decals();
virtual CoordinateSystem get_internal_coordinate_system() const;
INLINE float compute_distance_to(const LPoint3f &point) const;
virtual void set_color_clear_value(const Colorf& value);

View File

@ -366,7 +366,8 @@ reset_panda_gsg(void) {
////////////////////////////////////////////////////////////////////
DXGraphicsStateGuardian9::
DXGraphicsStateGuardian9(const FrameBufferProperties &properties) :
GraphicsStateGuardian(properties) {
GraphicsStateGuardian(properties, CS_yup_left)
{
reset_panda_gsg();
@ -983,11 +984,10 @@ prepare_display_region() {
// Function: DXGraphicsStateGuardian9::prepare_lens
// Access: Public, Virtual
// Description: Makes the current lens (whichever lens was most
// recently specified with push_lens()) active, so that
// it will transform future rendered geometry. Normally
// this is only called from the draw process, and
// usually it is called immediately after a call to
// push_lens().
// recently specified with set_scene()) active, so
// that it will transform future rendered geometry.
// Normally this is only called from the draw process,
// and usually it is called by set_scene().
//
// The return value is true if the lens is acceptable,
// false if it is not.
@ -1023,6 +1023,13 @@ prepare_lens() {
LMatrix4f new_projection_mat =
convert_mat * projection_mat * rescale_mat;
if (_scene_setup->get_inverted()) {
// If the scene is supposed to be inverted, then invert the
// projection matrix.
static LMatrix4f invert_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
new_projection_mat *= invert_mat;
}
HRESULT hr =
_pD3DDevice->SetTransform(D3DTS_PROJECTION,
(D3DMATRIX*)new_projection_mat.get_data());
@ -4079,24 +4086,6 @@ depth_offset_decals() {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian9::get_internal_coordinate_system
// Access: Public, Virtual
// Description: Should be overridden by derived classes to return the
// coordinate system used internally by the GSG, if any
// one particular coordinate system is used. The
// default, CS_default, indicates that the GSG can use
// any coordinate system.
//
// If this returns other than CS_default, the
// GraphicsEngine will automatically convert all
// transforms into the indicated coordinate system.
////////////////////////////////////////////////////////////////////
CoordinateSystem DXGraphicsStateGuardian9::
get_internal_coordinate_system() const {
return CS_yup_left;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian9::set_draw_buffer
// Access: Protected

View File

@ -140,7 +140,6 @@ public:
virtual bool depth_offset_decals();
virtual CoordinateSystem get_internal_coordinate_system() const;
INLINE float compute_distance_to(const LPoint3f &point) const;
virtual void set_color_clear_value(const Colorf& value);

View File

@ -272,7 +272,7 @@ fix_component_ordering(GLenum external_format, PixelBuffer *pb) {
////////////////////////////////////////////////////////////////////
CLP(GraphicsStateGuardian)::
CLP(GraphicsStateGuardian)(const FrameBufferProperties &properties) :
GraphicsStateGuardian(properties)
GraphicsStateGuardian(properties, CS_yup_right)
{
_error_count = 0;
#ifdef HAVE_CGGL
@ -640,11 +640,10 @@ prepare_display_region() {
// Function: CLP(GraphicsStateGuardian)::prepare_lens
// Access: Public, Virtual
// Description: Makes the current lens (whichever lens was most
// recently specified with push_lens()) active, so that
// it will transform future rendered geometry. Normally
// this is only called from the draw process, and
// usually it is called immediately after a call to
// push_lens().
// recently specified with set_scene()) active, so
// that it will transform future rendered geometry.
// Normally this is only called from the draw process,
// and usually it is called by set_scene().
//
// The return value is true if the lens is acceptable,
// false if it is not.
@ -672,6 +671,13 @@ prepare_lens() {
LMatrix4f::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) *
projection_mat;
if (_scene_setup->get_inverted()) {
// If the scene is supposed to be inverted, then invert the
// projection matrix.
static LMatrix4f invert_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
new_projection_mat *= invert_mat;
}
#ifdef GSG_VERBOSE
GLCAT.spam()
<< "glMatrixMode(GL_PROJECTION): " << new_projection_mat << endl;
@ -2822,24 +2828,6 @@ depth_offset_decals() {
return CLP(depth_offset_decals);
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::get_internal_coordinate_system
// Access: Public, Virtual
// Description: Should be overridden by derived classes to return the
// coordinate system used internally by the GSG, if any
// one particular coordinate system is used. The
// default, CS_default, indicates that the GSG can use
// any coordinate system.
//
// If this returns other than CS_default, the
// GraphicsEngine will automatically convert all
// transforms into the indicated coordinate system.
////////////////////////////////////////////////////////////////////
CoordinateSystem CLP(GraphicsStateGuardian)::
get_internal_coordinate_system() const {
return CS_yup_right;
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::compute_distance_to
// Access: Public, Virtual

View File

@ -134,7 +134,6 @@ public:
virtual bool depth_offset_decals();
virtual CoordinateSystem get_internal_coordinate_system() const;
virtual float compute_distance_to(const LPoint3f &point) const;
void print_gfx_visual();

View File

@ -556,7 +556,7 @@ set_view_mat(const LMatrix4f &view_mat) {
_lens_mat = view_mat;
adjust_user_flags(UF_view_vector | UF_view_hpr | UF_iod_offset,
UF_view_mat);
adjust_comp_flags(CF_lens_mat_inv | CF_view_hpr | CF_view_vector | CF_iod_offset,
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv | CF_lens_mat_inv | CF_view_hpr | CF_view_vector | CF_iod_offset,
CF_lens_mat);
throw_change_event();
}

View File

@ -27,10 +27,12 @@
INLINE void CullTraverser::
set_scene(SceneSetup *scene_setup) {
_scene_setup = scene_setup;
_initial_state = scene_setup->get_initial_state();
const Camera *camera = scene_setup->get_camera_node();
_tag_state_key = camera->get_tag_state_key();
_has_tag_state_key = !_tag_state_key.empty();
_initial_state = camera->get_initial_state();
_camera_mask = camera->get_camera_mask();
}
////////////////////////////////////////////////////////////////////

View File

@ -24,6 +24,8 @@
////////////////////////////////////////////////////////////////////
INLINE SceneSetup::
SceneSetup() {
_inverted = false;
_initial_state = RenderState::make_empty();
_camera_transform = TransformState::make_identity();
_world_transform = TransformState::make_identity();
_cs_transform = TransformState::make_identity();
@ -109,6 +111,32 @@ get_lens() const {
return _lens;
}
////////////////////////////////////////////////////////////////////
// Function: SceneSetup::set_inverted
// Access: Published
// Description: Changes the current setting of the inverted flag.
// When this is true, the scene is rendered into the
// window upside-down and backwards, that is, inverted
// as if viewed through a mirror placed on the floor.
////////////////////////////////////////////////////////////////////
INLINE void SceneSetup::
set_inverted(bool inverted) {
_inverted = inverted;
}
////////////////////////////////////////////////////////////////////
// Function: SceneSetup::get_inverted
// Access: Published
// Description: Returns the current setting of the inverted flag.
// When this is true, the scene is rendered into the
// window upside-down, flipped like a mirror along the X
// axis.
////////////////////////////////////////////////////////////////////
INLINE bool SceneSetup::
get_inverted() const {
return _inverted;
}
////////////////////////////////////////////////////////////////////
// Function: SceneSetup::get_cull_center
// Access: Public
@ -126,6 +154,29 @@ get_cull_center() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: SceneSetup::set_initial_state
// Access: Published
// Description: Sets the initial state which is applied to all nodes
// in the scene, as if it were set at the top of the
// scene graph.
////////////////////////////////////////////////////////////////////
INLINE void SceneSetup::
set_initial_state(const RenderState *state) {
_initial_state = state;
}
////////////////////////////////////////////////////////////////////
// Function: SceneSetup::get_initial_state
// Access: Published
// Description: Returns the initial state as set by a previous call
// to set_initial_state().
////////////////////////////////////////////////////////////////////
INLINE const RenderState *SceneSetup::
get_initial_state() const {
return _initial_state;
}
////////////////////////////////////////////////////////////////////
// Function: SceneSetup::set_camera_transform
// Access: Public

View File

@ -50,8 +50,14 @@ public:
INLINE void set_lens(const Lens *lens);
INLINE const Lens *get_lens() const;
INLINE void set_inverted(bool inverted);
INLINE bool get_inverted() const;
INLINE const NodePath &get_cull_center() const;
INLINE void set_initial_state(const RenderState *initial_state);
INLINE const RenderState *get_initial_state() const;
INLINE void set_camera_transform(const TransformState *camera_transform);
INLINE const TransformState *get_camera_transform() const;
@ -68,6 +74,8 @@ private:
NodePath _camera_path;
PT(Camera) _camera_node;
CPT(Lens) _lens;
bool _inverted;
CPT(RenderState) _initial_state;
CPT(TransformState) _camera_transform;
CPT(TransformState) _world_transform;
CPT(TransformState) _cs_transform;