diff --git a/Core/Config.cpp b/Core/Config.cpp index 9c4e256aa..8527a9dca 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -97,7 +97,7 @@ void Config::Load(const char *iniFileName) #else graphics->Get("ResolutionScale", &iWindowZoom, 1); #endif - graphics->Get("BufferedRendering", &bBufferedRendering, true); + graphics->Get("RenderingMode", &iRenderingMode, 1); // default is buffered rendering mode graphics->Get("HardwareTransform", &bHardwareTransform, true); graphics->Get("TextureFiltering", &iTexFiltering, 1); graphics->Get("SSAA", &SSAntiAliasing, 0); @@ -123,8 +123,6 @@ void Config::Load(const char *iniFileName) #endif graphics->Get("StretchToDisplay", &bStretchToDisplay, false); graphics->Get("TrueColor", &bTrueColor, true); - graphics->Get("FramebuffersToMem", &bFramebuffersToMem, false); - graphics->Get("FramebuffersCPUConvert", &bFramebuffersCPUConvert, true); graphics->Get("MipMap", &bMipMap, true); graphics->Get("TexScalingLevel", &iTexScalingLevel, 1); graphics->Get("TexScalingType", &iTexScalingType, 0); @@ -225,7 +223,7 @@ void Config::Save() graphics->Set("ShowFPSCounter", iShowFPSCounter); graphics->Set("DisplayFramebuffer", bDisplayFramebuffer); graphics->Set("ResolutionScale", iWindowZoom); - graphics->Set("BufferedRendering", bBufferedRendering); + graphics->Set("RenderingMode", iRenderingMode); graphics->Set("HardwareTransform", bHardwareTransform); graphics->Set("TextureFiltering", iTexFiltering); graphics->Set("SSAA", SSAntiAliasing); @@ -244,8 +242,6 @@ void Config::Save() #endif graphics->Set("StretchToDisplay", bStretchToDisplay); graphics->Set("TrueColor", bTrueColor); - graphics->Set("FramebuffersToMem", bFramebuffersToMem); - graphics->Set("FramebuffersCPUConvert", bFramebuffersCPUConvert); graphics->Set("MipMap", bMipMap); graphics->Set("TexScalingLevel", iTexScalingLevel); graphics->Set("TexScalingType", iTexScalingType); diff --git a/Core/Config.h b/Core/Config.h index bb2c75620..21ceba1c7 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -64,7 +64,7 @@ public: // GFX bool bDisplayFramebuffer; bool bHardwareTransform; - bool bBufferedRendering; + int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering 2 = Read Framebuffer to memory (GPU) 3 = Read Framebuffer to memory (CPU) int iTexFiltering; // 1 = off , 2 = nearest , 3 = linear , 4 = linear(CG) bool bUseVBO; #ifdef BLACKBERRY @@ -85,8 +85,6 @@ public: #endif int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso bool bTrueColor; - bool bFramebuffersToMem; - bool bFramebuffersCPUConvert; // for OpenGL devices bool bMipMap; int iTexScalingLevel; // 1 = off, 2 = 2x, ..., 5 = 5x int iTexScalingType; // 0 = xBRZ, 1 = Hybrid @@ -96,6 +94,7 @@ public: int iMaxRecent; bool bEnableCheats; bool bReloadCheats; + bool bFramebuffersToMem; // Sound bool bEnableSound; diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index c2a33bcd4..56aba91f1 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -241,7 +241,8 @@ void GLES_GPU::DeviceLost() { } void GLES_GPU::InitClear() { - if (!g_Config.bBufferedRendering) { + bool useBufferedRendering_ = g_Config.iRenderingMode != 0 ? 1 : 0; + if (!useBufferedRendering_) { glstate.depthWrite.set(GL_TRUE); glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearColor(0,0,0,1); diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 50ed9199e..18e55bcc2 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -172,7 +172,7 @@ FramebufferManager::FramebufferManager() : glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - useBufferedRendering_ = g_Config.bBufferedRendering; + bool useBufferedRendering_ = g_Config.iRenderingMode != 0 ? 1 : 0; // Check vendor string to try and guess GPU const char *cvendor = (char *)glGetString(GL_VENDOR); @@ -889,7 +889,7 @@ void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 stride, u32 height, int format) { void FramebufferManager::PackFramebufferGL_(VirtualFramebuffer *vfb) { GLubyte *packed = 0; bool unbind = false; - + bool useCPU_ = g_Config.iRenderingMode == FB_READFBOMEMORY_CPU ? 1 : 0; // We'll prepare two PBOs to switch between readying and reading if(!pixelBufObj_) { GLuint pbos[2]; @@ -962,7 +962,7 @@ void FramebufferManager::PackFramebufferGL_(VirtualFramebuffer *vfb) { if(pixelBufObj_[currentPBO_].maxSize < bufSize) { // We reserve a buffer big enough to fit all those pixels - if(g_Config.bFramebuffersCPUConvert && pixelType != GL_UNSIGNED_BYTE) { + if(useCPU_ && pixelType != GL_UNSIGNED_BYTE) { // Wnd result may be 16-bit but we are reading 32-bit, so we need double the space on the buffer glBufferData(GL_PIXEL_PACK_BUFFER, bufSize*2, NULL, GL_DYNAMIC_READ); } else { @@ -978,7 +978,7 @@ void FramebufferManager::PackFramebufferGL_(VirtualFramebuffer *vfb) { pixelBufObj_[currentPBO_].format = vfb->format; pixelBufObj_[currentPBO_].reading = true; - if(g_Config.bFramebuffersCPUConvert) { + if(useCPU_) { // If converting pixel formats on the CPU we'll always request RGBA8888 glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels(0, 0, vfb->fb_stride, vfb->height, GL_RGBA, GL_UNSIGNED_BYTE, 0); @@ -1006,7 +1006,7 @@ void FramebufferManager::PackFramebufferGL_(VirtualFramebuffer *vfb) { DEBUG_LOG(HLE, "Reading pbo to mem, bufSize = %u, packed = %08x, fb_address = %08x, pbo = %u", pixelBufObj_[nextPBO].size, packed, pixelBufObj_[nextPBO].fb_address, nextPBO); - if(g_Config.bFramebuffersCPUConvert) { + if(useCPU_) { ConvertFromRGBA8888(Memory::GetPointer(pixelBufObj_[nextPBO].fb_address), packed, pixelBufObj_[nextPBO].stride, pixelBufObj_[nextPBO].height, pixelBufObj_[nextPBO].format); @@ -1120,7 +1120,7 @@ void FramebufferManager::BeginFrame() { // TODO: restore state? } currentRenderVfb_ = 0; - useBufferedRendering_ = g_Config.bBufferedRendering; + useBufferedRendering_ = g_Config.iRenderingMode != 0 ? 1 : 0; } void FramebufferManager::SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) { @@ -1161,11 +1161,13 @@ void FramebufferManager::DecimateFBOs() { fbo_unbind(); currentRenderVfb_ = 0; bool thirdFrame = (gpuStats.numFrames % 3 == 0); + bool useFramebufferToMem_ = g_Config.iRenderingMode > 1 ? 1 : 0; + for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; int age = frameLastFramebufUsed - vfb->last_frame_used; - if(g_Config.bFramebuffersToMem) { + if(useFramebufferToMem_) { // Every third frame we'll commit framebuffers to memory if(thirdFrame && age <= FBO_OLD_AGE) { ReadFramebufferToMemory(vfb); @@ -1212,7 +1214,6 @@ void FramebufferManager::DestroyAllFBOs() { void FramebufferManager::UpdateFromMemory(u32 addr, int size) { addr &= ~0x40000000; - // TODO: Could go through all FBOs, but probably not important? // TODO: Could also check for inner changes, but video is most important. if (addr == DisplayFramebufAddr() || addr == PrevDisplayFramebufAddr()) { @@ -1230,7 +1231,7 @@ void FramebufferManager::UpdateFromMemory(u32 addr, int size) { vfb->dirtyAfterDisplay = true; // TODO: This without the fbo_unbind() above would be better than destroying the FBO. // However, it doesn't seem to work for Star Ocean, at least - if (g_Config.bBufferedRendering) { + if (useBufferedRendering_) { fbo_bind_as_render_target(vfb->fbo); needUnbind = true; DrawPixels(Memory::GetPointer(addr), vfb->format, vfb->fb_stride); diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 87203c761..1cb71b6be 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -52,6 +52,13 @@ enum { GPU_VENDOR_UNKNOWN = 0 }; + +enum { + FB_NON_BUFFERED_MODE = 0, + FB_BUFFERED_MODE = 1, + FB_READFBOMEMORY_GPU = 2, + FB_READFBOMEMORY_CPU = 3, +}; struct VirtualFramebuffer { int last_frame_used; diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 4b09b37e2..34516572b 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -281,7 +281,8 @@ void TransformDrawEngine::ApplyDrawState(int prim) { float renderWidthFactor, renderHeightFactor; float renderWidth, renderHeight; float renderX, renderY; - if (g_Config.bBufferedRendering) { + bool useBufferedRendering_ = g_Config.iRenderingMode != 0 ? 1 : 0; + if (useBufferedRendering_) { renderX = 0; renderY = 0; renderWidth = framebufferManager_->GetRenderWidth(); diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 32bef8d2e..e31cf6a9b 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -974,7 +974,7 @@ void TextureCache::SetTexture() { TexCacheEntry *entry = NULL; gstate_c.flipTexture = false; gstate_c.skipDrawReason &= ~SKIPDRAW_BAD_FB_TEXTURE; - bool useBufferedRendering_ = g_Config.bBufferedRendering; + bool useBufferedRendering_ = g_Config.iRenderingMode != 0 ? 1 : 0; bool replaceImages = false; if (iter != cache.end()) { diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 37a404994..46acb8a3b 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -455,7 +455,8 @@ void EmuScreen::render() { if (invalid_) return; - if (g_Config.bBufferedRendering) + bool useBufferedRendering_ = g_Config.iRenderingMode != 0 ? 1 : 0; + if (useBufferedRendering_) fbo_unbind(); UIShader_Prepare(); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 571a6284a..bde62c718 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -176,7 +176,7 @@ void GameSettingsScreen::CreateViews() { leftColumn->Add(new Spacer(new LinearLayoutParams(1.0))); leftColumn->Add(new Choice("Back"))->OnClick.Handle(this, &UIScreen::OnBack); - TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 200, new LinearLayoutParams(600, FILL_PARENT, actionMenuMargins)); + TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 200, new LinearLayoutParams(800, FILL_PARENT, actionMenuMargins)); root_->Add(tabHolder); // TODO: These currently point to global settings, not game specific ones. @@ -187,17 +187,13 @@ void GameSettingsScreen::CreateViews() { tabHolder->AddTab("Graphics", graphicsSettingsScroll); graphicsSettings->Add(new ItemHeader(gs->T("Features"))); graphicsSettings->Add(new CheckBox(&g_Config.bStretchToDisplay, gs->T("Stretch to Display"))); - graphicsSettings->Add(new CheckBox(&g_Config.bBufferedRendering, gs->T("Buffered Rendering"))); + static const char *renderingMode[] = { "Non-Buffered Rendering", "Buffered Rendering", "Read FBO To Mem(GPU)", "Read FBO To Mem(CPU)"}; + graphicsSettings->Add(new PopupMultiChoice(&g_Config.iRenderingMode, gs->T("Rendering Mode"), renderingMode, 0, 4, gs, screenManager())); graphicsSettings->Add(new CheckBox(&g_Config.bDisplayFramebuffer, gs->T("Display Raw Framebuffer"))); graphicsSettings->Add(new CheckBox(&g_Config.bMipMap, gs->T("Mipmapping"))); graphicsSettings->Add(new CheckBox(&g_Config.bVertexCache, gs->T("Vertex Cache"))); graphicsSettings->Add(new CheckBox(&g_Config.bUseVBO, gs->T("Stream VBO"))); graphicsSettings->Add(new CheckBox(&g_Config.SSAntiAliasing, gs->T("Anti Aliasing"))); - graphicsSettings->Add(new CheckBox(&g_Config.bFramebuffersToMem, gs->T("Read Framebuffer to memory"))); -#ifndef USING_GLES2 - graphicsSettings->Add(new CheckBox(&g_Config.bFramebuffersCPUConvert, gs->T("Convert Framebuffers Using CPU"))); -#endif - // TODO: Does frame rate belong among the graphics settings? graphicsSettings->Add(new ItemHeader(gs->T("Frame rate"))); graphicsSettings->Add(new CheckBox(&cap60FPS_, gs->T("Read Framebuffer to memory"))); diff --git a/UI/MenuScreens.cpp b/UI/MenuScreens.cpp index 09a052a95..535bdc3f5 100644 --- a/UI/MenuScreens.cpp +++ b/UI/MenuScreens.cpp @@ -502,20 +502,6 @@ void PauseScreen::render() { UICheckBox(GEN_ID, x, y += stride, gs->T("Stretch to Display"), ALIGN_TOPLEFT, &g_Config.bStretchToDisplay); UICheckBox(GEN_ID, x, y += stride, gs->T("Hardware Transform"), ALIGN_TOPLEFT, &g_Config.bHardwareTransform); - if (UICheckBox(GEN_ID, x, y += stride, gs->T("Buffered Rendering"), ALIGN_TOPLEFT, &g_Config.bBufferedRendering)) { - if (gpu) - gpu->Resized(); - } - if (g_Config.bBufferedRendering) { - if (UICheckBox(GEN_ID, x + 60, y += stride, gs->T("Read Framebuffers To Memory"), ALIGN_TOPLEFT, &g_Config.bFramebuffersToMem)) { - if (gpu) - gpu->Resized(); - } - if (UICheckBox(GEN_ID, x + 60, y += stride, gs->T("AA", "Anti-Aliasing"), ALIGN_TOPLEFT, &g_Config.SSAntiAliasing)) { - if (gpu) - gpu->Resized(); - } - } bool enableFrameSkip = g_Config.iFrameSkip != 0; UICheckBox(GEN_ID, x, y += stride , gs->T("Frame Skipping"), ALIGN_TOPLEFT, &enableFrameSkip); if (enableFrameSkip) { @@ -948,33 +934,35 @@ void GraphicsScreenP1::render() { UICheckBox(GEN_ID, x, y += stride, gs->T("Stream VBO"), ALIGN_TOPLEFT, &g_Config.bUseVBO); #endif UICheckBox(GEN_ID, x, y += stride, gs->T("Mipmapping"), ALIGN_TOPLEFT, &g_Config.bMipMap); -#ifdef _WIN32 - bool Vsync = g_Config.iVSyncInterval != 0; - UICheckBox(GEN_ID, x, y += stride, gs->T("VSync"), ALIGN_TOPLEFT, &Vsync); - g_Config.iVSyncInterval = Vsync ? 1 : 0; - UICheckBox(GEN_ID, x, y += stride, gs->T("Fullscreen"), ALIGN_TOPLEFT, &g_Config.bFullScreen); -#endif - if (UICheckBox(GEN_ID, x, y += stride, gs->T("Buffered Rendering"), ALIGN_TOPLEFT, &g_Config.bBufferedRendering)) { + if (UICheckBox(GEN_ID, x, y += stride, gs->T("AA", "Anti-Aliasing"), ALIGN_TOPLEFT, &g_Config.SSAntiAliasing)) { if (gpu) gpu->Resized(); } - if (g_Config.bBufferedRendering) { - if (UICheckBox(GEN_ID, x + 60, y += stride, gs->T("Read Framebuffers To Memory"), ALIGN_TOPLEFT, &g_Config.bFramebuffersToMem)) { - if (gpu) - gpu->Resized(); - } -#ifndef USING_GLES2 - if (UICheckBox(GEN_ID, x + 60, y += stride, gs->T("Convert Framebuffers Using CPU"), ALIGN_TOPLEFT, &g_Config.bFramebuffersCPUConvert)) { - if (gpu) - gpu->Resized(); - } + +#ifdef _WIN32 + //bool Vsync = g_Config.iVSyncInterval != 0; + //UICheckBox(GEN_ID, x, y += stride, gs->T("VSync"), ALIGN_TOPLEFT, &Vsync); + //g_Config.iVSyncInterval = Vsync ? 1 : 0; + //UICheckBox(GEN_ID, x, y += stride, gs->T("Fullscreen"), ALIGN_TOPLEFT, &g_Config.bFullScreen); #endif - if (UICheckBox(GEN_ID, x + 60, y += stride, gs->T("AA", "Anti-Aliasing"), ALIGN_TOPLEFT, &g_Config.SSAntiAliasing)) { - if (gpu) - gpu->Resized(); - } - } + y+=20; + + bool nonrendering = g_Config.iRenderingMode == 0; + if (UICheckBox(GEN_ID, x, y += stride, gs->T("Non-Buffered Rendering"), ALIGN_TOPLEFT, &nonrendering)) + g_Config.iRenderingMode = 0; + + bool rendering = g_Config.iRenderingMode == 1; + if (UICheckBox(GEN_ID, x, y += stride, gs->T("Buffered Rendering"), ALIGN_TOPLEFT, &rendering)) + g_Config.iRenderingMode = rendering ? 1 : 0; + + bool useFBO = g_Config.iRenderingMode == 2; + if (UICheckBox(GEN_ID, x, y += stride, gs->T("Read Framebuffers to Memory (GPU)"), ALIGN_TOPLEFT, &useFBO)) + g_Config.iRenderingMode = useFBO ? 2 : 0; + + bool useCPU = g_Config.iRenderingMode == 3; + if (UICheckBox(GEN_ID, x, y += stride, gs->T("Read Framebuffers to Memory (CPU)"), ALIGN_TOPLEFT, &useCPU)) + g_Config.iRenderingMode = useCPU ? 3 : 0; UIEnd(); } diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 511fa3ec8..46c640549 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -216,6 +216,10 @@ namespace MainWindow if(gpu) gpu->ClearCacheNextFrame(); } + void setRenderingMode(int num) { + g_Config.iRenderingMode = num; + } + void setFpsLimit(int fps) { g_Config.iFpsLimit = fps; } @@ -720,25 +724,20 @@ namespace MainWindow if(gpu) gpu->ClearCacheNextFrame(); break; + case ID_OPTIONS_NONBUFFEREDRENDERING: + setRenderingMode(0); + break; + case ID_OPTIONS_BUFFEREDRENDERING: - g_Config.bBufferedRendering = !g_Config.bBufferedRendering; - osm.ShowOnOff(g->T("Buffered Rendering"), g_Config.bBufferedRendering); - if (gpu) - gpu->Resized(); // easy way to force a clear... + setRenderingMode(1); break; - case ID_OPTIONS_READFBOTOMEMORY: - g_Config.bFramebuffersToMem = !g_Config.bFramebuffersToMem; - osm.ShowOnOff(g->T("Read Framebuffers To Memory"), g_Config.bFramebuffersToMem); - if (gpu) - gpu->Resized(); // easy way to force a clear... + case ID_OPTIONS_READFBOTOMEMORYGPU: + setRenderingMode(2); break; - case ID_OPTIONS_FBOCPUCONVERT: - g_Config.bFramebuffersCPUConvert = !g_Config.bFramebuffersCPUConvert; - osm.ShowOnOff(g->T("Convert Framebuffers Using CPU"), g_Config.bFramebuffersCPUConvert); - if(gpu) - gpu->Resized(); // easy way to force a clear... + case ID_OPTIONS_READFBOTOMEMORYCPU: + setRenderingMode(3); break; case ID_OPTIONS_SHOWDEBUGSTATISTICS: @@ -1041,9 +1040,6 @@ namespace MainWindow CHECKITEM(ID_OPTIONS_IGNOREILLEGALREADS,g_Config.bIgnoreBadMemAccess); CHECKITEM(ID_CPU_INTERPRETER,g_Config.bJit == false); CHECKITEM(ID_CPU_DYNAREC,g_Config.bJit == true); - CHECKITEM(ID_OPTIONS_BUFFEREDRENDERING, g_Config.bBufferedRendering); - CHECKITEM(ID_OPTIONS_READFBOTOMEMORY, g_Config.bFramebuffersToMem); - CHECKITEM(ID_OPTIONS_FBOCPUCONVERT, g_Config.bFramebuffersCPUConvert); CHECKITEM(ID_OPTIONS_SHOWDEBUGSTATISTICS, g_Config.bShowDebugStats); CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform); CHECKITEM(ID_OPTIONS_FASTMEMORY, g_Config.bFastMemory); @@ -1101,6 +1097,16 @@ namespace MainWindow CheckMenuItem(menu, texfilteringitems[i], MF_BYCOMMAND | ( (i + 1) == g_Config.iTexFiltering )? MF_CHECKED : MF_UNCHECKED); } + static const int renderingmode[] = { + ID_OPTIONS_NONBUFFEREDRENDERING, + ID_OPTIONS_BUFFEREDRENDERING, + ID_OPTIONS_READFBOTOMEMORYGPU, + ID_OPTIONS_READFBOTOMEMORYCPU, + }; + for (int i = 0; i < 4; i++) { + CheckMenuItem(menu, renderingmode[i], MF_BYCOMMAND | ( i == g_Config.iRenderingMode )? MF_CHECKED : MF_UNCHECKED); + } + UpdateCommands(); } diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 4f199195d..f86977a9a 100644 Binary files a/Windows/ppsspp.rc and b/Windows/ppsspp.rc differ diff --git a/Windows/resource.h b/Windows/resource.h index 164f4f46c..f95a7243b 100644 Binary files a/Windows/resource.h and b/Windows/resource.h differ diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 5bba70a79..63ff94420 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -190,7 +190,7 @@ int main(int argc, const char* argv[]) // Never report from tests. g_Config.sReportHost = ""; g_Config.bAutoSaveSymbolMap = false; - g_Config.bBufferedRendering = true; + g_Config.iRenderingMode = true; g_Config.bHardwareTransform = true; #ifdef USING_GLES2 g_Config.iAnisotropyLevel = 0;