mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
support real-time rendered cube maps
This commit is contained in:
parent
eacf0ccd13
commit
c045c5894d
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
<Scalar> stage-name { name }
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 << ")**";
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "string_utils.h"
|
||||
#include "preparedGraphicsObjects.h"
|
||||
#include "pnmImage.h"
|
||||
#include "virtualFileSystem.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 << ")";
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user