<commit_before>// Filename: graphicsOutput.cxx
// Created by:  drose (06Feb04)
//
////////////////////////////////////////////////////////////////////
//
// 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 "graphicsOutput.h"
#include "graphicsPipe.h"
#include "graphicsEngine.h"
#include "graphicsWindow.h"
#include "config_display.h"
#include "lightMutexHolder.h"
#include "renderBuffer.h"
#include "indirectLess.h"
#include "pStatTimer.h"
#include "configVariableBool.h"
#include "camera.h"
#include "displayRegion.h"
#include "lens.h"
#include "perspectiveLens.h"
#include "pointerTo.h"
#include "compassEffect.h"
#include "geom.h"
#include "geomNode.h"
#include "geomTristrips.h"
#include "geomVertexWriter.h"
#include "throw_event.h"
#include "config_gobj.h"

TypeHandle GraphicsOutput::_type_handle;

PStatCollector GraphicsOutput::_make_current_pcollector("Draw:Make current");
PStatCollector GraphicsOutput::_copy_texture_pcollector("Draw:Copy texture");
PStatCollector GraphicsOutput::_cull_pcollector("Cull");
PStatCollector GraphicsOutput::_draw_pcollector("Draw");

struct CubeFaceDef {
  CubeFaceDef(const char *name, const LPoint3f &look_at, const LVector3f &up) :
    _name(name), _look_at(look_at), _up(up) { }

  const char *_name;
  LPoint3f _look_at;
  LVector3f _up;
};

