Image.cpp 145 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #include "../Platforms/iOS/iOS.h"
  4. namespace EE{
  5. /******************************************************************************/
  6. #include "Import/BC.h"
  7. #include "Import/ETC.h"
  8. #include "Import/PVRTC.h"
  9. #if DX9
  10. // make sure that there's direct mapping for 'D3DMULTISAMPLE_TYPE'
  11. ASSERT(D3DMULTISAMPLE_2_SAMPLES==2 && D3DMULTISAMPLE_3_SAMPLES==3 && D3DMULTISAMPLE_16_SAMPLES==16);
  12. // make sure that there's direct mapping for cube face
  13. ASSERT(D3DCUBEMAP_FACE_POSITIVE_X==DIR_RIGHT
  14. && D3DCUBEMAP_FACE_NEGATIVE_X==DIR_LEFT
  15. && D3DCUBEMAP_FACE_POSITIVE_Y==DIR_UP
  16. && D3DCUBEMAP_FACE_NEGATIVE_Y==DIR_DOWN
  17. && D3DCUBEMAP_FACE_POSITIVE_Z==DIR_FORWARD
  18. && D3DCUBEMAP_FACE_NEGATIVE_Z==DIR_BACK);
  19. #elif DX11
  20. // make sure that there's direct mapping for cube face
  21. ASSERT(D3D11_TEXTURECUBE_FACE_POSITIVE_X==DIR_RIGHT
  22. && D3D11_TEXTURECUBE_FACE_NEGATIVE_X==DIR_LEFT
  23. && D3D11_TEXTURECUBE_FACE_POSITIVE_Y==DIR_UP
  24. && D3D11_TEXTURECUBE_FACE_NEGATIVE_Y==DIR_DOWN
  25. && D3D11_TEXTURECUBE_FACE_POSITIVE_Z==DIR_FORWARD
  26. && D3D11_TEXTURECUBE_FACE_NEGATIVE_Z==DIR_BACK);
  27. #elif GL
  28. // make sure that there's direct mapping for cube face
  29. ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X-GL_TEXTURE_CUBE_MAP_POSITIVE_X==DIR_RIGHT
  30. && GL_TEXTURE_CUBE_MAP_NEGATIVE_X-GL_TEXTURE_CUBE_MAP_POSITIVE_X==DIR_LEFT
  31. && GL_TEXTURE_CUBE_MAP_POSITIVE_Y-GL_TEXTURE_CUBE_MAP_POSITIVE_X==DIR_UP
  32. && GL_TEXTURE_CUBE_MAP_NEGATIVE_Y-GL_TEXTURE_CUBE_MAP_POSITIVE_X==DIR_DOWN
  33. && GL_TEXTURE_CUBE_MAP_POSITIVE_Z-GL_TEXTURE_CUBE_MAP_POSITIVE_X==DIR_FORWARD
  34. && GL_TEXTURE_CUBE_MAP_NEGATIVE_Z-GL_TEXTURE_CUBE_MAP_POSITIVE_X==DIR_BACK);
  35. #endif
  36. #define GL_ETC1_RGB8 0x8D64
  37. #define GL_COMPRESSED_RGBA_S3TC_DXT1 0x83F1
  38. #define GL_COMPRESSED_RGBA_S3TC_DXT3 0x83F2
  39. #define GL_COMPRESSED_RGBA_S3TC_DXT5 0x83F3
  40. #define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
  41. #define GL_COMPRESSED_RGB8_ETC2 0x9274
  42. #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
  43. #define GL_COMPRESSED_RGBA8_ETC2 0x9278
  44. #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
  45. #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
  46. #define GL_BGR 0x80E0
  47. #define GL_BGRA 0x80E1
  48. #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
  49. #define GL_ALPHA8 0x803C
  50. #define GL_LUMINANCE8 0x8040
  51. #define GL_LUMINANCE8_ALPHA8 0x8045
  52. #define GL_LUMINANCE16 0x8042
  53. #define GL_LUMINANCE 0x1909
  54. #define GL_LUMINANCE_ALPHA 0x190A
  55. #define GL_TEXTURE_MAX_ANISOTROPY 0x84FE
  56. #define GL_HALF_FLOAT_OES 0x8D61
  57. #define GL_SWIZZLE (GL && !GL_ES) // Modern Desktop OpenGL (3.2) does not support GL_ALPHA8, GL_LUMINANCE8, GL_LUMINANCE8_ALPHA8, use swizzle instead
  58. /******************************************************************************/
  59. DEFINE_CACHE(Image, Images, ImagePtr, "Image");
  60. const ImagePtr ImageNull;
  61. static SyncLock ImageSoftLock; // it's important to use a separate lock from 'D._lock' so we don't need to wait for GPU to finish drawing
  62. /******************************************************************************/
  63. const ImageTypeInfo ImageTI[IMAGE_ALL_TYPES]= // !! in case multiple types have the same format, preferred version must be specified in 'ImageFormatToType' !!
  64. {
  65. {"None" , false, 0, 0, 0, 0, 0, 0, 0,0, 0, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_UNKNOWN, 0)},
  66. {"B8G8R8A8" , false, 4, 32, 8, 8, 8, 8, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_A8R8G8B8, DXGI_FORMAT_B8G8R8A8_UNORM, 0 )},
  67. {"R8G8B8A8" , false, 4, 32, 8, 8, 8, 8, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_A8B8G8R8, DXGI_FORMAT_R8G8B8A8_UNORM, GL_RGBA8)},
  68. {"R8G8B8" , false, 3, 24, 8, 8, 8, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_UNKNOWN , GL_RGB8 )},
  69. {"R8G8" , false, 2, 16, 8, 8, 0, 0, 0,0, 2, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_R8G8_UNORM , GL_RG8 )},
  70. {"R8" , false, 1, 8, 8, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_R8_UNORM , GL_R8 )},
  71. {"A8" , false, 1, 8, 0, 0, 0, 8, 0,0, 1, IMAGE_PRECISION_8 , GPU_API(D3DFMT_A8 , DXGI_FORMAT_A8_UNORM, GL_SWIZZLE ? GL_R8 : GL_ALPHA8 )},
  72. {"L8" , false, 1, 8, 0, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_8 , GPU_API(D3DFMT_L8 , DXGI_FORMAT_UNKNOWN , GL_SWIZZLE ? GL_R8 : GL_LUMINANCE8 )},
  73. {"L8A8" , false, 2, 16, 0, 0, 0, 8, 0,0, 2, IMAGE_PRECISION_8 , GPU_API(D3DFMT_A8L8, DXGI_FORMAT_UNKNOWN , GL_SWIZZLE ? GL_RG8 : GL_LUMINANCE8_ALPHA8)},
  74. {"BC1" , true , 0, 4, 5, 6, 5, 1, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_DXT1, DXGI_FORMAT_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1)},
  75. {"BC2" , true , 1, 8, 5, 6, 5, 4, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_DXT3, DXGI_FORMAT_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3)},
  76. {"BC3" , true , 1, 8, 5, 6, 5, 8, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_DXT5, DXGI_FORMAT_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5)},
  77. {"I8" , false, 1, 8, 8, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_UNKNOWN , 0)},
  78. {"I16" , false, 2, 16, 16, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_16, GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_UNKNOWN , 0)},
  79. {"I24" , false, 3, 24, 24, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_24, GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_UNKNOWN , 0)},
  80. {"I32" , false, 4, 32, 32, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_32, GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_UNKNOWN , 0)},
  81. {"F16" , false, 2, 16, 16, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_16, GPU_API(D3DFMT_R16F , DXGI_FORMAT_R16_FLOAT , GL_R16F )},
  82. {"F32" , false, 4, 32, 32, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_32, GPU_API(D3DFMT_R32F , DXGI_FORMAT_R32_FLOAT , GL_R32F )},
  83. {"F16_2" , false, 4, 32, 16,16, 0, 0, 0,0, 2, IMAGE_PRECISION_16, GPU_API(D3DFMT_G16R16F , DXGI_FORMAT_R16G16_FLOAT , GL_RG16F )},
  84. {"F32_2" , false, 8, 64, 32,32, 0, 0, 0,0, 2, IMAGE_PRECISION_32, GPU_API(D3DFMT_G32R32F , DXGI_FORMAT_R32G32_FLOAT , GL_RG32F )},
  85. {"F16_3" , false, 6, 48, 16,16,16, 0, 0,0, 3, IMAGE_PRECISION_16, GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_UNKNOWN , GL_RGB16F )},
  86. {"F32_3" , false, 12, 96, 32,32,32, 0, 0,0, 3, IMAGE_PRECISION_32, GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_R32G32B32_FLOAT , GL_RGB32F )},
  87. {"F16_4" , false, 8, 64, 16,16,16,16, 0,0, 4, IMAGE_PRECISION_16, GPU_API(D3DFMT_A16B16G16R16F, DXGI_FORMAT_R16G16B16A16_FLOAT, GL_RGBA16F)},
  88. {"F32_4" , false, 16,128, 32,32,32,32, 0,0, 4, IMAGE_PRECISION_32, GPU_API(D3DFMT_A32B32G32R32F, DXGI_FORMAT_R32G32B32A32_FLOAT, GL_RGBA32F)},
  89. {"PVRTC1_2" , true , 0, 2, 8, 8, 8, 8, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_UNKNOWN, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG)},
  90. {"PVRTC1_4" , true , 0, 4, 8, 8, 8, 8, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_UNKNOWN, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG)},
  91. {"ETC1" , true , 0, 4, 8, 8, 8, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_UNKNOWN, GL_ETC1_RGB8)},
  92. {"ETC2" , true , 0, 4, 8, 8, 8, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_UNKNOWN, GL_COMPRESSED_RGB8_ETC2)},
  93. {"ETC2_A1" , true , 0, 4, 8, 8, 8, 1, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_UNKNOWN, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2)},
  94. {"ETC2_A8" , true , 1, 8, 8, 8, 8, 8, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_UNKNOWN, GL_COMPRESSED_RGBA8_ETC2)},
  95. {"BC7" , true , 1, 8, 7, 7, 7, 8, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_BC7_UNORM, GL_COMPRESSED_RGBA_BPTC_UNORM)},
  96. {"R10G10B10A2", false, 4, 32, 10,10,10, 2, 0,0, 4, IMAGE_PRECISION_10, GPU_API(D3DFMT_A2B10G10R10, DXGI_FORMAT_R10G10B10A2_UNORM, GL_RGB10_A2)},
  97. {null , false, 0, 0, 0, 0, 0, 0, 0,0, 0, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_UNKNOWN , 0 )},
  98. {"B4G4R4X4" , false, 2, 16, 4, 4, 4, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_X4R4G4B4 , DXGI_FORMAT_UNKNOWN , 0 )},
  99. {"B4G4R4A4" , false, 2, 16, 4, 4, 4, 4, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_A4R4G4B4 , DXGI_FORMAT_UNKNOWN , 0 )},
  100. {"B5G5R5X1" , false, 2, 16, 5, 5, 5, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_X1R5G5B5 , DXGI_FORMAT_UNKNOWN , 0 )},
  101. {"B5G5R5A1" , false, 2, 16, 5, 5, 5, 1, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_A1R5G5B5 , DXGI_FORMAT_B5G5R5A1_UNORM , 0 )},
  102. {"B5G6R5" , false, 2, 16, 5, 6, 5, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_R5G6B5 , DXGI_FORMAT_B5G6R5_UNORM , 0 )},
  103. {"B8G8R8" , false, 3, 24, 8, 8, 8, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_R8G8B8 , DXGI_FORMAT_UNKNOWN , 0 )},
  104. {"B8G8R8X8" , false, 4, 32, 8, 8, 8, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_X8R8G8B8 , DXGI_FORMAT_B8G8R8X8_UNORM , 0 )},
  105. {"R8G8B8X8" , false, 4, 32, 8, 8, 8, 0, 0,0, 3, IMAGE_PRECISION_8 , GPU_API(D3DFMT_X8B8G8R8 , DXGI_FORMAT_UNKNOWN , 0 )},
  106. {"R8G8B8A8_SIGN", false, 4, 32, 8, 8, 8, 8, 0,0, 4, IMAGE_PRECISION_8 , GPU_API(D3DFMT_Q8W8V8U8 , DXGI_FORMAT_R8G8B8A8_SNORM , GL_RGBA8_SNORM )},
  107. {"R8G8_SIGN" , false, 2, 16, 8, 8, 0, 0, 0,0, 2, IMAGE_PRECISION_8 , GPU_API(D3DFMT_V8U8 , DXGI_FORMAT_R8G8_SNORM , GL_RG8_SNORM )},
  108. {"R8_SIGN" , false, 1, 8, 8, 0, 0, 0, 0,0, 1, IMAGE_PRECISION_8 , GPU_API(D3DFMT_UNKNOWN , DXGI_FORMAT_R8_SNORM , GL_R8_SNORM )},
  109. {"D16" , false, 2, 16, 0, 0, 0, 0, 16,0, 1, IMAGE_PRECISION_16, GPU_API(D3DFMT_D16 , DXGI_FORMAT_D16_UNORM , GL_DEPTH_COMPONENT16 )},
  110. {"D24X8" , false, 4, 32, 0, 0, 0, 0, 24,0, 1, IMAGE_PRECISION_24, GPU_API(D3DFMT_D24X8 , DXGI_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH_COMPONENT24 )},
  111. {"D24S8" , false, 4, 32, 0, 0, 0, 0, 24,8, 2, IMAGE_PRECISION_24, GPU_API(D3DFMT_D24S8 , DXGI_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8 )},
  112. {"D32" , false, 4, 32, 0, 0, 0, 0, 32,0, 1, IMAGE_PRECISION_32, GPU_API(D3DFMT_D32 , DXGI_FORMAT_D32_FLOAT , GL_DEPTH_COMPONENT32F)},
  113. {"RAWZ" , false, 4, 32, 0, 0, 0, 0, 24,8, 2, IMAGE_PRECISION_24, GPU_API(D3DFORMAT(MAKEFOURCC('R','A','W','Z')), DXGI_FORMAT_UNKNOWN , 0 )},
  114. {"INTZ" , false, 4, 32, 0, 0, 0, 0, 24,8, 2, IMAGE_PRECISION_24, GPU_API(D3DFORMAT(MAKEFOURCC('I','N','T','Z')), DXGI_FORMAT_UNKNOWN , 0 )},
  115. {"DF24" , false, 4, 32, 0, 0, 0, 0, 24,0, 1, IMAGE_PRECISION_24, GPU_API(D3DFORMAT(MAKEFOURCC('D','F','2','4')), DXGI_FORMAT_UNKNOWN , 0 )}, // DF24 does not have stencil buffer
  116. {"NULL" , false, 0, 0, 0, 0, 0, 0, 0,0, 0, IMAGE_PRECISION_8 , GPU_API(D3DFORMAT(MAKEFOURCC('N','U','L','L')), DXGI_FORMAT_UNKNOWN , 0 )},
  117. }; ASSERT(IMAGE_ALL_TYPES==52);
  118. /******************************************************************************/
  119. Bool IsSoft(IMAGE_MODE mode)
  120. {
  121. switch(mode)
  122. {
  123. default: return false;
  124. case IMAGE_SOFT:
  125. case IMAGE_SOFT_CUBE: return true;
  126. }
  127. }
  128. Bool IsHW(IMAGE_MODE mode)
  129. {
  130. switch(mode)
  131. {
  132. default: return true;
  133. case IMAGE_SOFT:
  134. case IMAGE_SOFT_CUBE: return false;
  135. }
  136. }
  137. Bool IsCube(IMAGE_MODE mode)
  138. {
  139. switch(mode)
  140. {
  141. default: return false;
  142. case IMAGE_CUBE :
  143. case IMAGE_SOFT_CUBE:
  144. case IMAGE_RT_CUBE : return true;
  145. }
  146. }
  147. /******************************************************************************/
  148. IMAGE_TYPE BytesToImageType(Int byte_pp)
  149. {
  150. switch(byte_pp)
  151. {
  152. default: return IMAGE_NONE;
  153. case 1: return IMAGE_I8;
  154. case 2: return IMAGE_I16;
  155. case 3: return IMAGE_I24;
  156. case 4: return IMAGE_I32;
  157. }
  158. }
  159. /******************************************************************************/
  160. Int PaddedWidth(Int w, Int h, Int mip, IMAGE_TYPE type)
  161. {
  162. if(type==IMAGE_PVRTC1_2 || type==IMAGE_PVRTC1_4)w=h=CeilPow2(Max(w, h)); // PVRTC1 must be square and power of 2
  163. Int mw=Max(1, w>>mip);
  164. if(ImageTI[type].compressed)switch(type)
  165. {
  166. case IMAGE_PVRTC1_2: return Max(Ceil8(mw), 16); // blocks are sized 8x4 pixels, min texture size is 16x8
  167. case IMAGE_PVRTC1_4: return Max(Ceil4(mw), 8); // blocks are sized 4x4 pixels, min texture size is 8x8
  168. default : return Ceil4(mw) ; // blocks are sized 4x4 pixels, min texture size is 4x4
  169. } return mw ;
  170. }
  171. Int PaddedHeight(Int w, Int h, Int mip, IMAGE_TYPE type)
  172. {
  173. if(type==IMAGE_PVRTC1_2 || type==IMAGE_PVRTC1_4)w=h=CeilPow2(Max(w, h)); // PVRTC1 must be square and power of 2
  174. Int mh=Max(1, h>>mip);
  175. if(ImageTI[type].compressed)switch(type)
  176. {
  177. case IMAGE_PVRTC1_2: return Max(Ceil4(mh), 8); // blocks are sized 8x4 pixels, min texture size is 16x8
  178. case IMAGE_PVRTC1_4: return Max(Ceil4(mh), 8); // blocks are sized 4x4 pixels, min texture size is 8x8
  179. default : return Ceil4(mh) ; // blocks are sized 4x4 pixels, min texture size is 4x4
  180. } return mh ;
  181. }
  182. Int ImagePitch(Int w, Int h, Int mip, IMAGE_TYPE type)
  183. {
  184. w=PaddedWidth(w, h, mip, type);
  185. return ImageTI[type].compressed ? w*ImageTI[type].bit_pp/2 : w*ImageTI[type].byte_pp; // all compressed formats use 4 rows per block (4*bit_pp/8 == bit_pp/2)
  186. }
  187. Int ImageBlocksY(Int w, Int h, Int mip, IMAGE_TYPE type)
  188. {
  189. h=PaddedHeight(w, h, mip, type);
  190. return ImageTI[type].compressed ? h/4 : h; // all compressed formats use 4 rows per block
  191. }
  192. Int ImageMipSize(Int w, Int h, Int mip, IMAGE_TYPE type)
  193. {
  194. return ImagePitch (w, h, mip, type)
  195. *ImageBlocksY(w, h, mip, type);
  196. }
  197. Int ImageMipSize(Int w, Int h, Int d, Int mip, IMAGE_TYPE type)
  198. {
  199. return ImageMipSize(w, h, mip, type)*Max(1, d>>mip);
  200. }
  201. UInt ImageSize(Int w, Int h, Int d, IMAGE_TYPE type, IMAGE_MODE mode, Int mip_maps)
  202. {
  203. UInt size=0; REP(mip_maps)size+=ImageMipSize(w, h, d, i, type); if(IsCube(mode))size*=6;
  204. return size;
  205. }
  206. /******************************************************************************/
  207. Int TotalMipMaps(Int w, Int h, Int d, IMAGE_TYPE type)
  208. {
  209. if(type==IMAGE_PVRTC1_2 || type==IMAGE_PVRTC1_4){w=CeilPow2(w); h=CeilPow2(h);} // PVRTC1 format supports only Pow2 sizes
  210. Int total=0; for(Int i=Max(w, h, d); i>=1; i>>=1)total++;
  211. return total;
  212. }
  213. static Bool ForceDisableMipMaps(C Image &image)
  214. {
  215. return D._tex_pow2 && (image.hwW()!=CeilPow2(image.hwW()) || image.hwH()!=CeilPow2(image.hwH()));
  216. }
  217. /******************************************************************************/
  218. Bool CompatibleLock(LOCK_MODE cur, LOCK_MODE lock)
  219. {
  220. switch(cur)
  221. {
  222. default : // no lock yet
  223. case LOCK_READ_WRITE: return true; // full access
  224. case LOCK_WRITE :
  225. case LOCK_APPEND : return lock==LOCK_WRITE || lock==LOCK_APPEND;
  226. case LOCK_READ : return lock==LOCK_READ;
  227. }
  228. }
  229. /******************************************************************************/
  230. GPU_API(D3DFORMAT, DXGI_FORMAT, UInt) ImageTypeToFormat(Int type ) {return InRange(type, ImageTI) ? ImageTI[type].format : GPU_API(D3DFMT_UNKNOWN, DXGI_FORMAT_UNKNOWN, 0);}
  231. IMAGE_TYPE ImageFormatToType(GPU_API(D3DFORMAT, DXGI_FORMAT, UInt) format
  232. #if GL
  233. , IMAGE_TYPE type
  234. #endif
  235. )
  236. {
  237. // check these which are listed multiple times (then return the preferred version), or not listed at all but known
  238. switch(format)
  239. {
  240. #if DX9
  241. case D3DFMT_UNKNOWN: return IMAGE_NONE;
  242. #elif DX11
  243. case DXGI_FORMAT_UNKNOWN: return IMAGE_NONE;
  244. case DXGI_FORMAT_BC1_TYPELESS :
  245. case DXGI_FORMAT_BC1_UNORM_SRGB: return IMAGE_BC1;
  246. case DXGI_FORMAT_BC2_TYPELESS :
  247. case DXGI_FORMAT_BC2_UNORM_SRGB: return IMAGE_BC2;
  248. case DXGI_FORMAT_BC3_TYPELESS :
  249. case DXGI_FORMAT_BC3_UNORM_SRGB: return IMAGE_BC3;
  250. case DXGI_FORMAT_BC7_TYPELESS :
  251. case DXGI_FORMAT_BC7_UNORM_SRGB: return IMAGE_BC7;
  252. case DXGI_FORMAT_R16_TYPELESS : return IMAGE_D16;
  253. case DXGI_FORMAT_R24G8_TYPELESS: return IMAGE_D24S8;
  254. case DXGI_FORMAT_R32_TYPELESS : return IMAGE_D32;
  255. case DXGI_FORMAT_D24_UNORM_S8_UINT: return IMAGE_D24S8;
  256. #elif GL
  257. case 0: return IMAGE_NONE;
  258. #if GL_SWIZZLE
  259. case GL_R8 : if(type==IMAGE_A8 || type==IMAGE_L8)return type; return IMAGE_R8;
  260. case GL_RG8: if(type==IMAGE_L8A8 )return type; return IMAGE_R8G8;
  261. #endif
  262. #endif
  263. }
  264. FREPA(ImageTI)if(ImageTI[i].format==format)return IMAGE_TYPE(i);
  265. return IMAGE_NONE;
  266. }
  267. /******************************************************************************/
  268. IMAGE_TYPE ImageTypeIncludeAlpha(IMAGE_TYPE type)
  269. {
  270. switch(type)
  271. {
  272. default: return type;
  273. case IMAGE_R8G8B8:
  274. case IMAGE_R8G8 :
  275. case IMAGE_R8 : return IMAGE_R8G8B8A8;
  276. case IMAGE_L8 :
  277. case IMAGE_I8 :
  278. case IMAGE_I16:
  279. case IMAGE_I24:
  280. case IMAGE_I32: return IMAGE_L8A8;
  281. case IMAGE_BC1: return IMAGE_BC7; // BC1 has only 1-bit alpha which is not enough
  282. case IMAGE_F16 :
  283. case IMAGE_F16_2:
  284. case IMAGE_F16_3: return IMAGE_F16_4;
  285. case IMAGE_F32 :
  286. case IMAGE_F32_2:
  287. case IMAGE_F32_3: return IMAGE_F32_4;
  288. case IMAGE_ETC1 :
  289. case IMAGE_ETC2 :
  290. case IMAGE_ETC2_A1: return IMAGE_ETC2_A8; // ETC2_A1 has only 1-bit alpha which is not enough
  291. }
  292. }
  293. IMAGE_TYPE ImageTypeExcludeAlpha(IMAGE_TYPE type)
  294. {
  295. switch(type)
  296. {
  297. default: return type;
  298. case IMAGE_R8G8B8A8: return IMAGE_R8G8B8;
  299. case IMAGE_B8G8R8A8: return IMAGE_B8G8R8;
  300. case IMAGE_L8A8: return IMAGE_L8;
  301. case IMAGE_BC2:
  302. case IMAGE_BC3:
  303. case IMAGE_BC7: return IMAGE_BC1;
  304. case IMAGE_F16_4: return IMAGE_F16_3;
  305. case IMAGE_F32_4: return IMAGE_F32_3;
  306. case IMAGE_ETC2_A1:
  307. case IMAGE_ETC2_A8: return IMAGE_ETC2;
  308. }
  309. }
  310. /******************************************************************************/
  311. #if GL
  312. UInt SourceGLFormat(IMAGE_TYPE type)
  313. {
  314. switch(type)
  315. {
  316. case IMAGE_I8 :
  317. case IMAGE_I16:
  318. case IMAGE_I24:
  319. case IMAGE_I32: return GL_LUMINANCE;
  320. #if GL_SWIZZLE
  321. case IMAGE_A8 : return GL_RED;
  322. case IMAGE_L8 : return GL_RED;
  323. case IMAGE_L8A8: return GL_RG;
  324. #else
  325. case IMAGE_A8 : return GL_ALPHA;
  326. case IMAGE_L8 : return GL_LUMINANCE;
  327. case IMAGE_L8A8: return GL_LUMINANCE_ALPHA;
  328. #endif
  329. case IMAGE_F16 :
  330. case IMAGE_F32 :
  331. case IMAGE_R8 :
  332. case IMAGE_R8_SIGN: return GL_RED;
  333. case IMAGE_F16_2 :
  334. case IMAGE_F32_2 :
  335. case IMAGE_R8G8 :
  336. case IMAGE_R8G8_SIGN: return GL_RG;
  337. case IMAGE_F16_3 :
  338. case IMAGE_F32_3 :
  339. case IMAGE_R8G8B8 :
  340. case IMAGE_R8G8B8X8: return GL_RGB;
  341. case IMAGE_F16_4 :
  342. case IMAGE_F32_4 :
  343. case IMAGE_R8G8B8A8 :
  344. case IMAGE_R8G8B8A8_SIGN:
  345. case IMAGE_R10G10B10A2 : return GL_RGBA;
  346. case IMAGE_B4G4R4X4:
  347. case IMAGE_B5G5R5X1:
  348. case IMAGE_B5G6R5 :
  349. case IMAGE_B8G8R8 :
  350. case IMAGE_B8G8R8X8: return GL_BGR;
  351. case IMAGE_B4G4R4A4:
  352. case IMAGE_B5G5R5A1:
  353. case IMAGE_B8G8R8A8: return GL_BGRA;
  354. case IMAGE_D24S8: return GL_DEPTH_STENCIL;
  355. case IMAGE_D16 :
  356. case IMAGE_D24X8:
  357. case IMAGE_D32 : return GL_DEPTH_COMPONENT;
  358. default: return 0;
  359. }
  360. }
  361. /******************************************************************************/
  362. UInt SourceGLType(IMAGE_TYPE type)
  363. {
  364. switch(type)
  365. {
  366. case IMAGE_F16 :
  367. case IMAGE_F16_2:
  368. case IMAGE_F16_3:
  369. case IMAGE_F16_4: return D.shaderModelGLES2() ? GL_HALF_FLOAT_OES : GL_HALF_FLOAT; // GLES2 requires GL_HALF_FLOAT_OES (this was tested on WebGL1)
  370. case IMAGE_F32 :
  371. case IMAGE_F32_2:
  372. case IMAGE_F32_3:
  373. case IMAGE_F32_4: return GL_FLOAT;
  374. case IMAGE_D16 : return GL_UNSIGNED_SHORT;
  375. case IMAGE_D24S8: return GL_UNSIGNED_INT_24_8;
  376. case IMAGE_D24X8: return GL_UNSIGNED_INT;
  377. case IMAGE_D32 : return GL_FLOAT;
  378. case IMAGE_I8 : return GL_UNSIGNED_BYTE ;
  379. case IMAGE_I16: return GL_UNSIGNED_SHORT;
  380. case IMAGE_I32: return GL_UNSIGNED_INT ;
  381. case IMAGE_R10G10B10A2: return GL_UNSIGNED_INT_2_10_10_10_REV;
  382. case IMAGE_B4G4R4X4:
  383. case IMAGE_B4G4R4A4: return GL_UNSIGNED_SHORT_4_4_4_4;
  384. case IMAGE_B5G5R5X1:
  385. case IMAGE_B5G5R5A1: return GL_UNSIGNED_SHORT_5_5_5_1;
  386. case IMAGE_B5G6R5: return GL_UNSIGNED_SHORT_5_6_5;
  387. case IMAGE_R8G8B8A8_SIGN:
  388. case IMAGE_R8G8_SIGN :
  389. case IMAGE_R8_SIGN : return GL_BYTE;
  390. case IMAGE_B8G8R8A8:
  391. case IMAGE_R8G8B8A8:
  392. case IMAGE_R8G8B8 :
  393. case IMAGE_R8G8 :
  394. case IMAGE_R8 :
  395. case IMAGE_A8 :
  396. case IMAGE_L8 :
  397. case IMAGE_L8A8 :
  398. case IMAGE_B8G8R8 :
  399. case IMAGE_B8G8R8X8:
  400. case IMAGE_R8G8B8X8: return GL_UNSIGNED_BYTE;
  401. default: return 0;
  402. }
  403. }
  404. #endif
  405. /******************************************************************************/
  406. // MANAGE
  407. /******************************************************************************/
  408. Image& Image::operator=(C Image &src ) {if(this!=&src)src.copy(T); return T;}
  409. Image::Image ( ) {zero();}
  410. Image::Image (C Image &src ) : Image() {src.copy(T);}
  411. Image::Image (Int w, Int h, Int d, IMAGE_TYPE type, IMAGE_MODE mode, Int mip_maps) : Image() {create(w, h, d, type, mode, mip_maps);}
  412. /******************************************************************************/
  413. Image& Image::del()
  414. {
  415. unlock();
  416. if(D.created())
  417. {
  418. if(is() && hw()) // remove image from 'ShaderImages'
  419. {
  420. ShaderImages.lock (); REPA(ShaderImages){ShaderImage &image=ShaderImages.lockedData(i); if(image.get()==this)image.set(null);}
  421. ShaderImages.unlock();
  422. }
  423. #if DX9
  424. if(/*_base || */_surf || _txtr || _cube || _vol)
  425. {
  426. D.texClear(_base);
  427. SyncLocker locker(D._lock);
  428. if(D.created())
  429. {
  430. //RELEASE(_base); don't release '_base' because it's just a copy of one of below
  431. RELEASE(_surf);
  432. RELEASE(_txtr);
  433. RELEASE(_cube);
  434. RELEASE(_vol );
  435. }
  436. }
  437. #elif DX11
  438. if(_txtr || _vol || _srv || _rtv || _dsv || _rdsv)
  439. {
  440. D.texClear(_srv);
  441. //SyncLocker locker(D._lock); lock not needed for DX11 'Release'
  442. if(D.created())
  443. {
  444. // release children first
  445. RELEASE(_rdsv);
  446. RELEASE(_dsv );
  447. RELEASE(_rtv );
  448. RELEASE(_srv );
  449. // now main resources
  450. RELEASE(_txtr);
  451. RELEASE(_vol );
  452. }
  453. }
  454. #elif GL
  455. if(_txtr || _rb)
  456. {
  457. D.texClear(_txtr);
  458. #if GL_LOCK
  459. SyncLocker locker(D._lock);
  460. #endif
  461. if(D.created())
  462. {
  463. glDeleteTextures (1, &_txtr); _txtr=0; // clear while in lock
  464. glDeleteRenderbuffers(1, &_rb ); _rb =0; // clear while in lock
  465. }
  466. }
  467. #endif
  468. }
  469. Free(_data_all);
  470. zero(); return T;
  471. }
  472. /******************************************************************************
  473. void Image::duplicate(C Image &src)
  474. {
  475. if(this!=&src)
  476. {
  477. del();
  478. #if DX9
  479. if(_surf=src._surf)_surf->AddRef();
  480. if(_txtr=src._txtr)_txtr->AddRef();
  481. if(_vol =src._vol )_vol ->AddRef();
  482. if(_cube=src._cube)_cube->AddRef();
  483. _base=src._base; // don't 'AddRef' '_base' because it's just a copy of one of above
  484. #elif DX11
  485. if(_txtr=src._txtr)_txtr->AddRef();
  486. if(_vol =src._vol )_vol ->AddRef();
  487. if(_srv =src._srv )_srv ->AddRef();
  488. if(_rtv =src._rtv )_rtv ->AddRef();
  489. if(_dsv =src._dsv )_dsv ->AddRef();
  490. if(_rdsv=src._rdsv)_rdsv->AddRef();
  491. #elif GL
  492. _dup =true ;
  493. _txtr=src._txtr;
  494. _rb =src._rb ;
  495. _w_s =src._w_s ;
  496. _w_t =src._w_t ;
  497. _w_r =src._w_r ;
  498. #endif
  499. _type =src._type ;
  500. _hw_type=src._hw_type;
  501. _mode =src._mode ;
  502. _mms =src._mms ;
  503. _samples=src._samples;
  504. _byte_pp=src._byte_pp;
  505. _partial=src._partial;
  506. _part =src._part ;
  507. _pitch =src._pitch ;
  508. _pitch2 =src._pitch2 ;
  509. _size=src. _size;
  510. _hw_size=src._hw_size;
  511. //_lmm, _lcf, _lock_mode, _lock_count, _lock_size, _discard, _data, _data_all - ignored
  512. this may break because of _data, _data_all
  513. }
  514. }
  515. /******************************************************************************/
  516. void Image::setPartial()
  517. {
  518. if(_partial=(w()!=hwW() || h()!=hwH() || d()!=hwD()))_part.set(Flt(w())/hwW(), Flt(h())/hwH(), Flt(d())/hwD());
  519. else _part=1;
  520. }
  521. Image& Image::setInfo(Int w, Int h, Int d, Int type, IMAGE_MODE mode)
  522. {
  523. #if DX9
  524. D3DSURFACE_DESC desc;
  525. if(_txtr && !_surf)_txtr->GetSurfaceLevel(0, &_surf);
  526. if((_surf && OK(_surf->GetDesc ( &desc)))
  527. || (_txtr && OK(_txtr->GetLevelDesc(0, &desc))))
  528. {
  529. _hw_size.x=desc.Width;
  530. _hw_size.y=desc.Height;
  531. _hw_size.z=1;
  532. _hw_type =ImageFormatToType(desc.Format);
  533. _samples =((desc.MultiSampleType==D3DMULTISAMPLE_NONE) ? 1 : desc.MultiSampleType);
  534. }else
  535. if(_cube && OK(_cube->GetLevelDesc(0, &desc)))
  536. {
  537. _hw_size.x=desc.Width;
  538. _hw_size.y=desc.Height;
  539. _hw_size.z=1;
  540. _hw_type =ImageFormatToType(desc.Format);
  541. _samples =((desc.MultiSampleType==D3DMULTISAMPLE_NONE) ? 1 : desc.MultiSampleType);
  542. }else
  543. if(_vol)
  544. {
  545. D3DVOLUME_DESC desc;
  546. if(OK(_vol->GetLevelDesc(0, &desc)))
  547. {
  548. _hw_size.x=desc.Width;
  549. _hw_size.y=desc.Height;
  550. _hw_size.z=desc.Depth;
  551. _hw_type =ImageFormatToType(desc.Format);
  552. _samples =1;
  553. }
  554. }
  555. if(_txtr)T._base=_txtr;else
  556. if(_cube)T._base=_cube;else
  557. if(_vol )T._base=_vol ;else
  558. T._base= null;
  559. if(_base)T._mms=_base->GetLevelCount();
  560. #elif DX11
  561. // lock not needed for DX11 'D3D'
  562. if(_txtr)
  563. {
  564. D3D11_TEXTURE2D_DESC desc; _txtr->GetDesc(&desc);
  565. _mms =desc.MipLevels;
  566. _samples =desc.SampleDesc.Count;
  567. _hw_size.x=desc.Width;
  568. _hw_size.y=desc.Height;
  569. _hw_size.z=1;
  570. _hw_type =ImageFormatToType(desc.Format);
  571. if(desc.Format==DXGI_FORMAT_R16_TYPELESS)
  572. {
  573. D3D11_SHADER_RESOURCE_VIEW_DESC srvd; Zero(srvd); srvd.Format=DXGI_FORMAT_R16_UNORM;
  574. if(desc.SampleDesc.Count<=1){srvd.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2D ; srvd.Texture2D.MipLevels=1;}
  575. else {srvd.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2DMS;}
  576. D3D->CreateShaderResourceView(_txtr, &srvd, &_srv);
  577. D3D11_DEPTH_STENCIL_VIEW_DESC dsvd; Zero(dsvd); dsvd.Format=DXGI_FORMAT_D16_UNORM; dsvd.ViewDimension=((desc.SampleDesc.Count>1) ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D);
  578. D3D->CreateDepthStencilView(_txtr, &dsvd, &_dsv );
  579. dsvd.Flags=D3D11_DSV_READ_ONLY_DEPTH; D3D->CreateDepthStencilView(_txtr, &dsvd, &_rdsv); // D16 does not have stencil, this will work only on DX11.0 but not 10.0, 10.1
  580. }else
  581. if(desc.Format==DXGI_FORMAT_R32_TYPELESS)
  582. {
  583. D3D11_SHADER_RESOURCE_VIEW_DESC srvd; Zero(srvd); srvd.Format=DXGI_FORMAT_R32_FLOAT;
  584. if(desc.SampleDesc.Count<=1){srvd.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2D ; srvd.Texture2D.MipLevels=1;}
  585. else {srvd.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2DMS;}
  586. D3D->CreateShaderResourceView(_txtr, &srvd, &_srv);
  587. D3D11_DEPTH_STENCIL_VIEW_DESC dsvd; Zero(dsvd); dsvd.Format=DXGI_FORMAT_D32_FLOAT; dsvd.ViewDimension=((desc.SampleDesc.Count>1) ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D);
  588. D3D->CreateDepthStencilView(_txtr, &dsvd, &_dsv );
  589. dsvd.Flags=D3D11_DSV_READ_ONLY_DEPTH; D3D->CreateDepthStencilView(_txtr, &dsvd, &_rdsv); // D32 does not have stencil, this will work only on DX11.0 but not 10.0, 10.1
  590. }else
  591. if(desc.Format==DXGI_FORMAT_R24G8_TYPELESS)
  592. {
  593. D3D11_SHADER_RESOURCE_VIEW_DESC srvd; Zero(srvd); srvd.Format=DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
  594. if(desc.SampleDesc.Count<=1){srvd.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2D ; srvd.Texture2D.MipLevels=1;}
  595. else {srvd.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2DMS;}
  596. D3D->CreateShaderResourceView(_txtr, &srvd, &_srv);
  597. D3D11_DEPTH_STENCIL_VIEW_DESC dsvd; Zero(dsvd); dsvd.Format=DXGI_FORMAT_D24_UNORM_S8_UINT; dsvd.ViewDimension=((desc.SampleDesc.Count>1) ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D);
  598. D3D->CreateDepthStencilView(_txtr, &dsvd, &_dsv );
  599. dsvd.Flags=(D3D11_DSV_READ_ONLY_DEPTH|D3D11_DSV_READ_ONLY_STENCIL); D3D->CreateDepthStencilView(_txtr, &dsvd, &_rdsv); // this will work only on DX11.0 but not 10.0, 10.1
  600. }else
  601. {
  602. if(mode==IMAGE_2D || mode==IMAGE_3D || mode==IMAGE_CUBE || mode==IMAGE_RT || mode==IMAGE_RT_CUBE || mode==IMAGE_DS || mode==IMAGE_DS_RT || mode==IMAGE_SHADOW_MAP)D3D->CreateShaderResourceView(_txtr, null, &_srv);
  603. if( mode==IMAGE_RT || mode==IMAGE_RT_CUBE )D3D->CreateRenderTargetView(_txtr, null, &_rtv);
  604. if(mode==IMAGE_DS || mode==IMAGE_DS_RT || mode==IMAGE_SHADOW_MAP)D3D->CreateDepthStencilView(_txtr, null, &_dsv);
  605. }
  606. }else
  607. if(_vol)
  608. {
  609. D3D11_TEXTURE3D_DESC desc; _vol->GetDesc(&desc);
  610. _mms =desc.MipLevels;
  611. _samples =1;
  612. _hw_size.x=desc.Width;
  613. _hw_size.y=desc.Height;
  614. _hw_size.z=desc.Depth;
  615. _hw_type =ImageFormatToType(desc.Format);
  616. D3D->CreateShaderResourceView(_vol, null, &_srv);
  617. }
  618. #elif GL
  619. if(_txtr)switch(mode)
  620. {
  621. case IMAGE_2D :
  622. case IMAGE_RT :
  623. case IMAGE_SURF_SCRATCH:
  624. case IMAGE_SURF_SYSTEM :
  625. case IMAGE_SURF :
  626. case IMAGE_DS :
  627. case IMAGE_DS_RT :
  628. case IMAGE_SHADOW_MAP :
  629. {
  630. #if !GL_ES // texture info is unavailable on OpenGL ES, so just trust in what we've set
  631. Int format;
  632. D.texBind (GL_TEXTURE_2D, _txtr);
  633. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH , &_hw_size.x);
  634. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT , &_hw_size.y);
  635. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, & format );
  636. _hw_type=ImageFormatToType(format, hwType());
  637. #endif
  638. _hw_size.z=1;
  639. }break;
  640. case IMAGE_3D:
  641. {
  642. #if !GL_ES // texture info is unavailable on OpenGL ES, so just trust in what we've set
  643. Int format;
  644. D.texBind (GL_TEXTURE_3D, _txtr);
  645. glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_WIDTH , &_hw_size.x);
  646. glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT , &_hw_size.y);
  647. glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_DEPTH , &_hw_size.z);
  648. glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, & format );
  649. _hw_type=ImageFormatToType(format, hwType());
  650. #endif
  651. }break;
  652. case IMAGE_CUBE:
  653. case IMAGE_RT_CUBE:
  654. {
  655. #if !GL_ES // texture info is unavailable on OpenGL ES, so just trust in what we've set
  656. Int format;
  657. D.texBind (GL_TEXTURE_CUBE_MAP, _txtr);
  658. glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_TEXTURE_WIDTH , &_hw_size.x);
  659. glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_TEXTURE_HEIGHT , &_hw_size.y);
  660. glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_TEXTURE_INTERNAL_FORMAT, & format );
  661. _hw_type=ImageFormatToType(format, hwType());
  662. #endif
  663. _hw_size.z=1;
  664. }break;
  665. }else
  666. if(_rb)
  667. {
  668. Int format;
  669. glBindRenderbuffer (GL_RENDERBUFFER, _rb);
  670. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH , &_hw_size.x);
  671. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT , &_hw_size.y);
  672. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_INTERNAL_FORMAT, & format );
  673. _hw_type =ImageFormatToType(format, hwType());
  674. _hw_size.z=1;
  675. }
  676. #endif
  677. _size.x = ((w >0) ? w : hwW ());
  678. _size.y = ((h >0) ? h : hwH ());
  679. _size.z = ((d >0) ? d : hwD ());
  680. _type =IMAGE_TYPE((type>0) ? type : hwType());
  681. _mode = mode ;
  682. _byte_pp=ImageTI[hwType()].byte_pp; // keep a copy for faster access
  683. if(is()){MAX(_mms, 1); MAX(_samples, 1);}
  684. setPartial();
  685. return T;
  686. }
  687. Image& Image::forceInfo(Int w, Int h, Int d, IMAGE_TYPE type, IMAGE_MODE mode)
  688. {
  689. _hw_size.x=w;
  690. _hw_size.y=h;
  691. _hw_size.z=d;
  692. _hw_type =type;
  693. return setInfo(w, h, d, type, mode);
  694. }
  695. /******************************************************************************/
  696. void Image::setGLParams()
  697. {
  698. #if GL
  699. #if GL_LOCK
  700. SyncLocker locker(D._lock);
  701. #endif
  702. if(D.created() && _txtr)
  703. {
  704. Bool mip_maps=(mipMaps()>1), filterable=true;
  705. if(D.shaderModelGLES2() && mip_maps && mipMaps()!=TotalMipMaps(w(), h(), d(), hwType()))mip_maps=false; // GLES2 requires full chain of mip-maps
  706. #if GL_ES
  707. filterable=(ImageTI[hwType()].precision<IMAGE_PRECISION_32); // GLES2/3 don't support filtering F32 textures, without this check reading from F32 textures will fail - https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml
  708. #endif
  709. UInt target;
  710. switch(mode())
  711. {
  712. case IMAGE_2D :
  713. case IMAGE_RT :
  714. case IMAGE_SURF_SCRATCH:
  715. case IMAGE_SURF_SYSTEM :
  716. case IMAGE_SURF :
  717. {
  718. target=GL_TEXTURE_2D;
  719. #if GL_ES
  720. if(mip_maps && ForceDisableMipMaps(T))mip_maps=false;
  721. #endif
  722. }break;
  723. case IMAGE_3D: target=GL_TEXTURE_3D; break;
  724. case IMAGE_CUBE:
  725. case IMAGE_RT_CUBE: target=GL_TEXTURE_CUBE_MAP; break;
  726. default: return;
  727. }
  728. D.texBind(target, _txtr);
  729. // first call those that can generate GL ERROR and we're OK with that, so we will call 'glGetError' to clear them
  730. {glTexParameteri(target, GL_TEXTURE_MAX_LEVEL , mip_maps ? mipMaps()-1 : 0); glGetError();} // clear error in case GL_TEXTURE_MAX_LEVEL is not supported (can happen on GLES2)
  731. if(mip_maps){glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY, Max(D.texFilter(), 1)); glGetError();} // clear error in case anisotropy is not supported (can happen when using ETC2 on "Galaxy Note 4")
  732. // now call thost that must succeed
  733. glTexParameteri(target, GL_TEXTURE_MIN_FILTER , mip_maps ? (filterable ? D.texMipFilter() ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST) : filterable ? GL_LINEAR : GL_NEAREST);
  734. glTexParameteri(target, GL_TEXTURE_MAG_FILTER , (filterable && (D.texFilter() || mode()!=IMAGE_2D)) ? GL_LINEAR : GL_NEAREST);
  735. #if GL_SWIZZLE
  736. switch(hwType())
  737. {
  738. case IMAGE_A8:
  739. {
  740. glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_ZERO);
  741. glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_ZERO);
  742. glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_ZERO);
  743. glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_RED );
  744. }break;
  745. case IMAGE_L8:
  746. {
  747. glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_RED);
  748. glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_RED);
  749. glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
  750. glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_ONE);
  751. }break;
  752. case IMAGE_L8A8:
  753. {
  754. glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_RED );
  755. glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_RED );
  756. glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED );
  757. glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
  758. }break;
  759. }
  760. #endif
  761. }
  762. #endif
  763. }
  764. /******************************************************************************/
  765. void Image::setGLFont()
  766. {
  767. #if GL && defined GL_TEXTURE_LOD_BIAS
  768. #if GL_LOCK
  769. SyncLocker locker(D._lock);
  770. #endif
  771. if(D.created() && _txtr && mipMaps()>1)switch(mode())
  772. {
  773. case IMAGE_2D :
  774. case IMAGE_RT :
  775. case IMAGE_SURF_SCRATCH:
  776. case IMAGE_SURF_SYSTEM :
  777. case IMAGE_SURF :
  778. {
  779. D.texBind (GL_TEXTURE_2D, _txtr);
  780. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -D.fontSharpness());
  781. glFlush (); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  782. }break;
  783. }
  784. #endif
  785. }
  786. /******************************************************************************/
  787. Bool Image::createTryEx(Int w, Int h, Int d, IMAGE_TYPE type, IMAGE_MODE mode, Int mip_maps, Byte samples, IMAGE_TYPE type_on_fail, C Image *src)
  788. {
  789. // verify parameters
  790. if(w<=0 || h<=0 || d<=0 || type==IMAGE_NONE){del(); return !w && !h && !d;}
  791. if((d!=1 && mode!=IMAGE_SOFT && mode!=IMAGE_3D) // "d!=1" can be specified only for SOFT or 3D
  792. #if DX9
  793. || samples>16 // DX9 does not support more than 16 samples
  794. #endif
  795. || !InRange(type, IMAGE_ALL_TYPES))goto error; // type out of range
  796. if(type_on_fail==type || !InRange(type_on_fail, IMAGE_ALL_TYPES))type_on_fail=IMAGE_NONE;
  797. MAX(samples, 1);
  798. {
  799. // mip maps
  800. Int total_mip_maps=TotalMipMaps(w, h, d, type); // don't use hardware texture size hwW(), hwH(), hwD(), so that number of mip-maps will always be the same (and not dependant on hardware capabilities like TexPow2 sizes), also because 1x1 image has just 1 mip map, but if we use padding then 4x4 block would generate 3 mip maps
  801. if(mip_maps<=0)mip_maps=total_mip_maps ; // if mip maps not specified (or we want multiple mip maps with type that requires full chain) then use full chain
  802. else MIN(mip_maps,total_mip_maps); // don't use more than maximum allowed
  803. // check if already matches what we want
  804. if(T.w()==w && T.h()==h && T.d()==d && T.type()==type && T.mode()==mode && T.mipMaps()==mip_maps && T.samples()==samples && !src)
  805. {
  806. unlock(); // unlock if was locked
  807. return true;
  808. }
  809. // create as new
  810. #if GL
  811. Memt<Byte> temp;
  812. #endif
  813. // hardware size (do after calculating mip-maps)
  814. VecI hw_size (PaddedWidth(w, h, 0, type ), PaddedHeight(w, h, 0, type ), d);
  815. VecI2 hw_size_on_fail(PaddedWidth(w, h, 0, type_on_fail), PaddedHeight(w, h, 0, type_on_fail) );
  816. if(TotalMipMaps(hw_size_on_fail.x, hw_size_on_fail.y, d, type_on_fail)<mip_maps) // if the secondary type can't fit all required mip maps, then we need to increase it, this is needed in case the desired 'type' size is bumped up due to its requirements (like PVRTC) thus making its total number of mip maps bigger
  817. hw_size_on_fail.set(PaddedWidth (hw_size.x, hw_size.y, 0, type_on_fail),
  818. PaddedHeight(hw_size.x, hw_size.y, 0, type_on_fail));
  819. Bool pow2=false;
  820. switch(mode)
  821. {
  822. case IMAGE_2D: switch(D._tex_pow2)
  823. {
  824. case 2: pow2=true; break; // require always
  825. case 1: // conditional
  826. {
  827. #if !GL // on OpenGL we will create a non-pow2 texture, but we won't upload mip maps
  828. pow2=(mip_maps>1); // force pow2 size if we have mip maps
  829. #endif
  830. }break;
  831. }break;
  832. case IMAGE_3D : pow2=D._tex_pow2_3d ; break;
  833. case IMAGE_CUBE: pow2=D._tex_pow2_cube; break;
  834. }
  835. if(pow2)
  836. {
  837. hw_size.x=CeilPow2(hw_size.x); hw_size_on_fail.x=CeilPow2(hw_size_on_fail.x);
  838. hw_size.y=CeilPow2(hw_size.y); hw_size_on_fail.y=CeilPow2(hw_size_on_fail.y);
  839. hw_size.z=CeilPow2(hw_size.z);
  840. }
  841. #if DX11
  842. D3D11_SUBRESOURCE_DATA *initial_data=null; MemtN<D3D11_SUBRESOURCE_DATA, 32*6> res_data; // 32 mip maps * 6 faces
  843. #endif
  844. if(src) // if 'src' specified
  845. {
  846. #if DX11 || GL // !! if adding more API's here, then allow them in 'Load' "Image IO.cpp" too !! only DX11, GL support this
  847. if(src==this // can't be created from self
  848. || src->hwType()!=type || src->hwSize3()!=hw_size || src->mipMaps()!=mip_maps || !src->soft() || src->cube()!=IsCube(mode)) // 'src' must match exactly what was requested
  849. #endif
  850. goto error;
  851. type_on_fail=IMAGE_NONE; // no alternative types
  852. #if DX11
  853. C Byte *data=src->softData(); Int faces=src->faces();
  854. initial_data=res_data.setNum(mip_maps*faces).data();
  855. FREPD(m, mip_maps)
  856. { // have to specify HW sizes, because all images (HW and SOFT) are stored like that
  857. Int mip_pitch =ImagePitch (src->hwW(), src->hwH(), m, src->hwType()) , // X
  858. mip_pitch2=ImageBlocksY(src->hwW(), src->hwH(), m, src->hwType())*mip_pitch , // X*Y
  859. mip_size = Max(1, src->hwD()>>m )*mip_pitch2; // X*Y*Z
  860. FREPD(f, faces)
  861. {
  862. D3D11_SUBRESOURCE_DATA &srd=initial_data[D3D11CalcSubresource(m, f, mip_maps)];
  863. srd.pSysMem =data;
  864. srd.SysMemPitch =mip_pitch;
  865. srd.SysMemSlicePitch=mip_pitch2;
  866. data+=mip_size;
  867. }
  868. }
  869. #endif
  870. }
  871. #if DX9 || GL_LOCK
  872. SyncLockerEx locker(D._lock, IsHW(mode)); // lock not needed for DX11 'D3D'
  873. #endif
  874. if(IsHW(mode) && !D.created())goto error; // device not yet created
  875. del();
  876. // create
  877. _hw_size=hw_size;
  878. switch(mode)
  879. {
  880. case IMAGE_SOFT:
  881. case IMAGE_SOFT_CUBE:
  882. {
  883. _hw_type=type; // set before 'setInfo' because it affects 'byte_pp'
  884. _mms =mip_maps;
  885. setInfo(w, h, d, type, mode);
  886. Alloc(_data_all, memUsage());
  887. lockSoft(); // set default lock members to main mip map
  888. }return true;
  889. #if DX9
  890. case IMAGE_SURF_SCRATCH: if(samples==1 && OK(D3D->CreateOffscreenPlainSurface(hwW(), hwH(), ImageTI[type ].format, D3DPOOL_SCRATCH , &_surf, null))){setInfo(w, h, d, type, mode); return true;}
  891. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(samples==1 && OK(D3D->CreateOffscreenPlainSurface(hwW(), hwH(), ImageTI[type_on_fail].format, D3DPOOL_SCRATCH , &_surf, null))){setInfo(w, h, d, type, mode); return true;}} break;
  892. case IMAGE_SURF_SYSTEM : if(samples==1 && OK(D3D->CreateOffscreenPlainSurface(hwW(), hwH(), ImageTI[type ].format, D3DPOOL_SYSTEMMEM , &_surf, null))){setInfo(w, h, d, type, mode); return true;}
  893. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(samples==1 && OK(D3D->CreateOffscreenPlainSurface(hwW(), hwH(), ImageTI[type_on_fail].format, D3DPOOL_SYSTEMMEM , &_surf, null))){setInfo(w, h, d, type, mode); return true;}} break;
  894. case IMAGE_SURF : if(samples==1 && OK(D3D->CreateOffscreenPlainSurface(hwW(), hwH(), ImageTI[type ].format, D3DPOOL_DEFAULT , &_surf, null))){setInfo(w, h, d, type, mode); return true;}
  895. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(samples==1 && OK(D3D->CreateOffscreenPlainSurface(hwW(), hwH(), ImageTI[type_on_fail].format, D3DPOOL_DEFAULT , &_surf, null))){setInfo(w, h, d, type, mode); return true;}} break;
  896. case IMAGE_2D : if(samples==1 && OK(D3D->CreateTexture (hwW(), hwH(), mip_maps, 0 , ImageTI[type ].format, D._no_gpu ? D3DPOOL_SCRATCH : D3DPOOL_MANAGED, &_txtr, null))){setInfo(w, h, d, type, mode); return true;}
  897. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(samples==1 && OK(D3D->CreateTexture (hwW(), hwH(), mip_maps, 0 , ImageTI[type_on_fail].format, D._no_gpu ? D3DPOOL_SCRATCH : D3DPOOL_MANAGED, &_txtr, null))){setInfo(w, h, d, type, mode); return true;}} break;
  898. case IMAGE_3D : if(samples==1 && OK(D3D->CreateVolumeTexture (hwW(), hwH(), hwD(), mip_maps, 0 , ImageTI[type ].format, D._no_gpu ? D3DPOOL_SCRATCH : D3DPOOL_MANAGED, &_vol , null))){setInfo(w, h, d, type, mode); return true;}
  899. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(samples==1 && OK(D3D->CreateVolumeTexture (hwW(), hwH(), hwD(), mip_maps, 0 , ImageTI[type_on_fail].format, D._no_gpu ? D3DPOOL_SCRATCH : D3DPOOL_MANAGED, &_vol , null))){setInfo(w, h, d, type, mode); return true;}} break;
  900. case IMAGE_CUBE : if(samples==1 && OK(D3D->CreateCubeTexture (hwW(), mip_maps, 0 , ImageTI[type ].format, D._no_gpu ? D3DPOOL_SCRATCH : D3DPOOL_MANAGED, &_cube, null))){setInfo(w, h, d, type, mode); return true;}
  901. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(samples==1 && OK(D3D->CreateCubeTexture (hwW(), mip_maps, 0 , ImageTI[type_on_fail].format, D._no_gpu ? D3DPOOL_SCRATCH : D3DPOOL_MANAGED, &_cube, null))){setInfo(w, h, d, type, mode); return true;}} break;
  902. case IMAGE_RT_CUBE : if(samples==1 && OK(D3D->CreateCubeTexture (hwW(), 1, D3DUSAGE_RENDERTARGET, ImageTI[type ].format, D3DPOOL_DEFAULT , &_cube, null))){setInfo(w, h, d, type, mode); return true;}
  903. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(samples==1 && OK(D3D->CreateCubeTexture (hwW(), 1, D3DUSAGE_RENDERTARGET, ImageTI[type_on_fail].format, D3DPOOL_DEFAULT , &_cube, null))){setInfo(w, h, d, type, mode); return true;}} break;
  904. case IMAGE_DS_RT : if(samples==1 && OK(D3D->CreateTexture (hwW(), hwH(), 1, D3DUSAGE_DEPTHSTENCIL, ImageTI[type ].format, D3DPOOL_DEFAULT , &_txtr, null))){setInfo(w, h, d, type, mode); return true;} break;
  905. case IMAGE_SHADOW_MAP : if(samples==1 && OK(D3D->CreateTexture (hwW(), hwH(), 1, D3DUSAGE_DEPTHSTENCIL, ImageTI[type ].format, D3DPOOL_DEFAULT , &_txtr, null))){setInfo(w, h, d, type, mode); return true;} break;
  906. case IMAGE_DS:
  907. if(OK(D3D->CreateDepthStencilSurface(hwW(), hwH(), ImageTI[type].format, (samples>1) ? D3DMULTISAMPLE_TYPE(samples) : D3DMULTISAMPLE_NONE, 0, false, &_surf, null))){setInfo(w, h, d, type, mode); return true;}
  908. break;
  909. case IMAGE_RT:
  910. if(samples>1)
  911. {
  912. if(OK(D3D->CreateRenderTarget(hwW(), hwH(), ImageTI[type ].format, D3DMULTISAMPLE_TYPE(samples), 0, false, &_surf, null))){setInfo(w, h, d, type, mode); clearHw(); return true;}
  913. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(OK(D3D->CreateRenderTarget(hwW(), hwH(), ImageTI[type_on_fail].format, D3DMULTISAMPLE_TYPE(samples), 0, false, &_surf, null))){setInfo(w, h, d, type, mode); clearHw(); return true;}}
  914. }else
  915. {
  916. if(OK(D3D->CreateTexture(hwW(), hwH(), 1, D3DUSAGE_RENDERTARGET, ImageTI[type ].format, D3DPOOL_DEFAULT, &_txtr, null))){setInfo(w, h, d, type, mode); clearHw(); return true;}
  917. if(type_on_fail){_hw_size.xy=hw_size_on_fail; if(OK(D3D->CreateTexture(hwW(), hwH(), 1, D3DUSAGE_RENDERTARGET, ImageTI[type_on_fail].format, D3DPOOL_DEFAULT, &_txtr, null))){setInfo(w, h, d, type, mode); clearHw(); return true;}}
  918. }
  919. break;
  920. #elif DX11
  921. case IMAGE_2D:
  922. {
  923. D3D11_TEXTURE2D_DESC desc;
  924. desc.Width =hwW();
  925. desc.Height =hwH();
  926. desc.MipLevels =mip_maps;
  927. desc.Format =ImageTI[type].format;
  928. desc.Usage =D3D11_USAGE_DEFAULT;
  929. desc.BindFlags =D3D11_BIND_SHADER_RESOURCE;
  930. desc.MiscFlags =0;
  931. desc.CPUAccessFlags =0;
  932. desc.SampleDesc.Count =1;
  933. desc.SampleDesc.Quality=0;
  934. desc.ArraySize =1;
  935. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, initial_data, &_txtr))){setInfo(w, h, d, type, mode); return true;}
  936. if(type_on_fail)
  937. {
  938. desc.Width =_hw_size.x=hw_size_on_fail.x;
  939. desc.Height=_hw_size.y=hw_size_on_fail.y;
  940. desc.Format=ImageTI[type_on_fail].format;
  941. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); return true;}
  942. }
  943. }break;
  944. case IMAGE_SURF_SCRATCH:
  945. case IMAGE_SURF_SYSTEM :
  946. case IMAGE_SURF :
  947. {
  948. D3D11_TEXTURE2D_DESC desc;
  949. desc.Width =hwW();
  950. desc.Height =hwH();
  951. desc.MipLevels =mip_maps;
  952. desc.Format =ImageTI[type].format;
  953. desc.Usage =D3D11_USAGE_STAGING;
  954. desc.BindFlags =0;
  955. desc.MiscFlags =0;
  956. desc.CPUAccessFlags =D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE;
  957. desc.SampleDesc.Count =1;
  958. desc.SampleDesc.Quality=0;
  959. desc.ArraySize =1;
  960. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, initial_data, &_txtr))){setInfo(w, h, d, type, mode); return true;}
  961. if(type_on_fail)
  962. {
  963. desc.Width =_hw_size.x=hw_size_on_fail.x;
  964. desc.Height=_hw_size.y=hw_size_on_fail.y;
  965. desc.Format=ImageTI[type_on_fail].format;
  966. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); return true;}
  967. }
  968. }break;
  969. case IMAGE_RT:
  970. {
  971. D3D11_TEXTURE2D_DESC desc;
  972. desc.Width =hwW();
  973. desc.Height =hwH();
  974. desc.MipLevels =mip_maps;
  975. desc.Format =ImageTI[type].format;
  976. desc.Usage =D3D11_USAGE_DEFAULT;
  977. desc.BindFlags =D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE;
  978. desc.MiscFlags =0;
  979. desc.CPUAccessFlags =0;
  980. desc.SampleDesc.Count =samples;
  981. desc.SampleDesc.Quality=0;
  982. desc.ArraySize =1;
  983. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); SyncLocker locker(D._lock); clearHw(); return true;} // 'clearHw' needs lock, clear render targets to zero at start (especially important for floating point RT's), use 'clearHW' instead of 'initial_data' because that would require large memory allocations
  984. if(type_on_fail)
  985. {
  986. desc.Width =_hw_size.x=hw_size_on_fail.x;
  987. desc.Height=_hw_size.y=hw_size_on_fail.y;
  988. desc.Format=ImageTI[type_on_fail].format;
  989. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); SyncLocker locker(D._lock); clearHw(); return true;} // 'clearHw' needs lock, clear render targets to zero at start (especially important for floating point RT's), use 'clearHW' instead of 'initial_data' because that would require large memory allocations
  990. }
  991. }break;
  992. case IMAGE_3D:
  993. {
  994. D3D11_TEXTURE3D_DESC desc;
  995. desc.Width =hwW();
  996. desc.Height =hwH();
  997. desc.Depth =hwD();
  998. desc.MipLevels =mip_maps;
  999. desc.Format =ImageTI[type].format;
  1000. desc.Usage =D3D11_USAGE_DEFAULT;
  1001. desc.BindFlags =D3D11_BIND_SHADER_RESOURCE;
  1002. desc.MiscFlags =0;
  1003. desc.CPUAccessFlags =0;
  1004. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture3D(&desc, initial_data, &_vol))){setInfo(w, h, d, type, mode); return true;}
  1005. if(type_on_fail)
  1006. {
  1007. desc.Width =_hw_size.x=hw_size_on_fail.x;
  1008. desc.Height=_hw_size.y=hw_size_on_fail.y;
  1009. desc.Format=ImageTI[type_on_fail].format;
  1010. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture3D(&desc, null, &_vol))){setInfo(w, h, d, type, mode); return true;}
  1011. }
  1012. }break;
  1013. case IMAGE_CUBE:
  1014. {
  1015. D3D11_TEXTURE2D_DESC desc;
  1016. desc.Width =hwW();
  1017. desc.Height =hwH();
  1018. desc.MipLevels =mip_maps;
  1019. desc.Format =ImageTI[type].format;
  1020. desc.Usage =D3D11_USAGE_DEFAULT;
  1021. desc.BindFlags =D3D11_BIND_SHADER_RESOURCE;
  1022. desc.MiscFlags =D3D11_RESOURCE_MISC_TEXTURECUBE;
  1023. desc.CPUAccessFlags =0;
  1024. desc.SampleDesc.Count =1;
  1025. desc.SampleDesc.Quality=0;
  1026. desc.ArraySize =6;
  1027. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, initial_data, &_txtr))){setInfo(w, h, d, type, mode); return true;}
  1028. if(type_on_fail)
  1029. {
  1030. desc.Width =_hw_size.x=hw_size_on_fail.x;
  1031. desc.Height=_hw_size.y=hw_size_on_fail.y;
  1032. desc.Format=ImageTI[type_on_fail].format;
  1033. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); return true;}
  1034. }
  1035. }break;
  1036. case IMAGE_RT_CUBE:
  1037. {
  1038. D3D11_TEXTURE2D_DESC desc;
  1039. desc.Width =hwW();
  1040. desc.Height =hwH();
  1041. desc.MipLevels =mip_maps;
  1042. desc.Format =ImageTI[type].format;
  1043. desc.Usage =D3D11_USAGE_DEFAULT;
  1044. desc.BindFlags =D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE;
  1045. desc.MiscFlags =D3D11_RESOURCE_MISC_TEXTURECUBE;
  1046. desc.CPUAccessFlags =0;
  1047. desc.SampleDesc.Count =samples;
  1048. desc.SampleDesc.Quality=0;
  1049. desc.ArraySize =6;
  1050. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); SyncLocker locker(D._lock); clearHw(); return true;} // 'clearHw' needs lock, clear render targets to zero at start (especially important for floating point RT's), use 'clearHW' instead of 'initial_data' because that would require large memory allocations
  1051. if(type_on_fail)
  1052. {
  1053. desc.Width =_hw_size.x=hw_size_on_fail.x;
  1054. desc.Height=_hw_size.y=hw_size_on_fail.y;
  1055. desc.Format=ImageTI[type_on_fail].format;
  1056. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); SyncLocker locker(D._lock); clearHw(); return true;} // 'clearHw' needs lock, clear render targets to zero at start (especially important for floating point RT's), use 'clearHW' instead of 'initial_data' because that would require large memory allocations
  1057. }
  1058. }break;
  1059. case IMAGE_DS:
  1060. case IMAGE_DS_RT:
  1061. case IMAGE_SHADOW_MAP:
  1062. {
  1063. D3D11_TEXTURE2D_DESC desc;
  1064. desc.Width =hwW();
  1065. desc.Height =hwH();
  1066. desc.MipLevels =mip_maps;
  1067. desc.Format =ImageTI[type].format; if(desc.Format==DXGI_FORMAT_D24_UNORM_S8_UINT)desc.Format=DXGI_FORMAT_R24G8_TYPELESS;else if(desc.Format==DXGI_FORMAT_D32_FLOAT)desc.Format=DXGI_FORMAT_R32_TYPELESS;else if(desc.Format==DXGI_FORMAT_D16_UNORM)desc.Format=DXGI_FORMAT_R16_TYPELESS;
  1068. desc.Usage =D3D11_USAGE_DEFAULT;
  1069. desc.BindFlags =D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE;
  1070. desc.MiscFlags =0;
  1071. desc.CPUAccessFlags =0;
  1072. desc.SampleDesc.Count =samples;
  1073. desc.SampleDesc.Quality=0;
  1074. desc.ArraySize =1;
  1075. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); return true;}
  1076. FlagDisable(desc.BindFlags, D3D11_BIND_SHADER_RESOURCE); // disable shader reading
  1077. if(desc.Format!=DXGI_FORMAT_UNKNOWN && OK(D3D->CreateTexture2D(&desc, null, &_txtr))){setInfo(w, h, d, type, mode); return true;}
  1078. }break;
  1079. #elif GL
  1080. case IMAGE_2D :
  1081. case IMAGE_RT :
  1082. case IMAGE_SURF_SCRATCH:
  1083. case IMAGE_SURF_SYSTEM :
  1084. case IMAGE_SURF :
  1085. {
  1086. glGenTextures(1, &_txtr);
  1087. if(_txtr)
  1088. {
  1089. T._mms =mip_maps;
  1090. T._samples=1;
  1091. T._size.x =w;
  1092. T._size.y =h;
  1093. T._size.z =1;
  1094. T._mode =mode;
  1095. T._type =T._hw_type=type;
  1096. glGetError (); // clear any previous errors
  1097. setGLParams(); // call this first to bind the texture
  1098. UInt format=ImageTI[hwType()].format, gl_format=SourceGLFormat(hwType()), gl_type=SourceGLType(hwType());
  1099. if(src)
  1100. {
  1101. C Byte *data=src->softData(); FREPD(m, mipMaps()) // order important
  1102. {
  1103. if(m==1) // check at the start of mip-map #1, to skip this when there's only one mip-map
  1104. {
  1105. if(ForceDisableMipMaps(T))break;
  1106. if(glGetError()!=GL_NO_ERROR)goto error; // if first mip failed, then skip remaining
  1107. }
  1108. VecI2 size(Max(1, hwW()>>m), Max(1, hwH()>>m));
  1109. Int mip_size=ImageMipSize(size.x, size.y, 0, hwType());
  1110. if(!compressed())glTexImage2D(GL_TEXTURE_2D, m, format, size.x, size.y, 0, gl_format, gl_type, data);
  1111. else glCompressedTexImage2D(GL_TEXTURE_2D, m, format, size.x, size.y, 0, mip_size, data);
  1112. data+=mip_size;
  1113. }
  1114. }else
  1115. if(!compressed())
  1116. {
  1117. if(mode==IMAGE_RT)temp.setNumZero(CeilGL(memUsage())); // clear render targets to zero at start (especially important for floating point RT's)
  1118. glTexImage2D(GL_TEXTURE_2D, 0, format, hwW(), hwH(), 0, gl_format, gl_type, temp.dataNull());
  1119. }else
  1120. {
  1121. Int mip_size=ImageMipSize(hwW(), hwH(), 0, hwType());
  1122. if(WEB)temp.setNumZero(CeilGL(mip_size)); // for WEB, null can't be specified in 'glCompressedTexImage'
  1123. glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, hwW(), hwH(), 0, mip_size, temp.dataNull());
  1124. }
  1125. if(glGetError()!=GL_NO_ERROR) // error
  1126. {
  1127. if(!type_on_fail)goto error;
  1128. _hw_size.xy=hw_size_on_fail;
  1129. _hw_type =type_on_fail;
  1130. format =ImageTI[hwType()].format;
  1131. if(!compressed())
  1132. {
  1133. if(mode==IMAGE_RT)temp.setNumZero(CeilGL(memUsage()));else temp.del(); // clear render targets to zero at start (especially important for floating point RT's)
  1134. glTexImage2D(GL_TEXTURE_2D, 0, format, hwW(), hwH(), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), temp.dataNull());
  1135. }else
  1136. {
  1137. Int mip_size=ImageMipSize(hwW(), hwH(), 0, hwType());
  1138. if(WEB)temp.setNumZero(CeilGL(mip_size));else temp.del(); // for WEB, null can't be specified in 'glCompressedTexImage'
  1139. glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, hwW(), hwH(), 0, mip_size, temp.dataNull());
  1140. }
  1141. if(glGetError()!=GL_NO_ERROR)goto error; // error
  1142. }
  1143. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  1144. setInfo(w, h, d, type, mode);
  1145. #if GL_ES
  1146. if(mode!=IMAGE_RT)Alloc(_data_all, CeilGL(memUsage()));
  1147. #endif
  1148. return true;
  1149. }
  1150. }break;
  1151. case IMAGE_3D: if(D.notShaderModelGLES2())
  1152. {
  1153. glGenTextures(1, &_txtr);
  1154. if(_txtr)
  1155. {
  1156. T._mms =mip_maps;
  1157. T._samples=1;
  1158. T._size.x =w;
  1159. T._size.y =h;
  1160. T._size.z =d;
  1161. T._mode =mode;
  1162. T._type =T._hw_type=type;
  1163. glGetError (); // clear any previous errors
  1164. setGLParams(); // call this first to bind the texture
  1165. UInt format=ImageTI[hwType()].format, gl_format=SourceGLFormat(hwType()), gl_type=SourceGLType(hwType());
  1166. if(src)
  1167. {
  1168. C Byte *data=src->softData(); FREPD(m, mipMaps()) // order important
  1169. {
  1170. if(m==1) // check at the start of mip-map #1, to skip this when there's only one mip-map
  1171. {
  1172. if(glGetError()!=GL_NO_ERROR)goto error; // if first mip failed, then skip remaining
  1173. }
  1174. VecI size(Max(1, hwW()>>m), Max(1, hwH()>>m), Max(1, hwD()>>m));
  1175. Int mip_size=ImageMipSize(size.x, size.y, size.z, 0, hwType());
  1176. if(!compressed())glTexImage3D(GL_TEXTURE_3D, m, format, size.x, size.y, size.z, 0, gl_format, gl_type, data);
  1177. else glCompressedTexImage3D(GL_TEXTURE_3D, m, format, size.x, size.y, size.z, 0, mip_size, data);
  1178. data+=mip_size;
  1179. }
  1180. }else
  1181. if(!compressed())glTexImage3D(GL_TEXTURE_3D, 0, format, hwW(), hwH(), hwD(), 0, gl_format, gl_type, null);
  1182. else glCompressedTexImage3D(GL_TEXTURE_3D, 0, format, hwW(), hwH(), hwD(), 0, ImageMipSize(hwW(), hwH(), hwD(), 0, hwType()), null);
  1183. if(glGetError()!=GL_NO_ERROR) // error
  1184. {
  1185. if(!type_on_fail)goto error;
  1186. _hw_size.xy=hw_size_on_fail;
  1187. _hw_type =type_on_fail;
  1188. format =ImageTI[hwType()].format;
  1189. if(!compressed())glTexImage3D(GL_TEXTURE_3D, 0, format, hwW(), hwH(), hwD(), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), null);
  1190. else glCompressedTexImage3D(GL_TEXTURE_3D, 0, format, hwW(), hwH(), hwD(), 0, ImageMipSize(hwW(), hwH(), hwD(), 0, hwType()), null);
  1191. if(glGetError()!=GL_NO_ERROR)goto error; // error
  1192. }
  1193. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  1194. setInfo(w, h, d, type, mode);
  1195. #if GL_ES
  1196. Alloc(_data_all, CeilGL(memUsage()));
  1197. #endif
  1198. return true;
  1199. }
  1200. }break;
  1201. case IMAGE_CUBE:
  1202. case IMAGE_RT_CUBE:
  1203. {
  1204. glGenTextures(1, &_txtr);
  1205. if(_txtr)
  1206. {
  1207. T._mms =mip_maps;
  1208. T._samples=1;
  1209. T._size.x =w;
  1210. T._size.y =h;
  1211. T._size.z =1;
  1212. T._mode =mode;
  1213. T._type =T._hw_type=type;
  1214. glGetError (); // clear any previous errors
  1215. setGLParams(); // call this first to bind the texture
  1216. // set params which are set only at creation time, so they don't need to be set again later
  1217. glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  1218. glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  1219. again_cube:
  1220. UInt format=ImageTI[hwType()].format, gl_format=SourceGLFormat(hwType()), gl_type=SourceGLType(hwType());
  1221. C Byte *data=(src ? src->softData() : null); Int mip_maps=(src ? mipMaps() : 1); FREPD(m, mip_maps) // order important
  1222. {
  1223. VecI2 size(Max(1, hwW()>>m), Max(1, hwH()>>m));
  1224. Int mip_size=ImageMipSize(size.x, size.y, 0, hwType());
  1225. if(!m && !src)
  1226. if(mode==IMAGE_RT_CUBE || WEB && compressed())data=temp.setNumZero(CeilGL(mip_size)).dataNull(); // clear render targets to zero at start (especially important for floating point RT's), for WEB null can't be specified in 'glCompressedTexImage'
  1227. FREPD(f, 6) // faces, order important
  1228. {
  1229. if(!compressed())glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+f, m, format, size.x, size.y, 0, gl_format, gl_type, data);
  1230. else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+f, m, format, size.x, size.y, 0, mip_size, data);
  1231. if(!m && !f && glGetError()!=GL_NO_ERROR) // check for error only on the first mip and face
  1232. {
  1233. if(!type_on_fail)goto error;
  1234. _hw_size.xy=hw_size_on_fail;
  1235. _hw_type =type_on_fail; type_on_fail=IMAGE_NONE; // disable trying this again
  1236. goto again_cube;
  1237. }
  1238. if(src)data+=mip_size;
  1239. }
  1240. }
  1241. if(glGetError()==GL_NO_ERROR) // ok
  1242. {
  1243. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  1244. setInfo(w, h, d, type, mode);
  1245. #if GL_ES
  1246. if(mode!=IMAGE_RT_CUBE)Alloc(_data_all, CeilGL(memUsage()));
  1247. #endif
  1248. return true;
  1249. }
  1250. }
  1251. }break;
  1252. case IMAGE_DS:
  1253. {
  1254. glGenRenderbuffers(1, &_rb);
  1255. if(_rb)
  1256. {
  1257. T._mms =1;
  1258. T._samples=1;
  1259. T._size.x =w;
  1260. T._size.y =h;
  1261. T._size.z =1;
  1262. T._mode =mode;
  1263. T._type =T._hw_type=type;
  1264. //LogN(S+"x:"+hwW()+", y:"+hwH()+", type:"+ImageTI[hwType()].name);
  1265. glGetError(); // clear any previous errors
  1266. glBindRenderbuffer (GL_RENDERBUFFER, _rb);
  1267. glRenderbufferStorage(GL_RENDERBUFFER, ImageTI[hwType()].format, hwW(), hwH());
  1268. if(glGetError()==GL_NO_ERROR) // ok
  1269. {
  1270. setInfo(w, h, d, type, mode);
  1271. return true;
  1272. }
  1273. }
  1274. }break;
  1275. case IMAGE_DS_RT:
  1276. {
  1277. glGenTextures(1, &_txtr);
  1278. if(_txtr)
  1279. {
  1280. T._mms =1;
  1281. T._samples=1;
  1282. T._size.x =w;
  1283. T._size.y =h;
  1284. T._size.z =1;
  1285. T._mode =mode;
  1286. T._type =T._hw_type=type;
  1287. glGetError(); // clear any previous errors
  1288. D.texBind (GL_TEXTURE_2D, _txtr);
  1289. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
  1290. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
  1291. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  1292. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  1293. {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL , 0); glGetError();} // clear error in case GL_TEXTURE_MAX_LEVEL is not supported (can happen on GLES2)
  1294. glTexImage2D(GL_TEXTURE_2D, 0, ImageTI[hwType()].format, hwW(), hwH(), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), null);
  1295. if(glGetError()==GL_NO_ERROR) // ok
  1296. {
  1297. setInfo(w, h, d, type, mode);
  1298. return true;
  1299. }
  1300. }
  1301. }break;
  1302. case IMAGE_SHADOW_MAP: if(!WEB || D.notShaderModelGLES2()) // WebGL succeeds to create shadow map on GLES2 while not really supporting it, because of that shaders that use shadows fail to load complaining about 'sampler2DShadow' is not supported, however it works on Android GLES2
  1303. {
  1304. glGenTextures(1, &_txtr);
  1305. if(_txtr)
  1306. {
  1307. T._mms =1;
  1308. T._samples=1;
  1309. T._size.x =w;
  1310. T._size.y =h;
  1311. T._size.z =1;
  1312. T._mode =mode;
  1313. T._type =T._hw_type=type;
  1314. glGetError(); // clear any previous errors
  1315. D.texBind (GL_TEXTURE_2D, _txtr);
  1316. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
  1317. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
  1318. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER , GL_LINEAR);
  1319. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER , GL_LINEAR);
  1320. {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL , 0); glGetError();} // clear error in case GL_TEXTURE_MAX_LEVEL is not supported (can happen on GLES2)
  1321. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
  1322. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, REVERSE_DEPTH ? GL_GEQUAL : GL_LEQUAL);
  1323. glTexImage2D(GL_TEXTURE_2D, 0, ImageTI[hwType()].format, hwW(), hwH(), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), null);
  1324. if(glGetError()==GL_NO_ERROR) // ok
  1325. {
  1326. setInfo(w, h, d, type, mode);
  1327. return true;
  1328. }
  1329. }
  1330. }break;
  1331. #endif
  1332. }
  1333. }
  1334. error:
  1335. del(); return false;
  1336. }
  1337. Bool Image::createTry(Int w, Int h, Int d, IMAGE_TYPE type, IMAGE_MODE mode, Int mip_maps, Bool rgba_on_fail)
  1338. {
  1339. return createTryEx(w, h, d, type, mode, mip_maps, 1, rgba_on_fail ? IMAGE_DEFAULT : IMAGE_NONE);
  1340. }
  1341. Image& Image::create(Int w, Int h, Int d, IMAGE_TYPE type, IMAGE_MODE mode, Int mip_maps, Bool rgba_on_fail)
  1342. {
  1343. if(!createTry(w, h, d, type, mode, mip_maps, rgba_on_fail))Exit(MLT(S+"Can't create texture " +w+'x'+h+'x'+d+", type "+ImageTI[type].name+", mode "+mode+".",
  1344. PL,S+u"Nie można utworzyć tekstury "+w+'x'+h+'x'+d+", typ " +ImageTI[type].name+", tryb "+mode+"."));
  1345. return T;
  1346. }
  1347. /******************************************************************************/
  1348. static Bool Decompress(C Image &src, Image &dest) // assumes that 'src' and 'dest' are 2 different objects, 'src' is compressed, and 'dest' not yet created
  1349. {
  1350. void (*decompress_block)(C Byte *b, Color (&block)[4][4]), (*decompress_block_pitch)(C Byte *b, Color *dest, Int pitch);
  1351. switch(src.hwType())
  1352. {
  1353. default: return false;
  1354. case IMAGE_PVRTC1_2:
  1355. case IMAGE_PVRTC1_4: return DecompressPVRTC(src, dest);
  1356. case IMAGE_BC1 : decompress_block=DecompressBlockBC1 ; decompress_block_pitch=DecompressBlockBC1 ; break;
  1357. case IMAGE_BC2 : decompress_block=DecompressBlockBC2 ; decompress_block_pitch=DecompressBlockBC2 ; break;
  1358. case IMAGE_BC3 : decompress_block=DecompressBlockBC3 ; decompress_block_pitch=DecompressBlockBC3 ; break;
  1359. case IMAGE_BC7 : decompress_block=DecompressBlockBC7 ; decompress_block_pitch=DecompressBlockBC7 ; break;
  1360. case IMAGE_ETC1 : decompress_block=DecompressBlockETC1 ; decompress_block_pitch=DecompressBlockETC1 ; break;
  1361. case IMAGE_ETC2 : decompress_block=DecompressBlockETC2 ; decompress_block_pitch=DecompressBlockETC2 ; break;
  1362. case IMAGE_ETC2_A1: decompress_block=DecompressBlockETC2A1; decompress_block_pitch=DecompressBlockETC2A1; break;
  1363. case IMAGE_ETC2_A8: decompress_block=DecompressBlockETC2A8; decompress_block_pitch=DecompressBlockETC2A8; break;
  1364. }
  1365. Bool ok=false;
  1366. if(dest.is() || dest.createTry(src.w(), src.h(), src.d(), IMAGE_R8G8B8A8, IMAGE_SOFT, 1)) // use 'IMAGE_R8G8B8A8' because Decompress Block functions operate on 'Color'
  1367. if(dest.size3()==src.size3())
  1368. if(dest.lock(LOCK_WRITE))
  1369. {
  1370. if(src.lockRead())
  1371. {
  1372. ok=true;
  1373. Int full_blocks_x= dest.w()/4,
  1374. full_blocks_y= dest.h()/4,
  1375. all_blocks_x=DivCeil4(dest.w()),
  1376. all_blocks_y=DivCeil4(dest.h()),
  1377. x_mul =ImageTI[src.hwType()].bit_pp*2; // *2 because (4*4 colors / 8 bits)
  1378. REPD(z, dest.d())
  1379. {
  1380. Color color[4][4];
  1381. Int done_x=0, done_y=0;
  1382. if(dest.hwType()==IMAGE_R8G8B8A8 // decompress directly into 'dest'
  1383. && dest. type()==IMAGE_R8G8B8A8) // check 'type' too in case we have to perform color adjustment
  1384. {
  1385. // process full blocks only
  1386. C Byte * src_data_z= src.data() + z* src.pitch2();
  1387. Byte *dest_data_z=dest.data() + z*dest.pitch2();
  1388. REPD(by, full_blocks_y)
  1389. {
  1390. const Int py=by*4; // pixel
  1391. C Byte * src_data_y= src_data_z + by* src.pitch();
  1392. Byte *dest_data_y=dest_data_z + py*dest.pitch();
  1393. REPD(bx, full_blocks_x)
  1394. {
  1395. const Int px=bx*4; // pixel
  1396. decompress_block_pitch(src_data_y + bx*x_mul, (Color*)(dest_data_y + px*4), dest.pitch());
  1397. }
  1398. }
  1399. done_x=full_blocks_x;
  1400. done_y=full_blocks_y;
  1401. }
  1402. // process right blocks (excluding the shared corner)
  1403. for(Int by= 0; by<done_y ; by++)
  1404. for(Int bx=done_x; bx<all_blocks_x; bx++)
  1405. {
  1406. Int px=bx*4, py=by*4; // pixel
  1407. decompress_block(src.data() + bx*x_mul + by*src.pitch() + z*src.pitch2(), color);
  1408. REPD(y, 4)
  1409. REPD(x, 4)dest.color3D(px+x, py+y, z, color[y][x]);
  1410. }
  1411. // process bottom blocks (including the shared corner)
  1412. for(Int by=done_y; by<all_blocks_y; by++)
  1413. for(Int bx= 0; bx<all_blocks_x; bx++)
  1414. {
  1415. Int px=bx*4, py=by*4; // pixel
  1416. decompress_block(src.data() + bx*x_mul + by*src.pitch() + z*src.pitch2(), color);
  1417. REPD(y, 4)
  1418. REPD(x, 4)dest.color3D(px+x, py+y, z, color[y][x]);
  1419. }
  1420. }
  1421. src.unlock();
  1422. }
  1423. dest.unlock();
  1424. }
  1425. return ok;
  1426. }
  1427. /******************************************************************************/
  1428. static Bool Compress(C Image &src, Image &dest, Bool mtrl_base_1=false) // assumes that 'src' and 'dest' are 2 different objects, 'src' is created as non-compressed, and 'dest' is created as compressed
  1429. {
  1430. switch(dest.hwType())
  1431. {
  1432. case IMAGE_BC1:
  1433. case IMAGE_BC2:
  1434. case IMAGE_BC3: return CompressBC (src, dest, mtrl_base_1);
  1435. case IMAGE_BC7: return CompressBC7 ? CompressBC7(src, dest) : false;
  1436. case IMAGE_ETC1 :
  1437. case IMAGE_ETC2 :
  1438. case IMAGE_ETC2_A1:
  1439. case IMAGE_ETC2_A8: return CompressETC ? CompressETC(src, dest, -1, mtrl_base_1 ? false : true) : false;
  1440. case IMAGE_PVRTC1_2:
  1441. case IMAGE_PVRTC1_4: return CompressPVRTC ? CompressPVRTC(src, dest, -1) : false;
  1442. }
  1443. return false;
  1444. }
  1445. /******************************************************************************/
  1446. static Bool CopyMipMaps(C Image &src, Image &dest) // this assumes that "&src != &dest"
  1447. {
  1448. if(dest.hwType()==src.hwType()
  1449. && dest. type()==src. type() // check 'type' too in case we have to perform color adjustment
  1450. && dest.w()<=src.w()
  1451. && dest.h()<=src.h()
  1452. && dest.d()<=src.d())
  1453. FREP(src.mipMaps()) // find location of first 'dest' mip-map in 'src'
  1454. {
  1455. Int src_mip_w=Max(1, src.w()>>i),
  1456. src_mip_h=Max(1, src.h()>>i),
  1457. src_mip_d=Max(1, src.d()>>i);
  1458. if( src_mip_w==dest.w() && src_mip_h==dest.h() && src_mip_d==dest.d()) // i-th 'src' mip-map is the same as first 'dest' mip-map
  1459. {
  1460. if(src.mipMaps()-i>=dest.mipMaps()) // if 'src' has all mip-maps needed in 'dest'
  1461. {
  1462. Int faces=dest.faces();
  1463. FREPD(mip , dest.mipMaps())
  1464. REPD(face, faces)
  1465. {
  1466. if(!src .lockRead( i+mip, DIR_ENUM(face)))return false;
  1467. if(!dest.lock (LOCK_WRITE, mip, DIR_ENUM(face))){src.unlock(); return false;}
  1468. Int blocks_y=Min(ImageBlocksY(src .hwW(), src .hwH(), i+mip, src .hwType()),
  1469. ImageBlocksY(dest.hwW(), dest.hwH(), mip, dest.hwType()));
  1470. REPD(z, dest.ld())
  1471. {
  1472. C Byte * src_data= src.data() + z* src.pitch2();
  1473. Byte *dest_data=dest.data() + z*dest.pitch2();
  1474. if(dest.pitch()==src.pitch())CopyFast(dest_data, src_data, Min(dest.pitch2(), src.pitch2()));
  1475. else REPD(y, blocks_y)CopyFast(dest_data + y*dest.pitch(), src_data + y*src.pitch(), Min(dest.pitch(), src.pitch()));
  1476. }
  1477. dest.unlock();
  1478. src .unlock();
  1479. }
  1480. return true;
  1481. }
  1482. break;
  1483. }
  1484. }
  1485. return false;
  1486. }
  1487. /******************************************************************************/
  1488. Bool Image::copyTry(Image &dest, Int w, Int h, Int d, Int type, Int mode, Int mip_maps, FILTER_TYPE filter, Bool clamp, Bool alpha_weight, Bool keep_edges, Bool mtrl_base_1, Bool rgba_on_fail)C
  1489. {
  1490. if(!is()){dest.del(); return true;}
  1491. // adjust settings
  1492. if(type<= 0)type=T.type();
  1493. if(mode<=-1)mode=T.mode();
  1494. if(h <= 0)h =T.h();
  1495. if(d <= 0)d =T.d();
  1496. if(w <= 0)w =(( cube() && !IsCube(IMAGE_MODE(mode)) ) ? T.w()*6 // if converting from cube to non-cube then use "w*6" size
  1497. : (!cube() && IsCube(IMAGE_MODE(mode)) && aspect()>AvgF(1, 6)) ? T.w()/6 // if converting from non-cube to cube and we have all 6 faces in the image then use "w/6" size
  1498. : T.w()); // otherwise use "w" size
  1499. // mip maps
  1500. Int src_total_mip_maps=TotalMipMaps(T.w(), T.h(), T.d(), T.type()),
  1501. dest_total_mip_maps=TotalMipMaps( w , h , d , IMAGE_TYPE(type) );
  1502. if(mip_maps<=-1)
  1503. {
  1504. if(w==T.w() && h==T.h() && d==T.d())mip_maps=T.mipMaps();else // same size
  1505. if(T.mipMaps()< src_total_mip_maps )mip_maps=T.mipMaps();else // less than total
  1506. if(T.mipMaps()==1 )mip_maps= 1;else // use only one
  1507. mip_maps= 0; // auto-detect mip maps
  1508. }
  1509. if(mip_maps<=0)mip_maps=dest_total_mip_maps ; // if mip maps not specified then use full chain
  1510. else MIN(mip_maps,dest_total_mip_maps); // don't use more than maximum allowed
  1511. // check if doesn't require conversion
  1512. if(this==&dest && w==T.w() && h==T.h() && d==T.d() && type==T.type() && mip_maps==T.mipMaps() && mode==T.mode())return true;
  1513. // check for cubes
  1514. // FIXME CUBE's should be optimized, for case when both are IsCube
  1515. C Image *src=this;
  1516. Image temp_src; if(src->cube())if(temp_src.fromCube(*src, IMAGE_R8G8B8A8))src=&temp_src;else return false;
  1517. if(IsCube((IMAGE_MODE)mode))return dest.toCube(*src, h, type, (IMAGE_MODE)mode, filter);
  1518. // convert
  1519. {
  1520. // create destination
  1521. Image temp_dest, &target=((src==&dest) ? temp_dest : dest);
  1522. if(!target.createTry(w, h, d, IMAGE_TYPE(type), IMAGE_MODE(mode), mip_maps, rgba_on_fail))return false;
  1523. // copy
  1524. if(
  1525. (src->size3()==target.size3() // if we use the same size (for which case 'filter' and 'keep_edges' are ignored)
  1526. || (
  1527. (filter==FILTER_BEST || filter==FILTER_DOWN) // we're going to use default filter for downsampling (which is typically used for mip-map generation)
  1528. && !keep_edges // we're not keeping the edges (which is typically used for mip-map generation)
  1529. )
  1530. )
  1531. && CopyMipMaps(*src, target)) // and we were able to copy all mip-maps needed in the destination from source
  1532. {
  1533. // this does not require 'updateMipMaps'
  1534. }else
  1535. {
  1536. if(src->size3()==target.size3() && src->hwType()==target.hwType()) // if match in size and hardware type
  1537. {
  1538. if(!src->copySoft(target, FILTER_NONE, clamp, alpha_weight, keep_edges))return false; // do raw memory copy
  1539. }else
  1540. if(src->size3()==target.size3() && src->compressed() && !target.compressed() // if match in size and just want to be decompressed
  1541. && (src->hwType()==IMAGE_BC1 || src->hwType()==IMAGE_BC2 || src->hwType()==IMAGE_BC3 || src->hwType()==IMAGE_BC7 // currently only BC
  1542. || src->hwType()==IMAGE_ETC1 || src->hwType()==IMAGE_ETC2 || src->hwType()==IMAGE_ETC2_A1 || src->hwType()==IMAGE_ETC2_A8)) // and ETC decompressors have this implemented
  1543. {
  1544. if(!Decompress(*src, target))return false;
  1545. }else
  1546. {
  1547. Image decompressed_src, resized_src;
  1548. if(src ->compressed()){if(!Decompress(*src, decompressed_src))return false; src=&decompressed_src;} // take decompressed source
  1549. if(target.compressed()) // target wants to be compressed
  1550. {
  1551. if(src->size3()!=target.size3()) // resize needed
  1552. {
  1553. if(!resized_src.createTry(target.w(), target.h(), target.d(), src->hwType(), IMAGE_SOFT, 1))return false;
  1554. if(!src->copySoft(resized_src, filter, clamp, alpha_weight, keep_edges))return false; src=&resized_src; decompressed_src.del(); // we don't need 'decompressed_src' anymore so delete it to release memory
  1555. }
  1556. if(!Compress(*src, target, mtrl_base_1))return false;
  1557. }else
  1558. {
  1559. if(!src->copySoft(target, filter, clamp, alpha_weight, keep_edges))return false;
  1560. }
  1561. }
  1562. target.updateMipMaps(FILTER_BEST, clamp, alpha_weight, mtrl_base_1);
  1563. }
  1564. if(&target!=&dest)Swap(dest, target);
  1565. return true;
  1566. }
  1567. }
  1568. void Image::copy(Image &dest, Int w, Int h, Int d, Int type, Int mode, Int mip_maps, FILTER_TYPE filter, Bool clamp, Bool alpha_weight, Bool keep_edges, Bool mtrl_base_1, Bool rgba_on_fail)C
  1569. {
  1570. if(!copyTry(dest, w, h, d, type, mode, mip_maps, filter, clamp, alpha_weight, keep_edges, mtrl_base_1, rgba_on_fail))Exit(MLTC(u"Can't copy Image", PL,u"Nie można skopiować Image"));
  1571. }
  1572. /******************************************************************************/
  1573. Bool Image::toCube(C Image &src, Int size, Int type, IMAGE_MODE mode, FILTER_TYPE filter)
  1574. {
  1575. if(!src.cube() && src.is())
  1576. {
  1577. if(type<=0 )type=src.type();
  1578. if(size< 0 )size=src.h ();
  1579. if(!IsCube(mode))mode=IMAGE_SOFT_CUBE;
  1580. Bool one=(src.aspect()<AvgF(1, 6)); // source is only 1 face, not "6*face"
  1581. Image temp;
  1582. if(temp.createTry(size, size, 1, IMAGE_TYPE(type), mode, 1))
  1583. {
  1584. if(one)
  1585. {
  1586. REP(6)if(!temp.injectMipMap(src, 0, DIR_ENUM(i), filter))return false;
  1587. }else
  1588. {
  1589. C Image *s=&src;
  1590. Image decompressed; if(src.compressed()){if(!src.copyTry(decompressed, -1, -1, -1, IMAGE_R8G8B8A8, IMAGE_SOFT, 1))return false; s=&decompressed;}
  1591. Image face; // keep outside the loop in case we can reuse it
  1592. REP(6)
  1593. {
  1594. s->crop(face, i*s->w()/6, 0, s->w()/6, s->h());
  1595. DIR_ENUM cube_face;
  1596. switch(i)
  1597. {
  1598. case 0: cube_face=DIR_LEFT ; break;
  1599. case 1: cube_face=DIR_FORWARD; break;
  1600. case 2: cube_face=DIR_RIGHT ; break;
  1601. case 3: cube_face=DIR_BACK ; break;
  1602. case 4: cube_face=DIR_DOWN ; break;
  1603. case 5: cube_face=DIR_UP ; break;
  1604. }
  1605. if(!temp.injectMipMap(face, 0, cube_face, filter))return false; // inject face
  1606. }
  1607. }
  1608. Swap(T, temp.updateMipMaps());
  1609. return true;
  1610. }
  1611. }
  1612. return false;
  1613. }
  1614. /******************************************************************************/
  1615. Bool Image::fromCube(C Image &src, Int type, IMAGE_MODE mode)
  1616. {
  1617. if(src.cube())
  1618. {
  1619. if(type<=0 )type=src.type();
  1620. if(IsCube(mode))mode=IMAGE_SOFT;
  1621. // extract 6 faces
  1622. Int size=src.h();
  1623. Image temp; if(!temp.createTry(size*6, size, 1, ImageTI[type].compressed ? IMAGE_R8G8B8A8 : IMAGE_TYPE(type), ImageTI[type].compressed ? IMAGE_SOFT : mode, 1))return false;
  1624. if(temp.lock(LOCK_WRITE))
  1625. {
  1626. Image face; // keep outside the loop in case we can reuse it
  1627. REPD(f, 6)
  1628. {
  1629. DIR_ENUM cube_face;
  1630. switch(f)
  1631. {
  1632. case 0: cube_face=DIR_LEFT ; break;
  1633. case 1: cube_face=DIR_FORWARD; break;
  1634. case 2: cube_face=DIR_RIGHT ; break;
  1635. case 3: cube_face=DIR_BACK ; break;
  1636. case 4: cube_face=DIR_DOWN ; break;
  1637. case 5: cube_face=DIR_UP ; break;
  1638. }
  1639. if(!src.extractMipMap(face, temp.hwType(), IMAGE_SOFT, 0, cube_face))return false; // extract face
  1640. // copy non-compressed 2D face to non-compressed 6*2D
  1641. if(!face.lockRead())return false;
  1642. REPD(y, size)
  1643. {
  1644. CopyFast(temp.data() + y*temp.pitch() + f*temp.bytePP()*size,
  1645. face.data() + y*face.pitch() , face.bytePP()*size);
  1646. }
  1647. face.unlock();
  1648. }
  1649. temp.unlock();
  1650. if(temp.copyTry(temp, -1, -1, -1, type, mode)){Swap(T, temp); return true;}
  1651. }
  1652. }
  1653. return false;
  1654. }
  1655. /******************************************************************************/
  1656. // LOCK
  1657. /******************************************************************************/
  1658. Byte* Image::softData(Int mip_map, DIR_ENUM cube_face)
  1659. {
  1660. return _data_all+ImageSize(hwW(), hwH(), hwD(), hwType(), mode(), mip_map)+(cube_face ? ImageMipSize(hwW(), hwH(), hwD(), mip_map, hwType())*cube_face : 0); // call 'ImageMipSize' only when needed because most likely 'cube_face' is zero
  1661. }
  1662. void Image::lockSoft()
  1663. {
  1664. _pitch =ImagePitch (hwW(), hwH(), lMipMap(), hwType());
  1665. _pitch2 =ImageBlocksY(hwW(), hwH(), lMipMap(), hwType())*_pitch;
  1666. _lock_size.x=Max(1, w()>>lMipMap());
  1667. _lock_size.y=Max(1, h()>>lMipMap());
  1668. _lock_size.z=Max(1, d()>>lMipMap());
  1669. _data =softData(lMipMap(), lCubeFace());
  1670. }
  1671. Bool Image::lock(LOCK_MODE lock, Int mip_map, DIR_ENUM cube_face)
  1672. {
  1673. if(InRange(mip_map, mipMaps()) && InRange(cube_face, 6)) // this already handles the case of "is()"
  1674. {
  1675. if(mode()==IMAGE_SOFT)
  1676. {
  1677. if(mipMaps()==1)return true; // if there's only one mip-map then we don't need to do anything
  1678. SyncLocker locker(ImageSoftLock);
  1679. if(!_lock_count) // if wasn't locked yet
  1680. {
  1681. _lock_count=1;
  1682. _lmm =mip_map; lockSoft(); // set '_lmm' before calling 'lockSoft'
  1683. return true;
  1684. }
  1685. if(lMipMap()==mip_map){_lock_count++; return true;} // we want the same mip-map that's already locked
  1686. }else
  1687. if(mode()==IMAGE_SOFT_CUBE)
  1688. {
  1689. SyncLocker locker(ImageSoftLock);
  1690. if(!_lock_count) // if wasn't locked yet
  1691. {
  1692. _lock_count=1;
  1693. _lmm =mip_map; _lcf=cube_face; lockSoft(); // set '_lmm, _lcf' before calling 'lockSoft'
  1694. return true;
  1695. }
  1696. if(lMipMap()==mip_map && lCubeFace()==cube_face){_lock_count++; return true;} // we want the same mip-map and cube-face that's already locked
  1697. }else
  1698. if(lock) // we want to set a proper lock
  1699. {
  1700. SyncLocker locker(D._lock);
  1701. if(D.created())
  1702. {
  1703. if(!_lock_mode)switch(mode()) // first lock
  1704. {
  1705. #if DX9
  1706. case IMAGE_SURF :
  1707. case IMAGE_SURF_SYSTEM :
  1708. case IMAGE_SURF_SCRATCH: if(_surf)
  1709. {
  1710. D3DLOCKED_RECT lr;
  1711. if(OK(_surf->LockRect(&lr, null, (lock==LOCK_READ) ? D3DLOCK_READONLY : 0)))
  1712. {
  1713. _lock_size.x=w();
  1714. _lock_size.y=h();
  1715. _lock_size.z=1;
  1716. _lmm =mip_map;
  1717. //_lcf =0;
  1718. _lock_mode =lock;
  1719. _lock_count =1;
  1720. _pitch =lr.Pitch;
  1721. _pitch2 =lr.Pitch*ImageBlocksY(hwW(), hwH(), mip_map, hwType());
  1722. _data =(Byte*)lr.pBits;
  1723. return true;
  1724. }
  1725. }break;
  1726. case IMAGE_2D: if(_txtr)
  1727. {
  1728. D3DLOCKED_RECT lr;
  1729. if(OK(_txtr->LockRect(mip_map, &lr, null, (lock==LOCK_READ) ? D3DLOCK_READONLY : 0)))
  1730. {
  1731. if(lock!=LOCK_READ && mip_map>0)_txtr->AddDirtyRect(null); // this is needed in case editing mip maps (not the first one, because that has automatically dirty rect set)
  1732. _lock_size.x=Max(1, w()>>mip_map);
  1733. _lock_size.y=Max(1, h()>>mip_map);
  1734. _lock_size.z=1;
  1735. _lmm =mip_map;
  1736. //_lcf =0;
  1737. _lock_mode =lock;
  1738. _lock_count =1;
  1739. _pitch =lr.Pitch;
  1740. _pitch2 =lr.Pitch*ImageBlocksY(hwW(), hwH(), mip_map, hwType());
  1741. _data =(Byte*)lr.pBits;
  1742. return true;
  1743. }
  1744. }break;
  1745. case IMAGE_3D: if(_vol)
  1746. {
  1747. D3DLOCKED_BOX lb;
  1748. if(OK(_vol->LockBox(mip_map, &lb, null, (lock==LOCK_READ) ? D3DLOCK_READONLY : 0)))
  1749. {
  1750. if(lock!=LOCK_READ && mip_map>0)_vol->AddDirtyBox(null); // this is needed in case editing mip maps (not the first one, because that has automatically dirty rect set)
  1751. _lock_size.x=Max(1, w()>>mip_map);
  1752. _lock_size.y=Max(1, h()>>mip_map);
  1753. _lock_size.z=Max(1, d()>>mip_map);
  1754. _lmm =mip_map;
  1755. //_lcf =0;
  1756. _lock_mode =lock;
  1757. _lock_count =1;
  1758. _pitch =lb. RowPitch;
  1759. _pitch2 =lb.SlicePitch;
  1760. _data =(Byte*)lb.pBits;
  1761. return true;
  1762. }
  1763. }break;
  1764. case IMAGE_CUBE: if(_cube)
  1765. {
  1766. D3DLOCKED_RECT lr;
  1767. if(OK(_cube->LockRect(D3DCUBEMAP_FACES(cube_face), mip_map, &lr, null, (lock==LOCK_READ) ? D3DLOCK_READONLY : 0)))
  1768. {
  1769. if(lock!=LOCK_READ && mip_map>0)_cube->AddDirtyRect(D3DCUBEMAP_FACES(cube_face), null); // this is needed in case editing mip maps (not the first one, because that has automatically dirty rect set)
  1770. _lock_size.x=Max(1, w()>>mip_map);
  1771. _lock_size.y=Max(1, h()>>mip_map);
  1772. _lock_size.z=1;
  1773. _lmm =mip_map;
  1774. _lcf =cube_face;
  1775. _lock_mode =lock;
  1776. _lock_count =1;
  1777. _pitch =lr.Pitch;
  1778. _pitch2 =lr.Pitch*ImageBlocksY(hwW(), hwH(), mip_map, hwType());
  1779. _data =(Byte*)lr.pBits;
  1780. return true;
  1781. }
  1782. }break;
  1783. case IMAGE_RT: if(lock==LOCK_READ) // DX9 supports only reading for now
  1784. {
  1785. Image temp; if(temp.capture(T))if(temp.lockRead())
  1786. {
  1787. _lock_size =temp._lock_size;
  1788. _lmm =mip_map;
  1789. //_lcf =0;
  1790. _lock_mode =lock;
  1791. _lock_count=1;
  1792. _pitch =temp.pitch ();
  1793. _pitch2 =temp.pitch2();
  1794. Alloc(_data, pitch2()); CopyFast(_data, temp.data(), pitch2());
  1795. return true;
  1796. }
  1797. }break;
  1798. #elif DX11
  1799. case IMAGE_RT:
  1800. case IMAGE_DS: case IMAGE_DS_RT:
  1801. case IMAGE_2D: if(_txtr)
  1802. {
  1803. Int blocks_y=ImageBlocksY(hwW(), hwH(), mip_map, hwType()),
  1804. pitch =ImagePitch (hwW(), hwH(), mip_map, hwType()),
  1805. pitch2 =pitch*blocks_y;
  1806. if(lock==LOCK_WRITE)Alloc(_data, pitch2);else
  1807. {
  1808. // get from GPU
  1809. Image temp; if(temp.createTry(PaddedWidth(hwW(), hwH(), mip_map, hwType()), PaddedHeight(hwW(), hwH(), mip_map, hwType()), 1, hwType(), IMAGE_SURF, 1, false))
  1810. {
  1811. D3DC->CopySubresourceRegion(temp._txtr, D3D11CalcSubresource(0, 0, temp.mipMaps()), 0, 0, 0, _txtr, D3D11CalcSubresource(mip_map, 0, mipMaps()), null);
  1812. if(temp.lockRead())
  1813. {
  1814. Alloc(_data, pitch2);
  1815. REPD(y, blocks_y)CopyFast(data()+y*pitch, temp.data()+y*temp.pitch(), pitch);
  1816. }
  1817. }
  1818. }
  1819. if(data())
  1820. {
  1821. _lock_size.x=Max(1, w()>>mip_map);
  1822. _lock_size.y=Max(1, h()>>mip_map);
  1823. _lock_size.z=1;
  1824. _lmm =mip_map;
  1825. //_lcf =0;
  1826. _lock_mode =lock;
  1827. _lock_count =1;
  1828. _pitch =pitch;
  1829. _pitch2 =pitch2;
  1830. return true;
  1831. }
  1832. }break;
  1833. case IMAGE_SURF_SCRATCH:
  1834. case IMAGE_SURF_SYSTEM :
  1835. case IMAGE_SURF : if(_txtr)
  1836. {
  1837. D3D11_MAPPED_SUBRESOURCE map; if(OK(D3DC->Map(_txtr, D3D11CalcSubresource(mip_map, 0, mipMaps()), (lock==LOCK_READ) ? D3D11_MAP_READ : (lock==LOCK_WRITE) ? D3D11_MAP_WRITE : D3D11_MAP_READ_WRITE, 0, &map))) // staging does not support D3D11_MAP_WRITE_DISCARD
  1838. {
  1839. _lock_size.x=Max(1, w()>>mip_map);
  1840. _lock_size.y=Max(1, h()>>mip_map);
  1841. _lock_size.z=1;
  1842. _lmm =mip_map;
  1843. //_lcf =0;
  1844. _lock_mode =lock;
  1845. _lock_count =1;
  1846. _data =(Byte*)map.pData;
  1847. _pitch = map. RowPitch;
  1848. _pitch2 = map.DepthPitch;
  1849. return true;
  1850. }
  1851. }break;
  1852. case IMAGE_3D: if(_vol)
  1853. {
  1854. Int ld =Max(1, d()>>mip_map),
  1855. blocks_y=ImageBlocksY(hwW(), hwH(), mip_map, hwType()),
  1856. pitch =ImagePitch (hwW(), hwH(), mip_map, hwType()),
  1857. pitch2 =pitch *blocks_y,
  1858. pitch3 =pitch2*ld;
  1859. if(lock==LOCK_WRITE)Alloc(_data, pitch3);else
  1860. {
  1861. // get from GPU
  1862. D3D11_TEXTURE3D_DESC desc;
  1863. desc.Width =PaddedWidth (hwW(), hwH(), mip_map, hwType());
  1864. desc.Height =PaddedHeight(hwW(), hwH(), mip_map, hwType());
  1865. desc.Depth =ld;
  1866. desc.MipLevels =1;
  1867. desc.Format =ImageTI[hwType()].format;
  1868. desc.Usage =D3D11_USAGE_STAGING;
  1869. desc.BindFlags =0;
  1870. desc.MiscFlags =0;
  1871. desc.CPUAccessFlags=D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE;
  1872. ID3D11Texture3D *temp; if(OK(D3D->CreateTexture3D(&desc, null, &temp)))
  1873. {
  1874. D3DC->CopySubresourceRegion(temp, D3D11CalcSubresource(0,0,1), 0, 0, 0, _vol, D3D11CalcSubresource(mip_map, 0, mipMaps()), null);
  1875. D3D11_MAPPED_SUBRESOURCE map; if(OK(D3DC->Map(temp, D3D11CalcSubresource(0,0,1), D3D11_MAP_READ, 0, &map)))
  1876. {
  1877. Alloc(_data, pitch3);
  1878. REPD(z, ld)
  1879. {
  1880. Byte *src =(Byte*)map.pData +z*map.DepthPitch ,
  1881. *dest= data()+z* pitch2;
  1882. REPD(y, blocks_y)CopyFast(dest+y*pitch, src+y*map.RowPitch, pitch);
  1883. }
  1884. D3DC->Unmap(temp, D3D11CalcSubresource(0,0,1));
  1885. }
  1886. RELEASE(temp);
  1887. }
  1888. }
  1889. if(data())
  1890. {
  1891. _lock_size.x=Max(1, w()>>mip_map);
  1892. _lock_size.y=Max(1, h()>>mip_map);
  1893. _lock_size.z=ld;
  1894. _lmm =mip_map;
  1895. //_lcf =0;
  1896. _lock_mode =lock;
  1897. _lock_count =1;
  1898. _pitch =pitch;
  1899. _pitch2 =pitch2;
  1900. return true;
  1901. }
  1902. }break;
  1903. case IMAGE_CUBE: if(_txtr)
  1904. {
  1905. Int blocks_y=ImageBlocksY(hwW(), hwH(), mip_map, hwType()),
  1906. pitch =ImagePitch (hwW(), hwH(), mip_map, hwType()),
  1907. pitch2 =pitch*blocks_y;
  1908. if(lock==LOCK_WRITE)Alloc(_data, pitch2);else
  1909. {
  1910. // get from GPU
  1911. Image temp; if(temp.createTry(PaddedWidth(hwW(), hwH(), mip_map, hwType()), PaddedHeight(hwW(), hwH(), mip_map, hwType()), 1, hwType(), IMAGE_SURF, 1, false))
  1912. {
  1913. D3DC->CopySubresourceRegion(temp._txtr, D3D11CalcSubresource(0, 0, temp.mipMaps()), 0, 0, 0, _txtr, D3D11CalcSubresource(mip_map, cube_face, mipMaps()), null);
  1914. if(temp.lockRead())
  1915. {
  1916. Alloc(_data, pitch2);
  1917. REPD(y, blocks_y)CopyFast(data()+y*pitch, temp.data()+y*temp.pitch(), pitch);
  1918. }
  1919. }
  1920. }
  1921. if(data())
  1922. {
  1923. _lock_size.x=Max(1, w()>>mip_map);
  1924. _lock_size.y=Max(1, h()>>mip_map);
  1925. _lock_size.z=1;
  1926. _lmm =mip_map;
  1927. _lcf =cube_face;
  1928. _lock_mode =lock;
  1929. _lock_count =1;
  1930. _pitch =pitch;
  1931. _pitch2 =pitch2;
  1932. return true;
  1933. }
  1934. }break;
  1935. #elif GL
  1936. case IMAGE_2D :
  1937. case IMAGE_RT :
  1938. case IMAGE_SURF_SCRATCH:
  1939. case IMAGE_SURF_SYSTEM :
  1940. case IMAGE_SURF :
  1941. case IMAGE_DS_RT : if(_txtr)
  1942. {
  1943. Int pitch =ImagePitch (hwW(), hwH(), mip_map, hwType()),
  1944. pitch2=ImageBlocksY(hwW(), hwH(), mip_map, hwType())*pitch;
  1945. #if GL_ES // 'glGetTexImage' not available on GL ES
  1946. if(mode()==IMAGE_RT) // must use 'glReadPixels'
  1947. {
  1948. if(!compressed())
  1949. {
  1950. Alloc(_data, CeilGL(pitch2));
  1951. if(lock!=LOCK_WRITE) // get from GPU
  1952. {
  1953. Image *rt[Elms(Renderer._cur)], *ds;
  1954. Bool restore_viewport=!D._view_active.full;
  1955. REPAO(rt)=Renderer._cur[i];
  1956. ds =Renderer._cur_ds;
  1957. Renderer.set(this, null, false); // put 'this' to FBO
  1958. glGetError(); // clear any previous errors
  1959. UInt format=SourceGLFormat(hwType());
  1960. Bool ok =false;
  1961. Int pw=PaddedWidth (hwW(), hwH(), mip_map, hwType()),
  1962. ph=PaddedHeight(hwW(), hwH(), mip_map, hwType()),
  1963. type=SourceGLType(hwType());
  1964. glReadPixels(0, 0, pw, ph, format , type, _data); ok=(glGetError()==GL_NO_ERROR);
  1965. if(!ok)Free(_data);
  1966. // restore settings
  1967. Renderer.set(rt[0], rt[1], rt[2], rt[3], ds, restore_viewport);
  1968. }
  1969. }
  1970. }else
  1971. {
  1972. if(!_data_all && lock==LOCK_WRITE && mipMaps()==1)Alloc(_data_all, CeilGL(memUsage())); // if GL ES data is not available, but we want to write to it and we have only 1 mip map then re-create it
  1973. if( _data_all)_data=softData(mip_map);
  1974. }
  1975. #else
  1976. Alloc(_data, CeilGL(pitch2));
  1977. if(lock!=LOCK_WRITE) // get from GPU
  1978. {
  1979. glGetError(); // clear any previous errors
  1980. D.texBind(GL_TEXTURE_2D, _txtr);
  1981. if(!compressed())glGetTexImage(GL_TEXTURE_2D, mip_map, SourceGLFormat(hwType()), SourceGLType(hwType()), data());
  1982. else glGetCompressedTexImage(GL_TEXTURE_2D, mip_map, data());
  1983. if(glGetError()!=GL_NO_ERROR)Free(_data);
  1984. }
  1985. #endif
  1986. if(data())
  1987. {
  1988. _lock_size.x=Max(1, w()>>mip_map);
  1989. _lock_size.y=Max(1, h()>>mip_map);
  1990. _lock_size.z=1;
  1991. _lmm =mip_map;
  1992. //_lcf =0;
  1993. _lock_mode =lock;
  1994. _lock_count =1;
  1995. _pitch =pitch;
  1996. _pitch2 =pitch2;
  1997. return true;
  1998. }
  1999. }break;
  2000. case IMAGE_3D: if(_txtr)
  2001. {
  2002. Int ld =Max(1, d()>>mip_map),
  2003. pitch =ImagePitch (hwW(), hwH(), mip_map, hwType()),
  2004. pitch2=ImageBlocksY(hwW(), hwH(), mip_map, hwType())*pitch;
  2005. #if GL_ES // 'glGetTexImage' not available on GL ES
  2006. if(!_data_all && lock==LOCK_WRITE && mipMaps()==1)Alloc(_data_all, CeilGL(memUsage())); // if GL ES data is not available, but we want to write to it and we have only 1 mip map then re-create it
  2007. if( _data_all)_data=softData(mip_map);
  2008. #else
  2009. Alloc(_data, CeilGL(pitch2*ld));
  2010. if(lock!=LOCK_WRITE) // get from GPU
  2011. {
  2012. glGetError(); // clear any previous errors
  2013. D.texBind(GL_TEXTURE_3D, _txtr);
  2014. if(!compressed())glGetTexImage(GL_TEXTURE_3D, mip_map, SourceGLFormat(hwType()), SourceGLType(hwType()), data());
  2015. else glGetCompressedTexImage(GL_TEXTURE_3D, mip_map, data());
  2016. if(glGetError()!=GL_NO_ERROR)Free(_data);
  2017. }
  2018. #endif
  2019. if(data())
  2020. {
  2021. _lock_size.x=Max(1, w()>>mip_map);
  2022. _lock_size.y=Max(1, h()>>mip_map);
  2023. _lock_size.z=ld;
  2024. _lmm =mip_map;
  2025. //_lcf =0;
  2026. _lock_mode =lock;
  2027. _lock_count =1;
  2028. _pitch =pitch;
  2029. _pitch2 =pitch2;
  2030. return true;
  2031. }
  2032. }break;
  2033. case IMAGE_CUBE: if(_txtr)
  2034. {
  2035. Int pitch =ImagePitch (hwW(), hwH(), mip_map, hwType()),
  2036. pitch2=ImageBlocksY(hwW(), hwH(), mip_map, hwType())*pitch;
  2037. #if GL_ES
  2038. //if(!_data_all && lock==LOCK_WRITE && mipMaps()==1)Alloc(_data_all, CeilGL(memUsage())); // if GL ES data is not available, but we want to write to it and we have only 1 mip map then re-create it, can't do it here, because we have 6 faces, but we can lock only 1
  2039. if( _data_all)_data=softData(mip_map, cube_face);
  2040. #else
  2041. Alloc(_data, CeilGL(pitch2));
  2042. if(lock!=LOCK_WRITE) // get from GPU
  2043. {
  2044. glGetError(); // clear any previous errors
  2045. D.texBind(GL_TEXTURE_CUBE_MAP, _txtr);
  2046. if(!compressed())glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X+cube_face, mip_map, SourceGLFormat(hwType()), SourceGLType(hwType()), data());
  2047. else glGetCompressedTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X+cube_face, mip_map, data());
  2048. if(glGetError()!=GL_NO_ERROR)Free(_data);
  2049. }
  2050. #endif
  2051. if(data())
  2052. {
  2053. _lock_size.x=Max(1, w()>>mip_map);
  2054. _lock_size.y=Max(1, h()>>mip_map);
  2055. _lock_size.z=1;
  2056. _lmm =mip_map;
  2057. _lcf =cube_face;
  2058. _lock_mode =lock;
  2059. _lock_count =1;
  2060. _pitch =pitch;
  2061. _pitch2 =pitch2;
  2062. return true;
  2063. }
  2064. }break;
  2065. #endif
  2066. }else
  2067. if(CompatibleLock(_lock_mode, lock) && lMipMap()==mip_map && lCubeFace()==cube_face){_lock_count++; return true;} // there was already a lock, just increase the counter and return success
  2068. }
  2069. }
  2070. }
  2071. return false;
  2072. }
  2073. /******************************************************************************/
  2074. Image& Image::unlock()
  2075. {
  2076. if(_lock_count>0) // if image was locked
  2077. {
  2078. if(soft())
  2079. {
  2080. //for IMAGE_SOFT we don't need "if(mipMaps()>1)" check, because for IMAGE_SOFT, '_lock_count' will be set only if image has mip-maps, and since we've already checked "_lock_count>0" before, then we know we have mip-maps
  2081. SafeSyncLocker locker(ImageSoftLock);
  2082. if(_lock_count>0) // if locked
  2083. if(!--_lock_count) // if unlocked now
  2084. if(lMipMap()!=0 || lCubeFace()!=0) // if last locked mip-map or cube-face was not main
  2085. {
  2086. _lmm=0; _lcf=DIR_ENUM(0); lockSoft(); // set default lock members to main mip map and cube face, set '_lmm, _lcf' before calling 'lockSoft'
  2087. }
  2088. }else
  2089. {
  2090. SafeSyncLockerEx locker(D._lock);
  2091. if(_lock_count>0)if(!--_lock_count)switch(mode())
  2092. {
  2093. #if DX9
  2094. case IMAGE_SURF :
  2095. case IMAGE_SURF_SYSTEM :
  2096. case IMAGE_SURF_SCRATCH:
  2097. if(D.created())_surf->UnlockRect();
  2098. _lock_size.zero();
  2099. _lmm =0;
  2100. //_lcf =0;
  2101. _lock_mode=LOCK_NONE;
  2102. _pitch =0;
  2103. _pitch2 =0;
  2104. _data =null;
  2105. break;
  2106. case IMAGE_2D:
  2107. if(D.created())_txtr->UnlockRect(lMipMap());
  2108. _lock_size.zero();
  2109. _lmm =0;
  2110. //_lcf =0;
  2111. _lock_mode=LOCK_NONE;
  2112. _pitch =0;
  2113. _pitch2 =0;
  2114. _data =null;
  2115. break;
  2116. case IMAGE_3D:
  2117. if(D.created())_vol->UnlockBox(lMipMap());
  2118. _lock_size.zero();
  2119. _lmm =0;
  2120. //_lcf =0;
  2121. _lock_mode=LOCK_NONE;
  2122. _pitch =0;
  2123. _pitch2 =0;
  2124. _data =null;
  2125. break;
  2126. case IMAGE_CUBE:
  2127. {
  2128. if(D.created())_cube->UnlockRect(D3DCUBEMAP_FACES(lCubeFace()), lMipMap());
  2129. _lock_size.zero();
  2130. _lmm =0;
  2131. _lcf =DIR_ENUM(0);
  2132. _lock_mode=LOCK_NONE;
  2133. _pitch =0;
  2134. _pitch2 =0;
  2135. _data =null;
  2136. }break;
  2137. case IMAGE_RT:
  2138. {
  2139. _lock_size.zero();
  2140. _lmm =0;
  2141. //_lcf =0;
  2142. _lock_mode=LOCK_NONE;
  2143. _pitch =0;
  2144. _pitch2 =0;
  2145. Free(_data);
  2146. }break;
  2147. #elif DX11
  2148. case IMAGE_RT:
  2149. case IMAGE_2D:
  2150. case IMAGE_DS: case IMAGE_DS_RT:
  2151. {
  2152. if(_lock_mode!=LOCK_READ && D3DC)D3DC->UpdateSubresource(_txtr, D3D11CalcSubresource(lMipMap(), 0, mipMaps()), null, data(), pitch(), pitch2());
  2153. _lock_size.zero();
  2154. _lmm =0;
  2155. //_lcf =0;
  2156. _lock_mode=LOCK_NONE;
  2157. _pitch =0;
  2158. _pitch2 =0;
  2159. Free(_data);
  2160. }break;
  2161. case IMAGE_SURF_SCRATCH:
  2162. case IMAGE_SURF_SYSTEM :
  2163. case IMAGE_SURF :
  2164. {
  2165. if(D3DC)D3DC->Unmap(_txtr, D3D11CalcSubresource(lMipMap(), 0, mipMaps()));
  2166. _lock_size.zero();
  2167. _lmm =0;
  2168. //_lcf =0;
  2169. _lock_mode=LOCK_NONE;
  2170. _pitch =0;
  2171. _pitch2 =0;
  2172. _data =null;
  2173. }break;
  2174. case IMAGE_3D:
  2175. {
  2176. if(_lock_mode!=LOCK_READ && D3DC)D3DC->UpdateSubresource(_vol, D3D11CalcSubresource(lMipMap(), 0, mipMaps()), null, data(), pitch(), pitch2());
  2177. _lock_size.zero();
  2178. _lmm =0;
  2179. //_lcf =0;
  2180. _lock_mode=LOCK_NONE;
  2181. _pitch =0;
  2182. _pitch2 =0;
  2183. Free(_data);
  2184. }break;
  2185. case IMAGE_CUBE:
  2186. {
  2187. if(_lock_mode!=LOCK_READ && D3DC)D3DC->UpdateSubresource(_txtr, D3D11CalcSubresource(lMipMap(), lCubeFace(), mipMaps()), null, data(), pitch(), pitch2());
  2188. _lock_size.zero();
  2189. _lmm =0;
  2190. _lcf =DIR_ENUM(0);
  2191. _lock_mode=LOCK_NONE;
  2192. _pitch =0;
  2193. _pitch2 =0;
  2194. Free(_data);
  2195. }break;
  2196. #elif GL
  2197. case IMAGE_2D :
  2198. case IMAGE_RT :
  2199. case IMAGE_SURF_SCRATCH:
  2200. case IMAGE_SURF_SYSTEM :
  2201. case IMAGE_SURF :
  2202. case IMAGE_DS_RT :
  2203. {
  2204. if(_lock_mode!=LOCK_READ && D.created())
  2205. if(!(lMipMap() && ForceDisableMipMaps(T))) // don't upload mip maps if not allowed
  2206. {
  2207. #if GL_ES
  2208. if(mode()==IMAGE_RT)
  2209. {
  2210. // glDrawPixels
  2211. }else
  2212. #endif
  2213. {
  2214. _lock_count++; locker.off(); // OpenGL has per-thread context states, which means we don't need to be locked during following calls, this is important as following calls can be slow
  2215. D.texBind(GL_TEXTURE_2D, _txtr);
  2216. if(!compressed())glTexImage2D(GL_TEXTURE_2D, lMipMap(), ImageTI[hwType()].format, Max(1, hwW()>>lMipMap()), Max(1, hwH()>>lMipMap()), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), data());
  2217. else glCompressedTexImage2D(GL_TEXTURE_2D, lMipMap(), ImageTI[hwType()].format, Max(1, hwW()>>lMipMap()), Max(1, hwH()>>lMipMap()), 0, pitch2(), data());
  2218. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  2219. locker.on(); _lock_count--;
  2220. }
  2221. }
  2222. if(!_lock_count)
  2223. {
  2224. _lock_size.zero();
  2225. _lmm =0;
  2226. //_lcf =0;
  2227. _lock_mode=LOCK_NONE;
  2228. _pitch =0;
  2229. _pitch2 =0;
  2230. _discard =false;
  2231. #if GL_ES
  2232. if(mode()==IMAGE_RT)Free(_data);else _data=null;
  2233. #else
  2234. Free(_data);
  2235. #endif
  2236. }
  2237. }break;
  2238. case IMAGE_3D:
  2239. {
  2240. if(_lock_mode!=LOCK_READ && D.created())
  2241. {
  2242. _lock_count++; locker.off(); // OpenGL has per-thread context states, which means we don't need to be locked during following calls, this is important as following calls can be slow
  2243. D.texBind(GL_TEXTURE_3D, _txtr);
  2244. if(!compressed())glTexImage3D(GL_TEXTURE_3D, lMipMap(), ImageTI[hwType()].format, Max(1, hwW()>>lMipMap()), Max(1, hwH()>>lMipMap()), Max(1, hwD()>>lMipMap()), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), data());
  2245. else glCompressedTexImage3D(GL_TEXTURE_3D, lMipMap(), ImageTI[hwType()].format, Max(1, hwW()>>lMipMap()), Max(1, hwH()>>lMipMap()), Max(1, hwD()>>lMipMap()), 0, pitch2()*ld(), data());
  2246. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  2247. locker.on(); _lock_count--;
  2248. }
  2249. if(!_lock_count)
  2250. {
  2251. _lock_size.zero();
  2252. _lmm =0;
  2253. //_lcf =0;
  2254. _lock_mode=LOCK_NONE;
  2255. _pitch =0;
  2256. _pitch2 =0;
  2257. #if GL_ES
  2258. _data =null;
  2259. #else
  2260. Free(_data);
  2261. #endif
  2262. }
  2263. }break;
  2264. case IMAGE_CUBE:
  2265. {
  2266. if(_lock_mode!=LOCK_READ && D.created())
  2267. {
  2268. _lock_count++; locker.off(); // OpenGL has per-thread context states, which means we don't need to be locked during following calls, this is important as following calls can be slow
  2269. D.texBind(GL_TEXTURE_CUBE_MAP, _txtr);
  2270. if(!compressed())glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+lCubeFace(), lMipMap(), ImageTI[hwType()].format, Max(1, hwW()>>lMipMap()), Max(1, hwH()>>lMipMap()), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), data());
  2271. else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+lCubeFace(), lMipMap(), ImageTI[hwType()].format, Max(1, hwW()>>lMipMap()), Max(1, hwH()>>lMipMap()), 0, pitch2(), data());
  2272. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  2273. locker.on(); _lock_count--;
  2274. }
  2275. if(!_lock_count)
  2276. {
  2277. _lock_size.zero();
  2278. _lmm =0;
  2279. _lcf =DIR_ENUM(0);
  2280. _lock_mode=LOCK_NONE;
  2281. _pitch =0;
  2282. _pitch2 =0;
  2283. #if GL_ES
  2284. _data =null;
  2285. #else
  2286. Free(_data);
  2287. #endif
  2288. }
  2289. }break;
  2290. #endif
  2291. }
  2292. }
  2293. }
  2294. return T;
  2295. }
  2296. Bool Image:: lockRead(Int mip_map, DIR_ENUM cube_face)C {return ConstCast(T). lock(LOCK_READ, mip_map, cube_face);}
  2297. C Image& Image::unlock ( )C {return ConstCast(T).unlock();}
  2298. /******************************************************************************/
  2299. Bool Image::setFrom(CPtr data, Int data_pitch, Int mip_map, DIR_ENUM cube_face)
  2300. {
  2301. if(data)
  2302. {
  2303. Int valid_pitch =ImagePitch (w(), h(), mip_map, hwType()),
  2304. valid_blocks_y=ImageBlocksY(w(), h(), mip_map, hwType());
  2305. #if DEBUG && 0 // force HW size
  2306. #pragma message("!! Warning: Use this only for debugging !!")
  2307. Memt<Byte> temp;
  2308. {
  2309. Int hw_pitch =ImagePitch (hwW(), hwH(), mip_map, hwType()),
  2310. hw_blocks_y=ImageBlocksY(hwW(), hwH(), mip_map, hwType()),
  2311. hw_pitch2 =hw_pitch*hw_blocks_y;
  2312. temp.setNum(hw_pitch2);
  2313. Int copy_pitch=Min(hw_pitch, data_pitch, valid_pitch);
  2314. FREP(valid_blocks_y)Copy(temp.data()+hw_pitch*i, (Byte*)data+data_pitch*i, copy_pitch);
  2315. data=temp.data(); data_pitch=hw_pitch;
  2316. }
  2317. #endif
  2318. #if DX11
  2319. if(hw() && InRange(mip_map, mipMaps()) && InRange(cube_face, 6))
  2320. {
  2321. Int data_pitch2=data_pitch*valid_blocks_y; // 'data_pitch2' could be moved into a method parameter
  2322. SyncLocker locker(D._lock); if(D3DC)switch(mode())
  2323. {
  2324. case IMAGE_RT:
  2325. case IMAGE_2D:
  2326. case IMAGE_DS: case IMAGE_DS_RT:
  2327. {
  2328. D3DC->UpdateSubresource(_txtr, D3D11CalcSubresource(mip_map, 0, mipMaps()), null, data, data_pitch, data_pitch2);
  2329. }return true;
  2330. case IMAGE_3D:
  2331. {
  2332. D3DC->UpdateSubresource(_vol, D3D11CalcSubresource(mip_map, 0, mipMaps()), null, data, data_pitch, data_pitch2);
  2333. }return true;
  2334. case IMAGE_CUBE:
  2335. {
  2336. D3DC->UpdateSubresource(_txtr, D3D11CalcSubresource(mip_map, cube_face, mipMaps()), null, data, data_pitch, data_pitch2);
  2337. }return true;
  2338. }
  2339. }
  2340. #elif GL // GL can accept only HW sizes
  2341. Int hw_pitch =ImagePitch (hwW(), hwH(), mip_map, hwType()),
  2342. hw_blocks_y=ImageBlocksY(hwW(), hwH(), mip_map, hwType()),
  2343. hw_pitch2 =hw_pitch*hw_blocks_y;
  2344. if( hw_pitch==data_pitch && InRange(mip_map, mipMaps()) && InRange(cube_face, 6) && D.created())switch(mode())
  2345. {
  2346. case IMAGE_2D :
  2347. case IMAGE_RT :
  2348. case IMAGE_SURF_SCRATCH:
  2349. case IMAGE_SURF_SYSTEM :
  2350. case IMAGE_SURF :
  2351. case IMAGE_DS_RT :
  2352. { // OpenGL has per-thread context states, which means we don't need to be locked during following calls, this is important as following calls can be slow
  2353. D.texBind(GL_TEXTURE_2D, _txtr);
  2354. if(!compressed())glTexImage2D(GL_TEXTURE_2D, mip_map, ImageTI[hwType()].format, Max(1, hwW()>>mip_map), Max(1, hwH()>>mip_map), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), data);
  2355. else glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, ImageTI[hwType()].format, Max(1, hwW()>>mip_map), Max(1, hwH()>>mip_map), 0, hw_pitch2, data);
  2356. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  2357. _discard=false;
  2358. }return true;
  2359. case IMAGE_3D:
  2360. { // OpenGL has per-thread context states, which means we don't need to be locked during following calls, this is important as following calls can be slow
  2361. Int d=Max(1, hwD()>>mip_map);
  2362. D.texBind(GL_TEXTURE_3D, _txtr);
  2363. if(!compressed())glTexImage3D(GL_TEXTURE_3D, mip_map, ImageTI[hwType()].format, Max(1, hwW()>>mip_map), Max(1, hwH()>>mip_map), d, 0, SourceGLFormat(hwType()), SourceGLType(hwType()), data);
  2364. else glCompressedTexImage3D(GL_TEXTURE_3D, mip_map, ImageTI[hwType()].format, Max(1, hwW()>>mip_map), Max(1, hwH()>>mip_map), d, 0, hw_pitch2*d, data);
  2365. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  2366. }return true;
  2367. case IMAGE_CUBE:
  2368. { // OpenGL has per-thread context states, which means we don't need to be locked during following calls, this is important as following calls can be slow
  2369. D.texBind(GL_TEXTURE_CUBE_MAP, _txtr);
  2370. if(!compressed())glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+cube_face, mip_map, ImageTI[hwType()].format, Max(1, hwW()>>mip_map), Max(1, hwH()>>mip_map), 0, SourceGLFormat(hwType()), SourceGLType(hwType()), data);
  2371. else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+cube_face, mip_map, ImageTI[hwType()].format, Max(1, hwW()>>mip_map), Max(1, hwH()>>mip_map), 0, hw_pitch2, data);
  2372. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  2373. }return true;
  2374. }
  2375. #endif
  2376. if(lock(LOCK_WRITE, mip_map, cube_face))
  2377. {
  2378. Byte *dest_data =T.data();
  2379. const Int copy_pitch=Min(T.pitch(), data_pitch, valid_pitch),
  2380. zero_pitch=T.pitch ()-copy_pitch,
  2381. pitch2 =T.pitch ()*valid_blocks_y,
  2382. zero =T.pitch2()-pitch2; // how much to zero = total - what was set
  2383. FREPD(z, ld())
  2384. {
  2385. if(copy_pitch==data_pitch && !zero_pitch) // if all pitches are the same (copy_pitch, data_pitch, T.pitch)
  2386. { // we can copy both XY in one go !! use 'pitch2' and not 'T.pitch2', because 'T.pitch2' may be bigger !!
  2387. CopyFast(dest_data, data, pitch2);
  2388. dest_data+= pitch2;
  2389. data =(Byte*)data+pitch2;
  2390. }else
  2391. FREPD(y, valid_blocks_y) // copy each line separately
  2392. {
  2393. CopyFast(dest_data, data, copy_pitch);
  2394. Zero (dest_data+copy_pitch, zero_pitch); // zero remaining data to avoid garbage
  2395. dest_data+= T.pitch();
  2396. data =(Byte*)data+data_pitch;
  2397. }
  2398. Zero(dest_data, zero); // zero remaining data to avoid garbage
  2399. dest_data+=zero;
  2400. }
  2401. unlock();
  2402. return true;
  2403. }
  2404. }
  2405. return false;
  2406. }
  2407. /******************************************************************************/
  2408. Image& Image::freeOpenGLESData()
  2409. {
  2410. #if GL_ES
  2411. unlock();
  2412. if(hw())Free(_data_all);
  2413. #endif
  2414. return T;
  2415. }
  2416. /******************************************************************************/
  2417. Image& Image::updateMipMaps(FILTER_TYPE filter, Bool clamp, Bool alpha_weight, Bool mtrl_base_1, Int mip_start)
  2418. {
  2419. MAX(mip_start, 0);
  2420. if (InRange(mip_start+1, mipMaps())) // if we can set the next one
  2421. {
  2422. Image temp; // keep outside the loop in case we can reuse the image
  2423. REPD(f, faces())
  2424. {
  2425. extractMipMap(temp, ImageTI[type()].compressed ? IMAGE_R8G8B8A8 : type(), IMAGE_SOFT, mip_start, DIR_ENUM(f)); // use 'type' instead of 'hwType' (this is correct)
  2426. for(Int mip=mip_start; ++mip<mipMaps(); )
  2427. {
  2428. temp.downSample(filter, clamp, alpha_weight);
  2429. injectMipMap(temp, mip, DIR_ENUM(f), FILTER_BEST, clamp, mtrl_base_1);
  2430. }
  2431. }
  2432. }
  2433. return T;
  2434. }
  2435. /******************************************************************************/
  2436. // GET
  2437. /******************************************************************************/
  2438. Int Image::faces()C {return is() ? cube() ? 6 : 1 : 0;}
  2439. /******************************************************************************/
  2440. UInt Image:: memUsage()C {return ImageSize(hwW(), hwH(), hwD(), hwType(), mode(), mipMaps());}
  2441. UInt Image::typeMemUsage()C {return ImageSize(hwW(), hwH(), hwD(), type(), mode(), mipMaps());}
  2442. /******************************************************************************/
  2443. Bool Image::map()
  2444. {
  2445. #if DX9
  2446. del(); if(OK(D3D->GetRenderTarget(0, &T._surf))){setInfo(0, 0, 0, 0, IMAGE_SURF); return true;}
  2447. #elif DX11
  2448. del(); if(OK(SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (Ptr*)&_txtr))){setInfo(0, 0, 0, 0, IMAGE_RT); return true;}
  2449. #elif DX12
  2450. https://msdn.microsoft.com/en-us/library/windows/desktop/mt427784(v=vs.85).aspx
  2451. In Direct3D 11, applications could call GetBuffer( 0, .. ) only once. Every call to Present implicitly changed the resource identity of the returned interface. Direct3D 12 no longer supports that implicit resource identity change, due to the CPU overhead required and the flexible resource descriptor design. As a result, the application must manually call GetBuffer for every each buffer created with the swapchain. The application must manually render to the next buffer in the sequence after calling Present. Applications are encouraged to create a cache of descriptors for each buffer, instead of re-creating many objects each Present.
  2452. #elif IOS
  2453. del();
  2454. if(EAGLView *view=GetUIView())
  2455. {
  2456. glGenRenderbuffers(1, &_rb); if(_rb)
  2457. {
  2458. glGetError(); // clear any previous errors
  2459. glBindRenderbuffer(GL_RENDERBUFFER, _rb);
  2460. [MainContext.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)view.layer];
  2461. setInfo(0, 0, 0, 0, IMAGE_SURF); // this has a valid '_rb' so it can detect the size and type
  2462. D._res=size(); D.densityUpdate();
  2463. return true;
  2464. }
  2465. }
  2466. #elif ANDROID || WEB
  2467. // on Android and Web 'Renderer._main' has 'setInfo' called externally in the main loop
  2468. return true;
  2469. #elif DESKTOP
  2470. forceInfo(D.resW(), D.resH(), 1, type() ? type() : IMAGE_DEFAULT, IMAGE_SURF); return true;
  2471. #endif
  2472. return false;
  2473. }
  2474. /******************************************************************************/
  2475. void Image::unmap()
  2476. {
  2477. #if DX9 || DX11
  2478. del();
  2479. #elif IOS
  2480. if(_rb)
  2481. {
  2482. glBindRenderbuffer(GL_RENDERBUFFER, _rb);
  2483. [MainContext.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:nil]; // detach existing renderbuffer from the drawable object
  2484. del();
  2485. }
  2486. #else
  2487. // on other platforms we're not responsible for the 'Renderer._main' as the system creates it and deletes it, don't delete it here, to preserve info about IMAGE_TYPE and samples
  2488. #endif
  2489. }
  2490. /******************************************************************************/
  2491. // HARDWARE
  2492. /******************************************************************************/
  2493. void SetRects(C Image &src, C Image &dest, RectI &rect_src, RectI &rect_dest, C Rect &rect)
  2494. {
  2495. Rect uv=D.screenToUV(rect);
  2496. // first the smaller Image must be set, and then the bigger Image must be set proportionally
  2497. if(dest.hwW()<src.hwW()){rect_dest.setX(Round(uv.min.x*dest.hwW()), Round(uv.max.x*dest.hwW())); rect_src .setX(rect_dest.min.x* src.hwW()/dest.hwW(), rect_dest.max.x* src.hwW()/dest.hwW());}
  2498. else {rect_src .setX(Round(uv.min.x* src.hwW()), Round(uv.max.x* src.hwW())); rect_dest.setX(rect_src .min.x*dest.hwW()/ src.hwW(), rect_src .max.x*dest.hwW()/ src.hwW());}
  2499. if(dest.hwH()<src.hwH()){rect_dest.setY(Round(uv.min.y*dest.hwH()), Round(uv.max.y*dest.hwH())); rect_src .setY(rect_dest.min.y* src.hwH()/dest.hwH(), rect_dest.max.y* src.hwH()/dest.hwH());}
  2500. else {rect_src .setY(Round(uv.min.y* src.hwH()), Round(uv.max.y* src.hwH())); rect_dest.setY(rect_src .min.y*dest.hwH()/ src.hwH(), rect_src .max.y*dest.hwH()/ src.hwH());}
  2501. }
  2502. void Image::discard()
  2503. {
  2504. #if DX11
  2505. if(D3DC1)D3DC1->DiscardView(_rtv ? &SCAST(ID3D11View, *_rtv) : &SCAST(ID3D11View, *_dsv)); // will not crash if parameter is null
  2506. #elif GL && GL_ES // do this only on GLES, because on desktop it requires GL 4.3 TODO:
  2507. // this should be called only if this image is already attached to current FBO - https://community.arm.com/graphics/b/blog/posts/mali-performance-2-how-to-correctly-handle-framebuffers
  2508. // 'glInvalidateFramebuffer' can be called at the start of rendering (right after attaching to FBO) to specify that we don't need previous contents of this RT
  2509. // and at the end of rendering ( BEFORE detaching from FBO) to specify that we don't need to store the contents of this RT
  2510. if(D.notShaderModelGLES2()) // not available on GLES2
  2511. {
  2512. // !! remember that images can have only '_txtr' or '_rb' or nothing at all (if they're provided by the system) but we still should discard them !!
  2513. if(!IOS && D.mainFBO()) // iOS doesn't have main FBO
  2514. { // for main FBO we need to setup different values - https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glInvalidateFramebuffer.xhtml
  2515. if(Renderer._cur_ds==this) // no need to check '_cur_ds_id' because main FBO always has texture 0
  2516. {
  2517. GLenum attachments[]={GL_DEPTH, GL_STENCIL};
  2518. glInvalidateFramebuffer(GL_FRAMEBUFFER, ImageTI[hwType()].s ? 2 : 1, attachments); _discard=false;
  2519. }else
  2520. if(Renderer._cur[0]==this) // check '_cur' because '_txtr' can be 0 for RenderBuffers
  2521. {
  2522. GLenum attachment=GL_COLOR;
  2523. glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, &attachment); _discard=false;
  2524. }else
  2525. _discard=true; // discard at next opportunity when we want to attach it to FBO
  2526. }else
  2527. {
  2528. GLenum attachment;
  2529. if(Renderer._cur_ds==this && Renderer._cur_ds_id==_txtr)attachment=(ImageTI[hwType()].s ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);else // check both '_cur_ds' and '_cur_ds_id' because '_cur_ds_id' will be 0 when Image is a RenderBuffer or temporarily unbound Texture (only Textures can be temporarily unbound), this will work OK for RenderBuffers because both '_cur_ds_id' and '_txtr' will be zero
  2530. if(Renderer._cur[0]==this )attachment=GL_COLOR_ATTACHMENT0;else // check '_cur' because '_txtr' can be 0 for RenderBuffers
  2531. if(Renderer._cur[1]==this )attachment=GL_COLOR_ATTACHMENT1;else // check '_cur' because '_txtr' can be 0 for RenderBuffers
  2532. if(Renderer._cur[2]==this )attachment=GL_COLOR_ATTACHMENT2;else // check '_cur' because '_txtr' can be 0 for RenderBuffers
  2533. if(Renderer._cur[3]==this )attachment=GL_COLOR_ATTACHMENT3;else // check '_cur' because '_txtr' can be 0 for RenderBuffers
  2534. {_discard=true; return;} // discard at next opportunity when we want to attach it to FBO
  2535. glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, &attachment); _discard=false;
  2536. }
  2537. }
  2538. #endif
  2539. }
  2540. #if DX9
  2541. void Image::clearHw(C Color &color)
  2542. {
  2543. if(_surf)D3D->ColorFill(_surf, null, VecB4(color.b, color.g, color.r, color.a).u); // 'ColorFill' accepts colors in BGRA
  2544. }
  2545. #elif DX11
  2546. void Image::clearHw(C Vec4 &color)
  2547. {
  2548. if(_rtv)D3DC->ClearRenderTargetView(_rtv, color.c);
  2549. }
  2550. void Image::clearDS(Byte s)
  2551. {
  2552. if(_dsv)D3DC->ClearDepthStencilView(_dsv, D3D11_CLEAR_DEPTH|(ImageTI[hwType()].s ? D3D11_CLEAR_STENCIL : 0), 1, s);
  2553. }
  2554. void Image::copyMs(Image &dest, Bool restore_rt, Bool multi_sample, C RectI *rect)C
  2555. {
  2556. if(this!=&dest)
  2557. {
  2558. Image *rt[Elms(Renderer._cur)], *ds;
  2559. Bool restore_viewport;
  2560. if(restore_rt)
  2561. {
  2562. REPAO(rt)=Renderer._cur[i];
  2563. ds =Renderer._cur_ds;
  2564. restore_viewport=!D._view_active.full;
  2565. }
  2566. Renderer.set(&dest, null, false);
  2567. ALPHA_MODE alpha=D.alpha(ALPHA_NONE);
  2568. VI.shader(!multiSample() ? Sh.h_Draw : // 1s->1s, 1s->ms
  2569. !multi_sample ? Sh.h_DrawMs1 : // #0->1s, #0->ms
  2570. dest.multiSample() ? Sh.h_DrawMsM : // ms->ms
  2571. Sh.h_DrawMsN); // ms->1s
  2572. VI.image (this);
  2573. VI.setType(VI_2D_TEX, VI_STRIP);
  2574. if(Vtx2DTex *v=(Vtx2DTex*)VI.addVtx (4))
  2575. {
  2576. if(!rect)
  2577. {
  2578. v[0].pos.set(-1, 1);
  2579. v[1].pos.set( 1, 1);
  2580. v[2].pos.set(-1, -1);
  2581. v[3].pos.set( 1, -1);
  2582. v[0].tex.set(0, 0);
  2583. v[1].tex.set(1, 0);
  2584. v[2].tex.set(0, 1);
  2585. v[3].tex.set(1, 1);
  2586. }else
  2587. {
  2588. Rect frac(rect->min.x/Flt(dest.hwW())*2-1, rect->max.y/Flt(dest.hwH())*-2+1,
  2589. rect->max.x/Flt(dest.hwW())*2-1, rect->min.y/Flt(dest.hwH())*-2+1);
  2590. v[0].pos.set(frac.min.x, frac.max.y);
  2591. v[1].pos.set(frac.max.x, frac.max.y);
  2592. v[2].pos.set(frac.min.x, frac.min.y);
  2593. v[3].pos.set(frac.max.x, frac.min.y);
  2594. Rect tex(Flt(rect->min.x)/hwW(), Flt(rect->min.y)/hwH(),
  2595. Flt(rect->max.x)/hwW(), Flt(rect->max.y)/hwH());
  2596. v[0].tex.set(tex.min.x, tex.min.y);
  2597. v[1].tex.set(tex.max.x, tex.min.y);
  2598. v[2].tex.set(tex.min.x, tex.max.y);
  2599. v[3].tex.set(tex.max.x, tex.max.y);
  2600. }
  2601. }
  2602. VI.end();
  2603. D.alpha(alpha);
  2604. if(restore_rt)Renderer.set(rt[0], rt[1], rt[2], rt[3], ds, restore_viewport);
  2605. }
  2606. }
  2607. void Image::copyMs(Image &dest, Bool restore_rt, Bool multi_sample, C Rect &rect)C
  2608. {
  2609. copyMs(dest, restore_rt, multi_sample, &Round(D.screenToUV(rect)*size()));
  2610. }
  2611. #endif
  2612. /******************************************************************************/
  2613. void Image::copyHw(Image &dest, Bool restore_rt, C RectI *rect_src, C RectI *rect_dest, Bool *flipped)C
  2614. {
  2615. if(flipped)*flipped=false;
  2616. if(this!=&dest)
  2617. {
  2618. #if DX9
  2619. if(this==&Renderer._main || multiSample()) // in DX9 cannot directly copy from 'main' and multi-sampled surfaces
  2620. {
  2621. if(_surf && dest._surf)
  2622. {
  2623. RECT rs, rd;
  2624. if(rect_src ){rs.left=Max(rect_src ->min.x, 0); rs.right=Min(rect_src ->max.x, w()); if(rs.left>=rs.right)return; rs.top=Max(rect_src ->min.y, 0); rs.bottom=Min(rect_src ->max.y, h()); if(rs.top>=rs.bottom)return;}
  2625. if(rect_dest){rd.left=Max(rect_dest->min.x, 0); rd.right=Min(rect_dest->max.x, dest.w()); if(rd.left>=rd.right)return; rd.top=Max(rect_dest->min.y, 0); rd.bottom=Min(rect_dest->max.y, dest.h()); if(rd.top>=rd.bottom)return;}
  2626. D3D->StretchRect(_surf, rect_src ? &rs : null, dest._surf, rect_dest ? &rd : null, D3DTEXF_LINEAR);
  2627. }
  2628. return;
  2629. }
  2630. #elif GL
  2631. if(this==&Renderer._main) // in OpenGL cannot directly copy from main
  2632. {
  2633. if(dest._txtr)
  2634. {
  2635. RectI rs(0, 0, T.w(), T.h()); if(rect_src )rs&=*rect_src ; if(rs.min.x>=rs.max.x || rs.min.y>=rs.max.y)return;
  2636. RectI rd(0, 0, dest.w(), dest.h()); if(rect_dest)rd&=*rect_dest; if(rd.min.x>=rd.max.x || rd.min.y>=rd.max.y)return;
  2637. #if GL_ES
  2638. // remember render target settings
  2639. Image *rt[Elms(Renderer._cur)], *ds;
  2640. Bool restore_viewport;
  2641. if(restore_rt)
  2642. {
  2643. REPAO(rt)=Renderer._cur[i];
  2644. ds =Renderer._cur_ds;
  2645. restore_viewport=!D._view_active.full;
  2646. }
  2647. Renderer.set(&Renderer._main, null, false); // put '_main' to FBO
  2648. dest._discard=false;
  2649. if(rs.w()==rd.w() && rs.h()==rd.h() && hwType()==dest.hwType() && flipped) // 'glCopyTexSubImage2D' flips image, does not support stretching and format conversion
  2650. {
  2651. *flipped=true;
  2652. D.texBind (GL_TEXTURE_2D, dest._txtr); // set destination texture
  2653. glCopyTexSubImage2D(GL_TEXTURE_2D, 0, rd.min.x, rd.min.y, rs.min.x, rs.min.y, rs.w(), rs.h()); // copy partial FBO to texture (this will copy the image flipped vertically)
  2654. }else
  2655. {
  2656. ImageRTPtr temp(ImageRTDesc(w(), h(), GetImageRTType(type())));
  2657. D.texBind (GL_TEXTURE_2D, temp->_txtr); // set destination texture
  2658. glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, temp->w(), temp->h()); // copy entire FBO to texture (this will copy the image flipped vertically)
  2659. // flip
  2660. RectI rect_src_flipped; if(rect_src)rect_src_flipped=*rect_src;else rect_src_flipped.set(0, 0, w(), h()); Swap(rect_src_flipped.min.y, rect_src_flipped.max.y); // set flipped rectangle
  2661. temp->copyHw(dest, false, &rect_src_flipped, rect_dest); // perform additional copy
  2662. }
  2663. // restore settings
  2664. if(restore_rt)Renderer.set(rt[0], rt[1], rt[2], rt[3], ds, restore_viewport);
  2665. #else
  2666. // remember settings
  2667. Image *rt[Elms(Renderer._cur)], *ds;
  2668. Bool restore_viewport;
  2669. if(restore_rt)
  2670. {
  2671. REPAO(rt)=Renderer._cur[i];
  2672. ds =Renderer._cur_ds;
  2673. restore_viewport=!D._view_active.full;
  2674. }
  2675. Renderer.set(&dest, null, false); // put 'dest' to FBO
  2676. glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
  2677. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO);
  2678. glBlitFramebuffer(rs.min.x, h()-rs.min.y, rs.max.x, h()-rs.max.y,
  2679. rd.min.x, rd.min.y, rd.max.x, rd.max.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  2680. glBindFramebuffer(GL_FRAMEBUFFER, D._fbo); // restore framebuffer, for this function GL_FRAMEBUFFER acts as both GL_READ_FRAMEBUFFER and GL_DRAW_FRAMEBUFFER at the same time
  2681. // restore settings
  2682. if(restore_rt)Renderer.set(rt[0], rt[1], rt[2], rt[3], ds, restore_viewport);
  2683. #endif
  2684. }
  2685. return;
  2686. }
  2687. #endif
  2688. // remember settings
  2689. Image *rt[Elms(Renderer._cur)], *ds;
  2690. Bool restore_viewport;
  2691. if(restore_rt)
  2692. {
  2693. REPAO(rt)=Renderer._cur[i];
  2694. ds =Renderer._cur_ds;
  2695. restore_viewport=!D._view_active.full;
  2696. }
  2697. Renderer.set(&dest, null, false);
  2698. ALPHA_MODE alpha=D.alpha(ALPHA_NONE);
  2699. VI.image (this);
  2700. VI.shader (Sh.h_Draw);
  2701. VI.setType(VI_2D_TEX, VI_STRIP);
  2702. if(Vtx2DTex *v=(Vtx2DTex*)VI.addVtx(4))
  2703. {
  2704. if(!rect_dest)
  2705. {
  2706. v[0].pos.set(-1, 1);
  2707. v[1].pos.set( 1, 1);
  2708. v[2].pos.set(-1, -1);
  2709. v[3].pos.set( 1, -1);
  2710. }else
  2711. {
  2712. Rect frac(rect_dest->min.x/Flt(dest.hwW())*2-1, -rect_dest->max.y/Flt(dest.hwH())*2+1,
  2713. rect_dest->max.x/Flt(dest.hwW())*2-1, -rect_dest->min.y/Flt(dest.hwH())*2+1);
  2714. v[0].pos.set(frac.min.x, frac.max.y);
  2715. v[1].pos.set(frac.max.x, frac.max.y);
  2716. v[2].pos.set(frac.min.x, frac.min.y);
  2717. v[3].pos.set(frac.max.x, frac.min.y);
  2718. }
  2719. if(!rect_src)
  2720. {
  2721. v[0].tex.set(0, 0);
  2722. v[1].tex.set(1, 0);
  2723. v[2].tex.set(0, 1);
  2724. v[3].tex.set(1, 1);
  2725. }else
  2726. {
  2727. Rect tex(Flt(rect_src->min.x)/hwW(), Flt(rect_src->min.y)/hwH(),
  2728. Flt(rect_src->max.x)/hwW(), Flt(rect_src->max.y)/hwH());
  2729. v[0].tex.set(tex.min.x, tex.min.y);
  2730. v[1].tex.set(tex.max.x, tex.min.y);
  2731. v[2].tex.set(tex.min.x, tex.max.y);
  2732. v[3].tex.set(tex.max.x, tex.max.y);
  2733. }
  2734. #if GL
  2735. if(!D.mainFBO()) // in OpenGL when drawing to RenderTarget the 'dest.pos.y' must be flipped
  2736. {
  2737. CHS(v[0].pos.y);
  2738. CHS(v[1].pos.y);
  2739. CHS(v[2].pos.y);
  2740. CHS(v[3].pos.y);
  2741. }
  2742. #endif
  2743. }
  2744. VI.end();
  2745. // restore settings
  2746. D.alpha(alpha);
  2747. if(restore_rt)Renderer.set(rt[0], rt[1], rt[2], rt[3], ds, restore_viewport);
  2748. }
  2749. }
  2750. void Image::copyHw(Image &dest, Bool restore_rt, C Rect &rect)C
  2751. {
  2752. RectI rect_src, rect_dest;
  2753. SetRects(T, dest, rect_src, rect_dest, rect);
  2754. copyHw(dest, restore_rt, &rect_src, &rect_dest);
  2755. }
  2756. /******************************************************************************/
  2757. void Image::clearFull(C Vec4 &color, Bool restore_rt)
  2758. {
  2759. #if DX11
  2760. clearHw(color);
  2761. #else
  2762. Image *rt[Elms(Renderer._cur)], *ds;
  2763. Bool restore_viewport;
  2764. if(restore_rt)
  2765. {
  2766. REPAO(rt)=Renderer._cur[i];
  2767. ds =Renderer._cur_ds;
  2768. restore_viewport=!D._view_active.full;
  2769. }
  2770. if(color.min()>=0 && color.max()<=1)
  2771. {
  2772. #if DX9
  2773. clearHw(color); return; // no need to restore RT's as this doesn't change them
  2774. #else
  2775. Renderer.set(this, null, false); D.clearCol(color);
  2776. #endif
  2777. }else
  2778. {
  2779. Renderer.set(this, null, false); Bool clip=D._clip_allow; D.clipAllow(false); ALPHA_MODE alpha=D.alpha(ALPHA_NONE); Sh.clear(color);
  2780. D.clipAllow(clip ); D.alpha(alpha );
  2781. }
  2782. if(restore_rt)Renderer.set(rt[0], rt[1], rt[2], rt[3], ds, restore_viewport);
  2783. #endif
  2784. }
  2785. void Image::clearViewport(C Vec4 &color, Bool restore_rt)
  2786. {
  2787. if(D._view_main.full)clearFull(color, restore_rt);else
  2788. {
  2789. Image *rt[Elms(Renderer._cur)], *ds;
  2790. Bool restore_viewport;
  2791. if(restore_rt)
  2792. {
  2793. REPAO(rt)=Renderer._cur[i];
  2794. ds =Renderer._cur_ds;
  2795. restore_viewport=!D._view_active.full;
  2796. }
  2797. Renderer.set(this, null, true);
  2798. if(color.min()>=0 && color.max()<=1)D.clearCol(color);else
  2799. {
  2800. Bool clip=D._clip_allow; D.clipAllow(false); ALPHA_MODE alpha=D.alpha(ALPHA_NONE); Sh.clear(color);
  2801. D.clipAllow(clip ); D.alpha(alpha );
  2802. }
  2803. if(restore_rt)Renderer.set(rt[0], rt[1], rt[2], rt[3], ds, restore_viewport);
  2804. }
  2805. }
  2806. /******************************************************************************/
  2807. Bool Image::capture(C Image &src)
  2808. {
  2809. #if DX9
  2810. if(src._surf)
  2811. {
  2812. if(ImageTI[src.hwType()].d) // depth buffer
  2813. {
  2814. if(src.depthTexture())
  2815. {
  2816. SyncLocker locker(D._lock);
  2817. if(createTry(src.w(), src.h(), 1, IMAGE_F32, IMAGE_RT, 1, false))
  2818. {
  2819. src.copyHw(T, true);
  2820. return true;
  2821. }
  2822. }
  2823. }else
  2824. {
  2825. if(size()!=src.size() || hwType()!=src.hwType()
  2826. ||(mode()!=IMAGE_SURF_SCRATCH && mode()!=IMAGE_SURF_SYSTEM && mode()!=IMAGE_SURF) // only these modes can receive 'GetRenderTargetData'
  2827. )createTry(src.w(), src.h(), 1, src.hwType(), IMAGE_SURF_SYSTEM, 1, false);
  2828. if(_surf)
  2829. {
  2830. SyncLocker locker(D._lock);
  2831. if(OK(D3D->GetRenderTargetData(src._surf, _surf)))
  2832. {
  2833. Time.skipUpdate();
  2834. return true;
  2835. }
  2836. }
  2837. }
  2838. }
  2839. #elif DX11
  2840. if(src._txtr)
  2841. {
  2842. SyncLocker locker(D._lock);
  2843. if(src.multiSample())
  2844. {
  2845. if(createTry(src.w(), src.h(), 1, src.hwType(), IMAGE_RT, 1, false))
  2846. {
  2847. D3DC->ResolveSubresource(_txtr, 0, src._txtr, 0, ImageTI[src.hwType()].format);
  2848. return true;
  2849. }
  2850. }else
  2851. if(createTry(PaddedWidth(src.hwW(), src.hwH(), 0, src.hwType()), PaddedHeight(src.hwW(), src.hwH(), 0, src.hwType()), 1, src.hwType(), IMAGE_SURF, 1, false))
  2852. {
  2853. D3DC->CopySubresourceRegion(_txtr, D3D11CalcSubresource(0, 0, mipMaps()), 0, 0, 0, src._txtr, D3D11CalcSubresource(0, 0, src.mipMaps()), null);
  2854. return true;
  2855. }
  2856. }
  2857. #elif GL
  2858. if(src.lockRead())
  2859. {
  2860. Bool ok=false;
  2861. if(createTry(src.w(), src.h(), 1, src.hwType(), IMAGE_SOFT, 1, false))ok=src.copySoft(T, FILTER_NO_STRETCH);
  2862. src.unlock();
  2863. return ok;
  2864. }else
  2865. {
  2866. Bool depth=(ImageTI[src.hwType()].d>0);
  2867. if( !depth || src.depthTexture())
  2868. {
  2869. SyncLocker locker(D._lock);
  2870. if(createTry(src.w(), src.h(), 1, depth ? IMAGE_F32 : src.hwType(), IMAGE_RT, 1, false))
  2871. {
  2872. src.copyHw(T, true);
  2873. return true;
  2874. }
  2875. }
  2876. }
  2877. #endif
  2878. return false;
  2879. }
  2880. /******************************************************************************/
  2881. Bool Image::accessible()C
  2882. {
  2883. #if GL
  2884. return _rb || _txtr; // on some platforms with OpenGL, 'Renderer._main' and 'Renderer._main_ds' are provided by the system, so their values may be zero, and we can't directly access it
  2885. #else
  2886. return true;
  2887. #endif
  2888. }
  2889. Bool Image::depthTexture()C
  2890. {
  2891. #if DX9 || GL
  2892. return mode()==IMAGE_DS_RT;
  2893. #else
  2894. return _dsv && _srv; // on DX10+ IMAGE_DS and IMAGE_DS_RT is the same
  2895. #endif
  2896. }
  2897. Bool Image::compatible(C Image &image)C
  2898. {
  2899. return size3()==image.size3() && samples()==image.samples();
  2900. }
  2901. /******************************************************************************/
  2902. }
  2903. /******************************************************************************/