diff --git a/panda/src/display/displayRegion.I b/panda/src/display/displayRegion.I index b12990c513..4fb0e957c7 100644 --- a/panda/src/display/displayRegion.I +++ b/panda/src/display/displayRegion.I @@ -50,6 +50,34 @@ get_sort() const { return _sort; } +//////////////////////////////////////////////////////////////////// +// Function: DisplayRegion::set_cube_map_index +// Access: Published +// Description: This is a special parameter that is only used when +// rendering the faces of a cube map. Normally you +// should not need to set it directly. This sets up the +// DisplayRegion to render to the nth cube map face; the +// value must be between 0 and 5, inclusive. A normal +// DisplayRegion that is not associated with any +// particular cube map should be set to -1. +//////////////////////////////////////////////////////////////////// +INLINE void DisplayRegion:: +set_cube_map_index(int cube_map_index) { + _cube_map_index = cube_map_index; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayRegion::get_cube_map_index +// Access: Published +// Description: Returns the cube map face index associated with this +// particular DisplayRegion, or -1 if it is not +// associated with a cube map. See +// set_cube_map_index(). +//////////////////////////////////////////////////////////////////// +INLINE int DisplayRegion:: +get_cube_map_index() const { + return _cube_map_index; +} INLINE ostream &operator << (ostream &out, const DisplayRegion &dr) { dr.output(out); diff --git a/panda/src/display/displayRegion.cxx b/panda/src/display/displayRegion.cxx index 7c1147196d..cbd8f491c5 100644 --- a/panda/src/display/displayRegion.cxx +++ b/panda/src/display/displayRegion.cxx @@ -37,7 +37,8 @@ DisplayRegion(GraphicsOutput *window) : _window(window), _camera_node((Camera *)NULL), _active(true), - _sort(0) + _sort(0), + _cube_map_index(-1) { _draw_buffer_type = window->get_draw_buffer_type(); compute_pixels(); @@ -55,7 +56,8 @@ DisplayRegion(GraphicsOutput *window, const float l, _window(window), _camera_node((Camera *)NULL), _active(true), - _sort(0) + _sort(0), + _cube_map_index(-1) { _draw_buffer_type = window->get_draw_buffer_type(); compute_pixels(); @@ -535,7 +537,7 @@ get_screenshot(PNMImage &image) { PT(Texture) tex = new Texture; RenderBuffer buffer = gsg->get_render_buffer(get_screenshot_buffer_type()); - if (!gsg->framebuffer_copy_to_ram(tex, this, buffer)) { + if (!gsg->framebuffer_copy_to_ram(tex, -1, this, buffer)) { return false; } diff --git a/panda/src/display/displayRegion.h b/panda/src/display/displayRegion.h index 9d07fc5f5a..7cfefdb529 100644 --- a/panda/src/display/displayRegion.h +++ b/panda/src/display/displayRegion.h @@ -82,6 +82,9 @@ PUBLISHED: void set_sort(int sort); INLINE int get_sort() const; + INLINE void set_cube_map_index(int cube_map_index); + INLINE int get_cube_map_index() const; + void compute_pixels(); void compute_pixels(int x_size, int y_size); void get_pixels(int &pl, int &pr, int &pb, int &pt) const; @@ -123,6 +126,7 @@ private: bool _active; int _sort; + int _cube_map_index; // This is used to cache the culling result from last frame's // drawing into this display region. It should only be accessed or diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index dedfaf254f..3efacffc3b 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -240,7 +240,7 @@ make_window(GraphicsStateGuardian *gsg, const string &name, int sort) { //////////////////////////////////////////////////////////////////// GraphicsOutput *GraphicsEngine:: make_buffer(GraphicsStateGuardian *gsg, const string &name, - int sort, int x_size, int y_size, bool want_texture) { + int sort, int x_size, int y_size) { if (show_buffers) { GraphicsWindow *window = make_window(gsg, name, sort); if (window != (GraphicsWindow *)NULL) { @@ -249,11 +249,6 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name, props.set_fixed_size(true); props.set_title(name); window->request_properties(props); - - if (want_texture) { - window->setup_render_texture(); - } - return window; } } @@ -269,9 +264,6 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name, gsg->get_pipe()->make_buffer(gsg, name, x_size, y_size); if (buffer != (GraphicsBuffer *)NULL) { buffer->_sort = sort; - if (want_texture) { - buffer->setup_render_texture(); - } do_add_window(buffer, gsg, threading_model); } return buffer; @@ -303,7 +295,6 @@ make_parasite(GraphicsOutput *host, const string &name, props.set_fixed_size(true); props.set_title(name); window->request_properties(props); - window->setup_render_texture(); return window; } @@ -317,7 +308,6 @@ make_parasite(GraphicsOutput *host, const string &name, ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size); buffer->_sort = sort; - buffer->setup_render_texture(); do_add_window(buffer, gsg, threading_model); return buffer; @@ -643,12 +633,12 @@ flip_frame() { // whichever thread that may be. //////////////////////////////////////////////////////////////////// void GraphicsEngine:: -render_subframe(GraphicsStateGuardian *gsg, DisplayRegion *dr, +render_subframe(GraphicsOutput *win, DisplayRegion *dr, bool cull_sorting) { if (cull_sorting) { - cull_bin_draw(gsg, dr); + cull_bin_draw(win, dr); } else { - cull_and_draw_together(gsg, dr); + cull_and_draw_together(win, dr); } } @@ -736,7 +726,7 @@ cull_and_draw_together(const GraphicsEngine::Windows &wlist) { for (int i = 0; i < num_display_regions; i++) { DisplayRegion *dr = win->get_active_display_region(i); if (dr != (DisplayRegion *)NULL) { - cull_and_draw_together(win->get_gsg(), dr); + cull_and_draw_together(win, dr); } } win->end_frame(); @@ -765,11 +755,13 @@ cull_and_draw_together(const GraphicsEngine::Windows &wlist) { // only by render_subframe(). //////////////////////////////////////////////////////////////////// void GraphicsEngine:: -cull_and_draw_together(GraphicsStateGuardian *gsg, DisplayRegion *dr) { +cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr) { + GraphicsStateGuardian *gsg = win->get_gsg(); nassertv(gsg != (GraphicsStateGuardian *)NULL); PT(SceneSetup) scene_setup = setup_scene(gsg, dr); if (setup_gsg(gsg, scene_setup)) { + win->change_scenes(dr); DisplayRegionStack old_dr = gsg->push_display_region(dr); gsg->prepare_display_region(); if (dr->is_any_clear_active()) { @@ -808,7 +800,7 @@ cull_bin_draw(const GraphicsEngine::Windows &wlist) { for (int i = 0; i < num_display_regions; i++) { DisplayRegion *dr = win->get_active_display_region(i); if (dr != (DisplayRegion *)NULL) { - cull_bin_draw(win->get_gsg(), dr); + cull_bin_draw(win, dr); } } win->end_frame(); @@ -838,7 +830,8 @@ cull_bin_draw(const GraphicsEngine::Windows &wlist) { // implementation of cull_bin_draw(), above. //////////////////////////////////////////////////////////////////// void GraphicsEngine:: -cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr) { +cull_bin_draw(GraphicsOutput *win, DisplayRegion *dr) { + GraphicsStateGuardian *gsg = win->get_gsg(); nassertv(gsg != (GraphicsStateGuardian *)NULL); PT(CullResult) cull_result = dr->_cull_result; @@ -860,7 +853,7 @@ cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr) { // Now draw. // This should get deferred into the next pipeline stage. - do_draw(cull_result, scene_setup, gsg, dr); + do_draw(cull_result, scene_setup, win, dr); } } @@ -1121,11 +1114,13 @@ do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, //////////////////////////////////////////////////////////////////// void GraphicsEngine:: do_draw(CullResult *cull_result, SceneSetup *scene_setup, - GraphicsStateGuardian *gsg, DisplayRegion *dr) { + GraphicsOutput *win, DisplayRegion *dr) { // Statistics PStatTimer timer(_draw_pcollector); + GraphicsStateGuardian *gsg = win->get_gsg(); if (setup_gsg(gsg, scene_setup)) { + win->change_scenes(dr); DisplayRegionStack old_dr = gsg->push_display_region(dr); gsg->prepare_display_region(); if (dr->is_any_clear_active()) { diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index db9dce3810..b2e9696650 100644 --- a/panda/src/display/graphicsEngine.h +++ b/panda/src/display/graphicsEngine.h @@ -80,8 +80,7 @@ PUBLISHED: GraphicsWindow *make_window(GraphicsStateGuardian *gsg, const string &name, int sort); GraphicsOutput *make_buffer(GraphicsStateGuardian *gsg, const string &name, - int sort, - int x_size, int y_size, bool want_texture); + int sort, int x_size, int y_size); GraphicsOutput *make_parasite(GraphicsOutput *host, const string &name, int sort, int x_size, int y_size); @@ -98,7 +97,7 @@ PUBLISHED: void sync_frame(); void flip_frame(); - void render_subframe(GraphicsStateGuardian *gsg, DisplayRegion *dr, + void render_subframe(GraphicsOutput *win, DisplayRegion *dr, bool cull_sorting); public: @@ -143,10 +142,10 @@ private: void set_window_sort(GraphicsOutput *window, int sort); void cull_and_draw_together(const Windows &wlist); - void cull_and_draw_together(GraphicsStateGuardian *gsg, DisplayRegion *dr); + void cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr); void cull_bin_draw(const Windows &wlist); - void cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr); + void cull_bin_draw(GraphicsOutput *win, DisplayRegion *dr); void make_contexts(const Windows &wlist); void process_events(const Windows &wlist); @@ -159,7 +158,7 @@ private: void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, GraphicsStateGuardian *gsg); void do_draw(CullResult *cull_result, SceneSetup *scene_setup, - GraphicsStateGuardian *gsg, DisplayRegion *dr); + GraphicsOutput *win, DisplayRegion *dr); bool setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup); diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index 53a3bb3e6e..510ba2244d 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -26,12 +26,32 @@ #include "indirectLess.h" #include "pStatTimer.h" #include "configVariableBool.h" +#include "camera.h" +#include "displayRegion.h" +#include "lens.h" +#include "perspectiveLens.h" +#include "pointerTo.h" TypeHandle GraphicsOutput::_type_handle; PStatCollector GraphicsOutput::_make_current_pcollector("Draw:Make current"); PStatCollector GraphicsOutput::_copy_texture_pcollector("Draw:Copy texture"); +struct CubeFaceDef { + const char *_name; + LPoint3f _look_at; + LVector3f _up; +}; + +static CubeFaceDef cube_faces[6] = { + { "positive_x", LPoint3f(1, 0, 0), LVector3f(0, -1, 0) }, + { "negative_x", LPoint3f(-1, 0, 0), LVector3f(0, -1, 0) }, + { "positive_y", LPoint3f(0, 1, 0), LVector3f(0, 0, 1) }, + { "negative_y", LPoint3f(0, -1, 0), LVector3f(0, 0, -1) }, + { "positive_z", LPoint3f(0, 0, 1), LVector3f(0, -1, 0) }, + { "negative_z", LPoint3f(0, 0, -1), LVector3f(0, -1, 0) } +}; + //////////////////////////////////////////////////////////////////// // Function: GraphicsOutput::Constructor // Access: Protected @@ -52,10 +72,10 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, _y_size = 0; _has_size = false; _is_valid = false; - _copy_texture = false; - _render_texture = false; + _rtm_mode = RTM_none; _flip_ready = false; _needs_context = true; + _cube_map_index = -1; _sort = 0; _internal_sort_index = 0; _active = true; @@ -168,42 +188,67 @@ void GraphicsOutput:: detach_texture() { MutexHolder holder(_lock); - if (_render_texture && _gsg != (GraphicsStateGuardian *)NULL) { + if (_rtm_mode == RTM_bind_texture && _gsg != (GraphicsStateGuardian *)NULL) { _gsg->framebuffer_release_texture(this, get_texture()); } _texture = NULL; - _copy_texture = false; - _render_texture = false; + _rtm_mode = RTM_none; set_inverted(window_inverted); } //////////////////////////////////////////////////////////////////// // Function: GraphicsOutput::setup_render_texture -// Access: Published, Virtual +// Access: Published // Description: Creates a new Texture object, suitable for rendering // the contents of this buffer into, and stores it in // _texture. This also disassociates the previous // texture (if any). // -// If the backend supports it, this will actually set up -// the framebuffer to render directly into texture -// memory; otherwise, the framebuffer will be copied -// into the texture after each frame. +// 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 +// later). +// +// If allow_bind is true, and this GraphicsOutput is an +// offscreen graphics buffer that has not yet been +// rendered into, it will attempt to set up the buffer +// for rendering directly into the texture, avoiding the +// cost of the copy-to-texture-memory each frame. This +// is not supported by all graphics hardware, but if it +// is not supported, this option is quietly ignored. +// +// If to_ram is true, the texture image will be +// downloaded from the framebuffer memory into system +// RAM each frame, which is more expensive but allows +// the texture to subsequently be applied to any GSG. +// Otherwise, the texture image remains in texture +// memory only. +// +// Also see make_texture_buffer(), which is a +// higher-level interface for preparing +// render-to-a-texture mode. //////////////////////////////////////////////////////////////////// void GraphicsOutput:: -setup_render_texture() { +setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) { MutexHolder holder(_lock); - if (_render_texture && _gsg != (GraphicsStateGuardian *)NULL) { + if (_rtm_mode == RTM_bind_texture && _gsg != (GraphicsStateGuardian *)NULL) { _gsg->framebuffer_release_texture(this, get_texture()); } - _texture = new Texture(get_name()); + if (tex == (Texture *)NULL) { + _texture = new Texture(get_name()); + _texture->set_wrap_u(Texture::WM_clamp); + _texture->set_wrap_v(Texture::WM_clamp); + + } else { + _texture = tex; + _texture->clear_ram_image(); + } _texture->set_match_framebuffer_format(true); - _texture->set_wrap_u(Texture::WM_clamp); - _texture->set_wrap_v(Texture::WM_clamp); // Go ahead and tell the texture our anticipated size, even if it // might be inaccurate (particularly if this is a GraphicsWindow, @@ -211,8 +256,13 @@ setup_render_texture() { _texture->set_x_size(get_x_size()); _texture->set_y_size(get_y_size()); - _copy_texture = true; - _render_texture = false; + if (to_ram) { + _rtm_mode = RTM_copy_ram; + } else if (allow_bind) { + _rtm_mode = RTM_bind_if_possible; + } else { + _rtm_mode = RTM_copy_texture; + } nassertv(_gsg != (GraphicsStateGuardian *)NULL); set_inverted(_gsg->get_copy_texture_inverted()); @@ -412,6 +462,20 @@ get_active_display_region(int n) const { // for applying to geometry within the scene rendered // into this window. // +// 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 either case, the target +// texture can be retrieved from the return value with +// buffer->get_texture() (assuming the return value is +// not NULL). +// +// If to_ram is true, the buffer will be set up to +// download its contents to the system RAM memory +// associated with the Texture object, instead of +// keeping it strictly within texture memory; this is +// much slower, but it allows using the texture with any +// GSG. +// // This will attempt to be smart about maximizing render // performance while minimizing framebuffer waste. It // might return a GraphicsBuffer set to render directly @@ -420,14 +484,14 @@ get_active_display_region(int n) const { // return value is NULL if the buffer could not be // created for some reason. // -// Assuming the return value is not NULL, the texture -// that is represents the scene rendered to the new -// buffer can be accessed by buffer->get_texture(). // When you are done using the buffer, you should remove -// it with a call to GraphicsEngine::remove_window(). +// it with a call to GraphicsEngine::remove_window() (or +// set the one_shot flag so it removes itself after one +// frame). //////////////////////////////////////////////////////////////////// GraphicsOutput *GraphicsOutput:: -make_texture_buffer(const string &name, int x_size, int y_size) { +make_texture_buffer(const string &name, int x_size, int y_size, + Texture *tex, bool to_ram) { GraphicsStateGuardian *gsg = get_gsg(); GraphicsEngine *engine = gsg->get_engine(); GraphicsOutput *host = get_host(); @@ -437,26 +501,30 @@ make_texture_buffer(const string &name, int x_size, int y_size) { // value himself. int sort = get_sort() - 1; + GraphicsOutput *buffer = NULL; + if (show_buffers) { // If show_buffers is true, just go ahead and call make_buffer(), // since it all amounts to the same thing anyway--this will // actually create a new GraphicsWindow. - return engine->make_buffer(gsg, name, sort, x_size, y_size, true); + buffer = engine->make_buffer(gsg, name, sort, x_size, y_size); + buffer->setup_render_texture(tex, false, to_ram); + return buffer; } - - GraphicsOutput *buffer = NULL; + + bool allow_bind = + (prefer_texture_buffer && gsg->get_supports_render_texture() && !to_ram); // If the user so indicated in the Config.prc file, try to create a // parasite buffer first. We can only do this if the requested size // fits within the available framebuffer size. Also, don't do this - // if the GSG supports render-to-a-texture and prefer_texture_buffer - // is true, since using a ParasiteButter precludes - // render-to-a-texture. - if (prefer_parasite_buffer && - !(prefer_texture_buffer && gsg->get_supports_render_texture()) && + // if we want to try using render-to-a-texture mode, since using a + // ParasiteButter will preclude that. + if (prefer_parasite_buffer && !allow_bind && (x_size <= host->get_x_size() && y_size <= host->get_y_size())) { buffer = engine->make_parasite(host, name, sort, x_size, y_size); if (buffer != (GraphicsOutput *)NULL) { + buffer->setup_render_texture(tex, false, to_ram); return buffer; } } @@ -472,9 +540,10 @@ make_texture_buffer(const string &name, int x_size, int y_size) { PT(GraphicsStateGuardian) sb_gsg = engine->make_gsg(gsg->get_pipe(), sb_props, gsg); if (sb_gsg != (GraphicsStateGuardian *)NULL) { - buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size, true); + buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size); if (buffer != (GraphicsOutput *)NULL) { // Check the buffer for goodness. + buffer->setup_render_texture(tex, allow_bind, to_ram); engine->open_windows(); if (buffer->is_valid()) { return buffer; @@ -492,8 +561,9 @@ make_texture_buffer(const string &name, int x_size, int y_size) { // All right, attempt to create an offscreen buffer, using the same // GSG. This will be a double-buffered offscreen buffer, if the // source window is double-buffered. - buffer = engine->make_buffer(gsg, name, sort, x_size, y_size, true); + buffer = engine->make_buffer(gsg, name, sort, x_size, y_size); if (buffer != (GraphicsOutput *)NULL) { + buffer->setup_render_texture(tex, allow_bind, to_ram); engine->open_windows(); if (buffer->is_valid()) { return buffer; @@ -506,12 +576,82 @@ make_texture_buffer(const string &name, int x_size, int y_size) { // Looks like we have to settle for a parasite buffer. if (x_size <= host->get_x_size() && y_size <= host->get_y_size()) { - return engine->make_parasite(host, name, sort, x_size, y_size); + buffer = engine->make_parasite(host, name, sort, x_size, y_size); + buffer->setup_render_texture(tex, false, to_ram); + return buffer; } return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsOutput::make_cube_map +// Access: Published +// Description: This is similar to make_texture_buffer() in that it +// allocates a separate buffer suitable for rendering to +// a texture that can be assigned to geometry in this +// window, but in this case, the buffer is set up to +// render the six faces of a cube map. +// +// The buffer is automatically set up with six display +// regions and six cameras, each of which are assigned +// the indicated draw_mask and parented to the given +// camera_rig node (which you should then put in your +// scene to render the cube map from the appropriate +// point of view). +// +// You may take the texture associated with the buffer +// and apply it to geometry, particularly with +// TexGenAttrib::M_world_cube_map also in effect, to +// apply a reflection of everything seen by the camera +// rig. +//////////////////////////////////////////////////////////////////// +GraphicsOutput *GraphicsOutput:: +make_cube_map(const string &name, int size, bool to_ram, + NodePath &camera_rig, DrawMask camera_mask) { + if (!to_ram) { + // Check the limits imposed by the GSG. (However, if we're + // rendering the texture to RAM only, these limits may be + // irrelevant.) + GraphicsStateGuardian *gsg = get_gsg(); + int max_dimension = gsg->get_max_cube_map_dimension(); + if (max_dimension == 0) { + // The GSG doesn't support cube mapping; too bad for you. + return NULL; + } + if (max_dimension > 0) { + size = min(max_dimension, size); + } + } + + PT(Texture) tex = new Texture(name); + tex->setup_cube_map(); + GraphicsOutput *buffer = make_texture_buffer(name, size, size, tex, to_ram); + + // We don't need to clear the overall buffer; instead, we'll clear + // each display region. + buffer->set_clear_color_active(false); + buffer->set_clear_depth_active(false); + + PT(Lens) lens = new PerspectiveLens; + lens->set_fov(90.0f); + + for (int i = 0; i < 6; i++) { + PT(Camera) camera = new Camera(cube_faces[i]._name); + camera->set_lens(lens); + camera->set_camera_mask(camera_mask); + NodePath camera_np = camera_rig.attach_new_node(camera); + camera_np.look_at(cube_faces[i]._look_at, cube_faces[i]._up); + + DisplayRegion *dr = buffer->make_display_region(); + dr->set_cube_map_index(i); + dr->copy_clear_settings(*this); + dr->set_camera(camera_np); + } + + return buffer; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsOutput::get_host // Access: Public, Virtual @@ -604,11 +744,13 @@ begin_frame() { // Okay, we already have a GSG, so activate it. make_current(); - if (_render_texture) { + if (_rtm_mode == RTM_bind_texture) { // Release the texture so we can render into the frame buffer. _gsg->framebuffer_release_texture(this, get_texture()); } + _cube_map_index = -1; + return _gsg->begin_frame(); } @@ -657,17 +799,17 @@ end_frame() { nassertv(_gsg != (GraphicsStateGuardian *)NULL); _gsg->end_frame(); - // If _copy_texture is true, it means we should copy or lock the + // If _rtm_mode isn't RTM_none, it means we should copy or lock the // framebuffer to the GraphicsOutput's associated texture after the // frame has rendered. - if (_copy_texture) { + if (_rtm_mode != RTM_none) { PStatTimer timer(_copy_texture_pcollector); nassertv(has_texture()); - // If _render_texture is true, it means we should attempt to lock - // the framebuffer directly to the texture memory, avoiding the - // copy. - if (_render_texture) { + // If _rtm_mode is RTM_bind_texture, it means we should attempt to + // lock the framebuffer directly to the texture memory, avoiding + // the copy. + if (_rtm_mode == RTM_bind_texture) { if (display_cat.is_debug()) { display_cat.debug() << "Locking texture for " << get_name() << " at frame end.\n"; @@ -675,17 +817,25 @@ end_frame() { if (!_gsg->framebuffer_bind_to_texture(this, get_texture())) { display_cat.warning() << "Lock-to-texture failed, resorting to copy.\n"; - _render_texture = false; + _rtm_mode = RTM_copy_texture; } } - if (!_render_texture) { + if (_rtm_mode != RTM_bind_texture) { if (display_cat.is_debug()) { display_cat.debug() << "Copying texture for " << get_name() << " at frame end.\n"; + display_cat.debug() + << "cube_map_index = " << _cube_map_index << "\n"; } RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type()); - _gsg->framebuffer_copy_to_texture(get_texture(), _default_display_region, buffer); + if (_rtm_mode == RTM_copy_ram) { + _gsg->framebuffer_copy_to_ram(get_texture(), _cube_map_index, + _default_display_region, buffer); + } else { + _gsg->framebuffer_copy_to_texture(get_texture(), _cube_map_index, + _default_display_region, buffer); + } } } @@ -702,6 +852,68 @@ end_frame() { _active = false; _delete_flag = true; } + + _cube_map_index = -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsOutput::change_scenes +// Access: Public +// Description: Called by the GraphicsEngine when the window is about +// to change to another DisplayRegion. This exists +// mainly to provide a callback for switching the cube +// map face, if we are rendering to the different faces +// of a cube map. +//////////////////////////////////////////////////////////////////// +void GraphicsOutput:: +change_scenes(DisplayRegion *new_dr) { + int new_cube_map_index = new_dr->get_cube_map_index(); + if (new_cube_map_index != -1 && + new_cube_map_index != _cube_map_index) { + int old_cube_map_index = _cube_map_index; + _cube_map_index = new_cube_map_index; + + if (_rtm_mode != RTM_none) { + if (_rtm_mode == RTM_bind_texture) { + // In render-to-texture mode, switch the rendering backend to + // the new cube map face, so that the subsequent frame will be + // rendered to the new face. + + select_cube_map(new_cube_map_index); + + } else if (old_cube_map_index != -1) { + // In copy-to-texture mode, copy the just-rendered framebuffer + // to the old cube map face. + if (display_cat.is_debug()) { + display_cat.debug() + << "Copying texture for " << get_name() << " at scene change.\n"; + display_cat.debug() + << "cube_map_index = " << old_cube_map_index << "\n"; + } + RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type()); + if (_rtm_mode == RTM_copy_ram) { + _gsg->framebuffer_copy_to_ram(get_texture(), old_cube_map_index, + _default_display_region, buffer); + } else { + _gsg->framebuffer_copy_to_texture(get_texture(), old_cube_map_index, + _default_display_region, buffer); + } + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsOutput::select_cube_map +// Access: Public, Virtual +// Description: Called internally when the window is in +// render-to-a-texture mode and we are in the process of +// rendering the six faces of a cube map. This should +// do whatever needs to be done to switch the buffer to +// the indicated face. +//////////////////////////////////////////////////////////////////// +void GraphicsOutput:: +select_cube_map(int) { } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index 51ea28e5f6..f471e10467 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -32,6 +32,7 @@ #include "notify.h" #include "pmutex.h" #include "filename.h" +#include "drawMask.h" #include "pvector.h" class PNMImage; @@ -75,7 +76,7 @@ PUBLISHED: INLINE bool has_texture() const; INLINE Texture *get_texture() const; void detach_texture(); - virtual void setup_render_texture(); + void setup_render_texture(Texture *tex, bool allow_bind, bool to_ram); INLINE int get_x_size() const; INLINE int get_y_size() const; @@ -108,7 +109,10 @@ PUBLISHED: int get_num_active_display_regions() const; PT(DisplayRegion) get_active_display_region(int n) const; - GraphicsOutput *make_texture_buffer(const string &name, int x_size, int y_size); + GraphicsOutput *make_texture_buffer(const string &name, int x_size, int y_size, + Texture *tex = NULL, bool to_ram = false); + GraphicsOutput *make_cube_map(const string &name, int size, bool to_ram, + NodePath &camera_rig, DrawMask camera_mask); INLINE Filename save_screenshot_default(const string &prefix = "screenshot"); INLINE bool save_screenshot(const Filename &filename); @@ -136,6 +140,9 @@ public: void clear(); virtual void end_frame(); + void change_scenes(DisplayRegion *new_dr); + virtual void select_cube_map(int cube_map_index); + // This method is called in the draw thread prior to issuing any // drawing commands for the window. virtual bool make_context(); @@ -152,14 +159,22 @@ public: virtual void process_events(); protected: + enum RenderTextureMode { + RTM_none, + RTM_bind_texture, + RTM_bind_if_possible, + RTM_copy_texture, + RTM_copy_ram, + }; + PT(GraphicsStateGuardian) _gsg; PT(GraphicsPipe) _pipe; string _name; PT(Texture) _texture; - bool _copy_texture; - bool _render_texture; + RenderTextureMode _rtm_mode; bool _flip_ready; bool _needs_context; + int _cube_map_index; private: DisplayRegion *add_display_region(DisplayRegion *display_region); diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index e683373181..f7650d04c0 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -151,6 +151,56 @@ get_max_texture_stages() const { return _max_texture_stages; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_max_texture_dimension +// Access: Published +// Description: Returns the largest possible texture size in any one +// dimension supported by the GSG, or -1 if there is no +// particular limit. +// +// The value returned may not be meaningful until after +// the graphics context has been fully created (e.g. the +// window has been opened). +//////////////////////////////////////////////////////////////////// +INLINE int GraphicsStateGuardian:: +get_max_texture_dimension() const { + return _max_texture_dimension; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_max_3d_texture_dimension +// Access: Published +// Description: Returns the largest possible texture size in any one +// dimension for a 3-d texture, or -1 if there is no +// particular limit. Returns 0 if 3-d textures are not +// supported. +// +// The value returned may not be meaningful until after +// the graphics context has been fully created (e.g. the +// window has been opened). +//////////////////////////////////////////////////////////////////// +INLINE int GraphicsStateGuardian:: +get_max_3d_texture_dimension() const { + return _max_3d_texture_dimension; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_max_cube_map_dimension +// Access: Published +// Description: Returns the largest possible texture size in any one +// dimension for a cube map texture, or -1 if there is +// no particular limit. Returns 0 if cube map textures +// are not supported. +// +// The value returned may not be meaningful until after +// the graphics context has been fully created (e.g. the +// window has been opened). +//////////////////////////////////////////////////////////////////// +INLINE int GraphicsStateGuardian:: +get_max_cube_map_dimension() const { + return _max_cube_map_dimension; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::get_copy_texture_inverted // Access: Published diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 8b821907af..32f912e0ea 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -90,6 +90,12 @@ GraphicsStateGuardian(const FrameBufferProperties &properties, // supports multitexturing. _max_texture_stages = 1; + // Also initially, we assume there are no limits on texture sizes, + // and that 3-d and cube-map textures are not supported. + _max_texture_dimension = -1; + _max_3d_texture_dimension = 0; + _max_cube_map_dimension = 0; + // Initially, we set this to false; a GSG that knows it has this // property should set it to true. _copy_texture_inverted = false; diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 1d7c28d2fb..ea85f60f80 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -83,6 +83,10 @@ PUBLISHED: INLINE const GraphicsThreadingModel &get_threading_model() const; INLINE int get_max_texture_stages() const; + INLINE int get_max_texture_dimension() const; + INLINE int get_max_3d_texture_dimension() const; + INLINE int get_max_cube_map_dimension() const; + INLINE bool get_copy_texture_inverted() const; virtual bool get_supports_multisample() const; INLINE bool get_supports_generate_mipmap() const; @@ -278,6 +282,10 @@ protected: PT(PreparedGraphicsObjects) _prepared_objects; int _max_texture_stages; + int _max_texture_dimension; + int _max_3d_texture_dimension; + int _max_cube_map_dimension; + bool _copy_texture_inverted; bool _supports_multisample; bool _supports_generate_mipmap; diff --git a/panda/src/distort/nonlinearImager.cxx b/panda/src/distort/nonlinearImager.cxx index d075f65f28..aa1045b293 100644 --- a/panda/src/distort/nonlinearImager.cxx +++ b/panda/src/distort/nonlinearImager.cxx @@ -680,7 +680,8 @@ recompute_screen(NonlinearImager::Screen &screen, size_t vi) { if (screen._buffer == (GraphicsOutput *)NULL) { GraphicsOutput *win = viewer._dr->get_window(); - GraphicsOutput *buffer = win->make_texture_buffer(screen._name, screen._tex_width, screen._tex_height); + GraphicsOutput *buffer = win->make_texture_buffer + (screen._name, screen._tex_width, screen._tex_height, NULL, false); if (buffer != (GraphicsOutput *)NULL) { screen._buffer = buffer; diff --git a/panda/src/doc/eggSyntax.txt b/panda/src/doc/eggSyntax.txt index 42f420b78d..802bfdd663 100644 --- a/panda/src/doc/eggSyntax.txt +++ b/panda/src/doc/eggSyntax.txt @@ -279,12 +279,14 @@ appear before they are referenced. for instance to apply a reflection map or some other effect. The valid values for mode are: - SPHERE_MAP - CUBE_MAP + EYE_SPHERE_MAP (or SPHERE_MAP) + WORLD_CUBE_MAP + EYE_CUBE_MAP (or CUBE_MAP) + WORLD_NORMAL + EYE_NORMAL WORLD_POSITION OBJECT_POSITION EYE_POSITION - OBJECT_NORMAL stage-name { name } diff --git a/panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx b/panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx index c5cb021c31..cca427a0e8 100644 --- a/panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx +++ b/panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx @@ -3488,7 +3488,7 @@ release_texture(TextureContext *tc) { // Description: //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian7:: -framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb) { +framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { dxgsg7_cat.error() << "DX copy_texture unimplemented!!!"; } @@ -3498,7 +3498,7 @@ framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, const RenderB // Description: //////////////////////////////////////////////////////////////////// bool DXGraphicsStateGuardian7:: -framebuffer_copy_to_ram(Texture *tex, const DisplayRegion *dr, +framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { set_read_buffer(rb); diff --git a/panda/src/dxgsg7/dxGraphicsStateGuardian7.h b/panda/src/dxgsg7/dxGraphicsStateGuardian7.h index d378ff8b09..8053fd680e 100644 --- a/panda/src/dxgsg7/dxGraphicsStateGuardian7.h +++ b/panda/src/dxgsg7/dxGraphicsStateGuardian7.h @@ -91,10 +91,10 @@ public: virtual void apply_texture(TextureContext *tc); virtual void release_texture(TextureContext *tc); - virtual void framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, + virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); - virtual bool framebuffer_copy_to_ram(Texture *pb, const DisplayRegion *dr, + virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); virtual void apply_material(const Material *material); diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 38babf6888..1ff257001f 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -2783,7 +2783,7 @@ release_texture(TextureContext *tc) { // copies current display region in framebuffer to the texture // usually its more efficient to do SetRenderTgt void DXGraphicsStateGuardian8:: -framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb) { +framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { set_read_buffer(rb); HRESULT hr; @@ -2838,7 +2838,7 @@ framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, const RenderB // Description: //////////////////////////////////////////////////////////////////// bool DXGraphicsStateGuardian8:: -framebuffer_copy_to_ram(Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb) { +framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { set_read_buffer(rb); RECT SrcCopyRect; @@ -3145,7 +3145,7 @@ issue_tex_gen(const TexGenAttrib *attrib) { _pD3DDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0); _pD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); - } else if (attrib->get_mode(TextureStage::get_default()) == TexGenAttrib::M_sphere_map) { + } else if (attrib->get_mode(TextureStage::get_default()) == TexGenAttrib::M_eye_sphere_map) { #if 0 // best reflection on a sphere is achieved by camera space normals in directx diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index e9414ba463..60f4c9b930 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -93,9 +93,9 @@ public: virtual void apply_texture(TextureContext *tc); virtual void release_texture(TextureContext *tc); - virtual void framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, + virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); - virtual bool framebuffer_copy_to_ram(Texture *tex, const DisplayRegion *dr, + virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); virtual void apply_material(const Material *material); diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 1334541f04..94aa973567 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -2766,7 +2766,7 @@ release_texture(TextureContext *tc) { // copies current display region in framebuffer to the texture // usually its more efficient to do SetRenderTgt void DXGraphicsStateGuardian9:: -framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb) { +framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { set_read_buffer(rb); HRESULT hr; @@ -2825,7 +2825,7 @@ framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, const RenderB // Description: //////////////////////////////////////////////////////////////////// bool DXGraphicsStateGuardian9:: -framebuffer_copy_to_ram(Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb) { +framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { set_read_buffer(rb); RECT SrcCopyRect; @@ -3132,7 +3132,7 @@ issue_tex_gen(const TexGenAttrib *attrib) { _pD3DDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0); _pD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); - } else if (attrib->get_mode(TextureStage::get_default()) == TexGenAttrib::M_sphere_map) { + } else if (attrib->get_mode(TextureStage::get_default()) == TexGenAttrib::M_eye_sphere_map) { #if 0 // best reflection on a sphere is achieved by camera space normals in directx diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index af2ec51fb5..257b794f83 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -94,9 +94,9 @@ public: virtual void apply_texture(TextureContext *tc); virtual void release_texture(TextureContext *tc); - virtual void framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, + virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); - virtual bool framebuffer_copy_to_ram(Texture *tex, const DisplayRegion *dr, + virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); virtual void apply_material(const Material *material); diff --git a/panda/src/egg/eggTexture.cxx b/panda/src/egg/eggTexture.cxx index 0df30c071d..7092c91c96 100644 --- a/panda/src/egg/eggTexture.cxx +++ b/panda/src/egg/eggTexture.cxx @@ -801,11 +801,22 @@ string_tex_gen(const string &string) { if (cmp_nocase_uh(string, "unspecified") == 0) { return TG_unspecified; - } else if (cmp_nocase_uh(string, "sphere_map") == 0) { - return TG_sphere_map; + } else if (cmp_nocase_uh(string, "sphere_map") == 0 || + cmp_nocase_uh(string, "eye_sphere_map") == 0) { + return TG_eye_sphere_map; - } else if (cmp_nocase_uh(string, "cube_map") == 0) { - return TG_cube_map; + } else if (cmp_nocase_uh(string, "world_cube_map") == 0) { + return TG_world_cube_map; + + } else if (cmp_nocase_uh(string, "cube_map") == 0 || + cmp_nocase_uh(string, "eye_cube_map") == 0) { + return TG_eye_cube_map; + + } else if (cmp_nocase_uh(string, "world_normal") == 0) { + return TG_world_normal; + + } else if (cmp_nocase_uh(string, "eye_normal") == 0) { + return TG_eye_normal; } else if (cmp_nocase_uh(string, "world_position") == 0) { return TG_world_position; @@ -816,9 +827,6 @@ string_tex_gen(const string &string) { } else if (cmp_nocase_uh(string, "eye_position") == 0) { return TG_eye_position; - } else if (cmp_nocase_uh(string, "object_normal") == 0) { - return TG_object_normal; - } else { return TG_unspecified; } @@ -1114,11 +1122,20 @@ operator << (ostream &out, EggTexture::TexGen tex_gen) { case EggTexture::TG_unspecified: return out << "unspecified"; - case EggTexture::TG_sphere_map: - return out << "sphere_map"; + case EggTexture::TG_eye_sphere_map: + return out << "eye_sphere_map"; - case EggTexture::TG_cube_map: - return out << "cube_map"; + case EggTexture::TG_world_cube_map: + return out << "world_cube_map"; + + case EggTexture::TG_eye_cube_map: + return out << "eye_cube_map"; + + case EggTexture::TG_world_normal: + return out << "world_normal"; + + case EggTexture::TG_eye_normal: + return out << "eye_normal"; case EggTexture::TG_world_position: return out << "world_position"; @@ -1128,9 +1145,6 @@ operator << (ostream &out, EggTexture::TexGen tex_gen) { case EggTexture::TG_eye_position: return out << "eye_position"; - - case EggTexture::TG_object_normal: - return out << "object_normal"; } return out << "**invalid TexGen(" << (int)tex_gen << ")**"; diff --git a/panda/src/egg/eggTexture.h b/panda/src/egg/eggTexture.h index 65fcb9a863..891324cacf 100644 --- a/panda/src/egg/eggTexture.h +++ b/panda/src/egg/eggTexture.h @@ -129,12 +129,18 @@ PUBLISHED: }; enum TexGen { TG_unspecified, - TG_sphere_map, - TG_cube_map, + + TG_eye_sphere_map, + + TG_world_cube_map, + TG_eye_cube_map, + + TG_world_normal, + TG_eye_normal, + TG_world_position, TG_object_position, TG_eye_position, - TG_object_normal, }; INLINE void set_format(Format format); diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 6e5f69dd3e..773b50ad7e 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -3115,11 +3115,20 @@ get_tex_gen(const EggTexture *egg_tex) { case EggTexture::TG_unspecified: return TexGenAttrib::M_off; - case EggTexture::TG_sphere_map: - return TexGenAttrib::M_sphere_map; + case EggTexture::TG_eye_sphere_map: + return TexGenAttrib::M_eye_sphere_map; - case EggTexture::TG_cube_map: - return TexGenAttrib::M_cube_map; + case EggTexture::TG_world_cube_map: + return TexGenAttrib::M_world_cube_map; + + case EggTexture::TG_eye_cube_map: + return TexGenAttrib::M_eye_cube_map; + + case EggTexture::TG_world_normal: + return TexGenAttrib::M_world_normal; + + case EggTexture::TG_eye_normal: + return TexGenAttrib::M_eye_normal; case EggTexture::TG_world_position: return TexGenAttrib::M_world_position; @@ -3129,9 +3138,6 @@ get_tex_gen(const EggTexture *egg_tex) { case EggTexture::TG_eye_position: return TexGenAttrib::M_eye_position; - - case EggTexture::TG_object_normal: - return TexGenAttrib::M_object_normal; }; return TexGenAttrib::M_off; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 15ec7f8a11..6eb4d72f4d 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -487,25 +487,33 @@ reset() { _supports_multisample = false; } } + + GLint max_texture_size; + GLint max_3d_texture_size; + GLint max_cube_map_size; - GLP(GetIntegerv)(GL_MAX_TEXTURE_SIZE, &_max_texture_size); + GLP(GetIntegerv)(GL_MAX_TEXTURE_SIZE, &max_texture_size); + _max_texture_dimension = max_texture_size; + if (_supports_3d_texture) { - GLP(GetIntegerv)(GL_MAX_3D_TEXTURE_SIZE, &_max_3d_texture_size); + GLP(GetIntegerv)(GL_MAX_3D_TEXTURE_SIZE, &max_3d_texture_size); + _max_3d_texture_dimension = max_3d_texture_size; } else { - _max_3d_texture_size = 0; + _max_3d_texture_dimension = 0; } if (_supports_cube_map) { - GLP(GetIntegerv)(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &_max_cube_map_size); + GLP(GetIntegerv)(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &max_cube_map_size); + _max_cube_map_dimension = max_cube_map_size; } else { - _max_cube_map_size = 0; + _max_cube_map_dimension = 0; } if (GLCAT.is_debug()) { GLCAT.debug() - << "max texture size = " << _max_texture_size - << ", max 3d texture = " << _max_3d_texture_size - << ", max cube map = " << _max_cube_map_size << "\n"; + << "max texture dimension = " << _max_texture_dimension + << ", max 3d texture = " << _max_3d_texture_dimension + << ", max cube map = " << _max_cube_map_dimension << "\n"; } report_my_gl_errors(); @@ -723,7 +731,7 @@ do_clear(const RenderBuffer &buffer) { // Function: CLP(GraphicsStateGuardian)::prepare_display_region // Access: Public, Virtual // Description: Prepare a display region for rendering (set up -// scissor region and viewport) +// scissor region and viewport) //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: prepare_display_region() { @@ -2162,13 +2170,15 @@ static int binary_log_cap(const int x) { // Function: CLP(GraphicsStateGuardian)::framebuffer_copy_to_texture // Access: Public, Virtual // Description: Copy the pixels within the indicated display -// region from the framebuffer into texture memory +// region from the framebuffer into texture memory. +// +// If z > -1, it is the cube map index into which to +// copy. //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: -framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, +framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { - nassertv(tex != NULL && dr != NULL && - tex->get_texture_type() == Texture::TT_2d_texture); + nassertv(tex != NULL && dr != NULL); set_read_buffer(rb); int xo, yo, w, h; @@ -2181,9 +2191,27 @@ framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, nassertv(tc != (TextureContext *)NULL); bind_texture(tc); - GLP(CopyTexImage2D)(GL_TEXTURE_2D, 0, - get_internal_image_format(tex->get_format()), - xo, yo, w, h, 0); + if (z >= 0) { + // Copy to a cube map face. + nassertv(z < 6); + nassertv(tex->get_texture_type() == Texture::TT_cube_map); + + if (_supports_cube_map) { + // We cleverly defined the cube map faces to fall in the same + // order as the GL constants are defined, so we can just make this + // simple addition to get to the right GL constant. + GLP(CopyTexImage2D)(GL_TEXTURE_CUBE_MAP_POSITIVE_X + z, 0, + get_internal_image_format(tex->get_format()), + xo, yo, w, h, 0); + } + + } else { + // Copy to a regular texture. + nassertv(tex->get_texture_type() == Texture::TT_2d_texture); + GLP(CopyTexImage2D)(GL_TEXTURE_2D, 0, + get_internal_image_format(tex->get_format()), + xo, yo, w, h, 0); + } // Clear the internal texture state, since we've just monkeyed with it. modify_state(get_untextured_state()); @@ -2195,9 +2223,12 @@ framebuffer_copy_to_texture(Texture *tex, const DisplayRegion *dr, // Description: Copy the pixels within the indicated display region // from the framebuffer into system memory, not texture // memory. Returns true on success, false on failure. +// +// This completely redefines the ram image of the +// indicated texture. //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: -framebuffer_copy_to_ram(Texture *tex, const DisplayRegion *dr, +framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { nassertr(tex != NULL && dr != NULL, false); set_read_buffer(rb); @@ -2228,7 +2259,21 @@ framebuffer_copy_to_ram(Texture *tex, const DisplayRegion *dr, format = Texture::F_rgb; } - tex->setup_2d_texture(w, h, component_type, format); + Texture::TextureType texture_type; + if (z >= 0) { + texture_type = Texture::TT_cube_map; + } else { + texture_type = Texture::TT_2d_texture; + } + + if (tex->get_x_size() != w || tex->get_y_size() != h || + tex->get_component_type() != component_type || + tex->get_format() != format || + tex->get_texture_type() != texture_type) { + // Re-setup the texture; its properties have changed. + tex->setup_texture(texture_type, w, h, 1, component_type, format); + } + GLenum external_format = get_external_image_format(format); #ifdef GSG_VERBOSE @@ -2272,13 +2317,21 @@ framebuffer_copy_to_ram(Texture *tex, const DisplayRegion *dr, << ")" << endl; #endif + unsigned char *image = tex->modify_ram_image(); + if (z >= 0) { + nassertr(z < tex->get_z_size(), false); + image += z * tex->get_expected_ram_page_size(); + } + GLP(ReadPixels)(xo, yo, w, h, external_format, get_component_type(component_type), - tex->make_ram_image()); + image); // We may have to reverse the byte ordering of the image if GL - // didn't do it for us. - if (!_supports_bgr) { + // didn't do it for us. This assumes we render out the six faces of + // a cube map in ascending order, since we can't do this until we + // have rendered the last face. + if (!_supports_bgr && (z == -1 || z == 5)) { tex->set_ram_image(fix_component_ordering(tex->get_ram_image(), external_format, tex)); } @@ -3399,15 +3452,15 @@ apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex) { int max_dimension; switch (tex->get_texture_type()) { case Texture::TT_3d_texture: - max_dimension = _max_3d_texture_size; + max_dimension = _max_3d_texture_dimension; break; case Texture::TT_cube_map: - max_dimension = _max_cube_map_size; + max_dimension = _max_cube_map_dimension; break; default: - max_dimension = _max_texture_size; + max_dimension = _max_texture_dimension; } if (max_dimension == 0) { @@ -3421,48 +3474,51 @@ apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex) { // If it doesn't fit, we have to reduce it on-the-fly. This is kind // of expensive and it doesn't look great; it would have been better // if the user had specified max-texture-dimension to reduce the - // texture at load time instead. - if (width > max_dimension) { - int byte_chunk = texel_size; - int stride = 1; - int new_width = width; - while (new_width > max_dimension) { - stride <<= 1; - new_width >>= 1; + // texture at load time instead. Of course, the user doesn't always + // know ahead of time what the hardware limits are. + if (max_dimension > 0) { + if (width > max_dimension) { + int byte_chunk = texel_size; + int stride = 1; + int new_width = width; + while (new_width > max_dimension) { + stride <<= 1; + new_width >>= 1; + } + GLCAT.info() + << "Reducing width of " << tex->get_name() + << " from " << width << " to " << new_width << "\n"; + image = reduce_image(image, byte_chunk, stride); + width = new_width; } - GLCAT.info() - << "Reducing width of " << tex->get_name() - << " from " << width << " to " << new_width << "\n"; - image = reduce_image(image, byte_chunk, stride); - width = new_width; - } - if (height > max_dimension) { - int byte_chunk = width * texel_size; - int stride = 1; - int new_height = height; - while (new_height > max_dimension) { - stride <<= 1; - new_height >>= 1; + if (height > max_dimension) { + int byte_chunk = width * texel_size; + int stride = 1; + int new_height = height; + while (new_height > max_dimension) { + stride <<= 1; + new_height >>= 1; + } + GLCAT.info() + << "Reducing height of " << tex->get_name() + << " from " << height << " to " << new_height << "\n"; + image = reduce_image(image, byte_chunk, stride); + height = new_height; } - GLCAT.info() - << "Reducing height of " << tex->get_name() - << " from " << height << " to " << new_height << "\n"; - image = reduce_image(image, byte_chunk, stride); - height = new_height; - } - if (depth > max_dimension) { - int byte_chunk = height * width * texel_size; - int stride = 1; - int new_depth = depth; - while (new_depth > max_dimension) { - stride <<= 1; - new_depth >>= 1; + if (depth > max_dimension) { + int byte_chunk = height * width * texel_size; + int stride = 1; + int new_depth = depth; + while (new_depth > max_dimension) { + stride <<= 1; + new_depth >>= 1; + } + GLCAT.info() + << "Reducing depth of " << tex->get_name() + << " from " << depth << " to " << new_depth << "\n"; + image = reduce_image(image, byte_chunk, stride); + depth = new_depth; } - GLCAT.info() - << "Reducing depth of " << tex->get_name() - << " from " << depth << " to " << new_depth << "\n"; - image = reduce_image(image, byte_chunk, stride); - depth = new_depth; } if (!_supports_bgr) { @@ -4542,7 +4598,7 @@ finish_modify_state() { } // Apply the texture matrix, if needed. - if (_needs_tex_mat) { + if (_needs_tex_mat || _needs_tex_gen) { _needs_tex_mat = false; int num_stages = _current_texture->get_num_on_stages(); @@ -4590,8 +4646,9 @@ finish_modify_state() { for (int i = 0; i < num_stages; i++) { TextureStage *stage = _current_texture->get_on_stage(i); _glActiveTexture(GL_TEXTURE0 + i); - - switch (_current_tex_gen->get_mode(stage)) { + + TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage); + switch (mode) { case TexGenAttrib::M_off: GLP(Disable)(GL_TEXTURE_GEN_S); GLP(Disable)(GL_TEXTURE_GEN_T); @@ -4599,7 +4656,7 @@ finish_modify_state() { GLP(Disable)(GL_TEXTURE_GEN_Q); break; - case TexGenAttrib::M_sphere_map: + case TexGenAttrib::M_eye_sphere_map: GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); GLP(Enable)(GL_TEXTURE_GEN_S); @@ -4609,8 +4666,28 @@ finish_modify_state() { force_normal = true; break; - case TexGenAttrib::M_cube_map: + case TexGenAttrib::M_eye_cube_map: + case TexGenAttrib::M_world_cube_map: if (_supports_cube_map) { + if (mode != TexGenAttrib::M_eye_cube_map) { + // We dynamically transform normals from eye space to + // world space by applying the appropriate rotation + // transform to the current texture matrix. Although it's + // tempting to try, we can't safely convert to object + // space, since this method doesn't get called with each + // different object. + CPT(TransformState) transform = _scene_setup->get_render_transform(); + transform = transform->invert_compose(TransformState::make_identity()); + LMatrix4f mat = transform->get_mat(); + mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f)); + GLP(MatrixMode)(GL_TEXTURE); + GLP(MultMatrixf)(mat.get_data()); + + // Now we need to reset the texture matrix next time + // around to undo this. + _needs_tex_mat = true; + } + GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); @@ -4626,6 +4703,44 @@ finish_modify_state() { GLP(Disable)(GL_TEXTURE_GEN_Q); } break; + + case TexGenAttrib::M_eye_normal: + case TexGenAttrib::M_world_normal: + if (_supports_cube_map) { + if (mode != TexGenAttrib::M_eye_normal) { + // We dynamically transform normals from eye space to + // world space by applying the appropriate rotation + // transform to the current texture matrix. Although it's + // tempting to try, we can't safely convert to object + // space, since this method doesn't get called with each + // different object. + CPT(TransformState) transform = _scene_setup->get_render_transform(); + transform = transform->invert_compose(TransformState::make_identity()); + LMatrix4f mat = transform->get_mat(); + mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f)); + GLP(MatrixMode)(GL_TEXTURE); + GLP(MultMatrixf)(mat.get_data()); + + // Now we need to reset the texture matrix next time + // around to undo this. + _needs_tex_mat = true; + } + + GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); + GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); + GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); + GLP(Enable)(GL_TEXTURE_GEN_S); + GLP(Enable)(GL_TEXTURE_GEN_T); + GLP(Enable)(GL_TEXTURE_GEN_R); + GLP(Disable)(GL_TEXTURE_GEN_Q); + force_normal = true; + } else { + GLP(Disable)(GL_TEXTURE_GEN_S); + GLP(Disable)(GL_TEXTURE_GEN_T); + GLP(Disable)(GL_TEXTURE_GEN_R); + GLP(Disable)(GL_TEXTURE_GEN_Q); + } + break; case TexGenAttrib::M_object_position: GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); @@ -4698,24 +4813,6 @@ finish_modify_state() { GLP(PopMatrix)(); } break; - - case TexGenAttrib::M_object_normal: - if (_supports_cube_map) { - GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); - GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); - GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); - GLP(Enable)(GL_TEXTURE_GEN_S); - GLP(Enable)(GL_TEXTURE_GEN_T); - GLP(Enable)(GL_TEXTURE_GEN_R); - GLP(Disable)(GL_TEXTURE_GEN_Q); - force_normal = true; - } else { - GLP(Disable)(GL_TEXTURE_GEN_S); - GLP(Disable)(GL_TEXTURE_GEN_T); - GLP(Disable)(GL_TEXTURE_GEN_R); - GLP(Disable)(GL_TEXTURE_GEN_Q); - } - break; } } @@ -4829,16 +4926,20 @@ do_issue_texture() { _glActiveTexture(GL_TEXTURE0 + i); GLenum target = get_texture_target(texture->get_texture_type()); + + // First, turn off the previous texture mode. + GLP(Disable)(GL_TEXTURE_1D); + GLP(Disable)(GL_TEXTURE_2D); + if (_supports_3d_texture) { + GLP(Disable)(GL_TEXTURE_3D); + } + if (_supports_cube_map) { + GLP(Disable)(GL_TEXTURE_CUBE_MAP); + } + + // Then, turn on the current texture mode. if (target == GL_NONE) { // Unsupported texture mode. - GLP(Disable)(GL_TEXTURE_1D); - GLP(Disable)(GL_TEXTURE_2D); - if (_supports_3d_texture) { - GLP(Disable)(GL_TEXTURE_3D); - } - if (_supports_cube_map) { - GLP(Disable)(GL_TEXTURE_CUBE_MAP); - } break; } GLP(Enable)(target); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index a8530fe719..3c86873476 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -97,9 +97,9 @@ public: virtual void release_geom(GeomContext *gc); virtual void framebuffer_copy_to_texture - (Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb); + (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); virtual bool framebuffer_copy_to_ram - (Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb); + (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); virtual void apply_material(const Material *material); void apply_fog(Fog *fog); @@ -301,10 +301,6 @@ public: bool _supports_cube_map; - GLint _max_texture_size; - GLint _max_3d_texture_size; - GLint _max_cube_map_size; - bool _supports_bgr; bool _supports_rescale_normal; diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 1b34c53662..ecbba81f77 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -28,6 +28,7 @@ #include "string_utils.h" #include "preparedGraphicsObjects.h" #include "pnmImage.h" +#include "virtualFileSystem.h" #include @@ -263,6 +264,118 @@ write(const Filename &name, int z) const { return true; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::read_pages +// Access: Published +// Description: Automatically reads in a sequence of pages, for the +// purpose of reading in a 3-d texture or a cube map +// texture. The filename should contain a sequence of +// one or more hash marks ("#") which will be filled in +// with the z value of each page, zero-based. If z_size +// is specified, the reading will stop there; otherwise, +// all found textures will be loaded, until a gap in the +// sequence is encountered. +// +// If more than one hash mark is used, the numbers will +// be padded with zeroes if necessary to the +// corresponding number of digits. +//////////////////////////////////////////////////////////////////// +bool Texture:: +read_pages(const Filename &fullpath_template, int z_size) { + string fp = fullpath_template.get_fullpath(); + size_t hash = fp.rfind('#'); + if (hash == string::npos) { + gobj_cat.error() + << "Template " << fullpath_template << " contains no hash marks.\n"; + return false; + } + + // Count the number of hash marks. + size_t num_hash = 1; + while (hash >= num_hash && fp[hash - num_hash] == '#') { + num_hash++; + } + + string prefix = fp.substr(0, hash - num_hash + 1); + string suffix = fp.substr(hash + 1); + + clear_ram_image(); + + if (z_size != 0) { + set_z_size(z_size); + for (int z = 0; z < z_size; z++) { + ostringstream strm; + strm << prefix << setw(num_hash) << setfill('0') << z << suffix; + if (!read(strm.str(), z)) { + return false; + } + } + } else { + set_z_size(0); + int z = 0; + ostringstream strm; + strm << prefix << setw(num_hash) << setfill('0') << z << suffix; + Filename file(strm.str()); + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + + while (vfs->exists(file)) { + if (!read(file, z)) { + return false; + } + ++z; + + ostringstream strm; + strm << prefix << setw(num_hash) << setfill('0') << z << suffix; + file = Filename(strm.str()); + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::write_pages +// Access: Published +// Description: Automatically writes out a sequence of pages, for the +// purpose of writing out a 3-d texture or a cube map +// texture. The filename should contain a sequence of +// one or more hash marks ("#") which will be filled in +// with the z value of each page, zero-based. +// +// If more than one hash mark is used, the numbers will +// be padded with zeroes if necessary to the +// corresponding number of digits. +//////////////////////////////////////////////////////////////////// +bool Texture:: +write_pages(const Filename &fullpath_template) { + string fp = fullpath_template.get_fullpath(); + size_t hash = fp.rfind('#'); + if (hash == string::npos) { + gobj_cat.error() + << "Template " << fullpath_template << " contains no hash marks.\n"; + return false; + } + + // Count the number of hash marks. + size_t num_hash = 1; + while (hash >= num_hash && fp[hash - num_hash] == '#') { + num_hash++; + } + + string prefix = fp.substr(0, hash - num_hash + 1); + string suffix = fp.substr(hash + 1); + + for (int z = 0; z < _z_size; z++) { + ostringstream strm; + strm << prefix << setw(num_hash) << setfill('0') << z << suffix; + if (!write(strm.str(), z)) { + return false; + } + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::load // Access: Published @@ -500,7 +613,7 @@ store(PNMImage &pnmimage, int z) const { } } - nassertr(idx == (int)get_expected_ram_image_size(), false); + nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false); return true; @@ -526,7 +639,7 @@ store(PNMImage &pnmimage, int z) const { } } - nassertr(idx == (int)get_expected_ram_image_size(), false); + nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false); return true; } diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index af496d4605..baf2174943 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -157,6 +157,9 @@ PUBLISHED: int primary_file_num_channels = 0, int alpha_file_channel = 0); bool write(const Filename &fullpath, int z = 0) const; + bool read_pages(const Filename &fullpath_template, int z_size = 0); + bool write_pages(const Filename &fullpath_template); + bool load(const PNMImage &pnmimage, int z = 0); bool store(PNMImage &pnmimage, int z = 0) const; diff --git a/panda/src/grutil/multitexReducer.cxx b/panda/src/grutil/multitexReducer.cxx index c5596d8f8e..6aff78ae2e 100644 --- a/panda/src/grutil/multitexReducer.cxx +++ b/panda/src/grutil/multitexReducer.cxx @@ -263,8 +263,8 @@ flatten(GraphicsOutput *window) { multitex_name_strm << "multitex" << multitex_id; multitex_id++; - GraphicsOutput *buffer = - window->make_texture_buffer(multitex_name_strm.str(), x_size, y_size); + GraphicsOutput *buffer = window->make_texture_buffer + (multitex_name_strm.str(), x_size, y_size, NULL, false); buffer->set_one_shot(true); Texture *tex = buffer->get_texture(); tex->set_anisotropic_degree(aniso_degree); diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 3c106557fa..012451aaf5 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -166,9 +166,9 @@ public: virtual void draw_sphere(GeomSphere *geom, GeomContext *gc)=0; virtual void framebuffer_copy_to_texture - (Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb)=0; + (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0; virtual bool framebuffer_copy_to_ram - (Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb)=0; + (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0; virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex)=0; virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex)=0; diff --git a/panda/src/pgraph/texGenAttrib.cxx b/panda/src/pgraph/texGenAttrib.cxx index d2656e0e11..92fad3baf8 100755 --- a/panda/src/pgraph/texGenAttrib.cxx +++ b/panda/src/pgraph/texGenAttrib.cxx @@ -157,12 +157,25 @@ output(ostream &out) const { case M_off: out << "off"; break; - case M_sphere_map: - out << "sphere_map"; + + case M_eye_sphere_map: + out << "eye_sphere_map"; break; - case M_cube_map: - out << "cube_map"; + + case M_world_cube_map: + out << "world_cube_map"; break; + case M_eye_cube_map: + out << "eye_cube_map"; + break; + + case M_world_normal: + out << "world_normal"; + break; + case M_eye_normal: + out << "eye_normal"; + break; + case M_world_position: out << "world_position"; break; @@ -172,9 +185,6 @@ output(ostream &out) const { case M_eye_position: out << "eye_position"; break; - case M_object_normal: - out << "object_normal"; - break; } out << ")"; } diff --git a/panda/src/pgraph/texGenAttrib.h b/panda/src/pgraph/texGenAttrib.h index a0b047aac1..db2e287b2e 100755 --- a/panda/src/pgraph/texGenAttrib.h +++ b/panda/src/pgraph/texGenAttrib.h @@ -40,12 +40,42 @@ class EXPCL_PANDA TexGenAttrib : public RenderAttrib { PUBLISHED: enum Mode { M_off, - M_sphere_map, - M_cube_map, + + // In the types below, "eye" means the coordinate space of the + // observing camera, "object" means the local coordinate space of + // the object, and "world" means world coordinates, e.g. the + // coordinate space of the root of the graph. + + // Sphere maps are classic static reflection maps. They are + // supported on just about any hardware, and require a precomputed + // 180-degree fisheye image. Sphere maps only make sense in eye + // coordinate space. + M_eye_sphere_map, + + // Cube maps are a modern improvement on the sphere map; they + // don't suffer from any polar singularities, but they require six + // texture images. They can also be generated dynamically for + // real-time reflections (see GraphicsOutput::make_cube_map()). + // Typically, a statically-generated cube map will be in eye + // space, while a dynamically-generated map will be in world space + // or object space (depending on where the camera rig that + // generates the map is parented). + + // Cube mapping is not supported on all hardware. + M_world_cube_map, + M_eye_cube_map, + + // Normal maps are most useful for applying diffuse lighting + // effects via a pregenerated cube map. + M_world_normal, + M_eye_normal, + + // Position maps convert XYZ coordinates directly to texture + // coordinates. This is particularly useful for implementing + // projective texturing (see NodePath::project_texture()). M_world_position, M_object_position, M_eye_position, - M_object_normal, }; protected: diff --git a/panda/src/wgldisplay/wglGraphicsBuffer.cxx b/panda/src/wgldisplay/wglGraphicsBuffer.cxx index d6f800f8af..37bb07cedd 100644 --- a/panda/src/wgldisplay/wglGraphicsBuffer.cxx +++ b/panda/src/wgldisplay/wglGraphicsBuffer.cxx @@ -43,7 +43,6 @@ wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, // Since the pbuffer never gets flipped, we get screenshots from the // same buffer we draw into. _screenshot_buffer_type = _draw_buffer_type; - _render_texture = false; } //////////////////////////////////////////////////////////////////// @@ -204,12 +203,25 @@ open_buffer() { if (wgldisplay_cat.is_debug()) { wgldisplay_cat.debug() << "Created PBuffer " << _pbuffer << ", DC " << _pbuffer_dc << "\n"; - if (_render_texture) { + switch (_rtm_mode) { + case RTM_bind_texture: wgldisplay_cat.debug() << "pbuffer renders directly to texture.\n"; - } else if (_copy_texture) { + break; + + case RTM_copy_texture: + case RTM_bind_if_possible: wgldisplay_cat.debug() << "pbuffer copies indirectly into texture.\n"; + break; + + case RTM_copy_ram: + wgldisplay_cat.debug() + << "pbuffer copies indirectly into system RAM.\n"; + break; + + default: + break; } } @@ -245,14 +257,15 @@ make_pbuffer(HDC twindow_dc) { if (wglgsg->_supports_pixel_format) { bool got_pbuffer_format = false; - if (_copy_texture && wglgsg->_supports_render_texture) { + if (_rtm_mode == RTM_bind_if_possible && + wglgsg->_supports_render_texture) { // First, try to get a pbuffer format that supports // render-to-texture. int new_pbformat = choose_pbuffer_format(twindow_dc, true); if (new_pbformat != 0) { pbformat = new_pbformat; got_pbuffer_format = true; - _render_texture = true; + _rtm_mode = RTM_bind_texture; } } @@ -279,7 +292,7 @@ make_pbuffer(HDC twindow_dc) { int iattrib_list[max_attrib_list]; int ni = 0; - if (_render_texture) { + if (_rtm_mode == RTM_bind_texture) { if (_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_alpha) { iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB; iattrib_list[ni++] = WGL_TEXTURE_RGBA_ARB;