static CubeFaceDef cube_faces[6] = {
  CubeFaceDef("positive_x", LPoint3f(1, 0, 0), LVector3f(0, -1, 0)),
  CubeFaceDef("negative_x", LPoint3f(-1, 0, 0), LVector3f(0, -1, 0)),
  CubeFaceDef("positive_y", LPoint3f(0, 1, 0), LVector3f(0, 0, 1)),
  CubeFaceDef("negative_y", LPoint3f(0, -1, 0), LVector3f(0, 0, -1)),
  CubeFaceDef("positive_z", LPoint3f(0, 0, 1), LVector3f(0, -1, 0)),
  CubeFaceDef("negative_z", LPoint3f(0, 0, -1), LVector3f(0, -1, 0))
};

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::Constructor
//       Access: Protected
//  Description: Normally, the GraphicsOutput constructor is not
//               called directly; these are created instead via the
//               GraphicsEngine::make_window() function.
////////////////////////////////////////////////////////////////////
GraphicsOutput::
GraphicsOutput(GraphicsPipe *pipe,
               const string &name,
               const FrameBufferProperties &fb_prop,
               const WindowProperties &win_prop,
               int flags,
               GraphicsStateGuardian *gsg,
               GraphicsOutput *host) :
  _lock("GraphicsOutput"),
  _cull_window_pcollector(_cull_pcollector, name),
  _draw_window_pcollector(_draw_pcollector, name)
{
#ifdef DO_MEMORY_USAGE
  MemoryUsage::update_type(this, this);
#endif
  _pipe = pipe;
  _gsg = gsg;
  _host = host;
  _fb_properties = fb_prop;
  _name = name;
  _creation_flags = flags;
  _x_size = _y_size = 0;
  _has_size = win_prop.has_size();
  if (_has_size) {
    _x_size = win_prop.get_x_size();
    _y_size = win_prop.get_y_size();
  }
  _is_valid = false;
  _flip_ready = false;
  _cube_map_index = -1;
  _cube_map_dr = NULL;
  _sort = 0;
  _child_sort = 0;
  _got_child_sort = false;
  _internal_sort_index = 0;
  _active = true;
  _one_shot = false;
  _inverted = window_inverted;
  _red_blue_stereo = false;
  _left_eye_color_mask = 0x0f;
  _right_eye_color_mask = 0x0f;
  _delete_flag = false;
  _texture_card = 0;
  _trigger_copy = false;

  if (_fb_properties.is_single_buffered()) {
    _draw_buffer_type = RenderBuffer::T_front;
  } else {
    _draw_buffer_type = RenderBuffer::T_back;
  }

  // We start out with one DisplayRegion that covers the whole window,
  // 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;

  // By default, each new GraphicsOutput is set up to clear color and
  // depth.
  set_clear_color_active(true);
  set_clear_depth_active(true);
  set_clear_stencil_active(true);

  switch (background_color.get_num_words()) {
  case 1:
    set_clear_color(Colorf(background_color[0], background_color[0], background_color[0], 0.0f));
    break;

  case 2:
    set_clear_color(Colorf(background_color[0], background_color[0], background_color[0], background_color[1]));
    break;

  case 3:
    set_clear_color(Colorf(background_color[0], background_color[1], background_color[2], 0.0f));
    break;

  case 4:
    set_clear_color(Colorf(background_color[0], background_color[1], background_color[2], background_color[3]));
    break;

  default:
    display_cat.warning()
      << "Invalid background-color specification: "
      << background_color.get_string_value() << "\n";
  }
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::Copy Constructor
//       Access: Private
//  Description:
////////////////////////////////////////////////////////////////////
GraphicsOutput::
GraphicsOutput(const GraphicsOutput &) :
  _cull_window_pcollector(_cull_pcollector, "Invalid"),
  _draw_window_pcollector(_draw_pcollector, "Invalid")
{
  nassertv(false);
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::Copy Assignment Operator
//       Access: Private
//  Description:
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
operator = (const GraphicsOutput &) {
  nassertv(false);
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::Destructor
//       Access: Published, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
GraphicsOutput::
~GraphicsOutput() {
  // The window should be closed by the time we destruct.
  nassertv(!is_valid());

  // We shouldn't have a GraphicsPipe pointer anymore.
  nassertv(_pipe == (GraphicsPipe *)NULL);

  // We don't have to destruct our child display regions explicitly,
  // since they are all reference-counted and will go away when their
  // pointers do.  However, we do need to zero out their pointers to
  // us.
  TotalDisplayRegions::iterator dri;
  for (dri = _total_display_regions.begin();
       dri != _total_display_regions.end();
       ++dri) {
    (*dri)->_window = NULL;
  }

  _total_display_regions.clear();
  _active_display_regions.clear();
  _default_display_region = NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::clear_render_textures
//       Access: Published
//  Description: If the GraphicsOutput is currently rendering to
//               a texture, then all textures are dissociated from
//               the GraphicsOuput.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
clear_render_textures() {
  LightMutexHolder holder(_lock);
  throw_event("render-texture-targets-changed");
  _textures.clear();
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::add_render_texture
//       Access: Published
//  Description: Creates a new Texture object, suitable for rendering
//               the contents of this buffer into, and appends it to
//               the list of render textures.
//
//               If tex is not NULL, it is the texture that will be
//               set up for rendering into; otherwise, a new Texture
//               object will be created, in which case you may call
//               get_texture() to retrieve the new texture pointer.
//
//               You can specify a bitplane to attach the texture to.
//               the legal choices are:
//
//               * RTP_depth_stencil
//               * RTP_color
//               * RTP_aux_rgba_0
//               * RTP_aux_rgba_1
//               * RTP_aux_rgba_2
//               * RTP_aux_rgba_3
//
//               If you do not specify a bitplane to attach the
//               texture to, this routine will use a default based
//               on the texture's format:
//
//               * F_depth_stencil attaches to RTP_depth_stencil
//               * all other formats attach to RTP_color.
//
//               The texture's format will be changed to match
//               the format of the bitplane to which it is attached.
//               For example, if you pass in an F_rgba texture and
//               order that it be attached to RTP_depth_stencil, it will turn
//               into an F_depth_stencil texture.
//
//               Also see make_texture_buffer(), which is a
//               higher-level interface for preparing
//               render-to-a-texture mode.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
add_render_texture(Texture *tex, RenderTextureMode mode,
                   RenderTexturePlane plane) {
  
  if (mode == RTM_none) {
    return;
  }
  LightMutexHolder holder(_lock);

  throw_event("render-texture-targets-changed");

  // Create texture if necessary.
  if (tex == (Texture *)NULL) {
    tex = new Texture(get_name());
    tex->set_wrap_u(Texture::WM_clamp);
    tex->set_wrap_v(Texture::WM_clamp);
  } else {
    tex->clear_ram_image();
  }

  // Choose a default bitplane.
  if (plane == RTP_COUNT) {
    if (tex->get_format()==Texture::F_depth_stencil) {
      plane = RTP_depth_stencil;
    } else {
      plane = RTP_color;
    }
  }<commit_msg>enforce uncompressed render-to-texture<commit_after>// Filename: graphicsOutput.cxx
// Created by:  drose (06Feb04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) <NAME> 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 "graphicsOutput.h"
#include "graphicsPipe.h"
#include "graphicsEngine.h"
#include "graphicsWindow.h"
#include "config_display.h"
#include "lightMutexHolder.h"
#include "renderBuffer.h"
#include "indirectLess.h"
#include "pStatTimer.h"
#include "configVariableBool.h"
#include "camera.h"
#include "displayRegion.h"
#include "lens.h"
#include "perspectiveLens.h"
#include "pointerTo.h"
#include "compassEffect.h"
#include "geom.h"
#include "geomNode.h"
#include "geomTristrips.h"
#include "geomVertexWriter.h"
#include "throw_event.h"
#include "config_gobj.h"

TypeHandle GraphicsOutput::_type_handle;

PStatCollector GraphicsOutput::_make_current_pcollector("Draw:Make current");
PStatCollector GraphicsOutput::_copy_texture_pcollector("Draw:Copy texture");
PStatCollector GraphicsOutput::_cull_pcollector("Cull");
PStatCollector GraphicsOutput::_draw_pcollector("Draw");

struct CubeFaceDef {
  CubeFaceDef(const char *name, const LPoint3f &look_at, const LVector3f &up) :
    _name(name), _look_at(look_at), _up(up) { }

  const char *_name;
  LPoint3f _look_at;
  LVector3f _up;
};

static CubeFaceDef cube_faces[6] = {
  CubeFaceDef("positive_x", LPoint3f(1, 0, 0), LVector3f(0, -1, 0)),
  CubeFaceDef("negative_x", LPoint3f(-1, 0, 0), LVector3f(0, -1, 0)),
  CubeFaceDef("positive_y", LPoint3f(0, 1, 0), LVector3f(0, 0, 1)),
  CubeFaceDef("negative_y", LPoint3f(0, -1, 0), LVector3f(0, 0, -1)),
  CubeFaceDef("positive_z", LPoint3f(0, 0, 1), LVector3f(0, -1, 0)),
  CubeFaceDef("negative_z", LPoint3f(0, 0, -1), LVector3f(0, -1, 0))
};

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::Constructor
//       Access: Protected
//  Description: Normally, the GraphicsOutput constructor is not
//               called directly; these are created instead via the
//               GraphicsEngine::make_window() function.
////////////////////////////////////////////////////////////////////
GraphicsOutput::
GraphicsOutput(GraphicsPipe *pipe,
               const string &name,
               const FrameBufferProperties &fb_prop,
               const WindowProperties &win_prop,
               int flags,
               GraphicsStateGuardian *gsg,
               GraphicsOutput *host) :
  _lock("GraphicsOutput"),
  _cull_window_pcollector(_cull_pcollector, name),
  _draw_window_pcollector(_draw_pcollector, name)
{
#ifdef DO_MEMORY_USAGE
  MemoryUsage::update_type(this, this);
#endif
  _pipe = pipe;
  _gsg = gsg;
  _host = host;
  _fb_properties = fb_prop;
  _name = name;
  _creation_flags = flags;
  _x_size = _y_size = 0;
  _has_size = win_prop.has_size();
  if (_has_size) {
    _x_size = win_prop.get_x_size();
    _y_size = win_prop.get_y_size();
  }
  _is_valid = false;
  _flip_ready = false;
  _cube_map_index = -1;
  _cube_map_dr = NULL;
  _sort = 0;
  _child_sort = 0;
  _got_child_sort = false;
  _internal_sort_index = 0;
  _active = true;
  _one_shot = false;
  _inverted = window_inverted;
  _red_blue_stereo = false;
  _left_eye_color_mask = 0x0f;
  _right_eye_color_mask = 0x0f;
  _delete_flag = false;
  _texture_card = 0;
  _trigger_copy = false;

  if (_fb_properties.is_single_buffered()) {
    _draw_buffer_type = RenderBuffer::T_front;
  } else {
    _draw_buffer_type = RenderBuffer::T_back;
  }

  // We start out with one DisplayRegion that covers the whole window,
  // 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;

  // By default, each new GraphicsOutput is set up to clear color and
  // depth.
  set_clear_color_active(true);
  set_clear_depth_active(true);
  set_clear_stencil_active(true);

  switch (background_color.get_num_words()) {
  case 1:
    set_clear_color(Colorf(background_color[0], background_color[0], background_color[0], 0.0f));
    break;

  case 2:
    set_clear_color(Colorf(background_color[0], background_color[0], background_color[0], background_color[1]));
    break;

  case 3:
    set_clear_color(Colorf(background_color[0], background_color[1], background_color[2], 0.0f));
    break;

  case 4:
    set_clear_color(Colorf(background_color[0], background_color[1], background_color[2], background_color[3]));
    break;

  default:
    display_cat.warning()
      << "Invalid background-color specification: "
      << background_color.get_string_value() << "\n";
  }
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::Copy Constructor
//       Access: Private
//  Description:
////////////////////////////////////////////////////////////////////
GraphicsOutput::
GraphicsOutput(const GraphicsOutput &) :
  _cull_window_pcollector(_cull_pcollector, "Invalid"),
  _draw_window_pcollector(_draw_pcollector, "Invalid")
{
  nassertv(false);
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::Copy Assignment Operator
//       Access: Private
//  Description:
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
operator = (const GraphicsOutput &) {
  nassertv(false);
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::Destructor
//       Access: Published, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
GraphicsOutput::
~GraphicsOutput() {
  // The window should be closed by the time we destruct.
  nassertv(!is_valid());

  // We shouldn't have a GraphicsPipe pointer anymore.
  nassertv(_pipe == (GraphicsPipe *)NULL);

  // We don't have to destruct our child display regions explicitly,
  // since they are all reference-counted and will go away when their
  // pointers do.  However, we do need to zero out their pointers to
  // us.
  TotalDisplayRegions::iterator dri;
  for (dri = _total_display_regions.begin();
       dri != _total_display_regions.end();
       ++dri) {
    (*dri)->_window = NULL;
  }

  _total_display_regions.clear();
  _active_display_regions.clear();
  _default_display_region = NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::clear_render_textures
//       Access: Published
//  Description: If the GraphicsOutput is currently rendering to
//               a texture, then all textures are dissociated from
//               the GraphicsOuput.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
clear_render_textures() {
  LightMutexHolder holder(_lock);
  throw_event("render-texture-targets-changed");
  _textures.clear();
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsOutput::add_render_texture
//       Access: Published
//  Description: Creates a new Texture object, suitable for rendering
//               the contents of this buffer into, and appends it to
//               the list of render textures.
//
//               If tex is not NULL, it is the texture that will be
//               set up for rendering into; otherwise, a new Texture
//               object will be created, in which case you may call
//               get_texture() to retrieve the new texture pointer.
//
//               You can specify a bitplane to attach the texture to.
//               the legal choices are:
//
//               * RTP_depth_stencil
//               * RTP_color
//               * RTP_aux_rgba_0
//               * RTP_aux_rgba_1
//               * RTP_aux_rgba_2
//               * RTP_aux_rgba_3
//
//               If you do not specify a bitplane to attach the
//               texture to, this routine will use a default based
//               on the texture's format:
//
//               * F_depth_stencil attaches to RTP_depth_stencil
//               * all other formats attach to RTP_color.
//
//               The texture's format will be changed to match
//               the format of the bitplane to which it is attached.
//               For example, if you pass in an F_rgba texture and
//               order that it be attached to RTP_depth_stencil, it will turn
//               into an F_depth_stencil texture.
//
//               Also see make_texture_buffer(), which is a
//               higher-level interface for preparing
//               render-to-a-texture mode.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
add_render_texture(Texture *tex, RenderTextureMode mode,
                   RenderTexturePlane plane) {
  
  if (mode == RTM_none) {
    return;
  }
  LightMutexHolder holder(_lock);

  throw_event("render-texture-targets-changed");

  // Create texture if necessary.
  if (tex == (Texture *)NULL) {
    tex = new Texture(get_name());
    tex->set_wrap_u(Texture::WM_clamp);
    tex->set_wrap_v(Texture::WM_clamp);
  } else {
    tex->clear_ram_image();
  }

  // Set it to have no compression by default.  You can restore
  // compression later if you really, really want it; but this freaks
  // out some drivers, and presumably it's a mistake if you have
  // compression enabled for a rendered texture.
  tex->set_compression(Texture::CM_off);

  // Choose a default bitplane.
  if (plane == RTP_COUNT) {
    if (tex->get_format()==Texture::F_depth_stencil) {
      plane = RTP_depth_stencil;
    } else {
      plane = RTP_color;
    }
  }
{'fraction_non_alphanumeric': 0.19591857403281346, 'fraction_numerical': 0.010330160016204173, 'mean_word_length': 2.1715111610727478, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6943111', 'n_tokens_mistral': 5957, 'n_tokens_neox': 5747, 'n_words': 1483}