| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266 |
- // Filename: tinyGraphicsStateGuardian.cxx
- // Created by: drose (24Apr08)
- //
- ////////////////////////////////////////////////////////////////////
- //
- // PANDA 3D SOFTWARE
- // Copyright (c) Carnegie Mellon University. All rights reserved.
- //
- // All use of this software is subject to the terms of the revised BSD
- // license. You should have received a copy of this license along
- // with this source code in a file named "LICENSE."
- //
- ////////////////////////////////////////////////////////////////////
- #include "tinyGraphicsStateGuardian.h"
- #include "tinyGeomMunger.h"
- #include "tinyTextureContext.h"
- #include "config_tinydisplay.h"
- #include "pStatTimer.h"
- #include "geomVertexReader.h"
- #include "ambientLight.h"
- #include "pointLight.h"
- #include "directionalLight.h"
- #include "spotlight.h"
- #include "depthWriteAttrib.h"
- #include "depthOffsetAttrib.h"
- #include "colorWriteAttrib.h"
- #include "alphaTestAttrib.h"
- #include "depthTestAttrib.h"
- #include "shadeModelAttrib.h"
- #include "cullFaceAttrib.h"
- #include "rescaleNormalAttrib.h"
- #include "materialAttrib.h"
- #include "lightAttrib.h"
- #include "scissorAttrib.h"
- #include "bitMask.h"
- #include "zgl.h"
- #include "zmath.h"
- #include "ztriangle_table.h"
- #include "store_pixel_table.h"
- #include "graphicsEngine.h"
- TypeHandle TinyGraphicsStateGuardian::_type_handle;
- PStatCollector TinyGraphicsStateGuardian::_vertices_immediate_pcollector("Vertices:Immediate mode");
- PStatCollector TinyGraphicsStateGuardian::_draw_transform_pcollector("Draw:Transform");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_white_untextured_pcollector("Pixels:White untextured");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_flat_untextured_pcollector("Pixels:Flat untextured");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_untextured_pcollector("Pixels:Smooth untextured");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_white_textured_pcollector("Pixels:White textured");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_flat_textured_pcollector("Pixels:Flat textured");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_textured_pcollector("Pixels:Smooth textured");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_white_perspective_pcollector("Pixels:White perspective");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_flat_perspective_pcollector("Pixels:Flat perspective");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_perspective_pcollector("Pixels:Smooth perspective");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_multitex2_pcollector("Pixels:Smooth multitex 2");
- PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_multitex3_pcollector("Pixels:Smooth multitex 3");
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::Constructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- TinyGraphicsStateGuardian::
- TinyGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
- TinyGraphicsStateGuardian *share_with) :
- GraphicsStateGuardian(CS_yup_right, engine, pipe)
- {
- _current_frame_buffer = NULL;
- _aux_frame_buffer = NULL;
- _c = NULL;
- _vertices = NULL;
- _vertices_size = 0;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::Destructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- TinyGraphicsStateGuardian::
- ~TinyGraphicsStateGuardian() {
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::reset
- // Access: Public, Virtual
- // Description: Resets all internal state as if the gsg were newly
- // created.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- reset() {
- free_pointers();
- GraphicsStateGuardian::reset();
- // Build _inv_state_mask as a mask of 1's where we don't care, and
- // 0's where we do care, about the state.
- _inv_state_mask.clear_bit(ColorAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ColorScaleAttrib::get_class_slot());
- _inv_state_mask.clear_bit(CullFaceAttrib::get_class_slot());
- _inv_state_mask.clear_bit(DepthOffsetAttrib::get_class_slot());
- _inv_state_mask.clear_bit(RenderModeAttrib::get_class_slot());
- _inv_state_mask.clear_bit(RescaleNormalAttrib::get_class_slot());
- _inv_state_mask.clear_bit(TextureAttrib::get_class_slot());
- _inv_state_mask.clear_bit(MaterialAttrib::get_class_slot());
- _inv_state_mask.clear_bit(LightAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ScissorAttrib::get_class_slot());
- if (_c != (GLContext *)NULL) {
- glClose(_c);
- _c = NULL;
- }
- _c = (GLContext *)gl_zalloc(sizeof(GLContext));
- glInit(_c, _current_frame_buffer);
- _c->draw_triangle_front = gl_draw_triangle_fill;
- _c->draw_triangle_back = gl_draw_triangle_fill;
- _supported_geom_rendering =
- Geom::GR_point |
- Geom::GR_indexed_other |
- Geom::GR_triangle_strip |
- Geom::GR_flat_last_vertex;
- _max_texture_dimension = (1 << ZB_POINT_ST_FRAC_BITS);
- _max_texture_stages = MAX_TEXTURE_STAGES;
- _max_lights = MAX_LIGHTS;
- _color_scale_via_lighting = false;
- _alpha_scale_via_texture = false;
- _runtime_color_scale = true;
- _color_material_flags = 0;
- _texturing_state = 0;
- _texfilter_state = 0;
- _texture_replace = false;
- _filled_flat = false;
- _auto_rescale_normal = false;
- // Now that the GSG has been initialized, make it available for
- // optimizations.
- add_gsg(this);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::free_pointers
- // Access: Protected, Virtual
- // Description: Frees some memory that was explicitly allocated
- // within the glgsg.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- free_pointers() {
- if (_aux_frame_buffer != (ZBuffer *)NULL) {
- ZB_close(_aux_frame_buffer);
- _aux_frame_buffer = NULL;
- }
- if (_vertices != (GLVertex *)NULL) {
- PANDA_FREE_ARRAY(_vertices);
- _vertices = NULL;
- }
- _vertices_size = 0;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::close_gsg
- // Access: Protected, Virtual
- // Description: This is called by the associated GraphicsWindow when
- // close_window() is called. It should null out the
- // _win pointer and possibly free any open resources
- // associated with the GSG.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- close_gsg() {
- GraphicsStateGuardian::close_gsg();
- if (_c != (GLContext *)NULL) {
- glClose(_c);
- _c = NULL;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::depth_offset_decals
- // Access: Public, Virtual
- // Description: Returns true if this GSG can implement decals using a
- // DepthOffsetAttrib, or false if that is unreliable
- // and the three-step rendering process should be used
- // instead.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- depth_offset_decals() {
- return false;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::make_geom_munger
- // Access: Public, Virtual
- // Description: Creates a new GeomMunger object to munge vertices
- // appropriate to this GSG for the indicated state.
- ////////////////////////////////////////////////////////////////////
- PT(GeomMunger) TinyGraphicsStateGuardian::
- make_geom_munger(const RenderState *state, Thread *current_thread) {
- PT(TinyGeomMunger) munger = new TinyGeomMunger(this, state);
- return GeomMunger::register_munger(munger, current_thread);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::clear
- // Access: Public
- // Description: Clears the framebuffer within the current
- // DisplayRegion, according to the flags indicated by
- // the given DrawableRegion object.
- //
- // This does not set the DisplayRegion first. You
- // should call prepare_display_region() to specify the
- // region you wish the clear operation to apply to.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- clear(DrawableRegion *clearable) {
- PStatTimer timer(_clear_pcollector);
- if ((!clearable->get_clear_color_active())&&
- (!clearable->get_clear_depth_active())&&
- (!clearable->get_clear_stencil_active())) {
- return;
- }
-
- set_state_and_transform(RenderState::make_empty(), _internal_transform);
- bool clear_color = false;
- int r, g, b, a;
- if (clearable->get_clear_color_active()) {
- LColor v = clearable->get_clear_color();
- r = (int)(v[0] * 0xffff);
- g = (int)(v[1] * 0xffff);
- b = (int)(v[2] * 0xffff);
- a = (int)(v[3] * 0xffff);
- clear_color = true;
- }
-
- bool clear_z = false;
- int z;
- if (clearable->get_clear_depth_active()) {
- // We ignore the specified depth clear value, since we don't
- // support alternate depth compare functions anyway.
- z = 0;
- clear_z = true;
- }
- ZB_clear_viewport(_c->zb, clear_z, z,
- clear_color, r, g, b, a,
- _c->viewport.xmin, _c->viewport.ymin,
- _c->viewport.xsize, _c->viewport.ysize);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::prepare_display_region
- // Access: Public, Virtual
- // Description: Prepare a display region for rendering (set up
- // scissor region and viewport)
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- prepare_display_region(DisplayRegionPipelineReader *dr) {
- nassertv(dr != (DisplayRegionPipelineReader *)NULL);
- GraphicsStateGuardian::prepare_display_region(dr);
- int xmin, ymin, xsize, ysize;
- dr->get_region_pixels_i(xmin, ymin, xsize, ysize);
- PN_stdfloat pixel_factor = _current_display_region->get_pixel_factor();
- if (pixel_factor != 1.0) {
- // Render into an aux buffer, and zoom it up into the main
- // frame buffer later.
- xmin = 0;
- ymin = 0;
- xsize = int(xsize * pixel_factor);
- ysize = int(ysize * pixel_factor);
- if (_aux_frame_buffer == (ZBuffer *)NULL) {
- _aux_frame_buffer = ZB_open(xsize, ysize, ZB_MODE_RGBA, 0, 0, 0, 0);
- } else if (_aux_frame_buffer->xsize < xsize || _aux_frame_buffer->ysize < ysize) {
- ZB_resize(_aux_frame_buffer, NULL,
- max(_aux_frame_buffer->xsize, xsize),
- max(_aux_frame_buffer->ysize, ysize));
- }
- _c->zb = _aux_frame_buffer;
- } else {
- // Render directly into the main frame buffer.
- _c->zb = _current_frame_buffer;
- }
- _c->viewport.xmin = xmin;
- _c->viewport.ymin = ymin;
- _c->viewport.xsize = xsize;
- _c->viewport.ysize = ysize;
- set_scissor(0.0f, 1.0f, 0.0f, 1.0f);
- nassertv(xmin >= 0 && xmin < _c->zb->xsize &&
- ymin >= 0 && ymin < _c->zb->ysize &&
- xmin + xsize >= 0 && xmin + xsize <= _c->zb->xsize &&
- ymin + ysize >= 0 && ymin + ysize <= _c->zb->ysize);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::calc_projection_mat
- // Access: Public, Virtual
- // Description: Given a lens, calculates the appropriate projection
- // matrix for use with this gsg. Note that the
- // projection matrix depends a lot upon the coordinate
- // system of the rendering API.
- //
- // The return value is a TransformState if the lens is
- // acceptable, NULL if it is not.
- ////////////////////////////////////////////////////////////////////
- CPT(TransformState) TinyGraphicsStateGuardian::
- calc_projection_mat(const Lens *lens) {
- if (lens == (Lens *)NULL) {
- return NULL;
- }
- if (!lens->is_linear()) {
- return NULL;
- }
- // The projection matrix must always be right-handed Y-up, even if
- // our coordinate system of choice is otherwise, because certain GL
- // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of
- // a coordinate system. Sigh. In order to implement a Z-up (or
- // other arbitrary) coordinate system, we'll use a Y-up projection
- // matrix, and store the conversion to our coordinate system of
- // choice in the modelview matrix.
- LMatrix4 result =
- LMatrix4::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) *
- lens->get_projection_mat(_current_stereo_channel);
- if (_scene_setup->get_inverted()) {
- // If the scene is supposed to be inverted, then invert the
- // projection matrix.
- result *= LMatrix4::scale_mat(1.0f, -1.0f, 1.0f);
- }
- return TransformState::make_mat(result);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::prepare_lens
- // Access: Public, Virtual
- // Description: Makes the current lens (whichever lens was most
- // recently specified with set_scene()) active, so
- // that it will transform future rendered geometry.
- // Normally this is only called from the draw process,
- // and usually it is called by set_scene().
- //
- // The return value is true if the lens is acceptable,
- // false if it is not.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- prepare_lens() {
- _transform_stale = true;
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GraphicsStateGuardian::begin_frame
- // Access: Public, Virtual
- // Description: Called before each frame is rendered, to allow the
- // GSG a chance to do any internal cleanup before
- // beginning the frame.
- //
- // The return value is true if successful (in which case
- // the frame will be drawn and end_frame() will be
- // called later), or false if unsuccessful (in which
- // case nothing will be drawn and end_frame() will not
- // be called).
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- begin_frame(Thread *current_thread) {
- if (!GraphicsStateGuardian::begin_frame(current_thread)) {
- return false;
- }
- _c->zb = _current_frame_buffer;
- #ifdef DO_PSTATS
- _vertices_immediate_pcollector.clear_level();
- _pixel_count_white_untextured_pcollector.clear_level();
- _pixel_count_flat_untextured_pcollector.clear_level();
- _pixel_count_smooth_untextured_pcollector.clear_level();
- _pixel_count_white_textured_pcollector.clear_level();
- _pixel_count_flat_textured_pcollector.clear_level();
- _pixel_count_smooth_textured_pcollector.clear_level();
- _pixel_count_white_perspective_pcollector.clear_level();
- _pixel_count_flat_perspective_pcollector.clear_level();
- _pixel_count_smooth_perspective_pcollector.clear_level();
- _pixel_count_smooth_multitex2_pcollector.clear_level();
- _pixel_count_smooth_multitex3_pcollector.clear_level();
- #endif
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GraphicsStateGuardian::begin_scene
- // Access: Public, Virtual
- // Description: Called between begin_frame() and end_frame() to mark
- // the beginning of drawing commands for a "scene"
- // (usually a particular DisplayRegion) within a frame.
- // All 3-D drawing commands, except the clear operation,
- // must be enclosed within begin_scene() .. end_scene().
- //
- // The return value is true if successful (in which case
- // the scene will be drawn and end_scene() will be
- // called later), or false if unsuccessful (in which
- // case nothing will be drawn and end_scene() will not
- // be called).
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- begin_scene() {
- return GraphicsStateGuardian::begin_scene();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::end_scene
- // Access: Protected, Virtual
- // Description: Called between begin_frame() and end_frame() to mark
- // the end of drawing commands for a "scene" (usually a
- // particular DisplayRegion) within a frame. All 3-D
- // drawing commands, except the clear operation, must be
- // enclosed within begin_scene() .. end_scene().
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- end_scene() {
- if (_c->zb == _aux_frame_buffer) {
- // Copy the aux frame buffer into the main scene now, zooming it
- // up to the appropriate size.
- int xmin, ymin, xsize, ysize;
- _current_display_region->get_region_pixels_i(xmin, ymin, xsize, ysize);
- PN_stdfloat pixel_factor = _current_display_region->get_pixel_factor();
- int fb_xsize = int(xsize * pixel_factor);
- int fb_ysize = int(ysize * pixel_factor);
- ZB_zoomFrameBuffer(_current_frame_buffer, xmin, ymin, xsize, ysize,
- _aux_frame_buffer, 0, 0, fb_xsize, fb_ysize);
- _c->zb = _current_frame_buffer;
- }
- // Clear the lighting state.
- clear_light_state();
- _plights.clear();
- _dlights.clear();
- _slights.clear();
- GraphicsStateGuardian::end_scene();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::end_frame
- // Access: Public, Virtual
- // Description: Called after each frame is rendered, to allow the
- // GSG a chance to do any internal cleanup after
- // rendering the frame, and before the window flips.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- end_frame(Thread *current_thread) {
- GraphicsStateGuardian::end_frame(current_thread);
- #ifndef NDEBUG
- static ConfigVariableBool td_show_zbuffer
- ("td-show-zbuffer", false,
- 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"));
- if (td_show_zbuffer) {
- PIXEL *tp = _current_frame_buffer->pbuf;
- ZPOINT *tz = _current_frame_buffer->zbuf;
- for (int yi = 0; yi < _current_frame_buffer->ysize; ++yi) {
- for (int xi = 0; xi < _current_frame_buffer->xsize; ++xi) {
- (*tp) = (int)(*tz);
- ++tz;
- ++tp;
- }
- }
- }
- #endif // NDEBUG
- #ifdef DO_PSTATS
- // Flush any PCollectors specific to this kind of GSG.
- _vertices_immediate_pcollector.flush_level();
- _pixel_count_white_untextured_pcollector.flush_level();
- _pixel_count_flat_untextured_pcollector.flush_level();
- _pixel_count_smooth_untextured_pcollector.flush_level();
- _pixel_count_white_textured_pcollector.flush_level();
- _pixel_count_flat_textured_pcollector.flush_level();
- _pixel_count_smooth_textured_pcollector.flush_level();
- _pixel_count_white_perspective_pcollector.flush_level();
- _pixel_count_flat_perspective_pcollector.flush_level();
- _pixel_count_smooth_perspective_pcollector.flush_level();
- _pixel_count_smooth_multitex2_pcollector.flush_level();
- _pixel_count_smooth_multitex3_pcollector.flush_level();
- #endif // DO_PSTATS
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::begin_draw_primitives
- // Access: Public, Virtual
- // Description: Called before a sequence of draw_primitive()
- // functions are called, this should prepare the vertex
- // data for rendering. It returns true if the vertices
- // are ok, false to abort this group of primitives.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- begin_draw_primitives(const GeomPipelineReader *geom_reader,
- const GeomMunger *munger,
- const GeomVertexDataPipelineReader *data_reader,
- bool force) {
- #ifndef NDEBUG
- if (tinydisplay_cat.is_spam()) {
- tinydisplay_cat.spam() << "begin_draw_primitives: " << *(data_reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- if (!GraphicsStateGuardian::begin_draw_primitives(geom_reader, munger, data_reader, force)) {
- return false;
- }
- nassertr(_data_reader != (GeomVertexDataPipelineReader *)NULL, false);
- PStatTimer timer(_draw_transform_pcollector);
- // Set up the proper transform.
- if (_data_reader->is_vertex_transformed()) {
- // If the vertex data claims to be already transformed into clip
- // coordinates, wipe out the current projection and modelview
- // matrix (so we don't attempt to transform it again).
- const TransformState *ident = TransformState::make_identity();
- load_matrix(&_c->matrix_model_view, ident);
- load_matrix(&_c->matrix_projection, _scissor_mat);
- load_matrix(&_c->matrix_model_view_inv, ident);
- load_matrix(&_c->matrix_model_projection, _scissor_mat);
- _c->matrix_model_projection_no_w_transform = 1;
- _transform_stale = true;
- } else if (_transform_stale) {
- // Load the actual transform.
- CPT(TransformState) scissor_proj_mat = _scissor_mat->compose(_projection_mat);
- if (_c->lighting_enabled) {
- // With the lighting equation, we need to keep the modelview and
- // projection matrices separate.
- load_matrix(&_c->matrix_model_view, _internal_transform);
- load_matrix(&_c->matrix_projection, scissor_proj_mat);
- /* precompute inverse modelview */
- M4 tmp;
- gl_M4_Inv(&tmp, &_c->matrix_model_view);
- gl_M4_Transpose(&_c->matrix_model_view_inv, &tmp);
- }
- // Compose the modelview and projection matrices.
- load_matrix(&_c->matrix_model_projection,
- scissor_proj_mat->compose(_internal_transform));
- /* test to accelerate computation */
- _c->matrix_model_projection_no_w_transform = 0;
- PN_stdfloat *m = &_c->matrix_model_projection.m[0][0];
- if (m[12] == 0.0 && m[13] == 0.0 && m[14] == 0.0) {
- _c->matrix_model_projection_no_w_transform = 1;
- }
- _transform_stale = false;
- }
- // Figure out the subset of vertices we will be using in this
- // operation.
- int num_vertices = data_reader->get_num_rows();
- _min_vertex = num_vertices;
- _max_vertex = 0;
- int num_prims = geom_reader->get_num_primitives();
- int i;
- for (i = 0; i < num_prims; ++i) {
- CPT(GeomPrimitive) prim = geom_reader->get_primitive(i);
- int nv = prim->get_min_vertex();
- _min_vertex = min(_min_vertex, nv);
- int xv = prim->get_max_vertex();
- _max_vertex = max(_max_vertex, xv);
- }
- if (_min_vertex > _max_vertex) {
- return false;
- }
- // Now copy all of those vertices into our working table,
- // transforming into screen space them as we go.
- int num_used_vertices = _max_vertex - _min_vertex + 1;
- if (_vertices_size < num_used_vertices) {
- if (_vertices_size == 0) {
- _vertices_size = 1;
- }
- while (_vertices_size < num_used_vertices) {
- _vertices_size *= 2;
- }
- if (_vertices != (GLVertex *)NULL) {
- PANDA_FREE_ARRAY(_vertices);
- }
- _vertices = (GLVertex *)PANDA_MALLOC_ARRAY(_vertices_size * sizeof(GLVertex));
- }
- GeomVertexReader rcolor, rnormal;
- // We now support up to 3-stage multitexturing.
- GenTexcoordFunc *texgen_func[MAX_TEXTURE_STAGES];
- TexCoordData tcdata[MAX_TEXTURE_STAGES];
- const TexGenAttrib *target_tex_gen = DCAST(TexGenAttrib, _target_rs->get_attrib_def(TexGenAttrib::get_class_slot()));
- const TexMatrixAttrib *target_tex_matrix = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
- int max_stage_index = _target_texture->get_num_on_ff_stages();
- for (int si = 0; si < max_stage_index; ++si) {
- TextureStage *stage = _target_texture->get_on_ff_stage(si);
- switch (target_tex_gen->get_mode(stage)) {
- case TexGenAttrib::M_eye_sphere_map:
- tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_normal(),
- force);
- tcdata[si]._r2 = GeomVertexReader(data_reader, InternalName::get_vertex(),
- force);
- texgen_func[si] = &texgen_sphere_map;
- tcdata[si]._mat = _internal_transform->get_mat();
- break;
- case TexGenAttrib::M_eye_position:
- tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_vertex(),
- force);
- texgen_func[si] = &texgen_texmat;
- {
- CPT(TransformState) eye_transform =
- _cs_transform->invert_compose(_internal_transform);
- tcdata[si]._mat = eye_transform->get_mat();
- }
- if (target_tex_matrix->has_stage(stage)) {
- tcdata[si]._mat = tcdata[si]._mat * target_tex_matrix->get_mat(stage);
- }
- break;
- case TexGenAttrib::M_world_position:
- tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_vertex(),
- force);
- texgen_func[si] = &texgen_texmat;
- {
- CPT(TransformState) render_transform =
- _cs_transform->compose(_scene_setup->get_world_transform());
- CPT(TransformState) world_inv_transform =
- render_transform->invert_compose(_internal_transform);
- tcdata[si]._mat = world_inv_transform->get_mat();
- }
- if (target_tex_matrix->has_stage(stage)) {
- tcdata[si]._mat = tcdata[si]._mat * target_tex_matrix->get_mat(stage);
- }
- break;
- default:
- // Fall through: use the standard texture coordinates.
- tcdata[si]._r1 = GeomVertexReader(data_reader, stage->get_texcoord_name(),
- force);
- texgen_func[si] = &texgen_simple;
- if (target_tex_matrix->has_stage(stage)) {
- texgen_func[si] = &texgen_texmat;
- tcdata[si]._mat = target_tex_matrix->get_mat(stage);
- }
- break;
- }
- tcdata[si]._r1.set_row_unsafe(_min_vertex);
- tcdata[si]._r2.set_row_unsafe(_min_vertex);
- if (!tcdata[si]._r1.has_column()) {
- texgen_func[si] = &texgen_null;
- }
- }
- bool needs_color = false;
- if (_vertex_colors_enabled) {
- rcolor = GeomVertexReader(data_reader, InternalName::get_color(), force);
- rcolor.set_row_unsafe(_min_vertex);
- needs_color = rcolor.has_column();
- }
- if (!needs_color) {
- const LColor &d = _scene_graph_color;
- const LColor &s = _current_color_scale;
- _c->current_color.v[0] = d[0] * s[0];
- _c->current_color.v[1] = d[1] * s[1];
- _c->current_color.v[2] = d[2] * s[2];
- _c->current_color.v[3] = d[3] * s[3];
- }
- bool needs_normal = false;
- if (_c->lighting_enabled) {
- rnormal = GeomVertexReader(data_reader, InternalName::get_normal(), force);
- rnormal.set_row_unsafe(_min_vertex);
- needs_normal = rnormal.has_column();
- }
- GeomVertexReader rvertex(data_reader, InternalName::get_vertex(), force);
- rvertex.set_row_unsafe(_min_vertex);
- if (!rvertex.has_column()) {
- // Whoops, guess the vertex data isn't resident.
- return false;
- }
- if (!needs_color && _color_material_flags) {
- if (_color_material_flags & CMF_ambient) {
- _c->materials[0].ambient = _c->current_color;
- _c->materials[1].ambient = _c->current_color;
- }
- if (_color_material_flags & CMF_diffuse) {
- _c->materials[0].diffuse = _c->current_color;
- _c->materials[1].diffuse = _c->current_color;
- }
- }
- if (_texturing_state != 0 && _texture_replace) {
- // We don't need the vertex color or lighting calculation after
- // all, since the current texture will just hide all of that.
- needs_color = false;
- needs_normal = false;
- }
- bool lighting_enabled = (needs_normal && _c->lighting_enabled);
- for (i = 0; i < num_used_vertices; ++i) {
- GLVertex *v = &_vertices[i];
- const LVecBase4 &d = rvertex.get_data4();
-
- v->coord.v[0] = d[0];
- v->coord.v[1] = d[1];
- v->coord.v[2] = d[2];
- v->coord.v[3] = d[3];
- // Texture coordinates.
- for (int si = 0; si < max_stage_index; ++si) {
- LTexCoord d;
- (*texgen_func[si])(v->tex_coord[si], tcdata[si]);
- }
- if (needs_color) {
- const LColor &d = rcolor.get_data4();
- const LColor &s = _current_color_scale;
- _c->current_color.v[0] = d[0] * s[0];
- _c->current_color.v[1] = d[1] * s[1];
- _c->current_color.v[2] = d[2] * s[2];
- _c->current_color.v[3] = d[3] * s[3];
-
- if (_color_material_flags) {
- if (_color_material_flags & CMF_ambient) {
- _c->materials[0].ambient = _c->current_color;
- _c->materials[1].ambient = _c->current_color;
- }
- if (_color_material_flags & CMF_diffuse) {
- _c->materials[0].diffuse = _c->current_color;
- _c->materials[1].diffuse = _c->current_color;
- }
- }
- }
- v->color = _c->current_color;
- if (lighting_enabled) {
- const LVecBase3 &d = rnormal.get_data3();
- _c->current_normal.v[0] = d[0];
- _c->current_normal.v[1] = d[1];
- _c->current_normal.v[2] = d[2];
- _c->current_normal.v[3] = 0.0f;
- gl_vertex_transform(_c, v);
- gl_shade_vertex(_c, v);
- } else {
- gl_vertex_transform(_c, v);
- }
- if (v->clip_code == 0) {
- gl_transform_to_viewport(_c, v);
- }
- v->edge_flag = 1;
- }
- // Set up the appropriate function callback for filling triangles,
- // according to the current state.
- int depth_write_state = 0; // zon
- const DepthWriteAttrib *target_depth_write = DCAST(DepthWriteAttrib, _target_rs->get_attrib_def(DepthWriteAttrib::get_class_slot()));
- if (target_depth_write->get_mode() != DepthWriteAttrib::M_on) {
- depth_write_state = 1; // zoff
- }
- int color_write_state = 0; // cstore
- const ColorWriteAttrib *target_color_write = DCAST(ColorWriteAttrib, _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot()));
- unsigned int color_channels =
- target_color_write->get_channels() & _color_write_mask;
- if (color_channels != ColorWriteAttrib::C_all) {
- // Implement a color mask.
- int op_a = get_color_blend_op(ColorBlendAttrib::O_one);
- int op_b = get_color_blend_op(ColorBlendAttrib::O_zero);
- _c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
- color_write_state = 2; // cgeneral
- }
- const TransparencyAttrib *target_transparency = DCAST(TransparencyAttrib, _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
- switch (target_transparency->get_mode()) {
- case TransparencyAttrib::M_alpha:
- case TransparencyAttrib::M_dual:
- color_write_state = 1; // cblend
- if (color_channels != ColorWriteAttrib::C_all) {
- // Implement a color mask, with alpha blending.
- int op_a = get_color_blend_op(ColorBlendAttrib::O_incoming_alpha);
- int op_b = get_color_blend_op(ColorBlendAttrib::O_one_minus_incoming_alpha);
- _c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
- color_write_state = 2; // cgeneral
- }
- break;
- default:
- break;
- }
- const ColorBlendAttrib *target_color_blend = DCAST(ColorBlendAttrib, _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
- if (target_color_blend->get_mode() == ColorBlendAttrib::M_add) {
- // If we have a color blend set that we can support, it overrides
- // the transparency set.
- int op_a = get_color_blend_op(target_color_blend->get_operand_a());
- int op_b = get_color_blend_op(target_color_blend->get_operand_b());
- _c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
- LColor c = target_color_blend->get_color();
- _c->zb->blend_r = (int)(c[0] * ZB_POINT_RED_MAX);
- _c->zb->blend_g = (int)(c[1] * ZB_POINT_GREEN_MAX);
- _c->zb->blend_b = (int)(c[2] * ZB_POINT_BLUE_MAX);
- _c->zb->blend_a = (int)(c[3] * ZB_POINT_ALPHA_MAX);
- color_write_state = 2; // cgeneral
- }
- if (color_channels == ColorWriteAttrib::C_off) {
- color_write_state = 3; // coff
- }
- int alpha_test_state = 0; // anone
- const AlphaTestAttrib *target_alpha_test = DCAST(AlphaTestAttrib, _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
- switch (target_alpha_test->get_mode()) {
- case AlphaTestAttrib::M_none:
- case AlphaTestAttrib::M_never:
- case AlphaTestAttrib::M_always:
- case AlphaTestAttrib::M_equal:
- case AlphaTestAttrib::M_not_equal:
- alpha_test_state = 0; // anone
- break;
- case AlphaTestAttrib::M_less:
- case AlphaTestAttrib::M_less_equal:
- alpha_test_state = 1; // aless
- _c->zb->reference_alpha = (int)(target_alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX);
- break;
- case AlphaTestAttrib::M_greater:
- case AlphaTestAttrib::M_greater_equal:
- alpha_test_state = 2; // amore
- _c->zb->reference_alpha = (int)(target_alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX);
- break;
- }
- int depth_test_state = 1; // zless
- _c->depth_test = 1; // set this for ZB_line
- const DepthTestAttrib *target_depth_test = DCAST(DepthTestAttrib, _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot()));
- if (target_depth_test->get_mode() == DepthTestAttrib::M_none) {
- depth_test_state = 0; // zless
- _c->depth_test = 0;
- }
-
- const ShadeModelAttrib *target_shade_model = DCAST(ShadeModelAttrib, _target_rs->get_attrib_def(ShadeModelAttrib::get_class_slot()));
- ShadeModelAttrib::Mode shade_model = target_shade_model->get_mode();
- if (!needs_normal && !needs_color) {
- // With no per-vertex lighting, and no per-vertex colors, we might
- // as well use the flat shading model.
- shade_model = ShadeModelAttrib::M_flat;
- }
- int shade_model_state = 2; // smooth
- _c->smooth_shade_model = true;
- if (shade_model == ShadeModelAttrib::M_flat) {
- _c->smooth_shade_model = false;
- shade_model_state = 1; // flat
- if (_c->current_color.v[0] == 1.0f &&
- _c->current_color.v[1] == 1.0f &&
- _c->current_color.v[2] == 1.0f &&
- _c->current_color.v[3] == 1.0f) {
- shade_model_state = 0; // white
- }
- }
- int texturing_state = _texturing_state;
- int texfilter_state = 0; // tnearest
- if (texturing_state > 0) {
- texfilter_state = _texfilter_state;
- if (texturing_state < 3 &&
- (_c->matrix_model_projection_no_w_transform || _filled_flat)) {
- // Don't bother with the perspective-correct algorithm if we're
- // under an orthonormal lens, e.g. render2d; or if
- // RenderMode::M_filled_flat is in effect.
- texturing_state = 1; // textured (not perspective correct)
- }
- if (_texture_replace) {
- // If we're completely replacing the underlying color, then it
- // doesn't matter what the color is.
- shade_model_state = 0;
- }
- }
- _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];
- #ifdef DO_PSTATS
- pixel_count_white_untextured = 0;
- pixel_count_flat_untextured = 0;
- pixel_count_smooth_untextured = 0;
- pixel_count_white_textured = 0;
- pixel_count_flat_textured = 0;
- pixel_count_smooth_textured = 0;
- pixel_count_white_perspective = 0;
- pixel_count_flat_perspective = 0;
- pixel_count_smooth_perspective = 0;
- pixel_count_smooth_multitex2 = 0;
- pixel_count_smooth_multitex3 = 0;
- #endif // DO_PSTATS
-
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::draw_triangles
- // Access: Public, Virtual
- // Description: Draws a series of disconnected triangles.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
- PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (tinydisplay_cat.is_spam()) {
- tinydisplay_cat.spam() << "draw_triangles: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- int num_vertices = reader->get_num_vertices();
- _vertices_tri_pcollector.add_level(num_vertices);
- if (reader->is_indexed()) {
- switch (reader->get_index_type()) {
- case Geom::NT_uint8:
- {
- PN_uint8 *index = (PN_uint8 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; i += 3) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
- GLVertex *v2 = &_vertices[index[i + 2] - _min_vertex];
- gl_draw_triangle(_c, v0, v1, v2);
- }
- }
- break;
- case Geom::NT_uint16:
- {
- PN_uint16 *index = (PN_uint16 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; i += 3) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
- GLVertex *v2 = &_vertices[index[i + 2] - _min_vertex];
- gl_draw_triangle(_c, v0, v1, v2);
- }
- }
- break;
- case Geom::NT_uint32:
- {
- PN_uint32 *index = (PN_uint32 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; i += 3) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
- GLVertex *v2 = &_vertices[index[i + 2] - _min_vertex];
- gl_draw_triangle(_c, v0, v1, v2);
- }
- }
- break;
- default:
- break;
- }
- } else {
- int delta = reader->get_first_vertex() - _min_vertex;
- for (int vi = 0; vi < num_vertices; vi += 3) {
- GLVertex *v0 = &_vertices[vi + delta];
- GLVertex *v1 = &_vertices[vi + delta + 1];
- GLVertex *v2 = &_vertices[vi + delta + 2];
- gl_draw_triangle(_c, v0, v1, v2);
- }
- }
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::draw_tristrips
- // Access: Public, Virtual
- // Description: Draws a series of triangle strips.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
- PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (tinydisplay_cat.is_spam()) {
- tinydisplay_cat.spam() << "draw_tristrips: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- // Send the individual triangle strips, stepping over the
- // degenerate vertices.
- CPTA_int ends = reader->get_ends();
- _primitive_batches_tristrip_pcollector.add_level(ends.size());
- if (reader->is_indexed()) {
- unsigned int start = 0;
- for (size_t i = 0; i < ends.size(); i++) {
- _vertices_tristrip_pcollector.add_level(ends[i] - start);
- int end = ends[i];
- nassertr(end - start >= 3, false);
- switch (reader->get_index_type()) {
- case Geom::NT_uint8:
- {
- PN_uint8 *index = (PN_uint8 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- GLVertex *v0 = &_vertices[index[start] - _min_vertex];
- GLVertex *v1 = &_vertices[index[start + 1] - _min_vertex];
- bool reversed = false;
- for (int vi = start + 2; vi < end; ++vi) {
- GLVertex *v2 = &_vertices[index[vi] - _min_vertex];
- if (reversed) {
- gl_draw_triangle(_c, v1, v0, v2);
- reversed = false;
- } else {
- gl_draw_triangle(_c, v0, v1, v2);
- reversed = true;
- }
- v0 = v1;
- v1 = v2;
- }
- }
- break;
- case Geom::NT_uint16:
- {
- PN_uint16 *index = (PN_uint16 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- GLVertex *v0 = &_vertices[index[start] - _min_vertex];
- GLVertex *v1 = &_vertices[index[start + 1] - _min_vertex];
- bool reversed = false;
- for (int vi = start + 2; vi < end; ++vi) {
- GLVertex *v2 = &_vertices[index[vi] - _min_vertex];
- if (reversed) {
- gl_draw_triangle(_c, v1, v0, v2);
- reversed = false;
- } else {
- gl_draw_triangle(_c, v0, v1, v2);
- reversed = true;
- }
- v0 = v1;
- v1 = v2;
- }
- }
- break;
- case Geom::NT_uint32:
- {
- PN_uint32 *index = (PN_uint32 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- GLVertex *v0 = &_vertices[index[start] - _min_vertex];
- GLVertex *v1 = &_vertices[index[start + 1] - _min_vertex];
- bool reversed = false;
- for (int vi = start + 2; vi < end; ++vi) {
- GLVertex *v2 = &_vertices[index[vi] - _min_vertex];
- if (reversed) {
- gl_draw_triangle(_c, v1, v0, v2);
- reversed = false;
- } else {
- gl_draw_triangle(_c, v0, v1, v2);
- reversed = true;
- }
- v0 = v1;
- v1 = v2;
- }
- }
- break;
- }
- start = ends[i] + 2;
- }
- } else {
- unsigned int start = 0;
- int delta = reader->get_first_vertex() - _min_vertex;
- for (size_t i = 0; i < ends.size(); i++) {
- _vertices_tristrip_pcollector.add_level(ends[i] - start);
- int end = ends[i];
- nassertr(end - start >= 3, false);
- GLVertex *v0 = &_vertices[start + delta];
- GLVertex *v1 = &_vertices[start + delta + 1];
- bool reversed = false;
- for (int vi = start + 2; vi < end; ++vi) {
- GLVertex *v2 = &_vertices[vi + delta];
- if (reversed) {
- gl_draw_triangle(_c, v1, v0, v2);
- reversed = false;
- } else {
- gl_draw_triangle(_c, v0, v1, v2);
- reversed = true;
- }
- v0 = v1;
- v1 = v2;
- }
- start = ends[i] + 2;
- }
- }
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::draw_lines
- // Access: Public, Virtual
- // Description: Draws a series of disconnected line segments.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
- PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (tinydisplay_cat.is_spam()) {
- tinydisplay_cat.spam() << "draw_lines: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- int num_vertices = reader->get_num_vertices();
- _vertices_other_pcollector.add_level(num_vertices);
- if (reader->is_indexed()) {
- switch (reader->get_index_type()) {
- case Geom::NT_uint8:
- {
- PN_uint8 *index = (PN_uint8 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; i += 2) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
- gl_draw_line(_c, v0, v1);
- }
- }
- break;
- case Geom::NT_uint16:
- {
- PN_uint16 *index = (PN_uint16 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; i += 2) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
- gl_draw_line(_c, v0, v1);
- }
- }
- break;
- case Geom::NT_uint32:
- {
- PN_uint32 *index = (PN_uint32 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; i += 2) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- GLVertex *v1 = &_vertices[index[i + 1] - _min_vertex];
- gl_draw_line(_c, v0, v1);
- }
- }
- break;
- default:
- break;
- }
- } else {
- int delta = reader->get_first_vertex() - _min_vertex;
- for (int vi = 0; vi < num_vertices; vi += 2) {
- GLVertex *v0 = &_vertices[vi + delta];
- GLVertex *v1 = &_vertices[vi + delta + 1];
- gl_draw_line(_c, v0, v1);
- }
- }
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::draw_points
- // Access: Public, Virtual
- // Description: Draws a series of disconnected points.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
- PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (tinydisplay_cat.is_spam()) {
- tinydisplay_cat.spam() << "draw_points: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- int num_vertices = reader->get_num_vertices();
- _vertices_other_pcollector.add_level(num_vertices);
- if (reader->is_indexed()) {
- switch (reader->get_index_type()) {
- case Geom::NT_uint8:
- {
- PN_uint8 *index = (PN_uint8 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; ++i) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- gl_draw_point(_c, v0);
- }
- }
- break;
- case Geom::NT_uint16:
- {
- PN_uint16 *index = (PN_uint16 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; ++i) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- gl_draw_point(_c, v0);
- }
- }
- break;
- case Geom::NT_uint32:
- {
- PN_uint32 *index = (PN_uint32 *)reader->get_read_pointer(force);
- if (index == NULL) {
- return false;
- }
- for (int i = 0; i < num_vertices; ++i) {
- GLVertex *v0 = &_vertices[index[i] - _min_vertex];
- gl_draw_point(_c, v0);
- }
- }
- break;
- default:
- break;
- }
- } else {
- int delta = reader->get_first_vertex() - _min_vertex;
- for (int vi = 0; vi < num_vertices; ++vi) {
- GLVertex *v0 = &_vertices[vi + delta];
- gl_draw_point(_c, v0);
- }
- }
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::end_draw_primitives()
- // Access: Public, Virtual
- // Description: Called after a sequence of draw_primitive()
- // functions are called, this should do whatever cleanup
- // is appropriate.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- end_draw_primitives() {
- #ifdef DO_PSTATS
- _pixel_count_white_untextured_pcollector.add_level(pixel_count_white_untextured);
- _pixel_count_flat_untextured_pcollector.add_level(pixel_count_flat_untextured);
- _pixel_count_smooth_untextured_pcollector.add_level(pixel_count_smooth_untextured);
- _pixel_count_white_textured_pcollector.add_level(pixel_count_white_textured);
- _pixel_count_flat_textured_pcollector.add_level(pixel_count_flat_textured);
- _pixel_count_smooth_textured_pcollector.add_level(pixel_count_smooth_textured);
- _pixel_count_white_perspective_pcollector.add_level(pixel_count_white_perspective);
- _pixel_count_flat_perspective_pcollector.add_level(pixel_count_flat_perspective);
- _pixel_count_smooth_perspective_pcollector.add_level(pixel_count_smooth_perspective);
- _pixel_count_smooth_multitex2_pcollector.add_level(pixel_count_smooth_multitex2);
- _pixel_count_smooth_multitex3_pcollector.add_level(pixel_count_smooth_multitex3);
- #endif // DO_PSTATS
- GraphicsStateGuardian::end_draw_primitives();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::framebuffer_copy_to_texture
- // Access: Public, Virtual
- // Description: Copy the pixels within the indicated display
- // region from the framebuffer into texture memory.
- //
- // If z > -1, it is the cube map index into which to
- // copy.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
- const RenderBuffer &rb) {
- nassertr(tex != NULL && dr != NULL, false);
-
- int xo, yo, w, h;
- dr->get_region_pixels_i(xo, yo, w, h);
- tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgba);
- int view = dr->get_tex_view_offset();
- TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
- nassertr(tc != (TextureContext *)NULL, false);
- TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
- GLTexture *gltex = >c->_gltex;
- if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), 1)) {
- return false;
- }
- LColor border_color = tex->get_border_color();
- gltex->border_color.v[0] = border_color[0];
- gltex->border_color.v[1] = border_color[1];
- gltex->border_color.v[2] = border_color[2];
- gltex->border_color.v[3] = border_color[3];
- PIXEL *ip = gltex->levels[0].pixmap + gltex->xsize * gltex->ysize;
- PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
- for (int y = 0; y < gltex->ysize; ++y) {
- ip -= gltex->xsize;
- memcpy(ip, fo, gltex->xsize * PSZB);
- fo += _c->zb->linesize / PSZB;
- }
- gtc->update_data_size_bytes(gltex->xsize * gltex->ysize * 4);
- gtc->mark_loaded();
- gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::framebuffer_copy_to_ram
- // Access: Public, Virtual
- // Description: Copy the pixels within the indicated display region
- // from the framebuffer into system memory, not texture
- // memory. Returns true on success, false on failure.
- //
- // This completely redefines the ram image of the
- // indicated texture.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
- const RenderBuffer &rb) {
- nassertr(tex != NULL && dr != NULL, false);
-
- int xo, yo, w, h;
- dr->get_region_pixels_i(xo, yo, w, h);
- Texture::TextureType texture_type;
- int z_size;
- if (z >= 0) {
- texture_type = Texture::TT_cube_map;
- z_size = 6;
- } else {
- texture_type = Texture::TT_2d_texture;
- z_size = 1;
- }
- Texture::ComponentType component_type = Texture::T_unsigned_byte;
- Texture::Format format = Texture::F_rgba;
- if (tex->get_x_size() != w || tex->get_y_size() != h ||
- tex->get_z_size() != z_size ||
- tex->get_component_type() != component_type ||
- tex->get_format() != format ||
- tex->get_texture_type() != texture_type) {
- // Re-setup the texture; its properties have changed.
- tex->setup_texture(texture_type, w, h, z_size,
- component_type, format);
- }
- unsigned char *image_ptr = tex->modify_ram_image();
- size_t image_size = tex->get_ram_image_size();
- if (z >= 0) {
- nassertr(z < tex->get_z_size(), false);
- image_size = tex->get_expected_ram_page_size();
- image_ptr += z * image_size;
- }
- PIXEL *ip = (PIXEL *)(image_ptr + image_size);
- PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
- for (int y = 0; y < h; ++y) {
- ip -= w;
- #ifndef WORDS_BIGENDIAN
- // On a little-endian machine, we can copy the whole row at a time.
- memcpy(ip, fo, w * PSZB);
- #else
- // On a big-endian machine, we have to reverse the color-component order.
- const char *source = (const char *)fo;
- const char *stop = (const char *)fo + w * PSZB;
- char *dest = (char *)ip;
- while (source < stop) {
- char b = source[0];
- char g = source[1];
- char r = source[2];
- char a = source[3];
- dest[0] = a;
- dest[1] = r;
- dest[2] = g;
- dest[3] = b;
- dest += 4;
- source += 4;
- }
- #endif
- fo += _c->zb->linesize / PSZB;
- }
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::set_state_and_transform
- // Access: Public, Virtual
- // Description: Simultaneously resets the render state and the
- // transform state.
- //
- // This transform specified is the "internal" net
- // transform, already converted into the GSG's internal
- // coordinate space by composing it to
- // get_cs_transform(). (Previously, this used to be the
- // "external" net transform, with the assumption that
- // that GSG would convert it internally, but that is no
- // longer the case.)
- //
- // Special case: if (state==NULL), then the target
- // state is already stored in _target.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- set_state_and_transform(const RenderState *target,
- const TransformState *transform) {
- #ifndef NDEBUG
- if (tinydisplay_cat.is_spam()) {
- tinydisplay_cat.spam()
- << "Setting GSG state to " << (void *)target << ":\n";
- target->write(tinydisplay_cat.spam(false), 2);
- transform->write(tinydisplay_cat.spam(false), 2);
- }
- #endif
- _state_pcollector.add_level(1);
- PStatTimer timer1(_draw_set_state_pcollector);
- if (transform != _internal_transform) {
- PStatTimer timer(_draw_set_state_transform_pcollector);
- _state_pcollector.add_level(1);
- _internal_transform = transform;
- do_issue_transform();
- }
- if (target == _state_rs && (_state_mask | _inv_state_mask).is_all_on()) {
- return;
- }
- _target_rs = target;
- int color_slot = ColorAttrib::get_class_slot();
- int color_scale_slot = ColorScaleAttrib::get_class_slot();
- if (_target_rs->get_attrib(color_slot) != _state_rs->get_attrib(color_slot) ||
- _target_rs->get_attrib(color_scale_slot) != _state_rs->get_attrib(color_scale_slot) ||
- !_state_mask.get_bit(color_slot) ||
- !_state_mask.get_bit(color_scale_slot)) {
- PStatTimer timer(_draw_set_state_color_pcollector);
- do_issue_color();
- do_issue_color_scale();
- _state_mask.set_bit(color_slot);
- _state_mask.set_bit(color_scale_slot);
- }
- int cull_face_slot = CullFaceAttrib::get_class_slot();
- if (_target_rs->get_attrib(cull_face_slot) != _state_rs->get_attrib(cull_face_slot) ||
- !_state_mask.get_bit(cull_face_slot)) {
- PStatTimer timer(_draw_set_state_cull_face_pcollector);
- do_issue_cull_face();
- _state_mask.set_bit(cull_face_slot);
- }
- int depth_offset_slot = DepthOffsetAttrib::get_class_slot();
- if (_target_rs->get_attrib(depth_offset_slot) != _state_rs->get_attrib(depth_offset_slot) ||
- !_state_mask.get_bit(depth_offset_slot)) {
- //PStatTimer timer(_draw_set_state_depth_offset_pcollector);
- do_issue_depth_offset();
- _state_mask.set_bit(depth_offset_slot);
- }
- int rescale_normal_slot = RescaleNormalAttrib::get_class_slot();
- if (_target_rs->get_attrib(rescale_normal_slot) != _state_rs->get_attrib(rescale_normal_slot) ||
- !_state_mask.get_bit(rescale_normal_slot)) {
- PStatTimer timer(_draw_set_state_rescale_normal_pcollector);
- do_issue_rescale_normal();
- _state_mask.set_bit(rescale_normal_slot);
- }
- int render_mode_slot = RenderModeAttrib::get_class_slot();
- if (_target_rs->get_attrib(render_mode_slot) != _state_rs->get_attrib(render_mode_slot) ||
- !_state_mask.get_bit(render_mode_slot)) {
- PStatTimer timer(_draw_set_state_render_mode_pcollector);
- do_issue_render_mode();
- _state_mask.set_bit(render_mode_slot);
- }
- int texture_slot = TextureAttrib::get_class_slot();
- if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
- !_state_mask.get_bit(texture_slot)) {
- PStatTimer timer(_draw_set_state_texture_pcollector);
- determine_target_texture();
- do_issue_texture();
- _state_mask.set_bit(texture_slot);
- }
- int material_slot = MaterialAttrib::get_class_slot();
- if (_target_rs->get_attrib(material_slot) != _state_rs->get_attrib(material_slot) ||
- !_state_mask.get_bit(material_slot)) {
- PStatTimer timer(_draw_set_state_material_pcollector);
- do_issue_material();
- _state_mask.set_bit(material_slot);
- }
- int light_slot = LightAttrib::get_class_slot();
- if (_target_rs->get_attrib(light_slot) != _state_rs->get_attrib(light_slot) ||
- !_state_mask.get_bit(light_slot)) {
- PStatTimer timer(_draw_set_state_light_pcollector);
- do_issue_light();
- _state_mask.set_bit(light_slot);
- }
- int scissor_slot = ScissorAttrib::get_class_slot();
- if (_target_rs->get_attrib(scissor_slot) != _state_rs->get_attrib(scissor_slot) ||
- !_state_mask.get_bit(scissor_slot)) {
- PStatTimer timer(_draw_set_state_scissor_pcollector);
- do_issue_scissor();
- _state_mask.set_bit(scissor_slot);
- }
- _state_rs = _target_rs;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::prepare_texture
- // Access: Public, Virtual
- // Description: Creates whatever structures the GSG requires to
- // represent the texture internally, and returns a
- // newly-allocated TextureContext object with this data.
- // It is the responsibility of the calling function to
- // later call release_texture() with this same pointer
- // (which will also delete the pointer).
- //
- // This function should not be called directly to
- // prepare a texture. Instead, call Texture::prepare().
- ////////////////////////////////////////////////////////////////////
- TextureContext *TinyGraphicsStateGuardian::
- prepare_texture(Texture *tex, int view) {
- switch (tex->get_texture_type()) {
- case Texture::TT_1d_texture:
- case Texture::TT_2d_texture:
- // These are supported.
- break;
- default:
- // Anything else is not supported.
- tinydisplay_cat.info()
- << "Not loading texture " << tex->get_name() << ": "
- << tex->get_texture_type() << "\n";
- return NULL;
- }
- // Even though the texture might be compressed now, it might have an
- // available uncompressed version that we can load. So don't reject
- // it out-of-hand just because it's compressed.
- /*
- if (tex->get_ram_image_compression() != Texture::CM_off) {
- tinydisplay_cat.info()
- << "Not loading texture " << tex->get_name() << ": "
- << tex->get_ram_image_compression() << "\n";
- return NULL;
- }
- */
- TinyTextureContext *gtc = new TinyTextureContext(_prepared_objects, tex, view);
- return gtc;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::update_texture
- // Access: Public, Virtual
- // Description: Ensures that the current Texture data is refreshed
- // onto the GSG. This means updating the texture
- // properties and/or re-uploading the texture image, if
- // necessary. This should only be called within the
- // draw thread.
- //
- // If force is true, this function will not return until
- // the texture has been fully uploaded. If force is
- // false, the function may choose to upload a simple
- // version of the texture instead, if the texture is not
- // fully resident (and if get_incomplete_render() is
- // true).
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- update_texture(TextureContext *tc, bool force) {
- apply_texture(tc);
- TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
- GLTexture *gltex = >c->_gltex;
- if (gtc->was_image_modified() || gltex->num_levels == 0) {
- // If the texture image was modified, reload the texture.
- bool okflag = upload_texture(gtc, force);
- if (!okflag) {
- tinydisplay_cat.error()
- << "Could not load " << *gtc->get_texture() << "\n";
- return false;
- }
- }
- gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::update_texture
- // Access: Public
- // Description: Ensures that the current Texture data is refreshed
- // onto the GSG. This means updating the texture
- // properties and/or re-uploading the texture image, if
- // necessary. This should only be called within the
- // draw thread.
- //
- // If force is true, this function will not return until
- // the texture has been fully uploaded. If force is
- // false, the function may choose to upload a simple
- // version of the texture instead, if the texture is not
- // fully resident (and if get_incomplete_render() is
- // true).
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- update_texture(TextureContext *tc, bool force, int stage_index) {
- if (!update_texture(tc, force)) {
- return false;
- }
- TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
- GLTexture *gltex = >c->_gltex;
- _c->current_textures[stage_index] = gltex;
- ZTextureDef *texture_def = &_c->zb->current_textures[stage_index];
- texture_def->levels = gltex->levels;
- texture_def->s_max = gltex->s_max;
- texture_def->t_max = gltex->t_max;
- const V4 &bc = gltex->border_color;
- int r = (int)(bc.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN)
- + ZB_POINT_RED_MIN);
- int g = (int)(bc.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN)
- + ZB_POINT_GREEN_MIN);
- int b = (int)(bc.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN)
- + ZB_POINT_BLUE_MIN);
- int a = (int)(bc.v[3] * (ZB_POINT_ALPHA_MAX - ZB_POINT_ALPHA_MIN)
- + ZB_POINT_ALPHA_MIN);
- texture_def->border_color = RGBA_TO_PIXEL(r, g, b, a);
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::release_texture
- // Access: Public, Virtual
- // Description: Frees the GL resources previously allocated for the
- // texture. This function should never be called
- // directly; instead, call Texture::release() (or simply
- // let the Texture destruct).
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- release_texture(TextureContext *tc) {
- TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
- _texturing_state = 0; // just in case
- GLTexture *gltex = >c->_gltex;
- if (gltex->allocated_buffer != NULL) {
- nassertv(gltex->num_levels != 0);
- TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount);
- PANDA_FREE_ARRAY(gltex->allocated_buffer);
- gltex->allocated_buffer = NULL;
- gltex->total_bytecount = 0;
- gltex->num_levels = 0;
- } else {
- nassertv(gltex->num_levels == 0);
- }
- gtc->dequeue_lru();
- delete gtc;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_light
- // Access: Protected, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_light() {
- // Initialize the current ambient light total and newly enabled
- // light list
- LColor cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
- int num_enabled = 0;
- int num_on_lights = 0;
- const LightAttrib *target_light = DCAST(LightAttrib, _target_rs->get_attrib_def(LightAttrib::get_class_slot()));
- if (display_cat.is_spam()) {
- display_cat.spam()
- << "do_issue_light: " << target_light << "\n";
- }
- // First, release all of the previously-assigned lights.
- clear_light_state();
- // Now, assign new lights.
- if (target_light != (LightAttrib *)NULL) {
- CPT(LightAttrib) new_light = target_light->filter_to_max(_max_lights);
- if (display_cat.is_spam()) {
- new_light->write(display_cat.spam(false), 2);
- }
- num_on_lights = new_light->get_num_on_lights();
- for (int li = 0; li < num_on_lights; li++) {
- NodePath light = new_light->get_on_light(li);
- nassertv(!light.is_empty());
- Light *light_obj = light.node()->as_light();
- nassertv(light_obj != (Light *)NULL);
- _lighting_enabled = true;
- _c->lighting_enabled = true;
- if (light_obj->get_type() == AmbientLight::get_class_type()) {
- // Accumulate all of the ambient lights together into one.
- cur_ambient_light += light_obj->get_color();
- } else {
- // Other kinds of lights each get their own GLLight object.
- light_obj->bind(this, light, num_enabled);
- num_enabled++;
- // Handle the diffuse color here, since all lights have this
- // property.
- GLLight *gl_light = _c->first_light;
- nassertv(gl_light != NULL);
- const LColor &diffuse = light_obj->get_color();
- gl_light->diffuse.v[0] = diffuse[0];
- gl_light->diffuse.v[1] = diffuse[1];
- gl_light->diffuse.v[2] = diffuse[2];
- gl_light->diffuse.v[3] = diffuse[3];
- }
- }
- }
- _c->ambient_light_model.v[0] = cur_ambient_light[0];
- _c->ambient_light_model.v[1] = cur_ambient_light[1];
- _c->ambient_light_model.v[2] = cur_ambient_light[2];
- _c->ambient_light_model.v[3] = cur_ambient_light[3];
- // Changing the lighting state means we need to reapply the
- // transform in begin_draw_primitives().
- _transform_stale = true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::bind_light
- // Access: Public, Virtual
- // Description: Called the first time a particular light has been
- // bound to a given id within a frame, this should set
- // up the associated hardware light with the light's
- // properties.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
- pair<Lights::iterator, bool> lookup = _plights.insert(Lights::value_type(light, GLLight()));
- GLLight *gl_light = &(*lookup.first).second;
- if (lookup.second) {
- // It's a brand new light. Define it.
- memset(gl_light, 0, sizeof(GLLight));
- const LColor &specular = light_obj->get_specular_color();
- gl_light->specular.v[0] = specular[0];
- gl_light->specular.v[1] = specular[1];
- gl_light->specular.v[2] = specular[2];
- gl_light->specular.v[3] = specular[3];
- // Position needs to specify x, y, z, and w
- // w == 1 implies non-infinite position
- CPT(TransformState) render_transform =
- _cs_transform->compose(_scene_setup->get_world_transform());
- CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
- CPT(TransformState) net_transform = render_transform->compose(transform);
- LPoint3 pos = light_obj->get_point() * net_transform->get_mat();
- gl_light->position.v[0] = pos[0];
- gl_light->position.v[1] = pos[1];
- gl_light->position.v[2] = pos[2];
- gl_light->position.v[3] = 1.0f;
- // Exponent == 0 implies uniform light distribution
- gl_light->spot_exponent = 0.0f;
- // Cutoff == 180 means uniform point light source
- gl_light->spot_cutoff = 180.0f;
- const LVecBase3 &att = light_obj->get_attenuation();
- gl_light->attenuation[0] = att[0];
- gl_light->attenuation[1] = att[1];
- gl_light->attenuation[2] = att[2];
- }
- nassertv(gl_light->next == NULL);
- // Add it to the linked list of active lights.
- gl_light->next = _c->first_light;
- _c->first_light = gl_light;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::bind_light
- // Access: Public, Virtual
- // Description: Called the first time a particular light has been
- // bound to a given id within a frame, this should set
- // up the associated hardware light with the light's
- // properties.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
- pair<Lights::iterator, bool> lookup = _dlights.insert(Lights::value_type(light, GLLight()));
- GLLight *gl_light = &(*lookup.first).second;
- if (lookup.second) {
- // It's a brand new light. Define it.
- memset(gl_light, 0, sizeof(GLLight));
- const LColor &specular = light_obj->get_specular_color();
- gl_light->specular.v[0] = specular[0];
- gl_light->specular.v[1] = specular[1];
- gl_light->specular.v[2] = specular[2];
- gl_light->specular.v[3] = specular[3];
- // Position needs to specify x, y, z, and w
- // w == 0 implies light is at infinity
- CPT(TransformState) render_transform =
- _cs_transform->compose(_scene_setup->get_world_transform());
- CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
- CPT(TransformState) net_transform = render_transform->compose(transform);
- LVector3 dir = light_obj->get_direction() * net_transform->get_mat();
- dir.normalize();
- gl_light->position.v[0] = -dir[0];
- gl_light->position.v[1] = -dir[1];
- gl_light->position.v[2] = -dir[2];
- gl_light->position.v[3] = 0.0f;
- gl_light->norm_position.v[0] = -dir[0];
- gl_light->norm_position.v[1] = -dir[1];
- gl_light->norm_position.v[2] = -dir[2];
- gl_V3_Norm(&gl_light->norm_position);
- // Exponent == 0 implies uniform light distribution
- gl_light->spot_exponent = 0.0f;
- // Cutoff == 180 means uniform point light source
- gl_light->spot_cutoff = 180.0f;
- // Default attenuation values (only spotlight and point light can
- // modify these)
- gl_light->attenuation[0] = 1.0f;
- gl_light->attenuation[1] = 0.0f;
- gl_light->attenuation[2] = 0.0f;
- }
- nassertv(gl_light->next == NULL);
- // Add it to the linked list of active lights.
- gl_light->next = _c->first_light;
- _c->first_light = gl_light;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::bind_light
- // Access: Public, Virtual
- // Description: Called the first time a particular light has been
- // bound to a given id within a frame, this should set
- // up the associated hardware light with the light's
- // properties.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
- pair<Lights::iterator, bool> lookup = _plights.insert(Lights::value_type(light, GLLight()));
- GLLight *gl_light = &(*lookup.first).second;
- if (lookup.second) {
- // It's a brand new light. Define it.
- memset(gl_light, 0, sizeof(GLLight));
- const LColor &specular = light_obj->get_specular_color();
- gl_light->specular.v[0] = specular[0];
- gl_light->specular.v[1] = specular[1];
- gl_light->specular.v[2] = specular[2];
- gl_light->specular.v[3] = specular[3];
-
- Lens *lens = light_obj->get_lens();
- nassertv(lens != (Lens *)NULL);
- // Position needs to specify x, y, z, and w
- // w == 1 implies non-infinite position
- CPT(TransformState) render_transform =
- _cs_transform->compose(_scene_setup->get_world_transform());
- CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
- CPT(TransformState) net_transform = render_transform->compose(transform);
- const LMatrix4 &light_mat = net_transform->get_mat();
- LPoint3 pos = lens->get_nodal_point() * light_mat;
- LVector3 dir = lens->get_view_vector() * light_mat;
- dir.normalize();
- gl_light->position.v[0] = pos[0];
- gl_light->position.v[1] = pos[1];
- gl_light->position.v[2] = pos[2];
- gl_light->position.v[3] = 1.0f;
- gl_light->spot_direction.v[0] = dir[0];
- gl_light->spot_direction.v[1] = dir[1];
- gl_light->spot_direction.v[2] = dir[2];
- gl_light->norm_spot_direction.v[0] = dir[0];
- gl_light->norm_spot_direction.v[1] = dir[1];
- gl_light->norm_spot_direction.v[2] = dir[2];
- gl_V3_Norm(&gl_light->norm_spot_direction);
- gl_light->spot_exponent = light_obj->get_exponent();
- gl_light->spot_cutoff = lens->get_hfov() * 0.5f;
- const LVecBase3 &att = light_obj->get_attenuation();
- gl_light->attenuation[0] = att[0];
- gl_light->attenuation[1] = att[1];
- gl_light->attenuation[2] = att[2];
- }
- nassertv(gl_light->next == NULL);
- // Add it to the linked list of active lights.
- gl_light->next = _c->first_light;
- _c->first_light = gl_light;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_transform
- // Access: Protected
- // Description: Sends the indicated transform matrix to the graphics
- // API to be applied to future vertices.
- //
- // This transform is the internal_transform, already
- // converted into the GSG's internal coordinate system.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_transform() {
- _transform_state_pcollector.add_level(1);
- _transform_stale = true;
- if (_auto_rescale_normal) {
- do_auto_rescale_normal();
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_render_mode
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_render_mode() {
- const RenderModeAttrib *target_render_mode = DCAST(RenderModeAttrib, _target_rs->get_attrib_def(RenderModeAttrib::get_class_slot()));
- _filled_flat = false;
- switch (target_render_mode->get_mode()) {
- case RenderModeAttrib::M_unchanged:
- case RenderModeAttrib::M_filled:
- _c->draw_triangle_front = gl_draw_triangle_fill;
- _c->draw_triangle_back = gl_draw_triangle_fill;
- break;
- case RenderModeAttrib::M_filled_flat:
- _c->draw_triangle_front = gl_draw_triangle_fill;
- _c->draw_triangle_back = gl_draw_triangle_fill;
- _filled_flat = true;
- break;
- case RenderModeAttrib::M_wireframe:
- _c->draw_triangle_front = gl_draw_triangle_line;
- _c->draw_triangle_back = gl_draw_triangle_line;
- break;
- case RenderModeAttrib::M_point:
- _c->draw_triangle_front = gl_draw_triangle_point;
- _c->draw_triangle_back = gl_draw_triangle_point;
- break;
- default:
- tinydisplay_cat.error()
- << "Unknown render mode " << (int)target_render_mode->get_mode() << endl;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_rescale_normal
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_rescale_normal() {
- const RescaleNormalAttrib *target_rescale_normal = DCAST(RescaleNormalAttrib, _target_rs->get_attrib_def(RescaleNormalAttrib::get_class_slot()));
- RescaleNormalAttrib::Mode mode = target_rescale_normal->get_mode();
- _auto_rescale_normal = false;
- switch (mode) {
- case RescaleNormalAttrib::M_none:
- _c->normalize_enabled = false;
- _c->normal_scale = 1.0f;
- break;
- case RescaleNormalAttrib::M_normalize:
- _c->normalize_enabled = true;
- _c->normal_scale = 1.0f;
- break;
- case RescaleNormalAttrib::M_rescale:
- case RescaleNormalAttrib::M_auto:
- _auto_rescale_normal = true;
- do_auto_rescale_normal();
- break;
- default:
- tinydisplay_cat.error()
- << "Unknown rescale_normal mode " << (int)mode << endl;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_depth_offset
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_depth_offset() {
- const DepthOffsetAttrib *target_depth_offset = DCAST(DepthOffsetAttrib, _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot()));
- int offset = target_depth_offset->get_offset();
- _c->zbias = offset;
- PN_stdfloat min_value = target_depth_offset->get_min_value();
- PN_stdfloat max_value = target_depth_offset->get_max_value();
- if (min_value == 0.0f && max_value == 1.0f) {
- _c->has_zrange = false;
- } else {
- _c->has_zrange = true;
- _c->zmin = min_value;
- _c->zrange = max_value - min_value;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_cull_face
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_cull_face() {
- const CullFaceAttrib *target_cull_face = DCAST(CullFaceAttrib, _target_rs->get_attrib_def(CullFaceAttrib::get_class_slot()));
- CullFaceAttrib::Mode mode = target_cull_face->get_effective_mode();
- switch (mode) {
- case CullFaceAttrib::M_cull_none:
- _c->cull_face_enabled = false;
- break;
- case CullFaceAttrib::M_cull_clockwise:
- _c->cull_face_enabled = true;
- _c->cull_clockwise = true;
- break;
- case CullFaceAttrib::M_cull_counter_clockwise:
- _c->cull_face_enabled = true;
- _c->cull_clockwise = false;
- break;
- default:
- tinydisplay_cat.error()
- << "invalid cull face mode " << (int)mode << endl;
- break;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_material
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_material() {
- static Material empty;
- const MaterialAttrib *target_material = DCAST(MaterialAttrib, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()));
- const Material *material;
- if (target_material == (MaterialAttrib *)NULL ||
- target_material->is_off()) {
- material = ∅
- } else {
- material = target_material->get_material();
- }
- // Apply the material parameters to the front face.
- setup_material(&_c->materials[0], material);
- if (material->get_twoside()) {
- // Also apply the material parameters to the back face.
- setup_material(&_c->materials[1], material);
- }
- _c->local_light_model = material->get_local();
- _c->light_model_two_side = material->get_twoside();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_texture
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_texture() {
- _texturing_state = 0; // untextured
- _c->num_textures_enabled = 0;
- int num_stages = _target_texture->get_num_on_ff_stages();
- if (num_stages == 0) {
- // No texturing.
- return;
- }
- nassertv(num_stages <= MAX_TEXTURE_STAGES);
- bool all_replace = true;
- bool all_nearest = true;
- bool all_mipmap_nearest = true;
- bool any_mipmap = false;
- bool needs_general = false;
- Texture::QualityLevel best_quality_level = Texture::QL_default;
- for (int si = 0; si < num_stages; ++si) {
- TextureStage *stage = _target_texture->get_on_ff_stage(si);
- Texture *texture = _target_texture->get_on_texture(stage);
- nassertv(texture != (Texture *)NULL);
-
- int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
- TextureContext *tc = texture->prepare_now(view, _prepared_objects, this);
- if (tc == (TextureContext *)NULL) {
- // Something wrong with this texture; skip it.
- return;
- }
-
- // Then, turn on the current texture mode.
- if (!update_texture(tc, false, si)) {
- return;
- }
- // M_replace means M_replace; anything else is treated the same as
- // M_modulate.
- if (stage->get_mode() != TextureStage::M_replace) {
- all_replace = false;
- }
- Texture::QualityLevel quality_level = _texture_quality_override;
- if (quality_level == Texture::QL_default) {
- quality_level = texture->get_quality_level();
- }
- if (quality_level == Texture::QL_default) {
- quality_level = texture_quality_level;
- }
- best_quality_level = max(best_quality_level, quality_level);
- ZTextureDef *texture_def = &_c->zb->current_textures[si];
-
- // Fill in the filter func pointers. These may not actually get
- // called, if we decide below we can inline the filters.
- Texture::FilterType minfilter = texture->get_minfilter();
- Texture::FilterType magfilter = texture->get_magfilter();
- if (td_ignore_mipmaps && Texture::is_mipmap(minfilter)) {
- // Downgrade mipmaps.
- if (minfilter == Texture::FT_nearest_mipmap_nearest) {
- minfilter = Texture::FT_nearest;
- } else {
- minfilter = Texture::FT_linear;
- }
- }
- // Depending on this particular texture's quality level, we may
- // downgrade the requested filters.
- if (quality_level == Texture::QL_fastest) {
- minfilter = Texture::FT_nearest;
- magfilter = Texture::FT_nearest;
- } else if (quality_level == Texture::QL_normal) {
- if (Texture::is_mipmap(minfilter)) {
- minfilter = Texture::FT_nearest_mipmap_nearest;
- } else {
- minfilter = Texture::FT_nearest;
- }
- magfilter = Texture::FT_nearest;
- } else if (quality_level == Texture::QL_best) {
- minfilter = texture->get_effective_minfilter();
- magfilter = texture->get_effective_magfilter();
- }
- texture_def->tex_minfilter_func = get_tex_filter_func(minfilter);
- texture_def->tex_magfilter_func = get_tex_filter_func(magfilter);
-
- Texture::WrapMode wrap_u = texture->get_wrap_u();
- Texture::WrapMode wrap_v = texture->get_wrap_v();
- if (td_ignore_clamp) {
- wrap_u = Texture::WM_repeat;
- wrap_v = Texture::WM_repeat;
- }
- if (wrap_u != Texture::WM_repeat || wrap_v != Texture::WM_repeat) {
- // We have some nonstandard wrap mode. This will force the use
- // of the general texfilter mode.
- needs_general = true;
- // We need another level of indirection to implement the
- // different texcoord wrap modes. This means we will be using
- // the _impl function pointers, which are called by the toplevel
- // function.
- texture_def->tex_minfilter_func_impl = texture_def->tex_minfilter_func;
- texture_def->tex_magfilter_func_impl = texture_def->tex_magfilter_func;
- // Now assign the toplevel function pointer to do the
- // appropriate texture coordinate wrapping/clamping.
- texture_def->tex_minfilter_func = apply_wrap_general_minfilter;
- texture_def->tex_magfilter_func = apply_wrap_general_magfilter;
- texture_def->tex_wrap_u_func = get_tex_wrap_func(wrap_u);
- texture_def->tex_wrap_v_func = get_tex_wrap_func(wrap_v);
- // The following special cases are handled inline, rather than
- // relying on the above wrap function pointers.
- if (wrap_u && Texture::WM_border_color && wrap_v == Texture::WM_border_color) {
- texture_def->tex_minfilter_func = apply_wrap_border_color_minfilter;
- texture_def->tex_magfilter_func = apply_wrap_border_color_magfilter;
- } else if (wrap_u && Texture::WM_clamp && wrap_v == Texture::WM_clamp) {
- texture_def->tex_minfilter_func = apply_wrap_clamp_minfilter;
- texture_def->tex_magfilter_func = apply_wrap_clamp_magfilter;
- }
- }
- if (minfilter != Texture::FT_nearest || magfilter != Texture::FT_nearest) {
- all_nearest = false;
- }
- if (minfilter != Texture::FT_nearest_mipmap_nearest ||
- magfilter != Texture::FT_nearest) {
- all_mipmap_nearest = false;
- }
- if (Texture::is_mipmap(minfilter)) {
- any_mipmap = true;
- }
- }
- // Set a few state cache values.
- _c->num_textures_enabled = num_stages;
- _texture_replace = all_replace;
- _texturing_state = 2; // perspective (perspective-correct texturing)
- if (num_stages >= 3) {
- _texturing_state = 4; // multitex3
- } else if (num_stages == 2) {
- _texturing_state = 3; // multitex2
- } else if (!td_perspective_textures) {
- _texturing_state = 1; // textured (not perspective correct)
- }
- if (best_quality_level == Texture::QL_best) {
- // This is the most generic texture filter. Slow, but pretty.
- _texfilter_state = 2; // tgeneral
- if (!needs_general) {
- if (all_nearest) {
- // This case is inlined.
- _texfilter_state = 0; // tnearest
- } else if (all_mipmap_nearest) {
- // So is this case.
- _texfilter_state = 1; // tmipmap
- }
- }
- } else if (best_quality_level == Texture::QL_fastest) {
- // This is the cheapest texture filter. We disallow mipmaps and
- // perspective correctness.
- _texfilter_state = 0; // tnearest
- _texturing_state = 1; // textured (not perspective correct, no multitexture)
-
- } else {
- // This is the default texture filter. We use nearest sampling if
- // there are no mipmaps, and mipmap_nearest if there are any
- // mipmaps--these are the two inlined filters.
- _texfilter_state = 0; // tnearest
- if (any_mipmap) {
- _texfilter_state = 1; // tmipmap
- }
- if (needs_general) {
- // To support nonstandard texcoord wrapping etc, we need to
- // force the general texfilter mode.
- _texfilter_state = 2; // tgeneral
- }
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_issue_scissor
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_issue_scissor() {
- const ScissorAttrib *target_scissor = DCAST(ScissorAttrib, _target_rs->get_attrib_def(ScissorAttrib::get_class_slot()));
- const LVecBase4 &frame = target_scissor->get_frame();
- set_scissor(frame[0], frame[1], frame[2], frame[3]);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::set_scissor
- // Access: Private
- // Description: Sets up the scissor region, as a set of coordinates
- // relative to the current viewport.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
- _c->scissor.left = left;
- _c->scissor.right = right;
- _c->scissor.bottom = bottom;
- _c->scissor.top = top;
- gl_eval_viewport(_c);
- PN_stdfloat xsize = right - left;
- PN_stdfloat ysize = top - bottom;
- PN_stdfloat xcenter = (left + right) - 1.0f;
- PN_stdfloat ycenter = (bottom + top) - 1.0f;
- if (xsize == 0.0f || ysize == 0.0f) {
- // If the scissor region is zero, nothing will be drawn anyway, so
- // don't worry about it.
- _scissor_mat = TransformState::make_identity();
- } else {
- _scissor_mat = TransformState::make_scale(LVecBase3(1.0f / xsize, 1.0f / ysize, 1.0f))->compose(TransformState::make_pos(LPoint3(-xcenter, -ycenter, 0.0f)));
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::apply_texture
- // Access: Protected
- // Description: Updates the graphics state with the current
- // information for this texture, and makes it the
- // current texture available for rendering.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- apply_texture(TextureContext *tc) {
- TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
- gtc->set_active(true);
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::upload_texture
- // Access: Protected
- // Description: Uploads the texture image to the graphics state.
- //
- // The return value is true if successful, or false if
- // the texture has no image.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- upload_texture(TinyTextureContext *gtc, bool force) {
- Texture *tex = gtc->get_texture();
- if (_effective_incomplete_render && !force) {
- if (!tex->has_ram_image() && tex->might_have_ram_image() &&
- tex->has_simple_ram_image() &&
- !_loader.is_null()) {
- // If we don't have the texture data right now, go get it, but in
- // the meantime load a temporary simple image in its place.
- async_reload_texture(gtc);
- if (!tex->has_ram_image()) {
- if (gtc->was_simple_image_modified()) {
- return upload_simple_texture(gtc);
- }
- return true;
- }
- }
- }
- PStatTimer timer(_load_texture_pcollector);
- CPTA_uchar src_image = tex->get_uncompressed_ram_image();
- if (src_image.is_null()) {
- return false;
- }
- if (tinydisplay_cat.is_debug()) {
- tinydisplay_cat.debug()
- << "loading texture " << tex->get_name() << "\n";
- }
- #ifdef DO_PSTATS
- _data_transferred_pcollector.add_level(tex->get_ram_image_size());
- #endif
- GLTexture *gltex = >c->_gltex;
- int num_levels = 1;
- if (tex->uses_mipmaps()) {
- if (!tex->has_all_ram_mipmap_images()) {
- tex->generate_ram_mipmap_images();
- }
- num_levels = tex->get_num_ram_mipmap_images();
- }
- if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), num_levels)) {
- return false;
- }
- LColor border_color = tex->get_border_color();
- gltex->border_color.v[0] = border_color[0];
- gltex->border_color.v[1] = border_color[1];
- gltex->border_color.v[2] = border_color[2];
- gltex->border_color.v[3] = border_color[3];
- int bytecount = 0;
- int xsize = gltex->xsize;
- int ysize = gltex->ysize;
- for (int level = 0; level < gltex->num_levels; ++level) {
- ZTextureLevel *dest = &gltex->levels[level];
- switch (tex->get_format()) {
- case Texture::F_rgb:
- case Texture::F_rgb5:
- case Texture::F_rgb8:
- case Texture::F_rgb12:
- case Texture::F_rgb332:
- copy_rgb_image(dest, xsize, ysize, gtc, level);
- break;
- case Texture::F_rgba:
- case Texture::F_rgbm:
- case Texture::F_rgba4:
- case Texture::F_rgba5:
- case Texture::F_rgba8:
- case Texture::F_rgba12:
- case Texture::F_rgba16:
- case Texture::F_rgba32:
- copy_rgba_image(dest, xsize, ysize, gtc, level);
- break;
- case Texture::F_luminance:
- copy_lum_image(dest, xsize, ysize, gtc, level);
- break;
- case Texture::F_red:
- copy_one_channel_image(dest, xsize, ysize, gtc, level, 0);
- break;
- case Texture::F_green:
- copy_one_channel_image(dest, xsize, ysize, gtc, level, 1);
- break;
- case Texture::F_blue:
- copy_one_channel_image(dest, xsize, ysize, gtc, level, 2);
- break;
- case Texture::F_alpha:
- copy_alpha_image(dest, xsize, ysize, gtc, level);
- break;
- case Texture::F_luminance_alphamask:
- case Texture::F_luminance_alpha:
- copy_la_image(dest, xsize, ysize, gtc, level);
- break;
- }
- bytecount += xsize * ysize * 4;
- xsize = max(xsize >> 1, 1);
- ysize = max(ysize >> 1, 1);
- }
- gtc->update_data_size_bytes(bytecount);
-
- get_engine()->texture_uploaded(tex);
- gtc->mark_loaded();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::upload_simple_texture
- // Access: Protected
- // Description: This is used as a standin for upload_texture
- // when the texture in question is unavailable (e.g. it
- // hasn't yet been loaded from disk). Until the texture
- // image itself becomes available, we will render the
- // texture's "simple" image--a sharply reduced version
- // of the same texture.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- upload_simple_texture(TinyTextureContext *gtc) {
- PStatTimer timer(_load_texture_pcollector);
- Texture *tex = gtc->get_texture();
- nassertr(tex != (Texture *)NULL, false);
- const unsigned char *image_ptr = tex->get_simple_ram_image();
- if (image_ptr == (const unsigned char *)NULL) {
- return false;
- }
- size_t image_size = tex->get_simple_ram_image_size();
- int width = tex->get_simple_x_size();
- int height = tex->get_simple_y_size();
- #ifdef DO_PSTATS
- _data_transferred_pcollector.add_level(image_size);
- #endif
- GLTexture *gltex = >c->_gltex;
- if (tinydisplay_cat.is_debug()) {
- tinydisplay_cat.debug()
- << "loading simple image for " << tex->get_name() << "\n";
- }
- if (!setup_gltex(gltex, width, height, 1)) {
- return false;
- }
- LColor border_color = tex->get_border_color();
- gltex->border_color.v[0] = border_color[0];
- gltex->border_color.v[1] = border_color[1];
- gltex->border_color.v[2] = border_color[2];
- gltex->border_color.v[3] = border_color[3];
- ZTextureLevel *dest = &gltex->levels[0];
- memcpy(dest->pixmap, image_ptr, image_size);
- gtc->mark_simple_loaded();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::setup_gltex
- // Access: Private
- // Description: Sets the GLTexture size, bits, and masks
- // appropriately, and allocates space for a pixmap.
- // Does not fill the pixmap contents. Returns true if
- // the texture is a valid size, false otherwise.
- ////////////////////////////////////////////////////////////////////
- bool TinyGraphicsStateGuardian::
- setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
- int s_bits = get_tex_shift(x_size);
- int t_bits = get_tex_shift(y_size);
-
- if (s_bits < 0 || t_bits < 0) {
- return false;
- }
- num_levels = min(num_levels, MAX_MIPMAP_LEVELS);
- gltex->xsize = x_size;
- gltex->ysize = y_size;
- gltex->s_max = 1 << (s_bits + ZB_POINT_ST_FRAC_BITS);
- gltex->t_max = 1 << (t_bits + ZB_POINT_ST_FRAC_BITS);
- gltex->num_levels = num_levels;
-
- // We allocate one big buffer, large enough to include all the
- // mipmap levels, and index into that buffer for each level. This
- // cuts down on the number of individual alloc calls we have to make
- // for each texture.
- int total_bytecount = 0;
- // Count up the total bytes required for all mipmap levels.
- {
- int x = x_size;
- int y = y_size;
- for (int level = 0; level < num_levels; ++level) {
- int bytecount = x * y * 4;
- total_bytecount += bytecount;
- x = max((x >> 1), 1);
- y = max((y >> 1), 1);
- }
- }
- if (gltex->total_bytecount != total_bytecount) {
- if (gltex->allocated_buffer != NULL) {
- PANDA_FREE_ARRAY(gltex->allocated_buffer);
- TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount);
- }
- gltex->allocated_buffer = PANDA_MALLOC_ARRAY(total_bytecount);
- gltex->total_bytecount = total_bytecount;
- TinyTextureContext::get_class_type().inc_memory_usage(TypeHandle::MC_array, total_bytecount);
- }
- char *next_buffer = (char *)gltex->allocated_buffer;
- char *end_of_buffer = next_buffer + total_bytecount;
- int level = 0;
- ZTextureLevel *dest = NULL;
- while (level < num_levels) {
- dest = &gltex->levels[level];
- int bytecount = x_size * y_size * 4;
- dest->pixmap = (PIXEL *)next_buffer;
- next_buffer += bytecount;
- nassertr(next_buffer <= end_of_buffer, false);
- dest->s_mask = ((1 << (s_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
- dest->t_mask = ((1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
- dest->s_shift = (ZB_POINT_ST_FRAC_BITS + level);
- dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits + level);
-
- x_size = max((x_size >> 1), 1);
- y_size = max((y_size >> 1), 1);
- s_bits = max(s_bits - 1, 0);
- t_bits = max(t_bits - 1, 0);
- ++level;
- }
- // Fill out the remaining mipmap arrays with copies of the last
- // level, so we don't have to be concerned with running off the end
- // of this array while scanning out triangles.
- while (level < MAX_MIPMAP_LEVELS) {
- gltex->levels[level] = *dest;
- ++level;
- }
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::get_tex_shift
- // Access: Private
- // Description: Calculates the bit shift count, such that (1 << shift)
- // == size. Returns -1 if the size is not a power of 2
- // or is larger than our largest allowable size.
- ////////////////////////////////////////////////////////////////////
- int TinyGraphicsStateGuardian::
- get_tex_shift(int orig_size) {
- if ((orig_size & (orig_size - 1)) != 0) {
- // Not a power of 2.
- return -1;
- }
- if (orig_size > _max_texture_dimension) {
- return -1;
- }
- return count_bits_in_word((unsigned int)orig_size - 1);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::copy_lum_image
- // Access: Private, Static
- // Description: Copies and scales the one-channel luminance image
- // from the texture into the indicated ZTexture pixmap.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- copy_lum_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
- Texture *tex = gtc->get_texture();
- nassertv(tex->get_num_components() == 1);
- nassertv(tex->get_expected_mipmap_x_size(level) == xsize &&
- tex->get_expected_mipmap_y_size(level) == ysize);
- CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
- nassertv(!src_image.is_null());
- const unsigned char *src = src_image.p();
- size_t view_size = tex->get_ram_mipmap_view_size(level);
- src += view_size * gtc->get_view();
- // Component width, and offset to the high-order byte.
- int cw = tex->get_component_width();
- #ifdef WORDS_BIGENDIAN
- // Big-endian: the high-order byte is always first.
- static const int co = 0;
- #else
- // Little-endian: the high-order byte is last.
- int co = cw - 1;
- #endif
- unsigned int *dpix = (unsigned int *)dest->pixmap;
- nassertv(dpix != NULL);
- const unsigned char *spix = src;
- int pixel_count = xsize * ysize;
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(spix[co], spix[co], spix[co], 0xff);
- ++dpix;
- spix += cw;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::copy_alpha_image
- // Access: Private, Static
- // Description: Copies and scales the one-channel alpha image
- // from the texture into the indicated ZTexture pixmap.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- copy_alpha_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
- Texture *tex = gtc->get_texture();
- nassertv(tex->get_num_components() == 1);
- CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
- nassertv(!src_image.is_null());
- const unsigned char *src = src_image.p();
- size_t view_size = tex->get_ram_mipmap_view_size(level);
- src += view_size * gtc->get_view();
- // Component width, and offset to the high-order byte.
- int cw = tex->get_component_width();
- #ifdef WORDS_BIGENDIAN
- // Big-endian: the high-order byte is always first.
- static const int co = 0;
- #else
- // Little-endian: the high-order byte is last.
- int co = cw - 1;
- #endif
- unsigned int *dpix = (unsigned int *)dest->pixmap;
- nassertv(dpix != NULL);
- const unsigned char *spix = src;
- int pixel_count = xsize * ysize;
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(0xff, 0xff, 0xff, spix[co]);
- ++dpix;
- spix += cw;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::copy_one_channel_image
- // Access: Private, Static
- // Description: Copies and scales the one-channel image (with a
- // single channel, e.g. red, green, or blue) from
- // the texture into the indicated ZTexture pixmap.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- copy_one_channel_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level, int channel) {
- Texture *tex = gtc->get_texture();
- nassertv(tex->get_num_components() == 1);
- CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
- nassertv(!src_image.is_null());
- const unsigned char *src = src_image.p();
- size_t view_size = tex->get_ram_mipmap_view_size(level);
- src += view_size * gtc->get_view();
- // Component width, and offset to the high-order byte.
- int cw = tex->get_component_width();
- #ifdef WORDS_BIGENDIAN
- // Big-endian: the high-order byte is always first.
- static const int co = 0;
- #else
- // Little-endian: the high-order byte is last.
- int co = cw - 1;
- #endif
- unsigned int *dpix = (unsigned int *)dest->pixmap;
- nassertv(dpix != NULL);
- const unsigned char *spix = src;
- int pixel_count = xsize * ysize;
- switch (channel) {
- case 0:
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(spix[co], 0, 0, 0xff);
- ++dpix;
- spix += cw;
- }
- break;
- case 1:
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(0, spix[co], 0, 0xff);
- ++dpix;
- spix += cw;
- }
- break;
- case 2:
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(0, 0, spix[co], 0xff);
- ++dpix;
- spix += cw;
- }
- break;
- case 3:
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(0, 0, 0, spix[co]);
- ++dpix;
- spix += cw;
- }
- break;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::copy_la_image
- // Access: Private, Static
- // Description: Copies and scales the two-channel luminance-alpha
- // image from the texture into the indicated ZTexture
- // pixmap.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- copy_la_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
- Texture *tex = gtc->get_texture();
- nassertv(tex->get_num_components() == 2);
- CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
- nassertv(!src_image.is_null());
- const unsigned char *src = src_image.p();
- size_t view_size = tex->get_ram_mipmap_view_size(level);
- src += view_size * gtc->get_view();
- // Component width, and offset to the high-order byte.
- int cw = tex->get_component_width();
- #ifdef WORDS_BIGENDIAN
- // Big-endian: the high-order byte is always first.
- static const int co = 0;
- #else
- // Little-endian: the high-order byte is last.
- int co = cw - 1;
- #endif
- unsigned int *dpix = (unsigned int *)dest->pixmap;
- nassertv(dpix != NULL);
- const unsigned char *spix = src;
- int pixel_count = xsize * ysize;
- int inc = 2 * cw;
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(spix[co], spix[co], spix[co], spix[cw + co]);
- ++dpix;
- spix += inc;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::copy_rgb_image
- // Access: Private, Static
- // Description: Copies and scales the three-channel RGB image from
- // the texture into the indicated ZTexture pixmap.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- copy_rgb_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
- Texture *tex = gtc->get_texture();
- nassertv(tex->get_num_components() == 3);
- CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
- nassertv(!src_image.is_null());
- const unsigned char *src = src_image.p();
- size_t view_size = tex->get_ram_mipmap_view_size(level);
- src += view_size * gtc->get_view();
- // Component width, and offset to the high-order byte.
- int cw = tex->get_component_width();
- #ifdef WORDS_BIGENDIAN
- // Big-endian: the high-order byte is always first.
- static const int co = 0;
- #else
- // Little-endian: the high-order byte is last.
- int co = cw - 1;
- #endif
- unsigned int *dpix = (unsigned int *)dest->pixmap;
- nassertv(dpix != NULL);
- const unsigned char *spix = src;
- int pixel_count = xsize * ysize;
- int inc = 3 * cw;
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(spix[cw + cw + co], spix[cw + co], spix[co], 0xff);
- ++dpix;
- spix += inc;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::copy_rgba_image
- // Access: Private, Static
- // Description: Copies and scales the four-channel RGBA image from
- // the texture into the indicated ZTexture pixmap.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- copy_rgba_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
- Texture *tex = gtc->get_texture();
- nassertv(tex->get_num_components() == 4);
- CPTA_uchar src_image = tex->get_ram_mipmap_image(level);
- nassertv(!src_image.is_null());
- const unsigned char *src = src_image.p();
- size_t view_size = tex->get_ram_mipmap_view_size(level);
- src += view_size * gtc->get_view();
- // Component width, and offset to the high-order byte.
- int cw = tex->get_component_width();
- #ifdef WORDS_BIGENDIAN
- // Big-endian: the high-order byte is always first.
- static const int co = 0;
- #else
- // Little-endian: the high-order byte is last.
- int co = cw - 1;
- #endif
- unsigned int *dpix = (unsigned int *)dest->pixmap;
- nassertv(dpix != NULL);
- const unsigned char *spix = src;
- int pixel_count = xsize * ysize;
- int inc = 4 * cw;
- while (pixel_count-- > 0) {
- *dpix = RGBA8_TO_PIXEL(spix[cw + cw + co], spix[cw + co], spix[co], spix[cw + cw + cw + co]);
- ++dpix;
- spix += inc;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::setup_material
- // Access: Private
- // Description: Applies the desired parametesr to the indicated
- // GLMaterial object.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- setup_material(GLMaterial *gl_material, const Material *material) {
- const LColor &specular = material->get_specular();
- gl_material->specular.v[0] = specular[0];
- gl_material->specular.v[1] = specular[1];
- gl_material->specular.v[2] = specular[2];
- gl_material->specular.v[3] = specular[3];
- const LColor &emission = material->get_emission();
- gl_material->emission.v[0] = emission[0];
- gl_material->emission.v[1] = emission[1];
- gl_material->emission.v[2] = emission[2];
- gl_material->emission.v[3] = emission[3];
- gl_material->shininess = material->get_shininess();
- gl_material->shininess_i = (int)((material->get_shininess() / 128.0f) * SPECULAR_BUFFER_RESOLUTION);
- _color_material_flags = CMF_ambient | CMF_diffuse;
- if (material->has_ambient()) {
- const LColor &ambient = material->get_ambient();
- gl_material->ambient.v[0] = ambient[0];
- gl_material->ambient.v[1] = ambient[1];
- gl_material->ambient.v[2] = ambient[2];
- gl_material->ambient.v[3] = ambient[3];
- _color_material_flags &= ~CMF_ambient;
- }
- if (material->has_diffuse()) {
- const LColor &diffuse = material->get_diffuse();
- gl_material->diffuse.v[0] = diffuse[0];
- gl_material->diffuse.v[1] = diffuse[1];
- gl_material->diffuse.v[2] = diffuse[2];
- gl_material->diffuse.v[3] = diffuse[3];
- _color_material_flags &= ~CMF_diffuse;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::do_auto_rescale_normal
- // Access: Protected
- // Description: Sets the state to either rescale or normalize the
- // normals according to the current transform.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- do_auto_rescale_normal() {
- if (_internal_transform->has_uniform_scale()) {
- // There's a uniform scale; rescale the normals uniformly.
- _c->normalize_enabled = false;
- _c->normal_scale = _internal_transform->get_uniform_scale();
- } else {
- // If there's a non-uniform scale, normalize everything.
- _c->normalize_enabled = true;
- _c->normal_scale = 1.0f;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::load_matrix
- // Access: Private, Static
- // Description: Copies the Panda matrix stored in the indicated
- // TransformState object into the indicated TinyGL
- // matrix.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- load_matrix(M4 *matrix, const TransformState *transform) {
- const LMatrix4 &pm = transform->get_mat();
- for (int i = 0; i < 4; ++i) {
- matrix->m[0][i] = pm.get_cell(i, 0);
- matrix->m[1][i] = pm.get_cell(i, 1);
- matrix->m[2][i] = pm.get_cell(i, 2);
- matrix->m[3][i] = pm.get_cell(i, 3);
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::get_color_blend_op
- // Access: Private, Static
- // Description: Returns the integer element of store_pixel_funcs (as
- // defined by store_pixel.py) that corresponds to the
- // indicated ColorBlendAttrib operand code.
- ////////////////////////////////////////////////////////////////////
- int TinyGraphicsStateGuardian::
- get_color_blend_op(ColorBlendAttrib::Operand operand) {
- switch (operand) {
- case ColorBlendAttrib::O_zero:
- return 0;
- case ColorBlendAttrib::O_one:
- return 1;
- case ColorBlendAttrib::O_incoming_color:
- return 2;
- case ColorBlendAttrib::O_one_minus_incoming_color:
- return 3;
- case ColorBlendAttrib::O_fbuffer_color:
- return 4;
- case ColorBlendAttrib::O_one_minus_fbuffer_color:
- return 5;
- case ColorBlendAttrib::O_incoming_alpha:
- return 6;
- case ColorBlendAttrib::O_one_minus_incoming_alpha:
- return 7;
- case ColorBlendAttrib::O_fbuffer_alpha:
- return 8;
- case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
- return 9;
- case ColorBlendAttrib::O_constant_color:
- return 10;
- case ColorBlendAttrib::O_one_minus_constant_color:
- return 11;
- case ColorBlendAttrib::O_constant_alpha:
- return 12;
- case ColorBlendAttrib::O_one_minus_constant_alpha:
- return 13;
- case ColorBlendAttrib::O_incoming_color_saturate:
- return 1;
- case ColorBlendAttrib::O_color_scale:
- return 10;
- case ColorBlendAttrib::O_one_minus_color_scale:
- return 11;
- case ColorBlendAttrib::O_alpha_scale:
- return 12;
- case ColorBlendAttrib::O_one_minus_alpha_scale:
- return 13;
- }
- return 0;
- }
-
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::get_tex_filter_func
- // Access: Private, Static
- // Description: Returns the pointer to the appropriate filter
- // function according to the texture's filter type.
- ////////////////////////////////////////////////////////////////////
- ZB_lookupTextureFunc TinyGraphicsStateGuardian::
- get_tex_filter_func(Texture::FilterType filter) {
- switch (filter) {
- case Texture::FT_nearest:
- return &lookup_texture_nearest;
- case Texture::FT_linear:
- return &lookup_texture_bilinear;
- case Texture::FT_nearest_mipmap_nearest:
- return &lookup_texture_mipmap_nearest;
- case Texture::FT_nearest_mipmap_linear:
- return &lookup_texture_mipmap_linear;
-
- case Texture::FT_linear_mipmap_nearest:
- return &lookup_texture_mipmap_bilinear;
- case Texture::FT_linear_mipmap_linear:
- return &lookup_texture_mipmap_trilinear;
- default:
- return &lookup_texture_nearest;
- }
- }
-
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::get_tex_wrap_func
- // Access: Private, Static
- // Description: Returns the pointer to the appropriate wrap
- // function according to the texture's wrap mode.
- ////////////////////////////////////////////////////////////////////
- ZB_texWrapFunc TinyGraphicsStateGuardian::
- get_tex_wrap_func(Texture::WrapMode wrap_mode) {
- switch (wrap_mode) {
- case Texture::WM_clamp:
- case Texture::WM_border_color: // border_color is handled later.
- return &texcoord_clamp;
- case Texture::WM_repeat:
- case Texture::WM_invalid:
- return &texcoord_repeat;
- case Texture::WM_mirror:
- return &texcoord_mirror;
- case Texture::WM_mirror_once:
- return &texcoord_mirror_once;
- }
- return &texcoord_repeat;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::texgen_null
- // Access: Private, Static
- // Description: Generates invalid texture coordinates. Used when
- // texture coordinate params are invalid or unsupported.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- texgen_null(V2 &result, TinyGraphicsStateGuardian::TexCoordData &) {
- result.v[0] = 0.0;
- result.v[1] = 0.0;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::texgen_simple
- // Access: Private, Static
- // Description: Extracts a simple 2-d texture coordinate pair from
- // the vertex data, without applying any texture matrix.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- texgen_simple(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) {
- // No need to transform, so just extract as two-component.
- const LVecBase2 &d = tcdata._r1.get_data2();
- result.v[0] = d[0];
- result.v[1] = d[1];
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::texgen_simple
- // Access: Private, Static
- // Description: Extracts a simple 2-d texture coordinate pair from
- // the vertex data, and then applies a texture matrix.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- texgen_texmat(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) {
- // Transform texcoords as a four-component vector for most generality.
- LVecBase4 d = tcdata._r1.get_data4() * tcdata._mat;
- result.v[0] = d[0] / d[3];
- result.v[1] = d[1] / d[3];
- }
- ////////////////////////////////////////////////////////////////////
- // Function: TinyGraphicsStateGuardian::texgen_sphere_map
- // Access: Private, Static
- // Description: Computes appropriate sphere map texture coordinates
- // based on the eye normal coordinates.
- ////////////////////////////////////////////////////////////////////
- void TinyGraphicsStateGuardian::
- texgen_sphere_map(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) {
- // Get the normal and point in eye coordinates.
- LVector3 n = tcdata._mat.xform_vec(tcdata._r1.get_data3());
- LVector3 u = tcdata._mat.xform_point(tcdata._r2.get_data3());
- // Normalize the vectors.
- n.normalize();
- u.normalize();
- // Compute the reflection vector.
- LVector3 r = u - n * dot(n, u) * 2.0f;
-
- // compute the denominator, m.
- PN_stdfloat m = 2.0f * csqrt(r[0] * r[0] + r[1] * r[1] + (r[2] + 1.0f) * (r[2] + 1.0f));
- // Now we can compute the s and t coordinates.
- result.v[0] = r[0] / m + 0.5f;
- result.v[1] = r[1] / m + 0.5f;
- /*
- cerr << "n = " << n << " u = " << u << "\n"
- << " r = " << r << "\n"
- << " m = " << m << ", result = " << result.v[0] << " " << result.v[1]
- << "\n";
- */
- }
|