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