Panda3D

tinyGraphicsStateGuardian.cxx

00001 // Filename: tinyGraphicsStateGuardian.cxx
00002 // Created by:  drose (24Apr08)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "tinyGraphicsStateGuardian.h"
00016 #include "tinyGeomMunger.h"
00017 #include "tinyTextureContext.h"
00018 #include "config_tinydisplay.h"
00019 #include "pStatTimer.h"
00020 #include "geomVertexReader.h"
00021 #include "ambientLight.h"
00022 #include "pointLight.h"
00023 #include "directionalLight.h"
00024 #include "spotlight.h"
00025 #include "depthWriteAttrib.h"
00026 #include "depthOffsetAttrib.h"
00027 #include "colorWriteAttrib.h"
00028 #include "alphaTestAttrib.h"
00029 #include "depthTestAttrib.h"
00030 #include "shadeModelAttrib.h"
00031 #include "cullFaceAttrib.h"
00032 #include "rescaleNormalAttrib.h"
00033 #include "materialAttrib.h"
00034 #include "lightAttrib.h"
00035 #include "scissorAttrib.h"
00036 #include "bitMask.h"
00037 #include "zgl.h"
00038 #include "zmath.h"
00039 #include "ztriangle_table.h"
00040 #include "store_pixel_table.h"
00041 #include "graphicsEngine.h"
00042 
00043 TypeHandle TinyGraphicsStateGuardian::_type_handle;
00044 
00045 PStatCollector TinyGraphicsStateGuardian::_vertices_immediate_pcollector("Vertices:Immediate mode");
00046 PStatCollector TinyGraphicsStateGuardian::_draw_transform_pcollector("Draw:Transform");
00047 PStatCollector TinyGraphicsStateGuardian::_pixel_count_white_untextured_pcollector("Pixels:White untextured");
00048 PStatCollector TinyGraphicsStateGuardian::_pixel_count_flat_untextured_pcollector("Pixels:Flat untextured");
00049 PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_untextured_pcollector("Pixels:Smooth untextured");
00050 PStatCollector TinyGraphicsStateGuardian::_pixel_count_white_textured_pcollector("Pixels:White textured");
00051 PStatCollector TinyGraphicsStateGuardian::_pixel_count_flat_textured_pcollector("Pixels:Flat textured");
00052 PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_textured_pcollector("Pixels:Smooth textured");
00053 PStatCollector TinyGraphicsStateGuardian::_pixel_count_white_perspective_pcollector("Pixels:White perspective");
00054 PStatCollector TinyGraphicsStateGuardian::_pixel_count_flat_perspective_pcollector("Pixels:Flat perspective");
00055 PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_perspective_pcollector("Pixels:Smooth perspective");
00056 PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_multitex2_pcollector("Pixels:Smooth multitex 2");
00057 PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_multitex3_pcollector("Pixels:Smooth multitex 3");
00058 
00059 ////////////////////////////////////////////////////////////////////
00060 //     Function: TinyGraphicsStateGuardian::Constructor
00061 //       Access: Public
00062 //  Description:
00063 ////////////////////////////////////////////////////////////////////
00064 TinyGraphicsStateGuardian::
00065 TinyGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
00066                           TinyGraphicsStateGuardian *share_with) :
00067   GraphicsStateGuardian(CS_yup_right, engine, pipe)
00068 {
00069   _current_frame_buffer = NULL;
00070   _aux_frame_buffer = NULL;
00071   _c = NULL;
00072   _vertices = NULL;
00073   _vertices_size = 0;
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: TinyGraphicsStateGuardian::Destructor
00078 //       Access: Public
00079 //  Description:
00080 ////////////////////////////////////////////////////////////////////
00081 TinyGraphicsStateGuardian::
00082 ~TinyGraphicsStateGuardian() {
00083 }
00084 
00085 ////////////////////////////////////////////////////////////////////
00086 //     Function: TinyGraphicsStateGuardian::reset
00087 //       Access: Public, Virtual
00088 //  Description: Resets all internal state as if the gsg were newly
00089 //               created.
00090 ////////////////////////////////////////////////////////////////////
00091 void TinyGraphicsStateGuardian::
00092 reset() {
00093   free_pointers();
00094   GraphicsStateGuardian::reset();
00095 
00096   // Build _inv_state_mask as a mask of 1's where we don't care, and
00097   // 0's where we do care, about the state.
00098   _inv_state_mask = RenderState::SlotMask::all_on();
00099   _inv_state_mask.clear_bit(ColorAttrib::get_class_slot());
00100   _inv_state_mask.clear_bit(ColorScaleAttrib::get_class_slot());
00101   _inv_state_mask.clear_bit(CullFaceAttrib::get_class_slot());
00102   _inv_state_mask.clear_bit(DepthOffsetAttrib::get_class_slot());
00103   _inv_state_mask.clear_bit(RenderModeAttrib::get_class_slot());
00104   _inv_state_mask.clear_bit(RescaleNormalAttrib::get_class_slot());
00105   _inv_state_mask.clear_bit(TextureAttrib::get_class_slot());
00106   _inv_state_mask.clear_bit(MaterialAttrib::get_class_slot());
00107   _inv_state_mask.clear_bit(LightAttrib::get_class_slot());
00108   _inv_state_mask.clear_bit(ScissorAttrib::get_class_slot());
00109 
00110   if (_c != (GLContext *)NULL) {
00111     glClose(_c);
00112     _c = NULL;
00113   }
00114 
00115   _c = (GLContext *)gl_zalloc(sizeof(GLContext));
00116   glInit(_c, _current_frame_buffer);
00117 
00118   _c->draw_triangle_front = gl_draw_triangle_fill;
00119   _c->draw_triangle_back = gl_draw_triangle_fill;
00120 
00121   _supported_geom_rendering =
00122     Geom::GR_point | 
00123     Geom::GR_indexed_other |
00124     Geom::GR_triangle_strip |
00125     Geom::GR_flat_last_vertex;
00126 
00127   _max_texture_dimension = (1 << ZB_POINT_ST_FRAC_BITS);
00128   _max_texture_stages = MAX_TEXTURE_STAGES;
00129   _max_lights = MAX_LIGHTS;
00130 
00131   _color_scale_via_lighting = false;
00132   _alpha_scale_via_texture = false;
00133   _runtime_color_scale = true;
00134 
00135   _color_material_flags = 0;
00136   _texturing_state = 0;
00137   _texfilter_state = 0;
00138   _texture_replace = false;
00139   _filled_flat = false;
00140   _auto_rescale_normal = false;
00141 
00142   // Now that the GSG has been initialized, make it available for
00143   // optimizations.
00144   add_gsg(this);
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: TinyGraphicsStateGuardian::free_pointers
00149 //       Access: Protected, Virtual
00150 //  Description: Frees some memory that was explicitly allocated
00151 //               within the glgsg.
00152 ////////////////////////////////////////////////////////////////////
00153 void TinyGraphicsStateGuardian::
00154 free_pointers() {
00155   if (_aux_frame_buffer != (ZBuffer *)NULL) {
00156     ZB_close(_aux_frame_buffer);
00157     _aux_frame_buffer = NULL;
00158   }
00159 
00160   if (_vertices != (GLVertex *)NULL) {
00161     PANDA_FREE_ARRAY(_vertices);
00162     _vertices = NULL;
00163   }
00164   _vertices_size = 0;
00165 }
00166 
00167 ////////////////////////////////////////////////////////////////////
00168 //     Function: TinyGraphicsStateGuardian::close_gsg
00169 //       Access: Protected, Virtual
00170 //  Description: This is called by the associated GraphicsWindow when
00171 //               close_window() is called.  It should null out the
00172 //               _win pointer and possibly free any open resources
00173 //               associated with the GSG.
00174 ////////////////////////////////////////////////////////////////////
00175 void TinyGraphicsStateGuardian::
00176 close_gsg() {
00177   GraphicsStateGuardian::close_gsg();
00178 
00179   if (_c != (GLContext *)NULL) {
00180     glClose(_c);
00181     _c = NULL;
00182   }
00183 }
00184 
00185 ////////////////////////////////////////////////////////////////////
00186 //     Function: TinyGraphicsStateGuardian::depth_offset_decals
00187 //       Access: Public, Virtual
00188 //  Description: Returns true if this GSG can implement decals using a
00189 //               DepthOffsetAttrib, or false if that is unreliable
00190 //               and the three-step rendering process should be used
00191 //               instead.
00192 ////////////////////////////////////////////////////////////////////
00193 bool TinyGraphicsStateGuardian::
00194 depth_offset_decals() {
00195   return false;
00196 }
00197 
00198 ////////////////////////////////////////////////////////////////////
00199 //     Function: TinyGraphicsStateGuardian::make_geom_munger
00200 //       Access: Public, Virtual
00201 //  Description: Creates a new GeomMunger object to munge vertices
00202 //               appropriate to this GSG for the indicated state.
00203 ////////////////////////////////////////////////////////////////////
00204 PT(GeomMunger) TinyGraphicsStateGuardian::
00205 make_geom_munger(const RenderState *state, Thread *current_thread) {
00206   PT(TinyGeomMunger) munger = new TinyGeomMunger(this, state);
00207   return GeomMunger::register_munger(munger, current_thread);
00208 }
00209 
00210 ////////////////////////////////////////////////////////////////////
00211 //     Function: TinyGraphicsStateGuardian::clear
00212 //       Access: Public
00213 //  Description: Clears the framebuffer within the current
00214 //               DisplayRegion, according to the flags indicated by
00215 //               the given DrawableRegion object.
00216 //
00217 //               This does not set the DisplayRegion first.  You
00218 //               should call prepare_display_region() to specify the
00219 //               region you wish the clear operation to apply to.
00220 ////////////////////////////////////////////////////////////////////
00221 void TinyGraphicsStateGuardian::
00222 clear(DrawableRegion *clearable) {
00223   PStatTimer timer(_clear_pcollector);
00224 
00225   if ((!clearable->get_clear_color_active())&&
00226       (!clearable->get_clear_depth_active())&&
00227       (!clearable->get_clear_stencil_active())) {
00228     return;
00229   }
00230   
00231   set_state_and_transform(RenderState::make_empty(), _internal_transform);
00232 
00233   bool clear_color = false;
00234   int r, g, b, a;
00235   if (clearable->get_clear_color_active()) {
00236     Colorf v = clearable->get_clear_color();
00237     r = (int)(v[0] * 0xffff);
00238     g = (int)(v[1] * 0xffff);
00239     b = (int)(v[2] * 0xffff);
00240     a = (int)(v[3] * 0xffff);
00241     clear_color = true;
00242   }
00243   
00244   bool clear_z = false;
00245   int z;
00246   if (clearable->get_clear_depth_active()) {
00247     // We ignore the specified depth clear value, since we don't
00248     // support alternate depth compare functions anyway.
00249     z = 0;
00250     clear_z = true;
00251   }
00252 
00253   ZB_clear_viewport(_c->zb, clear_z, z,
00254                     clear_color, r, g, b, a,
00255                     _c->viewport.xmin, _c->viewport.ymin,
00256                     _c->viewport.xsize, _c->viewport.ysize);
00257 }
00258 
00259 ////////////////////////////////////////////////////////////////////
00260 //     Function: TinyGraphicsStateGuardian::prepare_display_region
00261 //       Access: Public, Virtual
00262 //  Description: Prepare a display region for rendering (set up
00263 //               scissor region and viewport)
00264 ////////////////////////////////////////////////////////////////////
00265 void TinyGraphicsStateGuardian::
00266 prepare_display_region(DisplayRegionPipelineReader *dr,
00267                        Lens::StereoChannel stereo_channel) {
00268   nassertv(dr != (DisplayRegionPipelineReader *)NULL);
00269   GraphicsStateGuardian::prepare_display_region(dr, stereo_channel);
00270 
00271   int xmin, ymin, xsize, ysize;
00272   dr->get_region_pixels_i(xmin, ymin, xsize, ysize);
00273 
00274   float pixel_factor = _current_display_region->get_pixel_factor();
00275   if (pixel_factor != 1.0) {
00276     // Render into an aux buffer, and zoom it up into the main
00277     // frame buffer later.
00278     xmin = 0;
00279     ymin = 0;
00280     xsize = int(xsize * pixel_factor);
00281     ysize = int(ysize * pixel_factor);
00282     if (_aux_frame_buffer == (ZBuffer *)NULL) {
00283       _aux_frame_buffer = ZB_open(xsize, ysize, ZB_MODE_RGBA, 0, 0, 0, 0);
00284     } else if (_aux_frame_buffer->xsize < xsize || _aux_frame_buffer->ysize < ysize) {
00285       ZB_resize(_aux_frame_buffer, NULL, 
00286                 max(_aux_frame_buffer->xsize, xsize),
00287                 max(_aux_frame_buffer->ysize, ysize));
00288     }
00289     _c->zb = _aux_frame_buffer;
00290 
00291   } else {
00292     // Render directly into the main frame buffer.
00293     _c->zb = _current_frame_buffer;
00294   }
00295 
00296   _c->viewport.xmin = xmin;
00297   _c->viewport.ymin = ymin;
00298   _c->viewport.xsize = xsize;
00299   _c->viewport.ysize = ysize;
00300   set_scissor(0.0f, 1.0f, 0.0f, 1.0f);
00301 
00302   nassertv(xmin >= 0 && xmin < _c->zb->xsize && 
00303            ymin >= 0 && ymin < _c->zb->ysize &&
00304            xmin + xsize >= 0 && xmin + xsize <= _c->zb->xsize &&
00305            ymin + ysize >= 0 && ymin + ysize <= _c->zb->ysize);
00306 }
00307 
00308 ////////////////////////////////////////////////////////////////////
00309 //     Function: TinyGraphicsStateGuardian::calc_projection_mat
00310 //       Access: Public, Virtual
00311 //  Description: Given a lens, calculates the appropriate projection
00312 //               matrix for use with this gsg.  Note that the
00313 //               projection matrix depends a lot upon the coordinate
00314 //               system of the rendering API.
00315 //
00316 //               The return value is a TransformState if the lens is
00317 //               acceptable, NULL if it is not.
00318 ////////////////////////////////////////////////////////////////////
00319 CPT(TransformState) TinyGraphicsStateGuardian::
00320 calc_projection_mat(const Lens *lens) {
00321   if (lens == (Lens *)NULL) {
00322     return NULL;
00323   }
00324 
00325   if (!lens->is_linear()) {
00326     return NULL;
00327   }
00328 
00329   // The projection matrix must always be right-handed Y-up, even if
00330   // our coordinate system of choice is otherwise, because certain GL
00331   // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of
00332   // a coordinate system.  Sigh.  In order to implement a Z-up (or
00333   // other arbitrary) coordinate system, we'll use a Y-up projection
00334   // matrix, and store the conversion to our coordinate system of
00335   // choice in the modelview matrix.
00336 
00337   LMatrix4f result =
00338     LMatrix4f::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) *
00339     lens->get_projection_mat(_current_stereo_channel);
00340 
00341   if (_scene_setup->get_inverted()) {
00342     // If the scene is supposed to be inverted, then invert the
00343     // projection matrix.
00344     result *= LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
00345   }
00346 
00347   return TransformState::make_mat(result);
00348 }
00349 
00350 ////////////////////////////////////////////////////////////////////
00351 //     Function: TinyGraphicsStateGuardian::prepare_lens
00352 //       Access: Public, Virtual
00353 //  Description: Makes the current lens (whichever lens was most
00354 //               recently specified with set_scene()) active, so
00355 //               that it will transform future rendered geometry.
00356 //               Normally this is only called from the draw process,
00357 //               and usually it is called by set_scene().
00358 //
00359 //               The return value is true if the lens is acceptable,
00360 //               false if it is not.
00361 ////////////////////////////////////////////////////////////////////
00362 bool TinyGraphicsStateGuardian::
00363 prepare_lens() {
00364   _transform_stale = true;
00365   return true;
00366 }
00367 
00368 ////////////////////////////////////////////////////////////////////
00369 //     Function: GraphicsStateGuardian::begin_frame
00370 //       Access: Public, Virtual
00371 //  Description: Called before each frame is rendered, to allow the
00372 //               GSG a chance to do any internal cleanup before
00373 //               beginning the frame.
00374 //
00375 //               The return value is true if successful (in which case
00376 //               the frame will be drawn and end_frame() will be
00377 //               called later), or false if unsuccessful (in which
00378 //               case nothing will be drawn and end_frame() will not
00379 //               be called).
00380 ////////////////////////////////////////////////////////////////////
00381 bool TinyGraphicsStateGuardian::
00382 begin_frame(Thread *current_thread) {
00383   if (!GraphicsStateGuardian::begin_frame(current_thread)) {
00384     return false;
00385   }
00386 
00387   _c->zb = _current_frame_buffer;
00388 
00389 #ifdef DO_PSTATS
00390   _vertices_immediate_pcollector.clear_level();
00391 
00392   _pixel_count_white_untextured_pcollector.clear_level();
00393   _pixel_count_flat_untextured_pcollector.clear_level();
00394   _pixel_count_smooth_untextured_pcollector.clear_level();
00395   _pixel_count_white_textured_pcollector.clear_level();
00396   _pixel_count_flat_textured_pcollector.clear_level();
00397   _pixel_count_smooth_textured_pcollector.clear_level();
00398   _pixel_count_white_perspective_pcollector.clear_level();
00399   _pixel_count_flat_perspective_pcollector.clear_level();
00400   _pixel_count_smooth_perspective_pcollector.clear_level();
00401   _pixel_count_smooth_multitex2_pcollector.clear_level();
00402   _pixel_count_smooth_multitex3_pcollector.clear_level();
00403 #endif
00404 
00405   return true;
00406 }
00407 
00408 ////////////////////////////////////////////////////////////////////
00409 //     Function: GraphicsStateGuardian::begin_scene
00410 //       Access: Public, Virtual
00411 //  Description: Called between begin_frame() and end_frame() to mark
00412 //               the beginning of drawing commands for a "scene"
00413 //               (usually a particular DisplayRegion) within a frame.
00414 //               All 3-D drawing commands, except the clear operation,
00415 //               must be enclosed within begin_scene() .. end_scene().
00416 //
00417 //               The return value is true if successful (in which case
00418 //               the scene will be drawn and end_scene() will be
00419 //               called later), or false if unsuccessful (in which
00420 //               case nothing will be drawn and end_scene() will not
00421 //               be called).
00422 ////////////////////////////////////////////////////////////////////
00423 bool TinyGraphicsStateGuardian::
00424 begin_scene() {
00425   return GraphicsStateGuardian::begin_scene();
00426 }
00427 
00428 ////////////////////////////////////////////////////////////////////
00429 //     Function: TinyGraphicsStateGuardian::end_scene
00430 //       Access: Protected, Virtual
00431 //  Description: Called between begin_frame() and end_frame() to mark
00432 //               the end of drawing commands for a "scene" (usually a
00433 //               particular DisplayRegion) within a frame.  All 3-D
00434 //               drawing commands, except the clear operation, must be
00435 //               enclosed within begin_scene() .. end_scene().
00436 ////////////////////////////////////////////////////////////////////
00437 void TinyGraphicsStateGuardian::
00438 end_scene() {
00439   if (_c->zb == _aux_frame_buffer) {
00440     // Copy the aux frame buffer into the main scene now, zooming it
00441     // up to the appropriate size.
00442     int xmin, ymin, xsize, ysize;
00443     _current_display_region->get_region_pixels_i(xmin, ymin, xsize, ysize);
00444     float pixel_factor = _current_display_region->get_pixel_factor();
00445 
00446     int fb_xsize = int(xsize * pixel_factor);
00447     int fb_ysize = int(ysize * pixel_factor);
00448 
00449     ZB_zoomFrameBuffer(_current_frame_buffer, xmin, ymin, xsize, ysize,
00450                        _aux_frame_buffer, 0, 0, fb_xsize, fb_ysize);
00451     _c->zb = _current_frame_buffer;
00452   }
00453 
00454   // Clear the lighting state.
00455   clear_light_state();
00456   _plights.clear();
00457   _dlights.clear();
00458   _slights.clear();
00459 
00460   GraphicsStateGuardian::end_scene();
00461 }
00462 
00463 ////////////////////////////////////////////////////////////////////
00464 //     Function: TinyGraphicsStateGuardian::end_frame
00465 //       Access: Public, Virtual
00466 //  Description: Called after each frame is rendered, to allow the
00467 //               GSG a chance to do any internal cleanup after
00468 //               rendering the frame, and before the window flips.
00469 ////////////////////////////////////////////////////////////////////
00470 void TinyGraphicsStateGuardian::
00471 end_frame(Thread *current_thread) {
00472   GraphicsStateGuardian::end_frame(current_thread);
00473 
00474 #ifndef NDEBUG
00475   static ConfigVariableBool td_show_zbuffer
00476     ("td-show-zbuffer", false,
00477      PRC_DESC("Set this true to draw the ZBuffer instead of the visible buffer, when rendering with tinydisplay.  This is useful to aid debugging the ZBuffer"));
00478   if (td_show_zbuffer) {
00479     PIXEL *tp = _current_frame_buffer->pbuf;
00480     ZPOINT *tz = _current_frame_buffer->zbuf;
00481     for (int yi = 0; yi < _current_frame_buffer->ysize; ++yi) {
00482       for (int xi = 0; xi < _current_frame_buffer->xsize; ++xi) {
00483         (*tp) = (int)(*tz);
00484         ++tz;
00485         ++tp;
00486       }
00487     }
00488   }
00489 #endif // NDEBUG
00490 
00491 #ifdef DO_PSTATS
00492   // Flush any PCollectors specific to this kind of GSG.
00493   _vertices_immediate_pcollector.flush_level();
00494 
00495   _pixel_count_white_untextured_pcollector.flush_level();
00496   _pixel_count_flat_untextured_pcollector.flush_level();
00497   _pixel_count_smooth_untextured_pcollector.flush_level();
00498   _pixel_count_white_textured_pcollector.flush_level();
00499   _pixel_count_flat_textured_pcollector.flush_level();
00500   _pixel_count_smooth_textured_pcollector.flush_level();
00501   _pixel_count_white_perspective_pcollector.flush_level();
00502   _pixel_count_flat_perspective_pcollector.flush_level();
00503   _pixel_count_smooth_perspective_pcollector.flush_level();
00504   _pixel_count_smooth_multitex2_pcollector.flush_level();
00505   _pixel_count_smooth_multitex3_pcollector.flush_level();
00506 #endif  // DO_PSTATS
00507 }
00508 
00509 
00510 ////////////////////////////////////////////////////////////////////
00511 //     Function: TinyGraphicsStateGuardian::begin_draw_primitives
00512 //       Access: Public, Virtual
00513 //  Description: Called before a sequence of draw_primitive()
00514 //               functions are called, this should prepare the vertex
00515 //               data for rendering.  It returns true if the vertices
00516 //               are ok, false to abort this group of primitives.
00517 ////////////////////////////////////////////////////////////////////
00518 bool TinyGraphicsStateGuardian::
00519 begin_draw_primitives(const GeomPipelineReader *geom_reader,
00520                       const GeomMunger *munger,
00521                       const GeomVertexDataPipelineReader *data_reader,
00522                       bool force) {
00523 #ifndef NDEBUG
00524   if (tinydisplay_cat.is_spam()) {
00525     tinydisplay_cat.spam() << "begin_draw_primitives: " << *(data_reader->get_object()) << "\n";
00526   }
00527 #endif  // NDEBUG
00528 
00529   if (!GraphicsStateGuardian::begin_draw_primitives(geom_reader, munger, data_reader, force)) {
00530     return false;
00531   }
00532   nassertr(_data_reader != (GeomVertexDataPipelineReader *)NULL, false);
00533 
00534   PStatTimer timer(_draw_transform_pcollector);
00535 
00536   // Set up the proper transform.
00537   if (_data_reader->is_vertex_transformed()) {
00538     // If the vertex data claims to be already transformed into clip
00539     // coordinates, wipe out the current projection and modelview
00540     // matrix (so we don't attempt to transform it again).
00541     const TransformState *ident = TransformState::make_identity();
00542     load_matrix(&_c->matrix_model_view, ident);
00543     load_matrix(&_c->matrix_projection, _scissor_mat);
00544     load_matrix(&_c->matrix_model_view_inv, ident);
00545     load_matrix(&_c->matrix_model_projection, _scissor_mat);
00546     _c->matrix_model_projection_no_w_transform = 1;
00547     _transform_stale = true;
00548 
00549   } else if (_transform_stale) {
00550     // Load the actual transform.
00551 
00552     CPT(TransformState) scissor_proj_mat = _scissor_mat->compose(_projection_mat);
00553 
00554     if (_c->lighting_enabled) {
00555       // With the lighting equation, we need to keep the modelview and
00556       // projection matrices separate.
00557 
00558       load_matrix(&_c->matrix_model_view, _internal_transform);
00559       load_matrix(&_c->matrix_projection, scissor_proj_mat);
00560 
00561       /* precompute inverse modelview */
00562       M4 tmp;
00563       gl_M4_Inv(&tmp, &_c->matrix_model_view);
00564       gl_M4_Transpose(&_c->matrix_model_view_inv, &tmp);
00565 
00566     }
00567 
00568     // Compose the modelview and projection matrices.
00569     load_matrix(&_c->matrix_model_projection, 
00570                 scissor_proj_mat->compose(_internal_transform));
00571 
00572     /* test to accelerate computation */
00573     _c->matrix_model_projection_no_w_transform = 0;
00574     float *m = &_c->matrix_model_projection.m[0][0];
00575     if (m[12] == 0.0 && m[13] == 0.0 && m[14] == 0.0) {
00576       _c->matrix_model_projection_no_w_transform = 1;
00577     }
00578     _transform_stale = false;
00579   }
00580 
00581   // Figure out the subset of vertices we will be using in this
00582   // operation.
00583   int num_vertices = data_reader->get_num_rows();
00584   _min_vertex = num_vertices;
00585   _max_vertex = 0;
00586   int num_prims = geom_reader->get_num_primitives();
00587   int i;
00588   for (i = 0; i < num_prims; ++i) {
00589     CPT(GeomPrimitive) prim = geom_reader->get_primitive(i);
00590     int nv = prim->get_min_vertex();
00591     _min_vertex = min(_min_vertex, nv);
00592     int xv = prim->get_max_vertex();
00593     _max_vertex = max(_max_vertex, xv);
00594   }
00595   if (_min_vertex > _max_vertex) {
00596     return false;
00597   }
00598 
00599   // Now copy all of those vertices into our working table,
00600   // transforming into screen space them as we go.
00601   int num_used_vertices = _max_vertex - _min_vertex + 1;
00602   if (_vertices_size < num_used_vertices) {
00603     if (_vertices_size == 0) {
00604       _vertices_size = 1;
00605     }
00606     while (_vertices_size < num_used_vertices) {
00607       _vertices_size *= 2;
00608     }
00609     if (_vertices != (GLVertex *)NULL) {
00610       PANDA_FREE_ARRAY(_vertices);
00611     }
00612     _vertices = (GLVertex *)PANDA_MALLOC_ARRAY(_vertices_size * sizeof(GLVertex));
00613   }
00614 
00615   GeomVertexReader  rcolor, rnormal;
00616 
00617   // We now support up to 3-stage multitexturing.
00618   GenTexcoordFunc *texgen_func[MAX_TEXTURE_STAGES];
00619   TexCoordData tcdata[MAX_TEXTURE_STAGES];
00620 
00621   const TexGenAttrib *target_tex_gen = DCAST(TexGenAttrib, _target_rs->get_attrib_def(TexGenAttrib::get_class_slot()));
00622   const TexMatrixAttrib *target_tex_matrix = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
00623 
00624   int max_stage_index = _target_texture->get_num_on_ff_stages();
00625   for (int si = 0; si < max_stage_index; ++si) {
00626     TextureStage *stage = _target_texture->get_on_ff_stage(si);
00627 
00628     switch (target_tex_gen->get_mode(stage)) {
00629     case TexGenAttrib::M_eye_sphere_map:
00630       tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_normal(),
00631                                         force);
00632       tcdata[si]._r2 = GeomVertexReader(data_reader, InternalName::get_vertex(),
00633                                         force);
00634       texgen_func[si] = &texgen_sphere_map;
00635       tcdata[si]._mat = _internal_transform->get_mat();
00636       break;
00637 
00638     case TexGenAttrib::M_eye_position:
00639       tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_vertex(),
00640                                        force);
00641       texgen_func[si] = &texgen_texmat;
00642       {
00643         CPT(TransformState) eye_transform =
00644           _cs_transform->invert_compose(_internal_transform);
00645         tcdata[si]._mat = eye_transform->get_mat();
00646       }
00647       if (target_tex_matrix->has_stage(stage)) {
00648         tcdata[si]._mat = tcdata[si]._mat * target_tex_matrix->get_mat(stage);
00649       }
00650       break;
00651 
00652     case TexGenAttrib::M_world_position:
00653       tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_vertex(),
00654                                        force);
00655       texgen_func[si] = &texgen_texmat;
00656       {
00657         CPT(TransformState) render_transform =
00658           _cs_transform->compose(_scene_setup->get_world_transform());
00659         CPT(TransformState) world_inv_transform = 
00660           render_transform->invert_compose(_internal_transform);
00661         tcdata[si]._mat = world_inv_transform->get_mat();
00662       }
00663       if (target_tex_matrix->has_stage(stage)) {
00664         tcdata[si]._mat = tcdata[si]._mat * target_tex_matrix->get_mat(stage);
00665       }
00666       break;
00667 
00668     default:
00669       // Fall through: use the standard texture coordinates.
00670       tcdata[si]._r1 = GeomVertexReader(data_reader, stage->get_texcoord_name(),
00671                                        force);
00672       texgen_func[si] = &texgen_simple;
00673       if (target_tex_matrix->has_stage(stage)) {
00674         texgen_func[si] = &texgen_texmat;
00675         tcdata[si]._mat = target_tex_matrix->get_mat(stage);
00676       }
00677 
00678       break;
00679     }
00680     tcdata[si]._r1.set_row(_min_vertex);
00681     tcdata[si]._r2.set_row(_min_vertex);
00682     if (!tcdata[si]._r1.has_column()) {
00683       texgen_func[si] = &texgen_null;
00684     }
00685   }
00686 
00687   bool needs_color = false;
00688   if (_vertex_colors_enabled) {
00689     rcolor = GeomVertexReader(data_reader, InternalName::get_color(), force);
00690     rcolor.set_row(_min_vertex);
00691     needs_color = rcolor.has_column();
00692   }
00693 
00694   if (!needs_color) {
00695     const Colorf &d = _scene_graph_color;
00696     const Colorf &s = _current_color_scale;
00697     _c->current_color.v[0] = d[0] * s[0];
00698     _c->current_color.v[1] = d[1] * s[1];
00699     _c->current_color.v[2] = d[2] * s[2];
00700     _c->current_color.v[3] = d[3] * s[3];
00701   }
00702 
00703   bool needs_normal = false;
00704   if (_c->lighting_enabled) {
00705     rnormal = GeomVertexReader(data_reader, InternalName::get_normal(), force);
00706     rnormal.set_row(_min_vertex);
00707     needs_normal = rnormal.has_column();
00708   }
00709 
00710   GeomVertexReader rvertex(data_reader, InternalName::get_vertex(), force); 
00711   rvertex.set_row(_min_vertex);
00712 
00713   if (!rvertex.has_column()) {
00714     // Whoops, guess the vertex data isn't resident.
00715     return false;
00716   }
00717 
00718   if (!needs_color && _color_material_flags) {
00719     if (_color_material_flags & CMF_ambient) {
00720       _c->materials[0].ambient = _c->current_color;
00721       _c->materials[1].ambient = _c->current_color;
00722     }
00723     if (_color_material_flags & CMF_diffuse) {
00724       _c->materials[0].diffuse = _c->current_color;
00725       _c->materials[1].diffuse = _c->current_color;
00726     }
00727   }
00728 
00729   if (_texturing_state != 0 && _texture_replace) {
00730     // We don't need the vertex color or lighting calculation after
00731     // all, since the current texture will just hide all of that.
00732     needs_color = false;
00733     needs_normal = false;
00734   }
00735 
00736   bool lighting_enabled = (needs_normal && _c->lighting_enabled);
00737 
00738   for (i = 0; i < num_used_vertices; ++i) {
00739     GLVertex *v = &_vertices[i];
00740     const LVecBase4f &d = rvertex.get_data4f();
00741     
00742     v->coord.v[0] = d[0];
00743     v->coord.v[1] = d[1];
00744     v->coord.v[2] = d[2];
00745     v->coord.v[3] = d[3];
00746 
00747     // Texture coordinates.
00748     for (int si = 0; si < max_stage_index; ++si) {
00749       TexCoordf d;
00750       (*texgen_func[si])(v->tex_coord[si], tcdata[si]);
00751     }
00752 
00753     if (needs_color) {
00754       const Colorf &d = rcolor.get_data4f();
00755       const Colorf &s = _current_color_scale;
00756       _c->current_color.v[0] = d[0] * s[0];
00757       _c->current_color.v[1] = d[1] * s[1];
00758       _c->current_color.v[2] = d[2] * s[2];
00759       _c->current_color.v[3] = d[3] * s[3];
00760       
00761       if (_color_material_flags) {
00762         if (_color_material_flags & CMF_ambient) {
00763           _c->materials[0].ambient = _c->current_color;
00764           _c->materials[1].ambient = _c->current_color;
00765         }
00766         if (_color_material_flags & CMF_diffuse) {
00767           _c->materials[0].diffuse = _c->current_color;
00768           _c->materials[1].diffuse = _c->current_color;
00769         }
00770       }
00771     }
00772 
00773     v->color = _c->current_color;
00774 
00775     if (lighting_enabled) {
00776       const LVecBase3f &d = rnormal.get_data3f();
00777       _c->current_normal.v[0] = d[0];
00778       _c->current_normal.v[1] = d[1];
00779       _c->current_normal.v[2] = d[2];
00780       _c->current_normal.v[3] = 0.0f;
00781 
00782       gl_vertex_transform(_c, v);
00783       gl_shade_vertex(_c, v);
00784 
00785     } else {
00786       gl_vertex_transform(_c, v);
00787     }
00788 
00789     if (v->clip_code == 0) {
00790       gl_transform_to_viewport(_c, v);
00791     }
00792 
00793     v->edge_flag = 1;
00794   }
00795 
00796   // Set up the appropriate function callback for filling triangles,
00797   // according to the current state.
00798 
00799   int depth_write_state = 0;  // zon
00800   const DepthWriteAttrib *target_depth_write = DCAST(DepthWriteAttrib, _target_rs->get_attrib_def(DepthWriteAttrib::get_class_slot()));
00801   if (target_depth_write->get_mode() != DepthWriteAttrib::M_on) {
00802     depth_write_state = 1;  // zoff
00803   }
00804 
00805   int color_write_state = 0;  // cstore
00806 
00807   const ColorWriteAttrib *target_color_write = DCAST(ColorWriteAttrib, _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot()));
00808   unsigned int color_channels =
00809     target_color_write->get_channels() & _color_write_mask;
00810   if (color_channels != ColorWriteAttrib::C_all) {
00811     // Implement a color mask.
00812     int op_a = get_color_blend_op(ColorBlendAttrib::O_one);
00813     int op_b = get_color_blend_op(ColorBlendAttrib::O_zero);
00814     _c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
00815     color_write_state = 2;   // cgeneral
00816   }
00817 
00818   const TransparencyAttrib *target_transparency = DCAST(TransparencyAttrib, _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
00819   switch (target_transparency->get_mode()) {
00820   case TransparencyAttrib::M_alpha:
00821   case TransparencyAttrib::M_dual:
00822     color_write_state = 1;    // cblend
00823     if (color_channels != ColorWriteAttrib::C_all) {
00824       // Implement a color mask, with alpha blending.
00825       int op_a = get_color_blend_op(ColorBlendAttrib::O_incoming_alpha);
00826       int op_b = get_color_blend_op(ColorBlendAttrib::O_one_minus_incoming_alpha);
00827       _c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
00828       color_write_state = 2;   // cgeneral
00829     }
00830     break;
00831 
00832   default:
00833     break;
00834   }
00835 
00836   const ColorBlendAttrib *target_color_blend = DCAST(ColorBlendAttrib, _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
00837   if (target_color_blend->get_mode() == ColorBlendAttrib::M_add) {
00838     // If we have a color blend set that we can support, it overrides
00839     // the transparency set.
00840     int op_a = get_color_blend_op(target_color_blend->get_operand_a());
00841     int op_b = get_color_blend_op(target_color_blend->get_operand_b());
00842     _c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
00843     Colorf c = target_color_blend->get_color();
00844     _c->zb->blend_r = (int)(c[0] * ZB_POINT_RED_MAX);
00845     _c->zb->blend_g = (int)(c[1] * ZB_POINT_GREEN_MAX);
00846     _c->zb->blend_b = (int)(c[2] * ZB_POINT_BLUE_MAX);
00847     _c->zb->blend_a = (int)(c[3] * ZB_POINT_ALPHA_MAX);
00848 
00849     color_write_state = 2;     // cgeneral
00850   }
00851 
00852   if (color_channels == ColorWriteAttrib::C_off) {
00853     color_write_state = 3;    // coff
00854   }
00855 
00856   int alpha_test_state = 0;   // anone
00857   const AlphaTestAttrib *target_alpha_test = DCAST(AlphaTestAttrib, _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
00858   switch (target_alpha_test->get_mode()) {
00859   case AlphaTestAttrib::M_none:
00860   case AlphaTestAttrib::M_never:
00861   case AlphaTestAttrib::M_always:
00862   case AlphaTestAttrib::M_equal:
00863   case AlphaTestAttrib::M_not_equal:
00864     alpha_test_state = 0;    // anone
00865     break;
00866 
00867   case AlphaTestAttrib::M_less:
00868   case AlphaTestAttrib::M_less_equal:
00869     alpha_test_state = 1;    // aless
00870     _c->zb->reference_alpha = (int)(target_alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX);
00871     break;
00872 
00873   case AlphaTestAttrib::M_greater:
00874   case AlphaTestAttrib::M_greater_equal:
00875     alpha_test_state = 2;    // amore
00876     _c->zb->reference_alpha = (int)(target_alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX);
00877     break;
00878   }
00879 
00880   int depth_test_state = 1;    // zless
00881   _c->depth_test = 1;  // set this for ZB_line
00882   const DepthTestAttrib *target_depth_test = DCAST(DepthTestAttrib, _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot()));
00883   if (target_depth_test->get_mode() == DepthTestAttrib::M_none) {
00884     depth_test_state = 0;      // zless
00885     _c->depth_test = 0;
00886   }
00887   
00888   const ShadeModelAttrib *target_shade_model = DCAST(ShadeModelAttrib, _target_rs->get_attrib_def(ShadeModelAttrib::get_class_slot()));
00889   ShadeModelAttrib::Mode shade_model = target_shade_model->get_mode();
00890   if (!needs_normal && !needs_color) {
00891     // With no per-vertex lighting, and no per-vertex colors, we might
00892     // as well use the flat shading model.
00893     shade_model = ShadeModelAttrib::M_flat;
00894   }
00895   int shade_model_state = 2;  // smooth
00896   _c->smooth_shade_model = true;
00897 
00898   if (shade_model == ShadeModelAttrib::M_flat) {
00899     _c->smooth_shade_model = false;
00900     shade_model_state = 1;  // flat
00901     if (_c->current_color.v[0] == 1.0f &&
00902         _c->current_color.v[1] == 1.0f &&
00903         _c->current_color.v[2] == 1.0f &&
00904         _c->current_color.v[3] == 1.0f) {
00905       shade_model_state = 0;  // white
00906     }
00907   }
00908 
00909   int texturing_state = _texturing_state;
00910   int texfilter_state = 0;  // tnearest
00911   if (texturing_state > 0) {
00912     texfilter_state = _texfilter_state;
00913 
00914     if (texturing_state < 3 &&
00915         (_c->matrix_model_projection_no_w_transform || _filled_flat)) {
00916       // Don't bother with the perspective-correct algorithm if we're
00917       // under an orthonormal lens, e.g. render2d; or if
00918       // RenderMode::M_filled_flat is in effect.
00919       texturing_state = 1;    // textured (not perspective correct)
00920     }
00921 
00922     if (_texture_replace) {
00923       // If we're completely replacing the underlying color, then it
00924       // doesn't matter what the color is.
00925       shade_model_state = 0;
00926     }
00927   }
00928 
00929   _c->zb_fill_tri = fill_tri_funcs[depth_write_state][color_write_state][alpha_test_state][depth_test_state][texfilter_state][shade_model_state][texturing_state];
00930 
00931 #ifdef DO_PSTATS
00932   pixel_count_white_untextured = 0;
00933   pixel_count_flat_untextured = 0;
00934   pixel_count_smooth_untextured = 0;
00935   pixel_count_white_textured = 0;
00936   pixel_count_flat_textured = 0;
00937   pixel_count_smooth_textured = 0;
00938   pixel_count_white_perspective = 0;
00939   pixel_count_flat_perspective = 0;
00940   pixel_count_smooth_perspective = 0;
00941   pixel_count_smooth_multitex2 = 0;
00942   pixel_count_smooth_multitex3 = 0;
00943 #endif  // DO_PSTATS
00944   
00945   return true;
00946 }
00947 
00948 ////////////////////////////////////////////////////////////////////
00949 //     Function: TinyGraphicsStateGuardian::draw_triangles
00950 //       Access: Public, Virtual
00951 //  Description: Draws a series of disconnected triangles.
00952 ////////////////////////////////////////////////////////////////////
00953 bool TinyGraphicsStateGuardian::
00954 draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
00955   PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
00956 
00957 #ifndef NDEBUG
00958   if (tinydisplay_cat.is_spam()) {
00959     tinydisplay_cat.spam() << "draw_triangles: " << *(reader->get_object()) << "\n";
00960   }
00961 #endif  // NDEBUG
00962 
00963   int num_vertices = reader->get_num_vertices();
00964   _vertices_tri_pcollector.add_level(num_vertices);
00965 
00966   if (reader->is_indexed()) {
00967     switch (reader->get_index_type()) {
00968     case Geom::NT_uint8:
00969       {
00970         PN_uint8 *index = (PN_uint8 *)reader->get_read_pointer(force);
00971         if (index == NULL) {
00972           return false;
00973         }
00974         for (int i = 0; i < num_vertices; i += 3) {
00975           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
00976           GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
00977           GLVertex *v2 = &_vertices[index[i + 2] - _min_vertex];
00978           gl_draw_triangle(_c, v0, v1, v2);
00979         }
00980       }
00981       break;
00982 
00983     case Geom::NT_uint16:
00984       {
00985         PN_uint16 *index = (PN_uint16 *)reader->get_read_pointer(force);
00986         if (index == NULL) {
00987           return false;
00988         }
00989         for (int i = 0; i < num_vertices; i += 3) {
00990           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
00991           GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
00992           GLVertex *v2 = &_vertices[index[i + 2] - _min_vertex];
00993           gl_draw_triangle(_c, v0, v1, v2);
00994         }
00995       }
00996       break;
00997 
00998     case Geom::NT_uint32:
00999       {
01000         PN_uint32 *index = (PN_uint32 *)reader->get_read_pointer(force);
01001         if (index == NULL) {
01002           return false;
01003         }
01004         for (int i = 0; i < num_vertices; i += 3) {
01005           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
01006           GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
01007           GLVertex *v2 = &_vertices[index[i + 2] - _min_vertex];
01008           gl_draw_triangle(_c, v0, v1, v2);
01009         }
01010       }
01011       break;
01012 
01013     default:
01014       break;
01015     }
01016 
01017   } else {
01018     int delta = reader->get_first_vertex() - _min_vertex;
01019     for (int vi = 0; vi < num_vertices; vi += 3) {
01020       GLVertex *v0 = &_vertices[vi + delta];
01021       GLVertex *v1 = &_vertices[vi + delta + 1];
01022       GLVertex *v2 = &_vertices[vi + delta + 2];
01023       gl_draw_triangle(_c, v0, v1, v2);
01024     }
01025   }
01026 
01027   return true;
01028 }
01029 
01030 ////////////////////////////////////////////////////////////////////
01031 //     Function: TinyGraphicsStateGuardian::draw_tristrips
01032 //       Access: Public, Virtual
01033 //  Description: Draws a series of triangle strips.
01034 ////////////////////////////////////////////////////////////////////
01035 bool TinyGraphicsStateGuardian::
01036 draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
01037   PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
01038 
01039 #ifndef NDEBUG
01040   if (tinydisplay_cat.is_spam()) {
01041     tinydisplay_cat.spam() << "draw_tristrips: " << *(reader->get_object()) << "\n";
01042   }
01043 #endif  // NDEBUG
01044 
01045   // Send the individual triangle strips, stepping over the
01046   // degenerate vertices.
01047   CPTA_int ends = reader->get_ends();
01048 
01049   _primitive_batches_tristrip_pcollector.add_level(ends.size());
01050   if (reader->is_indexed()) {
01051     unsigned int start = 0;
01052     for (size_t i = 0; i < ends.size(); i++) {
01053       _vertices_tristrip_pcollector.add_level(ends[i] - start);
01054 
01055       int end = ends[i];
01056       nassertr(end - start >= 3, false);
01057 
01058       switch (reader->get_index_type()) {
01059       case Geom::NT_uint8:
01060         {
01061           PN_uint8 *index = (PN_uint8 *)reader->get_read_pointer(force);
01062           if (index == NULL) {
01063             return false;
01064           }
01065           GLVertex *v0 = &_vertices[index[start] - _min_vertex];
01066           GLVertex *v1 = &_vertices[index[start + 1] - _min_vertex];
01067 
01068           bool reversed = false;
01069           for (int vi = start + 2; vi < end; ++vi) {
01070             GLVertex *v2 = &_vertices[index[vi] - _min_vertex];
01071             if (reversed) {
01072               gl_draw_triangle(_c, v1, v0, v2);
01073               reversed = false;
01074             } else {
01075               gl_draw_triangle(_c, v0, v1, v2);
01076               reversed = true;
01077             }
01078             v0 = v1;
01079             v1 = v2;
01080           }
01081         }
01082         break;
01083 
01084       case Geom::NT_uint16:
01085         {
01086           PN_uint16 *index = (PN_uint16 *)reader->get_read_pointer(force);
01087           if (index == NULL) {
01088             return false;
01089           }
01090           GLVertex *v0 = &_vertices[index[start] - _min_vertex];
01091           GLVertex *v1 = &_vertices[index[start + 1] - _min_vertex];
01092 
01093           bool reversed = false;
01094           for (int vi = start + 2; vi < end; ++vi) {
01095             GLVertex *v2 = &_vertices[index[vi] - _min_vertex];
01096             if (reversed) {
01097               gl_draw_triangle(_c, v1, v0, v2);
01098               reversed = false;
01099             } else {
01100               gl_draw_triangle(_c, v0, v1, v2);
01101               reversed = true;
01102             }
01103             v0 = v1;
01104             v1 = v2;
01105           }
01106         }
01107         break;
01108 
01109       case Geom::NT_uint32:
01110         {
01111           PN_uint32 *index = (PN_uint32 *)reader->get_read_pointer(force);
01112           if (index == NULL) {
01113             return false;
01114           }
01115           GLVertex *v0 = &_vertices[index[start] - _min_vertex];
01116           GLVertex *v1 = &_vertices[index[start + 1] - _min_vertex];
01117 
01118           bool reversed = false;
01119           for (int vi = start + 2; vi < end; ++vi) {
01120             GLVertex *v2 = &_vertices[index[vi] - _min_vertex];
01121             if (reversed) {
01122               gl_draw_triangle(_c, v1, v0, v2);
01123               reversed = false;
01124             } else {
01125               gl_draw_triangle(_c, v0, v1, v2);
01126               reversed = true;
01127             }
01128             v0 = v1;
01129             v1 = v2;
01130           }
01131         }
01132         break;
01133       }
01134 
01135       start = ends[i] + 2;
01136     }
01137   } else {
01138     unsigned int start = 0;
01139     int delta = reader->get_first_vertex() - _min_vertex;
01140     for (size_t i = 0; i < ends.size(); i++) {
01141       _vertices_tristrip_pcollector.add_level(ends[i] - start);
01142 
01143       int end = ends[i];
01144       nassertr(end - start >= 3, false);
01145       GLVertex *v0 = &_vertices[start + delta];
01146       GLVertex *v1 = &_vertices[start + delta + 1];
01147 
01148       bool reversed = false;
01149       for (int vi = start + 2; vi < end; ++vi) {
01150         GLVertex *v2 = &_vertices[vi + delta];
01151         if (reversed) {
01152           gl_draw_triangle(_c, v1, v0, v2);
01153           reversed = false;
01154         } else {
01155           gl_draw_triangle(_c, v0, v1, v2);
01156           reversed = true;
01157         }
01158         v0 = v1;
01159         v1 = v2;
01160       }
01161       start = ends[i] + 2;
01162     }
01163   }
01164 
01165   return true;
01166 }
01167 
01168 ////////////////////////////////////////////////////////////////////
01169 //     Function: TinyGraphicsStateGuardian::draw_lines
01170 //       Access: Public, Virtual
01171 //  Description: Draws a series of disconnected line segments.
01172 ////////////////////////////////////////////////////////////////////
01173 bool TinyGraphicsStateGuardian::
01174 draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
01175   PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
01176 #ifndef NDEBUG
01177   if (tinydisplay_cat.is_spam()) {
01178     tinydisplay_cat.spam() << "draw_lines: " << *(reader->get_object()) << "\n";
01179   }
01180 #endif  // NDEBUG
01181 
01182   int num_vertices = reader->get_num_vertices();
01183   _vertices_other_pcollector.add_level(num_vertices);
01184 
01185   if (reader->is_indexed()) {
01186     switch (reader->get_index_type()) {
01187     case Geom::NT_uint8:
01188       {
01189         PN_uint8 *index = (PN_uint8 *)reader->get_read_pointer(force);
01190         if (index == NULL) {
01191           return false;
01192         }
01193         for (int i = 0; i < num_vertices; i += 2) {
01194           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
01195           GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
01196           gl_draw_line(_c, v0, v1);
01197         }
01198       }
01199       break;
01200 
01201     case Geom::NT_uint16:
01202       {
01203         PN_uint16 *index = (PN_uint16 *)reader->get_read_pointer(force);
01204         if (index == NULL) {
01205           return false;
01206         }
01207         for (int i = 0; i < num_vertices; i += 2) {
01208           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
01209           GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
01210           gl_draw_line(_c, v0, v1);
01211         }
01212       }
01213       break;
01214 
01215     case Geom::NT_uint32:
01216       {
01217         PN_uint32 *index = (PN_uint32 *)reader->get_read_pointer(force);
01218         if (index == NULL) {
01219           return false;
01220         }
01221         for (int i = 0; i < num_vertices; i += 2) {
01222           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
01223           GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
01224           gl_draw_line(_c, v0, v1);
01225         }
01226       }
01227       break;
01228 
01229     default:
01230       break;
01231     }
01232 
01233   } else {
01234     int delta = reader->get_first_vertex() - _min_vertex;
01235     for (int vi = 0; vi < num_vertices; vi += 2) {
01236       GLVertex *v0 = &_vertices[vi + delta];
01237       GLVertex *v1 = &_vertices[vi + delta + 1];
01238       gl_draw_line(_c, v0, v1);
01239     }
01240   }
01241 
01242   return true;
01243 }
01244 
01245 ////////////////////////////////////////////////////////////////////
01246 //     Function: TinyGraphicsStateGuardian::draw_points
01247 //       Access: Public, Virtual
01248 //  Description: Draws a series of disconnected points.
01249 ////////////////////////////////////////////////////////////////////
01250 bool TinyGraphicsStateGuardian::
01251 draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
01252   PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
01253 #ifndef NDEBUG
01254   if (tinydisplay_cat.is_spam()) {
01255     tinydisplay_cat.spam() << "draw_points: " << *(reader->get_object()) << "\n";
01256   }
01257 #endif  // NDEBUG
01258 
01259   int num_vertices = reader->get_num_vertices();
01260   _vertices_other_pcollector.add_level(num_vertices);
01261 
01262   if (reader->is_indexed()) {
01263     switch (reader->get_index_type()) {
01264     case Geom::NT_uint8:
01265       {
01266         PN_uint8 *index = (PN_uint8 *)reader->get_read_pointer(force);
01267         if (index == NULL) {
01268           return false;
01269         }
01270         for (int i = 0; i < num_vertices; ++i) {
01271           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
01272           gl_draw_point(_c, v0);
01273         }
01274       }
01275       break;
01276 
01277     case Geom::NT_uint16:
01278       {
01279         PN_uint16 *index = (PN_uint16 *)reader->get_read_pointer(force);
01280         if (index == NULL) {
01281           return false;
01282         }
01283         for (int i = 0; i < num_vertices; ++i) {
01284           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
01285           gl_draw_point(_c, v0);
01286         }
01287       }
01288       break;
01289 
01290     case Geom::NT_uint32:
01291       {
01292         PN_uint32 *index = (PN_uint32 *)reader->get_read_pointer(force);
01293         if (index == NULL) {
01294           return false;
01295         }
01296         for (int i = 0; i < num_vertices; ++i) {
01297           GLVertex *v0 = &_vertices[index[i] - _min_vertex];
01298           gl_draw_point(_c, v0);
01299         }
01300       }
01301       break;
01302 
01303     default:
01304       break;
01305     }
01306 
01307   } else {
01308     int delta = reader->get_first_vertex() - _min_vertex;
01309     for (int vi = 0; vi < num_vertices; ++vi) {
01310       GLVertex *v0 = &_vertices[vi + delta];
01311       gl_draw_point(_c, v0);
01312     }
01313   }
01314 
01315   return true;
01316 }
01317 
01318 ////////////////////////////////////////////////////////////////////
01319 //     Function: TinyGraphicsStateGuardian::end_draw_primitives()
01320 //       Access: Public, Virtual
01321 //  Description: Called after a sequence of draw_primitive()
01322 //               functions are called, this should do whatever cleanup
01323 //               is appropriate.
01324 ////////////////////////////////////////////////////////////////////
01325 void TinyGraphicsStateGuardian::
01326 end_draw_primitives() {
01327 
01328 #ifdef DO_PSTATS
01329   _pixel_count_white_untextured_pcollector.add_level(pixel_count_white_untextured);
01330   _pixel_count_flat_untextured_pcollector.add_level(pixel_count_flat_untextured);
01331   _pixel_count_smooth_untextured_pcollector.add_level(pixel_count_smooth_untextured);
01332   _pixel_count_white_textured_pcollector.add_level(pixel_count_white_textured);
01333   _pixel_count_flat_textured_pcollector.add_level(pixel_count_flat_textured);
01334   _pixel_count_smooth_textured_pcollector.add_level(pixel_count_smooth_textured);
01335   _pixel_count_white_perspective_pcollector.add_level(pixel_count_white_perspective);
01336   _pixel_count_flat_perspective_pcollector.add_level(pixel_count_flat_perspective);
01337   _pixel_count_smooth_perspective_pcollector.add_level(pixel_count_smooth_perspective);
01338   _pixel_count_smooth_multitex2_pcollector.add_level(pixel_count_smooth_multitex2);
01339   _pixel_count_smooth_multitex3_pcollector.add_level(pixel_count_smooth_multitex3);
01340 #endif  // DO_PSTATS
01341 
01342   GraphicsStateGuardian::end_draw_primitives();
01343 }
01344 
01345 ////////////////////////////////////////////////////////////////////
01346 //     Function: TinyGraphicsStateGuardian::framebuffer_copy_to_texture
01347 //       Access: Public, Virtual
01348 //  Description: Copy the pixels within the indicated display
01349 //               region from the framebuffer into texture memory.
01350 //
01351 //               If z > -1, it is the cube map index into which to
01352 //               copy.
01353 ////////////////////////////////////////////////////////////////////
01354 bool TinyGraphicsStateGuardian::
01355 framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
01356                             const RenderBuffer &rb) {
01357   nassertr(tex != NULL && dr != NULL, false);
01358   
01359   int xo, yo, w, h;
01360   dr->get_region_pixels_i(xo, yo, w, h);
01361 
01362   tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgba);
01363 
01364   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
01365   nassertr(tc != (TextureContext *)NULL, false);
01366   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
01367 
01368   GLTexture *gltex = &gtc->_gltex;
01369   if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), 1)) {
01370     return false;
01371   }
01372   Colorf border_color = tex->get_border_color();
01373   gltex->border_color.v[0] = border_color[0];
01374   gltex->border_color.v[1] = border_color[1];
01375   gltex->border_color.v[2] = border_color[2];
01376   gltex->border_color.v[3] = border_color[3];
01377 
01378   PIXEL *ip = gltex->levels[0].pixmap + gltex->xsize * gltex->ysize;
01379   PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
01380   for (int y = 0; y < gltex->ysize; ++y) {
01381     ip -= gltex->xsize;
01382     memcpy(ip, fo, gltex->xsize * PSZB);
01383     fo += _c->zb->linesize / PSZB;
01384   }
01385 
01386   gtc->update_data_size_bytes(gltex->xsize * gltex->ysize * 4);
01387   gtc->mark_loaded();
01388   gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
01389 
01390   return true;
01391 }
01392 
01393 
01394 ////////////////////////////////////////////////////////////////////
01395 //     Function: TinyGraphicsStateGuardian::framebuffer_copy_to_ram
01396 //       Access: Public, Virtual
01397 //  Description: Copy the pixels within the indicated display region
01398 //               from the framebuffer into system memory, not texture
01399 //               memory.  Returns true on success, false on failure.
01400 //
01401 //               This completely redefines the ram image of the
01402 //               indicated texture.
01403 ////////////////////////////////////////////////////////////////////
01404 bool TinyGraphicsStateGuardian::
01405 framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
01406                         const RenderBuffer &rb) {
01407   nassertr(tex != NULL && dr != NULL, false);
01408   
01409   int xo, yo, w, h;
01410   dr->get_region_pixels_i(xo, yo, w, h);
01411 
01412   Texture::TextureType texture_type;
01413   int z_size;
01414   if (z >= 0) {
01415     texture_type = Texture::TT_cube_map;
01416     z_size = 6;
01417   } else {
01418     texture_type = Texture::TT_2d_texture;
01419     z_size = 1;
01420   }
01421 
01422   Texture::ComponentType component_type = Texture::T_unsigned_byte;
01423   Texture::Format format = Texture::F_rgba;
01424 
01425   if (tex->get_x_size() != w || tex->get_y_size() != h ||
01426       tex->get_z_size() != z_size ||
01427       tex->get_component_type() != component_type ||
01428       tex->get_format() != format ||
01429       tex->get_texture_type() != texture_type) {
01430     // Re-setup the texture; its properties have changed.
01431     tex->setup_texture(texture_type, w, h, z_size,
01432                        component_type, format);
01433   }
01434 
01435   unsigned char *image_ptr = tex->modify_ram_image();
01436   size_t image_size = tex->get_ram_image_size();
01437   if (z >= 0) {
01438     nassertr(z < tex->get_z_size(), false);
01439     image_size = tex->get_expected_ram_page_size();
01440     image_ptr += z * image_size;
01441   }
01442 
01443   PIXEL *ip = (PIXEL *)(image_ptr + image_size);
01444   PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
01445   for (int y = 0; y < h; ++y) {
01446     ip -= w;
01447 #ifndef WORDS_BIGENDIAN
01448     // On a little-endian machine, we can copy the whole row at a time.
01449     memcpy(ip, fo, w * PSZB);
01450 #else
01451     // On a big-endian machine, we have to reverse the color-component order.
01452     const char *source = (const char *)fo;
01453     const char *stop = (const char *)fo + w * PSZB;
01454     char *dest = (char *)ip;
01455     while (source < stop) {
01456       char b = source[0];
01457       char g = source[1];
01458       char r = source[2];
01459       char a = source[3];
01460       dest[0] = a;
01461       dest[1] = r;
01462       dest[2] = g;
01463       dest[3] = b;
01464       dest += 4;
01465       source += 4;
01466     }
01467 #endif
01468     fo += _c->zb->linesize / PSZB;
01469   }
01470 
01471   return true;
01472 }
01473 
01474 ////////////////////////////////////////////////////////////////////
01475 //     Function: TinyGraphicsStateGuardian::set_state_and_transform
01476 //       Access: Public, Virtual
01477 //  Description: Simultaneously resets the render state and the
01478 //               transform state.
01479 //
01480 //               This transform specified is the "internal" net
01481 //               transform, already converted into the GSG's internal
01482 //               coordinate space by composing it to
01483 //               get_cs_transform().  (Previously, this used to be the
01484 //               "external" net transform, with the assumption that
01485 //               that GSG would convert it internally, but that is no
01486 //               longer the case.)
01487 //
01488 //               Special case: if (state==NULL), then the target
01489 //               state is already stored in _target.
01490 ////////////////////////////////////////////////////////////////////
01491 void TinyGraphicsStateGuardian::
01492 set_state_and_transform(const RenderState *target,
01493                         const TransformState *transform) {
01494 #ifndef NDEBUG
01495   if (tinydisplay_cat.is_spam()) {
01496     tinydisplay_cat.spam()
01497       << "Setting GSG state to " << (void *)target << ":\n";
01498     target->write(tinydisplay_cat.spam(false), 2);
01499     transform->write(tinydisplay_cat.spam(false), 2);
01500   }
01501 #endif
01502 
01503   _state_pcollector.add_level(1);
01504   PStatTimer timer1(_draw_set_state_pcollector);
01505 
01506   if (transform != _internal_transform) {
01507     PStatTimer timer(_draw_set_state_transform_pcollector);
01508     _state_pcollector.add_level(1);
01509     _internal_transform = transform;
01510     do_issue_transform();
01511   }
01512 
01513   if (target == _state_rs && (_state_mask | _inv_state_mask).is_all_on()) {
01514     return;
01515   }
01516   _target_rs = target;
01517 
01518   int color_slot = ColorAttrib::get_class_slot();
01519   int color_scale_slot = ColorScaleAttrib::get_class_slot();
01520   if (_target_rs->get_attrib(color_slot) != _state_rs->get_attrib(color_slot) ||
01521       _target_rs->get_attrib(color_scale_slot) != _state_rs->get_attrib(color_scale_slot) ||
01522       !_state_mask.get_bit(color_slot) ||
01523       !_state_mask.get_bit(color_scale_slot)) {
01524     PStatTimer timer(_draw_set_state_color_pcollector);
01525     do_issue_color();
01526     do_issue_color_scale();
01527     _state_mask.set_bit(color_slot);
01528     _state_mask.set_bit(color_scale_slot);
01529   }
01530 
01531   int cull_face_slot = CullFaceAttrib::get_class_slot();
01532   if (_target_rs->get_attrib(cull_face_slot) != _state_rs->get_attrib(cull_face_slot) ||
01533       !_state_mask.get_bit(cull_face_slot)) {
01534     PStatTimer timer(_draw_set_state_cull_face_pcollector);
01535     do_issue_cull_face();
01536     _state_mask.set_bit(cull_face_slot);
01537   }
01538 
01539   int depth_offset_slot = DepthOffsetAttrib::get_class_slot();
01540   if (_target_rs->get_attrib(depth_offset_slot) != _state_rs->get_attrib(depth_offset_slot) ||
01541       !_state_mask.get_bit(depth_offset_slot)) {
01542     //PStatTimer timer(_draw_set_state_depth_offset_pcollector);
01543     do_issue_depth_offset();
01544     _state_mask.set_bit(depth_offset_slot);
01545   }
01546 
01547   int rescale_normal_slot = RescaleNormalAttrib::get_class_slot();
01548   if (_target_rs->get_attrib(rescale_normal_slot) != _state_rs->get_attrib(rescale_normal_slot) ||
01549       !_state_mask.get_bit(rescale_normal_slot)) {
01550     PStatTimer timer(_draw_set_state_rescale_normal_pcollector);
01551     do_issue_rescale_normal();
01552     _state_mask.set_bit(rescale_normal_slot);
01553   }
01554 
01555   int render_mode_slot = RenderModeAttrib::get_class_slot();
01556   if (_target_rs->get_attrib(render_mode_slot) != _state_rs->get_attrib(render_mode_slot) ||
01557       !_state_mask.get_bit(render_mode_slot)) {
01558     PStatTimer timer(_draw_set_state_render_mode_pcollector);
01559     do_issue_render_mode();
01560     _state_mask.set_bit(render_mode_slot);
01561   }
01562 
01563   int texture_slot = TextureAttrib::get_class_slot();
01564   if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
01565       !_state_mask.get_bit(texture_slot)) {
01566     PStatTimer timer(_draw_set_state_texture_pcollector);
01567     determine_target_texture();
01568     do_issue_texture();
01569     _state_mask.set_bit(texture_slot);
01570   }
01571 
01572   int material_slot = MaterialAttrib::get_class_slot();
01573   if (_target_rs->get_attrib(material_slot) != _state_rs->get_attrib(material_slot) ||
01574       !_state_mask.get_bit(material_slot)) {
01575     PStatTimer timer(_draw_set_state_material_pcollector);
01576     do_issue_material();
01577     _state_mask.set_bit(material_slot);
01578   }
01579 
01580   int light_slot = LightAttrib::get_class_slot();
01581   if (_target_rs->get_attrib(light_slot) != _state_rs->get_attrib(light_slot) ||
01582       !_state_mask.get_bit(light_slot)) {
01583     PStatTimer timer(_draw_set_state_light_pcollector);
01584     do_issue_light();
01585     _state_mask.set_bit(light_slot);
01586   }
01587 
01588   int scissor_slot = ScissorAttrib::get_class_slot();
01589   if (_target_rs->get_attrib(scissor_slot) != _state_rs->get_attrib(scissor_slot) ||
01590       !_state_mask.get_bit(scissor_slot)) {
01591     PStatTimer timer(_draw_set_state_scissor_pcollector);
01592     do_issue_scissor();
01593     _state_mask.set_bit(scissor_slot);
01594   }
01595 
01596   _state_rs = _target_rs;
01597 }
01598 
01599 ////////////////////////////////////////////////////////////////////
01600 //     Function: TinyGraphicsStateGuardian::prepare_texture
01601 //       Access: Public, Virtual
01602 //  Description: Creates whatever structures the GSG requires to
01603 //               represent the texture internally, and returns a
01604 //               newly-allocated TextureContext object with this data.
01605 //               It is the responsibility of the calling function to
01606 //               later call release_texture() with this same pointer
01607 //               (which will also delete the pointer).
01608 //
01609 //               This function should not be called directly to
01610 //               prepare a texture.  Instead, call Texture::prepare().
01611 ////////////////////////////////////////////////////////////////////
01612 TextureContext *TinyGraphicsStateGuardian::
01613 prepare_texture(Texture *tex) {
01614   switch (tex->get_texture_type()) {
01615   case Texture::TT_1d_texture:
01616   case Texture::TT_2d_texture:
01617     // These are supported.
01618     break;
01619 
01620   default:
01621     // Anything else is not supported.
01622     tinydisplay_cat.info()
01623       << "Not loading texture " << tex->get_name() << ": "
01624       << tex->get_texture_type() << "\n";
01625     return NULL;
01626   }
01627 
01628   // Even though the texture might be compressed now, it might have an
01629   // available uncompressed version that we can load.  So don't reject
01630   // it out-of-hand just because it's compressed.
01631   /*
01632   if (tex->get_ram_image_compression() != Texture::CM_off) {
01633     tinydisplay_cat.info()
01634       << "Not loading texture " << tex->get_name() << ": "
01635       << tex->get_ram_image_compression() << "\n";
01636     return NULL;
01637   }
01638   */
01639 
01640   TinyTextureContext *gtc = new TinyTextureContext(_prepared_objects, tex);
01641 
01642   return gtc;
01643 }
01644 
01645 ////////////////////////////////////////////////////////////////////
01646 //     Function: TinyGraphicsStateGuardian::update_texture
01647 //       Access: Public, Virtual
01648 //  Description: Ensures that the current Texture data is refreshed
01649 //               onto the GSG.  This means updating the texture
01650 //               properties and/or re-uploading the texture image, if
01651 //               necessary.  This should only be called within the
01652 //               draw thread.
01653 //
01654 //               If force is true, this function will not return until
01655 //               the texture has been fully uploaded.  If force is
01656 //               false, the function may choose to upload a simple
01657 //               version of the texture instead, if the texture is not
01658 //               fully resident (and if get_incomplete_render() is
01659 //               true).
01660 ////////////////////////////////////////////////////////////////////
01661 bool TinyGraphicsStateGuardian::
01662 update_texture(TextureContext *tc, bool force) {
01663   apply_texture(tc);
01664 
01665   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
01666 
01667   GLTexture *gltex = &gtc->_gltex;
01668 
01669   if (gtc->was_image_modified() || gltex->num_levels == 0) {
01670     // If the texture image was modified, reload the texture.
01671     bool okflag = upload_texture(gtc, force);
01672     if (!okflag) {
01673       tinydisplay_cat.error()
01674         << "Could not load " << *gtc->get_texture() << "\n";
01675       return false;
01676     }
01677   }
01678   gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
01679 
01680   return true;
01681 }
01682 
01683 ////////////////////////////////////////////////////////////////////
01684 //     Function: TinyGraphicsStateGuardian::update_texture
01685 //       Access: Public
01686 //  Description: Ensures that the current Texture data is refreshed
01687 //               onto the GSG.  This means updating the texture
01688 //               properties and/or re-uploading the texture image, if
01689 //               necessary.  This should only be called within the
01690 //               draw thread.
01691 //
01692 //               If force is true, this function will not return until
01693 //               the texture has been fully uploaded.  If force is
01694 //               false, the function may choose to upload a simple
01695 //               version of the texture instead, if the texture is not
01696 //               fully resident (and if get_incomplete_render() is
01697 //               true).
01698 ////////////////////////////////////////////////////////////////////
01699 bool TinyGraphicsStateGuardian::
01700 update_texture(TextureContext *tc, bool force, int stage_index) {
01701   if (!update_texture(tc, force)) {
01702     return false;
01703   }
01704 
01705   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
01706   GLTexture *gltex = &gtc->_gltex;
01707 
01708   _c->current_textures[stage_index] = gltex;
01709 
01710   ZTextureDef *texture_def = &_c->zb->current_textures[stage_index];
01711   texture_def->levels = gltex->levels;
01712   texture_def->s_max = gltex->s_max;
01713   texture_def->t_max = gltex->t_max;
01714 
01715   const V4 &bc = gltex->border_color;
01716   int r = (int)(bc.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) 
01717                 + ZB_POINT_RED_MIN);
01718   int g = (int)(bc.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) 
01719                 + ZB_POINT_GREEN_MIN);
01720   int b = (int)(bc.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) 
01721                 + ZB_POINT_BLUE_MIN);
01722   int a = (int)(bc.v[3] * (ZB_POINT_ALPHA_MAX - ZB_POINT_ALPHA_MIN) 
01723                 + ZB_POINT_ALPHA_MIN);
01724   texture_def->border_color = RGBA_TO_PIXEL(r, g, b, a);
01725 
01726   return true;
01727 }
01728 
01729 ////////////////////////////////////////////////////////////////////
01730 //     Function: TinyGraphicsStateGuardian::release_texture
01731 //       Access: Public, Virtual
01732 //  Description: Frees the GL resources previously allocated for the
01733 //               texture.  This function should never be called
01734 //               directly; instead, call Texture::release() (or simply
01735 //               let the Texture destruct).
01736 ////////////////////////////////////////////////////////////////////
01737 void TinyGraphicsStateGuardian::
01738 release_texture(TextureContext *tc) {
01739   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
01740 
01741   _texturing_state = 0;  // just in case
01742 
01743   GLTexture *gltex = &gtc->_gltex;
01744   if (gltex->allocated_buffer != NULL) {
01745     nassertv(gltex->num_levels != 0);
01746     TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount);
01747     PANDA_FREE_ARRAY(gltex->allocated_buffer);
01748     gltex->allocated_buffer = NULL;
01749     gltex->total_bytecount = 0;
01750     gltex->num_levels = 0;
01751   } else {
01752     nassertv(gltex->num_levels == 0);
01753   }
01754 
01755   gtc->dequeue_lru();
01756 
01757   delete gtc;
01758 }
01759 
01760 ////////////////////////////////////////////////////////////////////
01761 //     Function: TinyGraphicsStateGuardian::do_issue_light
01762 //       Access: Protected, Virtual
01763 //  Description: 
01764 ////////////////////////////////////////////////////////////////////
01765 void TinyGraphicsStateGuardian::
01766 do_issue_light() {
01767   // Initialize the current ambient light total and newly enabled
01768   // light list
01769   Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
01770 
01771   int num_enabled = 0;
01772   int num_on_lights = 0;
01773 
01774   const LightAttrib *target_light = DCAST(LightAttrib, _target_rs->get_attrib_def(LightAttrib::get_class_slot()));
01775   if (display_cat.is_spam()) {
01776     display_cat.spam()
01777       << "do_issue_light: " << target_light << "\n";
01778   }
01779 
01780   // First, release all of the previously-assigned lights.
01781   clear_light_state();
01782 
01783   // Now, assign new lights.
01784   if (target_light != (LightAttrib *)NULL) {
01785     CPT(LightAttrib) new_light = target_light->filter_to_max(_max_lights);
01786     if (display_cat.is_spam()) {
01787       new_light->write(display_cat.spam(false), 2);
01788     }
01789 
01790     num_on_lights = new_light->get_num_on_lights();
01791     for (int li = 0; li < num_on_lights; li++) {
01792       NodePath light = new_light->get_on_light(li);
01793       nassertv(!light.is_empty());
01794       Light *light_obj = light.node()->as_light();
01795       nassertv(light_obj != (Light *)NULL);
01796 
01797       _lighting_enabled = true;
01798       _c->lighting_enabled = true;
01799 
01800       if (light_obj->get_type() == AmbientLight::get_class_type()) {
01801         // Accumulate all of the ambient lights together into one.
01802         cur_ambient_light += light_obj->get_color();
01803 
01804       } else {
01805         // Other kinds of lights each get their own GLLight object.
01806         light_obj->bind(this, light, num_enabled);
01807         num_enabled++;
01808 
01809         // Handle the diffuse color here, since all lights have this
01810         // property.
01811         GLLight *gl_light = _c->first_light;
01812         nassertv(gl_light != NULL);
01813         const Colorf &diffuse = light_obj->get_color();
01814         gl_light->diffuse.v[0] = diffuse[0];
01815         gl_light->diffuse.v[1] = diffuse[1];
01816         gl_light->diffuse.v[2] = diffuse[2];
01817         gl_light->diffuse.v[3] = diffuse[3];
01818       }
01819     }
01820   }
01821 
01822   _c->ambient_light_model.v[0] = cur_ambient_light[0];
01823   _c->ambient_light_model.v[1] = cur_ambient_light[1];
01824   _c->ambient_light_model.v[2] = cur_ambient_light[2];
01825   _c->ambient_light_model.v[3] = cur_ambient_light[3];
01826 
01827   // Changing the lighting state means we need to reapply the
01828   // transform in begin_draw_primitives().
01829   _transform_stale = true;
01830 }
01831 
01832 ////////////////////////////////////////////////////////////////////
01833 //     Function: TinyGraphicsStateGuardian::bind_light
01834 //       Access: Public, Virtual
01835 //  Description: Called the first time a particular light has been
01836 //               bound to a given id within a frame, this should set
01837 //               up the associated hardware light with the light's
01838 //               properties.
01839 ////////////////////////////////////////////////////////////////////
01840 void TinyGraphicsStateGuardian::
01841 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
01842   pair<Lights::iterator, bool> lookup = _plights.insert(Lights::value_type(light, GLLight()));
01843   GLLight *gl_light = &(*lookup.first).second;
01844   if (lookup.second) {
01845     // It's a brand new light.  Define it.
01846     memset(gl_light, 0, sizeof(GLLight));
01847 
01848     const Colorf &specular = light_obj->get_specular_color();
01849     gl_light->specular.v[0] = specular[0];
01850     gl_light->specular.v[1] = specular[1];
01851     gl_light->specular.v[2] = specular[2];
01852     gl_light->specular.v[3] = specular[3];
01853 
01854     // Position needs to specify x, y, z, and w
01855     // w == 1 implies non-infinite position
01856     CPT(TransformState) render_transform =
01857       _cs_transform->compose(_scene_setup->get_world_transform());
01858 
01859     CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
01860     CPT(TransformState) net_transform = render_transform->compose(transform);
01861 
01862     LPoint3f pos = light_obj->get_point() * net_transform->get_mat();
01863     gl_light->position.v[0] = pos[0];
01864     gl_light->position.v[1] = pos[1];
01865     gl_light->position.v[2] = pos[2];
01866     gl_light->position.v[3] = 1.0f;
01867 
01868     // Exponent == 0 implies uniform light distribution
01869     gl_light->spot_exponent = 0.0f;
01870 
01871     // Cutoff == 180 means uniform point light source
01872     gl_light->spot_cutoff = 180.0f;
01873 
01874     const LVecBase3f &att = light_obj->get_attenuation();
01875     gl_light->attenuation[0] = att[0];
01876     gl_light->attenuation[1] = att[1];
01877     gl_light->attenuation[2] = att[2];
01878   }
01879 
01880   nassertv(gl_light->next == NULL);
01881 
01882   // Add it to the linked list of active lights.
01883   gl_light->next = _c->first_light;
01884   _c->first_light = gl_light;
01885 }
01886 
01887 ////////////////////////////////////////////////////////////////////
01888 //     Function: TinyGraphicsStateGuardian::bind_light
01889 //       Access: Public, Virtual
01890 //  Description: Called the first time a particular light has been
01891 //               bound to a given id within a frame, this should set
01892 //               up the associated hardware light with the light's
01893 //               properties.
01894 ////////////////////////////////////////////////////////////////////
01895 void TinyGraphicsStateGuardian::
01896 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
01897   pair<Lights::iterator, bool> lookup = _dlights.insert(Lights::value_type(light, GLLight()));
01898   GLLight *gl_light = &(*lookup.first).second;
01899   if (lookup.second) {
01900     // It's a brand new light.  Define it.
01901     memset(gl_light, 0, sizeof(GLLight));
01902 
01903     const Colorf &specular = light_obj->get_specular_color();
01904     gl_light->specular.v[0] = specular[0];
01905     gl_light->specular.v[1] = specular[1];
01906     gl_light->specular.v[2] = specular[2];
01907     gl_light->specular.v[3] = specular[3];
01908 
01909     // Position needs to specify x, y, z, and w
01910     // w == 0 implies light is at infinity
01911     CPT(TransformState) render_transform =
01912       _cs_transform->compose(_scene_setup->get_world_transform());
01913 
01914     CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
01915     CPT(TransformState) net_transform = render_transform->compose(transform);
01916 
01917     LVector3f dir = light_obj->get_direction() * net_transform->get_mat();
01918     dir.normalize();
01919     gl_light->position.v[0] = -dir[0];
01920     gl_light->position.v[1] = -dir[1];
01921     gl_light->position.v[2] = -dir[2];
01922     gl_light->position.v[3] = 0.0f;
01923 
01924     gl_light->norm_position.v[0] = -dir[0];
01925     gl_light->norm_position.v[1] = -dir[1];
01926     gl_light->norm_position.v[2] = -dir[2];
01927     gl_V3_Norm(&gl_light->norm_position);
01928 
01929     // Exponent == 0 implies uniform light distribution
01930     gl_light->spot_exponent = 0.0f;
01931 
01932     // Cutoff == 180 means uniform point light source
01933     gl_light->spot_cutoff = 180.0f;
01934 
01935     // Default attenuation values (only spotlight and point light can
01936     // modify these)
01937     gl_light->attenuation[0] = 1.0f;
01938     gl_light->attenuation[1] = 0.0f;
01939     gl_light->attenuation[2] = 0.0f;
01940   }
01941 
01942   nassertv(gl_light->next == NULL);
01943 
01944   // Add it to the linked list of active lights.
01945   gl_light->next = _c->first_light;
01946   _c->first_light = gl_light;
01947 }
01948 
01949 ////////////////////////////////////////////////////////////////////
01950 //     Function: TinyGraphicsStateGuardian::bind_light
01951 //       Access: Public, Virtual
01952 //  Description: Called the first time a particular light has been
01953 //               bound to a given id within a frame, this should set
01954 //               up the associated hardware light with the light's
01955 //               properties.
01956 ////////////////////////////////////////////////////////////////////
01957 void TinyGraphicsStateGuardian::
01958 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
01959   pair<Lights::iterator, bool> lookup = _plights.insert(Lights::value_type(light, GLLight()));
01960   GLLight *gl_light = &(*lookup.first).second;
01961   if (lookup.second) {
01962     // It's a brand new light.  Define it.
01963     memset(gl_light, 0, sizeof(GLLight));
01964 
01965     const Colorf &specular = light_obj->get_specular_color();
01966     gl_light->specular.v[0] = specular[0];
01967     gl_light->specular.v[1] = specular[1];
01968     gl_light->specular.v[2] = specular[2];
01969     gl_light->specular.v[3] = specular[3];
01970   
01971     Lens *lens = light_obj->get_lens();
01972     nassertv(lens != (Lens *)NULL);
01973 
01974     // Position needs to specify x, y, z, and w
01975     // w == 1 implies non-infinite position
01976     CPT(TransformState) render_transform =
01977       _cs_transform->compose(_scene_setup->get_world_transform());
01978 
01979     CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
01980     CPT(TransformState) net_transform = render_transform->compose(transform);
01981 
01982     const LMatrix4f &light_mat = net_transform->get_mat();
01983     LPoint3f pos = lens->get_nodal_point() * light_mat;
01984     LVector3f dir = lens->get_view_vector() * light_mat;
01985     dir.normalize();
01986 
01987     gl_light->position.v[0] = pos[0];
01988     gl_light->position.v[1] = pos[1];
01989     gl_light->position.v[2] = pos[2];
01990     gl_light->position.v[3] = 1.0f;
01991 
01992     gl_light->spot_direction.v[0] = dir[0];
01993     gl_light->spot_direction.v[1] = dir[1];
01994     gl_light->spot_direction.v[2] = dir[2];
01995 
01996     gl_light->norm_spot_direction.v[0] = dir[0];
01997     gl_light->norm_spot_direction.v[1] = dir[1];
01998     gl_light->norm_spot_direction.v[2] = dir[2];
01999     gl_V3_Norm(&gl_light->norm_spot_direction);
02000 
02001     gl_light->spot_exponent = light_obj->get_exponent();
02002     gl_light->spot_cutoff = lens->get_hfov() * 0.5f;
02003 
02004     const LVecBase3f &att = light_obj->get_attenuation();
02005     gl_light->attenuation[0] = att[0];
02006     gl_light->attenuation[1] = att[1];
02007     gl_light->attenuation[2] = att[2];
02008   }
02009 
02010   nassertv(gl_light->next == NULL);
02011 
02012   // Add it to the linked list of active lights.
02013   gl_light->next = _c->first_light;
02014   _c->first_light = gl_light;
02015 }
02016 
02017 ////////////////////////////////////////////////////////////////////
02018 //     Function: TinyGraphicsStateGuardian::do_issue_transform
02019 //       Access: Protected
02020 //  Description: Sends the indicated transform matrix to the graphics
02021 //               API to be applied to future vertices.
02022 //
02023 //               This transform is the internal_transform, already
02024 //               converted into the GSG's internal coordinate system.
02025 ////////////////////////////////////////////////////////////////////
02026 void TinyGraphicsStateGuardian::
02027 do_issue_transform() {
02028   _transform_state_pcollector.add_level(1);
02029   _transform_stale = true;
02030 
02031   if (_auto_rescale_normal) {
02032     do_auto_rescale_normal();
02033   }
02034 }
02035 
02036 ////////////////////////////////////////////////////////////////////
02037 //     Function: TinyGraphicsStateGuardian::do_issue_render_mode
02038 //       Access: Protected
02039 //  Description:
02040 ////////////////////////////////////////////////////////////////////
02041 void TinyGraphicsStateGuardian::
02042 do_issue_render_mode() {
02043   const RenderModeAttrib *target_render_mode = DCAST(RenderModeAttrib, _target_rs->get_attrib_def(RenderModeAttrib::get_class_slot()));
02044 
02045   _filled_flat = false;
02046 
02047   switch (target_render_mode->get_mode()) {
02048   case RenderModeAttrib::M_unchanged:
02049   case RenderModeAttrib::M_filled:
02050     _c->draw_triangle_front = gl_draw_triangle_fill;
02051     _c->draw_triangle_back = gl_draw_triangle_fill;
02052     break;
02053 
02054   case RenderModeAttrib::M_filled_flat:
02055     _c->draw_triangle_front = gl_draw_triangle_fill;
02056     _c->draw_triangle_back = gl_draw_triangle_fill;
02057     _filled_flat = true;
02058     break;
02059 
02060   case RenderModeAttrib::M_wireframe:
02061     _c->draw_triangle_front = gl_draw_triangle_line;
02062     _c->draw_triangle_back = gl_draw_triangle_line;
02063     break;
02064 
02065   case RenderModeAttrib::M_point:
02066     _c->draw_triangle_front = gl_draw_triangle_point;
02067     _c->draw_triangle_back = gl_draw_triangle_point;
02068     break;
02069 
02070   default:
02071     tinydisplay_cat.error()
02072       << "Unknown render mode " << (int)target_render_mode->get_mode() << endl;
02073   }
02074 }
02075 
02076 ////////////////////////////////////////////////////////////////////
02077 //     Function: TinyGraphicsStateGuardian::do_issue_rescale_normal
02078 //       Access: Protected
02079 //  Description:
02080 ////////////////////////////////////////////////////////////////////
02081 void TinyGraphicsStateGuardian::
02082 do_issue_rescale_normal() {
02083   const RescaleNormalAttrib *target_rescale_normal = DCAST(RescaleNormalAttrib, _target_rs->get_attrib_def(RescaleNormalAttrib::get_class_slot()));
02084   RescaleNormalAttrib::Mode mode = target_rescale_normal->get_mode();
02085 
02086   _auto_rescale_normal = false;
02087 
02088   switch (mode) {
02089   case RescaleNormalAttrib::M_none:
02090     _c->normalize_enabled = false;
02091     _c->normal_scale = 1.0f;
02092     break;
02093 
02094   case RescaleNormalAttrib::M_normalize:
02095     _c->normalize_enabled = true;
02096     _c->normal_scale = 1.0f;
02097     break;
02098 
02099   case RescaleNormalAttrib::M_rescale:
02100   case RescaleNormalAttrib::M_auto:
02101     _auto_rescale_normal = true;
02102     do_auto_rescale_normal();
02103     break;
02104 
02105   default:
02106     tinydisplay_cat.error()
02107       << "Unknown rescale_normal mode " << (int)mode << endl;
02108   }
02109 }
02110 
02111 ////////////////////////////////////////////////////////////////////
02112 //     Function: TinyGraphicsStateGuardian::do_issue_depth_offset
02113 //       Access: Protected
02114 //  Description:
02115 ////////////////////////////////////////////////////////////////////
02116 void TinyGraphicsStateGuardian::
02117 do_issue_depth_offset() {
02118   const DepthOffsetAttrib *target_depth_offset = DCAST(DepthOffsetAttrib, _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot()));
02119   int offset = target_depth_offset->get_offset();
02120   _c->zbias = offset;
02121 }
02122 
02123 ////////////////////////////////////////////////////////////////////
02124 //     Function: TinyGraphicsStateGuardian::do_issue_cull_face
02125 //       Access: Protected
02126 //  Description:
02127 ////////////////////////////////////////////////////////////////////
02128 void TinyGraphicsStateGuardian::
02129 do_issue_cull_face() {
02130   const CullFaceAttrib *target_cull_face = DCAST(CullFaceAttrib, _target_rs->get_attrib_def(CullFaceAttrib::get_class_slot()));
02131   CullFaceAttrib::Mode mode = target_cull_face->get_effective_mode();
02132 
02133   switch (mode) {
02134   case CullFaceAttrib::M_cull_none:
02135     _c->cull_face_enabled = false;
02136     break;
02137   case CullFaceAttrib::M_cull_clockwise:
02138     _c->cull_face_enabled = true;
02139     _c->cull_clockwise = true;
02140     break;
02141   case CullFaceAttrib::M_cull_counter_clockwise:
02142     _c->cull_face_enabled = true;
02143     _c->cull_clockwise = false;
02144     break;
02145   default:
02146     tinydisplay_cat.error()
02147       << "invalid cull face mode " << (int)mode << endl;
02148     break;
02149   }
02150 }
02151 
02152 ////////////////////////////////////////////////////////////////////
02153 //     Function: TinyGraphicsStateGuardian::do_issue_material
02154 //       Access: Protected
02155 //  Description:
02156 ////////////////////////////////////////////////////////////////////
02157 void TinyGraphicsStateGuardian::
02158 do_issue_material() {
02159   static Material empty;
02160 
02161   const MaterialAttrib *target_material = DCAST(MaterialAttrib, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()));
02162 
02163   const Material *material;
02164   if (target_material == (MaterialAttrib *)NULL ||
02165       target_material->is_off()) {
02166     material = &empty;
02167   } else {
02168     material = target_material->get_material();
02169   }
02170 
02171   // Apply the material parameters to the front face.
02172   setup_material(&_c->materials[0], material);
02173 
02174   if (material->get_twoside()) {
02175     // Also apply the material parameters to the back face.
02176     setup_material(&_c->materials[1], material);
02177   }
02178 
02179   _c->local_light_model = material->get_local();
02180   _c->light_model_two_side = material->get_twoside();
02181 }
02182 
02183 ////////////////////////////////////////////////////////////////////
02184 //     Function: TinyGraphicsStateGuardian::do_issue_texture
02185 //       Access: Protected
02186 //  Description:
02187 ////////////////////////////////////////////////////////////////////
02188 void TinyGraphicsStateGuardian::
02189 do_issue_texture() {
02190   _texturing_state = 0;   // untextured
02191   _c->num_textures_enabled = 0;
02192 
02193   int num_stages = _target_texture->get_num_on_ff_stages();
02194   if (num_stages == 0) {
02195     // No texturing.
02196     return;
02197   }
02198   nassertv(num_stages <= MAX_TEXTURE_STAGES);
02199 
02200   bool all_replace = true;
02201   bool all_nearest = true;
02202   bool all_mipmap_nearest = true;
02203   bool any_mipmap = false;
02204   bool needs_general = false;
02205   Texture::QualityLevel best_quality_level = Texture::QL_default;
02206 
02207   for (int si = 0; si < num_stages; ++si) {
02208     TextureStage *stage = _target_texture->get_on_ff_stage(si);
02209     Texture *texture = _target_texture->get_on_texture(stage);
02210     nassertv(texture != (Texture *)NULL);
02211     
02212     TextureContext *tc = texture->prepare_now(_prepared_objects, this);
02213     if (tc == (TextureContext *)NULL) {
02214       // Something wrong with this texture; skip it.
02215       return;
02216     }
02217     
02218     // Then, turn on the current texture mode.
02219     if (!update_texture(tc, false, si)) {
02220       return;
02221     }
02222 
02223     // M_replace means M_replace; anything else is treated the same as
02224     // M_modulate.
02225     if (stage->get_mode() != TextureStage::M_replace) {
02226       all_replace = false;
02227     }
02228 
02229     Texture::QualityLevel quality_level = _texture_quality_override;
02230     if (quality_level == Texture::QL_default) {
02231       quality_level = texture->get_quality_level();
02232     }
02233     if (quality_level == Texture::QL_default) {
02234       quality_level = texture_quality_level;
02235     }
02236 
02237     best_quality_level = max(best_quality_level, quality_level);
02238 
02239     ZTextureDef *texture_def = &_c->zb->current_textures[si];
02240     
02241     // Fill in the filter func pointers.  These may not actually get
02242     // called, if we decide below we can inline the filters.
02243     Texture::FilterType minfilter = texture->get_minfilter();
02244     Texture::FilterType magfilter = texture->get_magfilter();
02245 
02246     if (td_ignore_mipmaps && Texture::is_mipmap(minfilter)) {
02247       // Downgrade mipmaps.
02248       if (minfilter == Texture::FT_nearest_mipmap_nearest) {
02249         minfilter = Texture::FT_nearest;
02250       } else {
02251         minfilter = Texture::FT_linear;
02252       }
02253     }
02254 
02255     // Depending on this particular texture's quality level, we may
02256     // downgrade the requested filters.
02257     if (quality_level == Texture::QL_fastest) {
02258       minfilter = Texture::FT_nearest;
02259       magfilter = Texture::FT_nearest;
02260 
02261     } else if (quality_level == Texture::QL_normal) {
02262       if (Texture::is_mipmap(minfilter)) {
02263         minfilter = Texture::FT_nearest_mipmap_nearest;
02264       } else {
02265         minfilter = Texture::FT_nearest;
02266       }
02267       magfilter = Texture::FT_nearest;
02268 
02269     } else if (quality_level == Texture::QL_best) {
02270       minfilter = texture->get_effective_minfilter();
02271       magfilter = texture->get_effective_magfilter();
02272     }
02273 
02274     texture_def->tex_minfilter_func = get_tex_filter_func(minfilter);
02275     texture_def->tex_magfilter_func = get_tex_filter_func(magfilter);
02276     
02277     Texture::WrapMode wrap_u = texture->get_wrap_u();
02278     Texture::WrapMode wrap_v = texture->get_wrap_v();
02279     if (td_ignore_clamp) {
02280       wrap_u = Texture::WM_repeat;
02281       wrap_v = Texture::WM_repeat;
02282     }
02283 
02284     if (wrap_u != Texture::WM_repeat || wrap_v != Texture::WM_repeat) {
02285       // We have some nonstandard wrap mode.  This will force the use
02286       // of the general texfilter mode.
02287       needs_general = true;
02288 
02289       // We need another level of indirection to implement the
02290       // different texcoord wrap modes.  This means we will be using
02291       // the _impl function pointers, which are called by the toplevel
02292       // function.
02293 
02294       texture_def->tex_minfilter_func_impl = texture_def->tex_minfilter_func;
02295       texture_def->tex_magfilter_func_impl = texture_def->tex_magfilter_func;
02296 
02297       // Now assign the toplevel function pointer to do the
02298       // appropriate texture coordinate wrapping/clamping.
02299       texture_def->tex_minfilter_func = apply_wrap_general_minfilter;
02300       texture_def->tex_magfilter_func = apply_wrap_general_magfilter;
02301 
02302       texture_def->tex_wrap_u_func = get_tex_wrap_func(wrap_u);
02303       texture_def->tex_wrap_v_func = get_tex_wrap_func(wrap_v);
02304 
02305       // The following special cases are handled inline, rather than
02306       // relying on the above wrap function pointers.
02307       if (wrap_u && Texture::WM_border_color && wrap_v == Texture::WM_border_color) {
02308         texture_def->tex_minfilter_func = apply_wrap_border_color_minfilter;
02309         texture_def->tex_magfilter_func = apply_wrap_border_color_magfilter;
02310       } else if (wrap_u && Texture::WM_clamp && wrap_v == Texture::WM_clamp) {
02311         texture_def->tex_minfilter_func = apply_wrap_clamp_minfilter;
02312         texture_def->tex_magfilter_func = apply_wrap_clamp_magfilter;
02313       }
02314     }
02315 
02316     if (minfilter != Texture::FT_nearest || magfilter != Texture::FT_nearest) {
02317       all_nearest = false;
02318     }
02319 
02320     if (minfilter != Texture::FT_nearest_mipmap_nearest ||
02321         magfilter != Texture::FT_nearest) {
02322       all_mipmap_nearest = false;
02323     }
02324 
02325     if (Texture::is_mipmap(minfilter)) {
02326       any_mipmap = true;
02327     }
02328   }
02329 
02330   // Set a few state cache values.
02331   _c->num_textures_enabled = num_stages;
02332   _texture_replace = all_replace;
02333 
02334   _texturing_state = 2;   // perspective (perspective-correct texturing)
02335   if (num_stages >= 3) {
02336     _texturing_state = 4;  // multitex3
02337   } else if (num_stages == 2) {
02338     _texturing_state = 3;  // multitex2
02339   } else if (!td_perspective_textures) {
02340     _texturing_state = 1;    // textured (not perspective correct)
02341   }
02342 
02343   if (best_quality_level == Texture::QL_best) {
02344     // This is the most generic texture filter.  Slow, but pretty.
02345     _texfilter_state = 2;  // tgeneral
02346 
02347     if (!needs_general) {
02348       if (all_nearest) {
02349         // This case is inlined.
02350         _texfilter_state = 0;    // tnearest
02351       } else if (all_mipmap_nearest) {
02352         // So is this case.
02353         _texfilter_state = 1;  // tmipmap
02354       }
02355     }
02356 
02357   } else if (best_quality_level == Texture::QL_fastest) {
02358     // This is the cheapest texture filter.  We disallow mipmaps and
02359     // perspective correctness.
02360     _texfilter_state = 0;    // tnearest
02361     _texturing_state = 1;    // textured (not perspective correct, no multitexture)
02362   
02363   } else {
02364     // This is the default texture filter.  We use nearest sampling if
02365     // there are no mipmaps, and mipmap_nearest if there are any
02366     // mipmaps--these are the two inlined filters.
02367     _texfilter_state = 0;    // tnearest
02368     if (any_mipmap) {
02369       _texfilter_state = 1;  // tmipmap
02370     }
02371 
02372     if (needs_general) {
02373       // To support nonstandard texcoord wrapping etc, we need to
02374       // force the general texfilter mode.
02375       _texfilter_state = 2;  // tgeneral
02376     }
02377   }
02378 }
02379 
02380 ////////////////////////////////////////////////////////////////////
02381 //     Function: TinyGraphicsStateGuardian::do_issue_scissor
02382 //       Access: Protected
02383 //  Description:
02384 ////////////////////////////////////////////////////////////////////
02385 void TinyGraphicsStateGuardian::
02386 do_issue_scissor() {
02387   const ScissorAttrib *target_scissor = DCAST(ScissorAttrib, _target_rs->get_attrib_def(ScissorAttrib::get_class_slot()));
02388   const LVecBase4f &frame = target_scissor->get_frame();
02389   set_scissor(frame[0], frame[1], frame[2], frame[3]);
02390 }
02391 
02392 ////////////////////////////////////////////////////////////////////
02393 //     Function: TinyGraphicsStateGuardian::set_scissor
02394 //       Access: Private
02395 //  Description: Sets up the scissor region, as a set of coordinates
02396 //               relative to the current viewport.
02397 ////////////////////////////////////////////////////////////////////
02398 void TinyGraphicsStateGuardian::
02399 set_scissor(float left, float right, float bottom, float top) {
02400   _c->scissor.left = left;
02401   _c->scissor.right = right;
02402   _c->scissor.bottom = bottom;
02403   _c->scissor.top = top;
02404   gl_eval_viewport(_c);
02405 
02406   float xsize = right - left;
02407   float ysize = top - bottom;
02408   float xcenter = (left + right) - 1.0f;
02409   float ycenter = (bottom + top) - 1.0f;
02410   if (xsize == 0.0f || ysize == 0.0f) {
02411     // If the scissor region is zero, nothing will be drawn anyway, so
02412     // don't worry about it.
02413     _scissor_mat = TransformState::make_identity();
02414   } else {
02415     _scissor_mat = TransformState::make_scale(LVecBase3f(1.0f / xsize, 1.0f / ysize, 1.0f))->compose(TransformState::make_pos(LPoint3f(-xcenter, -ycenter, 0.0f)));
02416   }
02417 }
02418 
02419 ////////////////////////////////////////////////////////////////////
02420 //     Function: TinyGraphicsStateGuardian::apply_texture
02421 //       Access: Protected
02422 //  Description: Updates the graphics state with the current
02423 //               information for this texture, and makes it the
02424 //               current texture available for rendering.
02425 ////////////////////////////////////////////////////////////////////
02426 bool TinyGraphicsStateGuardian::
02427 apply_texture(TextureContext *tc) {
02428   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
02429 
02430   gtc->set_active(true);
02431   return true;
02432 }
02433 
02434 ////////////////////////////////////////////////////////////////////
02435 //     Function: TinyGraphicsStateGuardian::upload_texture
02436 //       Access: Protected
02437 //  Description: Uploads the texture image to the graphics state.
02438 //
02439 //               The return value is true if successful, or false if
02440 //               the texture has no image.
02441 ////////////////////////////////////////////////////////////////////
02442 bool TinyGraphicsStateGuardian::
02443 upload_texture(TinyTextureContext *gtc, bool force) {
02444   Texture *tex = gtc->get_texture();
02445 
02446   if (_effective_incomplete_render && !force) {
02447     if (!tex->has_ram_image() && tex->might_have_ram_image() &&
02448         tex->has_simple_ram_image() &&
02449         !_loader.is_null()) {
02450       // If we don't have the texture data right now, go get it, but in
02451       // the meantime load a temporary simple image in its place.
02452       async_reload_texture(gtc);
02453       if (!tex->has_ram_image()) {
02454         if (gtc->was_simple_image_modified()) {
02455           return upload_simple_texture(gtc);
02456         }
02457         return true;
02458       }
02459     }
02460   }
02461 
02462   PStatTimer timer(_load_texture_pcollector);
02463   CPTA_uchar src_image = tex->get_uncompressed_ram_image();
02464   if (src_image.is_null()) {
02465     return false;
02466   }
02467 
02468   if (tinydisplay_cat.is_debug()) {
02469     tinydisplay_cat.debug()
02470       << "loading texture " << tex->get_name() << "\n";
02471   }
02472 #ifdef DO_PSTATS
02473   _data_transferred_pcollector.add_level(tex->get_ram_image_size());
02474 #endif
02475   GLTexture *gltex = &gtc->_gltex;
02476 
02477   int num_levels = 1;
02478   if (tex->uses_mipmaps()) {
02479     if (!tex->has_all_ram_mipmap_images()) {
02480       tex->generate_ram_mipmap_images();
02481     }
02482     num_levels = tex->get_num_ram_mipmap_images();
02483   }
02484 
02485   if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), num_levels)) {
02486     return false;
02487   }
02488   Colorf border_color = tex->get_border_color();
02489   gltex->border_color.v[0] = border_color[0];
02490   gltex->border_color.v[1] = border_color[1];
02491   gltex->border_color.v[2] = border_color[2];
02492   gltex->border_color.v[3] = border_color[3];
02493 
02494   int bytecount = 0;
02495   int xsize = gltex->xsize;
02496   int ysize = gltex->ysize;
02497 
02498   for (int level = 0; level < gltex->num_levels; ++level) {
02499     ZTextureLevel *dest = &gltex->levels[level];
02500 
02501     switch (tex->get_format()) {
02502     case Texture::F_rgb:
02503     case Texture::F_rgb5:
02504     case Texture::F_rgb8:
02505     case Texture::F_rgb12:
02506     case Texture::F_rgb332:
02507       copy_rgb_image(dest, xsize, ysize, tex, level);
02508       break;
02509 
02510     case Texture::F_rgba:
02511     case Texture::F_rgbm:
02512     case Texture::F_rgba4:
02513     case Texture::F_rgba5:
02514     case Texture::F_rgba8:
02515     case Texture::F_rgba12:
02516     case Texture::F_rgba16:
02517     case Texture::F_rgba32:
02518       copy_rgba_image(dest, xsize, ysize, tex, level);
02519       break;
02520 
02521     case Texture::F_luminance:
02522       copy_lum_image(dest, xsize, ysize, tex, level);
02523       break;
02524 
02525     case Texture::F_red:
02526       copy_one_channel_image(dest, xsize, ysize, tex, level, 0);
02527       break;
02528 
02529     case Texture::F_green:
02530       copy_one_channel_image(dest, xsize, ysize, tex, level, 1);
02531       break;
02532 
02533     case Texture::F_blue:
02534       copy_one_channel_image(dest, xsize, ysize, tex, level, 2);
02535       break;
02536 
02537     case Texture::F_alpha:
02538       copy_alpha_image(dest, xsize, ysize, tex, level);
02539       break;
02540 
02541     case Texture::F_luminance_alphamask:
02542     case Texture::F_luminance_alpha:
02543       copy_la_image(dest, xsize, ysize, tex, level);
02544       break;
02545     }
02546 
02547     bytecount += xsize * ysize * 4;
02548     xsize = max(xsize >> 1, 1);
02549     ysize = max(ysize >> 1, 1);
02550   }
02551 
02552   gtc->update_data_size_bytes(bytecount);
02553   
02554   get_engine()->texture_uploaded(tex);
02555   gtc->mark_loaded();
02556 
02557   return true;
02558 }
02559 
02560 ////////////////////////////////////////////////////////////////////
02561 //     Function: TinyGraphicsStateGuardian::upload_simple_texture
02562 //       Access: Protected
02563 //  Description: This is used as a standin for upload_texture
02564 //               when the texture in question is unavailable (e.g. it
02565 //               hasn't yet been loaded from disk).  Until the texture
02566 //               image itself becomes available, we will render the
02567 //               texture's "simple" image--a sharply reduced version
02568 //               of the same texture.
02569 ////////////////////////////////////////////////////////////////////
02570 bool TinyGraphicsStateGuardian::
02571 upload_simple_texture(TinyTextureContext *gtc) {
02572   PStatTimer timer(_load_texture_pcollector);
02573   Texture *tex = gtc->get_texture();
02574   nassertr(tex != (Texture *)NULL, false);
02575 
02576   const unsigned char *image_ptr = tex->get_simple_ram_image();
02577   if (image_ptr == (const unsigned char *)NULL) {
02578     return false;
02579   }
02580 
02581   size_t image_size = tex->get_simple_ram_image_size();
02582   int width = tex->get_simple_x_size();
02583   int height = tex->get_simple_y_size();
02584 
02585 #ifdef DO_PSTATS
02586   _data_transferred_pcollector.add_level(image_size);
02587 #endif
02588   GLTexture *gltex = &gtc->_gltex;
02589 
02590   if (tinydisplay_cat.is_debug()) {
02591     tinydisplay_cat.debug()
02592       << "loading simple image for " << tex->get_name() << "\n";
02593   }
02594 
02595   if (!setup_gltex(gltex, width, height, 1)) {
02596     return false;
02597   }
02598   Colorf border_color = tex->get_border_color();
02599   gltex->border_color.v[0] = border_color[0];
02600   gltex->border_color.v[1] = border_color[1];
02601   gltex->border_color.v[2] = border_color[2];
02602   gltex->border_color.v[3] = border_color[3];
02603 
02604   ZTextureLevel *dest = &gltex->levels[0];
02605   memcpy(dest->pixmap, image_ptr, image_size);
02606 
02607   gtc->mark_simple_loaded();
02608 
02609   return true;
02610 }
02611 
02612 ////////////////////////////////////////////////////////////////////
02613 //     Function: TinyGraphicsStateGuardian::setup_gltex
02614 //       Access: Private
02615 //  Description: Sets the GLTexture size, bits, and masks
02616 //               appropriately, and allocates space for a pixmap.
02617 //               Does not fill the pixmap contents.  Returns true if
02618 //               the texture is a valid size, false otherwise.
02619 ////////////////////////////////////////////////////////////////////
02620 bool TinyGraphicsStateGuardian::
02621 setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
02622   int s_bits = get_tex_shift(x_size);
02623   int t_bits = get_tex_shift(y_size);
02624   
02625   if (s_bits < 0 || t_bits < 0) {
02626     return false;
02627   }
02628 
02629   num_levels = min(num_levels, MAX_MIPMAP_LEVELS);
02630 
02631   gltex->xsize = x_size;
02632   gltex->ysize = y_size;
02633 
02634   gltex->s_max = 1 << (s_bits + ZB_POINT_ST_FRAC_BITS);
02635   gltex->t_max = 1 << (t_bits + ZB_POINT_ST_FRAC_BITS);
02636 
02637   gltex->num_levels = num_levels;
02638   
02639   // We allocate one big buffer, large enough to include all the
02640   // mipmap levels, and index into that buffer for each level.  This
02641   // cuts down on the number of individual alloc calls we have to make
02642   // for each texture.
02643   int total_bytecount = 0;
02644 
02645   // Count up the total bytes required for all mipmap levels.
02646   {
02647     int x = x_size;
02648     int y = y_size;
02649     for (int level = 0; level < num_levels; ++level) {
02650       int bytecount = x * y * 4;
02651       total_bytecount += bytecount;
02652       x = max((x >> 1), 1);
02653       y = max((y >> 1), 1);
02654     }
02655   }
02656 
02657   if (gltex->total_bytecount != total_bytecount) {
02658     if (gltex->allocated_buffer != NULL) {
02659       PANDA_FREE_ARRAY(gltex->allocated_buffer);
02660       TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount);
02661     }
02662     gltex->allocated_buffer = PANDA_MALLOC_ARRAY(total_bytecount);
02663     gltex->total_bytecount = total_bytecount;
02664     TinyTextureContext::get_class_type().inc_memory_usage(TypeHandle::MC_array, total_bytecount);
02665   }
02666 
02667   char *next_buffer = (char *)gltex->allocated_buffer;
02668   char *end_of_buffer = next_buffer + total_bytecount;
02669 
02670   int level = 0;
02671   ZTextureLevel *dest = NULL;
02672   while (level < num_levels) {
02673     dest = &gltex->levels[level];
02674     int bytecount = x_size * y_size * 4;
02675     dest->pixmap = (PIXEL *)next_buffer;
02676     next_buffer += bytecount;
02677     nassertr(next_buffer <= end_of_buffer, false);
02678 
02679     dest->s_mask = ((1 << (s_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
02680     dest->t_mask = ((1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
02681     dest->s_shift = (ZB_POINT_ST_FRAC_BITS + level);
02682     dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits + level);
02683     
02684     x_size = max((x_size >> 1), 1);
02685     y_size = max((y_size >> 1), 1);
02686     s_bits = max(s_bits - 1, 0);
02687     t_bits = max(t_bits - 1, 0);
02688 
02689     ++level;
02690   }
02691 
02692   // Fill out the remaining mipmap arrays with copies of the last
02693   // level, so we don't have to be concerned with running off the end
02694   // of this array while scanning out triangles.
02695   while (level < MAX_MIPMAP_LEVELS) {
02696     gltex->levels[level] = *dest;
02697     ++level;
02698   }
02699 
02700   return true;
02701 }
02702 
02703 ////////////////////////////////////////////////////////////////////
02704 //     Function: TinyGraphicsStateGuardian::get_tex_shift
02705 //       Access: Private
02706 //  Description: Calculates the bit shift count, such that (1 << shift)
02707 //               == size.  Returns -1 if the size is not a power of 2
02708 //               or is larger than our largest allowable size.
02709 ////////////////////////////////////////////////////////////////////
02710 int TinyGraphicsStateGuardian::
02711 get_tex_shift(int orig_size) {
02712   if ((orig_size & (orig_size - 1)) != 0) {
02713     // Not a power of 2.
02714     return -1;
02715   }
02716   if (orig_size > _max_texture_dimension) {
02717     return -1;
02718   }
02719 
02720   return count_bits_in_word((unsigned int)orig_size - 1);
02721 }
02722 
02723 ////////////////////////////////////////////////////////////////////
02724 //     Function: TinyGraphicsStateGuardian::copy_lum_image
02725 //       Access: Private, Static
02726 //  Description: Copies and scales the one-channel luminance image
02727 //               from the texture into the indicated ZTexture pixmap.
02728 ////////////////////////////////////////////////////////////////////
02729 void TinyGraphicsStateGuardian::
02730 copy_lum_image(ZTextureLevel *dest, int xsize, int ysize, Texture *tex, int level) {
02731   nassertv(tex->get_num_components() == 1);
02732   nassertv(tex->get_expected_mipmap_x_size(level) == xsize &&
02733            tex->get_expected_mipmap_y_size(level) == ysize);
02734 
02735   CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
02736   nassertv(!src_image.is_null());
02737   const unsigned char *src = src_image.p();
02738 
02739   // Component width, and offset to the high-order byte.
02740   int cw = tex->get_component_width();
02741 #ifdef WORDS_BIGENDIAN
02742   // Big-endian: the high-order byte is always first.
02743   static const int co = 0;
02744 #else
02745   // Little-endian: the high-order byte is last.
02746   int co = cw - 1;
02747 #endif
02748 
02749   unsigned int *dpix = (unsigned int *)dest->pixmap;
02750   nassertv(dpix != NULL);
02751   const unsigned char *spix = src;
02752   int pixel_count = xsize * ysize;
02753   while (pixel_count-- > 0) {
02754     *dpix = RGBA8_TO_PIXEL(spix[co], spix[co], spix[co], 0xff);
02755     ++dpix;
02756     spix += cw;
02757   }
02758 }
02759 
02760 ////////////////////////////////////////////////////////////////////
02761 //     Function: TinyGraphicsStateGuardian::copy_alpha_image
02762 //       Access: Private, Static
02763 //  Description: Copies and scales the one-channel alpha image
02764 //               from the texture into the indicated ZTexture pixmap.
02765 ////////////////////////////////////////////////////////////////////
02766 void TinyGraphicsStateGuardian::
02767 copy_alpha_image(ZTextureLevel *dest, int xsize, int ysize, Texture *tex, int level) {
02768   nassertv(tex->get_num_components() == 1);
02769 
02770   CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
02771   nassertv(!src_image.is_null());
02772   const unsigned char *src = src_image.p();
02773 
02774   // Component width, and offset to the high-order byte.
02775   int cw = tex->get_component_width();
02776 #ifdef WORDS_BIGENDIAN
02777   // Big-endian: the high-order byte is always first.
02778   static const int co = 0;
02779 #else
02780   // Little-endian: the high-order byte is last.
02781   int co = cw - 1;
02782 #endif
02783 
02784   unsigned int *dpix = (unsigned int *)dest->pixmap;
02785   nassertv(dpix != NULL);
02786   const unsigned char *spix = src;
02787   int pixel_count = xsize * ysize;
02788   while (pixel_count-- > 0) {
02789     *dpix = RGBA8_TO_PIXEL(0xff, 0xff, 0xff, spix[co]);
02790     ++dpix;
02791     spix += cw;
02792   }
02793 }
02794 
02795 ////////////////////////////////////////////////////////////////////
02796 //     Function: TinyGraphicsStateGuardian::copy_one_channel_image
02797 //       Access: Private, Static
02798 //  Description: Copies and scales the one-channel image (with a
02799 //               single channel, e.g. red, green, or blue) from
02800 //               the texture into the indicated ZTexture pixmap.
02801 ////////////////////////////////////////////////////////////////////
02802 void TinyGraphicsStateGuardian::
02803 copy_one_channel_image(ZTextureLevel *dest, int xsize, int ysize, Texture *tex, int level, int channel) {
02804   nassertv(tex->get_num_components() == 1);
02805 
02806   CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
02807   nassertv(!src_image.is_null());
02808   const unsigned char *src = src_image.p();
02809 
02810   // Component width, and offset to the high-order byte.
02811   int cw = tex->get_component_width();
02812 #ifdef WORDS_BIGENDIAN
02813   // Big-endian: the high-order byte is always first.
02814   static const int co = 0;
02815 #else
02816   // Little-endian: the high-order byte is last.
02817   int co = cw - 1;
02818 #endif
02819 
02820   unsigned int *dpix = (unsigned int *)dest->pixmap;
02821   nassertv(dpix != NULL);
02822   const unsigned char *spix = src;
02823   int pixel_count = xsize * ysize;
02824 
02825   switch (channel) {
02826   case 0:
02827     while (pixel_count-- > 0) {
02828       *dpix = RGBA8_TO_PIXEL(spix[co], 0, 0, 0xff);
02829       ++dpix;
02830       spix += cw;
02831     }
02832     break;
02833 
02834   case 1:
02835     while (pixel_count-- > 0) {
02836       *dpix = RGBA8_TO_PIXEL(0, spix[co], 0, 0xff);
02837       ++dpix;
02838       spix += cw;
02839     }
02840     break;
02841 
02842   case 2:
02843     while (pixel_count-- > 0) {
02844       *dpix = RGBA8_TO_PIXEL(0, 0, spix[co], 0xff);
02845       ++dpix;
02846       spix += cw;
02847     }
02848     break;
02849 
02850   case 3:
02851     while (pixel_count-- > 0) {
02852       *dpix = RGBA8_TO_PIXEL(0, 0, 0, spix[co]);
02853       ++dpix;
02854       spix += cw;
02855     }
02856     break;
02857   }
02858 }
02859 
02860 ////////////////////////////////////////////////////////////////////
02861 //     Function: TinyGraphicsStateGuardian::copy_la_image
02862 //       Access: Private, Static
02863 //  Description: Copies and scales the two-channel luminance-alpha
02864 //               image from the texture into the indicated ZTexture
02865 //               pixmap.
02866 ////////////////////////////////////////////////////////////////////
02867 void TinyGraphicsStateGuardian::
02868 copy_la_image(ZTextureLevel *dest, int xsize, int ysize, Texture *tex, int level) {
02869   nassertv(tex->get_num_components() == 2);
02870 
02871   CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
02872   nassertv(!src_image.is_null());
02873   const unsigned char *src = src_image.p();
02874 
02875   // Component width, and offset to the high-order byte.
02876   int cw = tex->get_component_width();
02877 #ifdef WORDS_BIGENDIAN
02878   // Big-endian: the high-order byte is always first.
02879   static const int co = 0;
02880 #else
02881   // Little-endian: the high-order byte is last.
02882   int co = cw - 1;
02883 #endif
02884 
02885   unsigned int *dpix = (unsigned int *)dest->pixmap;
02886   nassertv(dpix != NULL);
02887   const unsigned char *spix = src;
02888   int pixel_count = xsize * ysize;
02889   int inc = 2 * cw;
02890   while (pixel_count-- > 0) {
02891     *dpix = RGBA8_TO_PIXEL(spix[co], spix[co], spix[co], spix[cw + co]);
02892     ++dpix;
02893     spix += inc;
02894   }
02895 }
02896 
02897 ////////////////////////////////////////////////////////////////////
02898 //     Function: TinyGraphicsStateGuardian::copy_rgb_image
02899 //       Access: Private, Static
02900 //  Description: Copies and scales the three-channel RGB image from
02901 //               the texture into the indicated ZTexture pixmap.
02902 ////////////////////////////////////////////////////////////////////
02903 void TinyGraphicsStateGuardian::
02904 copy_rgb_image(ZTextureLevel *dest, int xsize, int ysize, Texture *tex, int level) {
02905   nassertv(tex->get_num_components() == 3);
02906 
02907   CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
02908   nassertv(!src_image.is_null());
02909   const unsigned char *src = src_image.p();
02910 
02911   // Component width, and offset to the high-order byte.
02912   int cw = tex->get_component_width();
02913 #ifdef WORDS_BIGENDIAN
02914   // Big-endian: the high-order byte is always first.
02915   static const int co = 0;
02916 #else
02917   // Little-endian: the high-order byte is last.
02918   int co = cw - 1;
02919 #endif
02920 
02921   unsigned int *dpix = (unsigned int *)dest->pixmap;
02922   nassertv(dpix != NULL);
02923   const unsigned char *spix = src;
02924   int pixel_count = xsize * ysize;
02925   int inc = 3 * cw;
02926   while (pixel_count-- > 0) {
02927     *dpix = RGBA8_TO_PIXEL(spix[cw + cw + co], spix[cw + co], spix[co], 0xff);
02928     ++dpix;
02929     spix += inc;
02930   }
02931 }
02932 
02933 ////////////////////////////////////////////////////////////////////
02934 //     Function: TinyGraphicsStateGuardian::copy_rgba_image
02935 //       Access: Private, Static
02936 //  Description: Copies and scales the four-channel RGBA image from
02937 //               the texture into the indicated ZTexture pixmap.
02938 ////////////////////////////////////////////////////////////////////
02939 void TinyGraphicsStateGuardian::
02940 copy_rgba_image(ZTextureLevel *dest, int xsize, int ysize, Texture *tex, int level) {
02941   nassertv(tex->get_num_components() == 4);
02942 
02943   CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
02944   nassertv(!src_image.is_null());
02945   const unsigned char *src = src_image.p();
02946 
02947   // Component width, and offset to the high-order byte.
02948   int cw = tex->get_component_width();
02949 #ifdef WORDS_BIGENDIAN
02950   // Big-endian: the high-order byte is always first.
02951   static const int co = 0;
02952 #else
02953   // Little-endian: the high-order byte is last.
02954   int co = cw - 1;
02955 #endif
02956 
02957   unsigned int *dpix = (unsigned int *)dest->pixmap;
02958   nassertv(dpix != NULL);
02959   const unsigned char *spix = src;
02960   int pixel_count = xsize * ysize;
02961   int inc = 4 * cw;
02962   while (pixel_count-- > 0) {
02963     *dpix = RGBA8_TO_PIXEL(spix[cw + cw + co], spix[cw + co], spix[co], spix[cw + cw + cw + co]);
02964     ++dpix;
02965     spix += inc;
02966   }
02967 }
02968 
02969 ////////////////////////////////////////////////////////////////////
02970 //     Function: TinyGraphicsStateGuardian::setup_material
02971 //       Access: Private
02972 //  Description: Applies the desired parametesr to the indicated
02973 //               GLMaterial object.
02974 ////////////////////////////////////////////////////////////////////
02975 void TinyGraphicsStateGuardian::
02976 setup_material(GLMaterial *gl_material, const Material *material) {
02977   const Colorf &specular = material->get_specular();
02978   gl_material->specular.v[0] = specular[0];
02979   gl_material->specular.v[1] = specular[1];
02980   gl_material->specular.v[2] = specular[2];
02981   gl_material->specular.v[3] = specular[3];
02982 
02983   const Colorf &emission = material->get_emission();
02984   gl_material->emission.v[0] = emission[0];
02985   gl_material->emission.v[1] = emission[1];
02986   gl_material->emission.v[2] = emission[2];
02987   gl_material->emission.v[3] = emission[3];
02988 
02989   gl_material->shininess = material->get_shininess();
02990   gl_material->shininess_i = (int)((material->get_shininess() / 128.0f) * SPECULAR_BUFFER_RESOLUTION);
02991 
02992   _color_material_flags = CMF_ambient | CMF_diffuse;
02993 
02994   if (material->has_ambient()) {
02995     const Colorf &ambient = material->get_ambient();
02996     gl_material->ambient.v[0] = ambient[0];
02997     gl_material->ambient.v[1] = ambient[1];
02998     gl_material->ambient.v[2] = ambient[2];
02999     gl_material->ambient.v[3] = ambient[3];
03000 
03001     _color_material_flags &= ~CMF_ambient;
03002   }
03003 
03004   if (material->has_diffuse()) {
03005     const Colorf &diffuse = material->get_diffuse();
03006     gl_material->diffuse.v[0] = diffuse[0];
03007     gl_material->diffuse.v[1] = diffuse[1];
03008     gl_material->diffuse.v[2] = diffuse[2];
03009     gl_material->diffuse.v[3] = diffuse[3];
03010 
03011     _color_material_flags &= ~CMF_diffuse;
03012   }
03013 }
03014 
03015 ////////////////////////////////////////////////////////////////////
03016 //     Function: TinyGraphicsStateGuardian::do_auto_rescale_normal
03017 //       Access: Protected
03018 //  Description: Sets the state to either rescale or normalize the
03019 //               normals according to the current transform.
03020 ////////////////////////////////////////////////////////////////////
03021 void TinyGraphicsStateGuardian::
03022 do_auto_rescale_normal() {
03023   if (_internal_transform->has_uniform_scale()) {
03024     // There's a uniform scale; rescale the normals uniformly.
03025     _c->normalize_enabled = false;
03026     _c->normal_scale = _internal_transform->get_uniform_scale();
03027 
03028   } else {
03029     // If there's a non-uniform scale, normalize everything.
03030     _c->normalize_enabled = true;
03031     _c->normal_scale = 1.0f;
03032   }
03033 }
03034 
03035 ////////////////////////////////////////////////////////////////////
03036 //     Function: TinyGraphicsStateGuardian::load_matrix
03037 //       Access: Private, Static
03038 //  Description: Copies the Panda matrix stored in the indicated
03039 //               TransformState object into the indicated TinyGL
03040 //               matrix.
03041 ////////////////////////////////////////////////////////////////////
03042 void TinyGraphicsStateGuardian::
03043 load_matrix(M4 *matrix, const TransformState *transform) {
03044   const LMatrix4f &pm = transform->get_mat();
03045   for (int i = 0; i < 4; ++i) {
03046     matrix->m[0][i] = pm.get_cell(i, 0);
03047     matrix->m[1][i] = pm.get_cell(i, 1);
03048     matrix->m[2][i] = pm.get_cell(i, 2);
03049     matrix->m[3][i] = pm.get_cell(i, 3);
03050   }
03051 }
03052 
03053 ////////////////////////////////////////////////////////////////////
03054 //     Function: TinyGraphicsStateGuardian::get_color_blend_op
03055 //       Access: Private, Static
03056 //  Description: Returns the integer element of store_pixel_funcs (as
03057 //               defined by store_pixel.py) that corresponds to the
03058 //               indicated ColorBlendAttrib operand code.
03059 ////////////////////////////////////////////////////////////////////
03060 int TinyGraphicsStateGuardian::
03061 get_color_blend_op(ColorBlendAttrib::Operand operand) {
03062   switch (operand) {
03063   case ColorBlendAttrib::O_zero:
03064     return 0;
03065   case ColorBlendAttrib::O_one:
03066     return 1;
03067   case ColorBlendAttrib::O_incoming_color:
03068     return 2;
03069   case ColorBlendAttrib::O_one_minus_incoming_color:
03070     return 3;
03071   case ColorBlendAttrib::O_fbuffer_color:
03072     return 4;
03073   case ColorBlendAttrib::O_one_minus_fbuffer_color:
03074     return 5;
03075   case ColorBlendAttrib::O_incoming_alpha:
03076     return 6;
03077   case ColorBlendAttrib::O_one_minus_incoming_alpha:
03078     return 7;
03079   case ColorBlendAttrib::O_fbuffer_alpha:
03080     return 8;
03081   case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
03082     return 9;
03083   case ColorBlendAttrib::O_constant_color:
03084     return 10;
03085   case ColorBlendAttrib::O_one_minus_constant_color:
03086     return 11;
03087   case ColorBlendAttrib::O_constant_alpha:
03088     return 12;
03089   case ColorBlendAttrib::O_one_minus_constant_alpha:
03090     return 13;
03091 
03092   case ColorBlendAttrib::O_incoming_color_saturate:
03093     return 1;
03094 
03095   case ColorBlendAttrib::O_color_scale:
03096     return 10;
03097   case ColorBlendAttrib::O_one_minus_color_scale:
03098     return 11;
03099   case ColorBlendAttrib::O_alpha_scale:
03100     return 12;
03101   case ColorBlendAttrib::O_one_minus_alpha_scale:
03102     return 13;
03103   }
03104   return 0;
03105 }
03106  
03107 ////////////////////////////////////////////////////////////////////
03108 //     Function: TinyGraphicsStateGuardian::get_tex_filter_func
03109 //       Access: Private, Static
03110 //  Description: Returns the pointer to the appropriate filter
03111 //               function according to the texture's filter type.
03112 ////////////////////////////////////////////////////////////////////
03113 ZB_lookupTextureFunc TinyGraphicsStateGuardian::
03114 get_tex_filter_func(Texture::FilterType filter) {
03115   switch (filter) {
03116   case Texture::FT_nearest:
03117     return &lookup_texture_nearest;
03118 
03119   case Texture::FT_linear:
03120     return &lookup_texture_bilinear;
03121 
03122   case Texture::FT_nearest_mipmap_nearest:
03123     return &lookup_texture_mipmap_nearest;
03124 
03125   case Texture::FT_nearest_mipmap_linear:
03126     return &lookup_texture_mipmap_linear;
03127       
03128   case Texture::FT_linear_mipmap_nearest:
03129     return &lookup_texture_mipmap_bilinear;
03130 
03131   case Texture::FT_linear_mipmap_linear:
03132     return &lookup_texture_mipmap_trilinear;
03133 
03134   default:
03135     return &lookup_texture_nearest;
03136   }
03137 }
03138  
03139 ////////////////////////////////////////////////////////////////////
03140 //     Function: TinyGraphicsStateGuardian::get_tex_wrap_func
03141 //       Access: Private, Static
03142 //  Description: Returns the pointer to the appropriate wrap
03143 //               function according to the texture's wrap mode.
03144 ////////////////////////////////////////////////////////////////////
03145 ZB_texWrapFunc TinyGraphicsStateGuardian::
03146 get_tex_wrap_func(Texture::WrapMode wrap_mode) {
03147   switch (wrap_mode) {
03148   case Texture::WM_clamp:
03149   case Texture::WM_border_color:  // border_color is handled later.
03150     return &texcoord_clamp;
03151 
03152   case Texture::WM_repeat:
03153   case Texture::WM_invalid:
03154     return &texcoord_repeat;
03155 
03156   case Texture::WM_mirror:
03157     return &texcoord_mirror;
03158 
03159   case Texture::WM_mirror_once:
03160     return &texcoord_mirror_once;
03161   }
03162 
03163   return &texcoord_repeat;
03164 }
03165 
03166 ////////////////////////////////////////////////////////////////////
03167 //     Function: TinyGraphicsStateGuardian::texgen_null
03168 //       Access: Private, Static
03169 //  Description: Generates invalid texture coordinates.  Used when
03170 //               texture coordinate params are invalid or unsupported.
03171 ////////////////////////////////////////////////////////////////////
03172 void TinyGraphicsStateGuardian::
03173 texgen_null(V2 &result, TinyGraphicsStateGuardian::TexCoordData &) {
03174   result.v[0] = 0.0;
03175   result.v[1] = 0.0;
03176 }
03177 
03178 ////////////////////////////////////////////////////////////////////
03179 //     Function: TinyGraphicsStateGuardian::texgen_simple
03180 //       Access: Private, Static
03181 //  Description: Extracts a simple 2-d texture coordinate pair from
03182 //               the vertex data, without applying any texture matrix.
03183 ////////////////////////////////////////////////////////////////////
03184 void TinyGraphicsStateGuardian::
03185 texgen_simple(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) {
03186   // No need to transform, so just extract as two-component.
03187   const LVecBase2f &d = tcdata._r1.get_data2f();
03188   result.v[0] = d[0];
03189   result.v[1] = d[1];
03190 }
03191 
03192 ////////////////////////////////////////////////////////////////////
03193 //     Function: TinyGraphicsStateGuardian::texgen_simple
03194 //       Access: Private, Static
03195 //  Description: Extracts a simple 2-d texture coordinate pair from
03196 //               the vertex data, and then applies a texture matrix.
03197 ////////////////////////////////////////////////////////////////////
03198 void TinyGraphicsStateGuardian::
03199 texgen_texmat(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) {
03200   // Transform texcoords as a four-component vector for most generality.
03201   LVecBase4f d = tcdata._r1.get_data4f() * tcdata._mat;
03202   result.v[0] = d[0] / d[3];
03203   result.v[1] = d[1] / d[3];
03204 }
03205 
03206 ////////////////////////////////////////////////////////////////////
03207 //     Function: TinyGraphicsStateGuardian::texgen_sphere_map
03208 //       Access: Private, Static
03209 //  Description: Computes appropriate sphere map texture coordinates
03210 //               based on the eye normal coordinates.
03211 ////////////////////////////////////////////////////////////////////
03212 void TinyGraphicsStateGuardian::
03213 texgen_sphere_map(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) {
03214   // Get the normal and point in eye coordinates.
03215   LVector3f n = tcdata._mat.xform_vec(tcdata._r1.get_data3f());
03216   LVector3f u = tcdata._mat.xform_point(tcdata._r2.get_data3f());
03217 
03218   // Normalize the vectors.
03219   n.normalize();
03220   u.normalize();
03221 
03222   // Compute the reflection vector.
03223   LVector3f r = u - n * dot(n, u) * 2.0f;
03224   
03225   // compute the denominator, m.
03226   float m = 2.0f * csqrt(r[0] * r[0] + r[1] * r[1] + (r[2] + 1.0f) * (r[2] + 1.0f));
03227 
03228   // Now we can compute the s and t coordinates.
03229   result.v[0] = r[0] / m + 0.5f;
03230   result.v[1] = r[1] / m + 0.5f;
03231 
03232   /*
03233   cerr << "n = " << n << " u = " << u << "\n"
03234        << "  r = " << r << "\n"
03235        << "  m = " << m << ", result = " << result.v[0] << " " << result.v[1]
03236        << "\n";
03237   */
03238 }
 All Classes Functions Variables Enumerations