/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "hsTypes.h" #include "plLayerTex.h" #include "plLayerTexBitmapPB.h" #include "plDetailCurveCtrl.h" #if 1 class BMTexPBAccessor; extern BMTexPBAccessor bmtex_accessor; class BitmapDlgProc; extern BitmapDlgProc gBitmapDlgProc; static ParamBlockDesc2 gBitmapParamBlk ( plLayerTex::kBlkBitmap, _T("bitmap"), 0, GetLayerTexDesc(),//NULL, P_AUTO_CONSTRUCT + P_AUTO_UI, plLayerTex::kRefBitmap, IDD_LAYER_TEX, IDS_LAYER_TEX, 0, 0, &gBitmapDlgProc, // Bitmap kBmpUseBitmap, _T("useBitmap"), TYPE_BOOL, 0, 0, p_default, TRUE, p_ui, TYPE_SINGLECHEKBOX, IDC_USE_BITMAP, end, kBmpBitmap, _T("bitmap"), TYPE_BITMAP, P_SHORT_LABELS, 0, p_accessor, &bmtex_accessor, end, // Crop/Place kBmpApply, _T("apply"), TYPE_BOOL, 0, 0, p_default, FALSE, p_ui, TYPE_SINGLECHEKBOX, IDC_BM_CLIP, end, kBmpCropPlace, _T("cropPlace"), TYPE_INT, 0, 0, p_default, 0, p_range, 0, 1, p_ui, TYPE_RADIO, 2, IDC_BM_CROP,IDC_BM_PLACE, end, kBmpClipU, _T("clipU"), TYPE_FLOAT, P_ANIMATABLE, IDS_BITMAP_CLIPU, p_default, 0.0, p_range, 0.0, 1.0, p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_CLIP_X, IDC_CLIP_XSPIN, 0.001f, p_accessor, &bmtex_accessor, end, kBmpClipV, _T("clipV"), TYPE_FLOAT, P_ANIMATABLE, IDS_BITMAP_CLIPV, p_default, 0.0, p_range, 0.0, 1.0, p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_CLIP_Y, IDC_CLIP_YSPIN, 0.001f, p_accessor, &bmtex_accessor, end, kBmpClipW, _T("clipW"), TYPE_FLOAT, P_ANIMATABLE, IDS_BITMAP_CLIPW, p_default, 1.0, p_range, 0.0, 1.0, p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_CLIP_W, IDC_CLIP_WSPIN, 0.001f, p_accessor, &bmtex_accessor, end, kBmpClipH, _T("clipH"), TYPE_FLOAT, P_ANIMATABLE, IDS_BITMAP_CLIPH, p_default, 1.0, p_range, 0.0, 1.0, p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_CLIP_H, IDC_CLIP_HSPIN, 0.001f, p_accessor, &bmtex_accessor, end, // Texture Color/Alpha kBmpDiscardColor, _T("discardColor"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_BLEND_NO_COLOR, end, kBmpInvertColor, _T("invertColor"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_BLEND_INV_COLOR, end, kBmpDiscardAlpha, _T("discardAlpha"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_DISCARD_ALPHA, end, kBmpInvertAlpha, _T("invertAlpha"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_BLEND_INV_ALPHA, end, // Texture Quality kBmpNonCompressed, _T("nonCompressed"),TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_FORCE_NONCOMPRESSED, end, kBmpScaling, _T("scaling"), TYPE_INT, 0, 0, p_ui, TYPE_RADIO, 3, IDC_SCALE_ALL, IDC_SCALE_HALF, IDC_SCALE_NONE, end, // Max Only kBmpMonoOutput, _T("monoOutput"), TYPE_INT, 0, 0, p_ui, TYPE_RADIO, 2, IDC_HSMAX_LAYER_RGBOUT, IDC_HSMAX_LAYER_ALPHAOUT, end, kBmpRGBOutput, _T("rgbOutput"), TYPE_INT, 0, 0, p_ui, TYPE_RADIO, 2, IDC_HSMAX_LAYER_RGBOUT2, IDC_HSMAX_LAYER_ALPHAOUT2, end, // Mipmap kBmpNoFilter, _T("noFilter"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_NO_FILTERING, end, kBmpMipBlur, _T("mipBlur"), TYPE_FLOAT, 0, 0, p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_MIPBLUR_EDIT, IDC_MIPBLUR_SPIN, 0.4, p_range, 0.01f, 100.0f, p_default, 1.0, end, kBmpMipBias, _T("mipBias"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_USE_MIPBIAS, p_enable_ctrls, 1, kBmpMipBiasAmt, end, kBmpMipBiasAmt, _T("mipBiasAmt"), TYPE_FLOAT, 0, 0, p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_MIPBIAS_EDIT, IDC_MIPBIAS_SPIN, 0.7, p_range, -100.0, 100.0, p_default, 1.0, end, // Detail kBmpUseDetail, _T("useDetail"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_USE_DETAIL, p_default, FALSE, p_enable_ctrls, 4, kBmpDetailStartSize, kBmpDetailStopSize, kBmpDetailStartOpac, kBmpDetailStopOpac, p_accessor, &bmtex_accessor, end, kBmpDetailStartSize,_T("dropOffStart"), TYPE_INT, 0, 0, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_DETAIL_START_SIZE_EDIT, IDC_DETAIL_START_SIZE_SPIN, 0.4, p_range, 0, 100, p_default, 0, p_accessor, &bmtex_accessor, end, kBmpDetailStopSize, _T("dropOffStop"), TYPE_INT, 0, 0, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_DETAIL_STOP_SIZE_EDIT, IDC_DETAIL_STOP_SIZE_SPIN, 0.4, p_range, 0, 100, p_default, 100, p_accessor, &bmtex_accessor, end, kBmpDetailStartOpac, _T("detailMax"), TYPE_INT, 0, 0, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_DETAIL_START_OPAC_EDIT, IDC_DETAIL_START_OPAC_SPIN, 0.4, p_range, 0, 100, p_default, 100, p_accessor, &bmtex_accessor, end, kBmpDetailStopOpac, _T("detailMin"), TYPE_INT, 0, 0, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_DETAIL_STOP_OPAC_EDIT, IDC_DETAIL_STOP_OPAC_SPIN, 0.4, p_range, 0, 100, p_default, 0, p_accessor, &bmtex_accessor, end, kBmpExportWidth, _T("exportWidth"), TYPE_INT, 0, 0, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_EXPORTWIDTH, IDC_EXPORTWIDTH_SPINNER, SPIN_AUTOSCALE, p_range, 4, 2048, p_default, 512, end, kBmpExportHeight, _T("exportHeight"), TYPE_INT, 0, 0, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_EXPORTHEIGHT, IDC_EXPORTHEIGHT_SPINNER, SPIN_AUTOSCALE, p_range, 4, 2048, p_default, 512, end, kBmpExportLastWidth, _T("lastExportWidth"), TYPE_INT, 0, 0, end, kBmpExportLastHeight, _T("lastExportHeight"), TYPE_INT, 0, 0, end, // Keep a sysmem copy at runtime (for image examination/manipulation). kBmpNoDiscard, _T("noDiscard"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_NO_DISCARD, p_default, FALSE, end, end ); ParamBlockDesc2 *GetBitmapBlk() { return &gBitmapParamBlk; } class BMCropper; class BMTexPBAccessor : public PBAccessor { public: void Set(PB2Value& val, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t) { plLayerTex* layer = (plLayerTex*)owner; if(layer == NULL) return; IParamBlock2 *pb = layer->GetParamBlockByID(plLayerTex::kBlkBitmap); switch (id) { case kBmpBitmap: if (pb->GetMap()) pb->GetMap()->Invalidate(kBmpBitmap); // Update the bitmap saved by the layer //layer->SetBitmap(&val.bm->bi, tabIndex); break; /* case kBmpFilename: bmt->SetMapName(val.s); break; case kBmpFiltering: bmt->filterType = val.i; if (bmt->thebm) bmt->thebm->SetFilter(bmFilterType(val.i)); break; */ case kBmpClipU: { float u = val.f; float w = pb->GetFloat(kBmpClipW, t); if (u + w > 1.0f) { pb->SetValue(kBmpClipW, t, 1.0f-u); if (pb->GetMap()) pb->GetMap()->Invalidate(kBmpClipW); } break; } case kBmpClipW: { float w = val.f; float u = pb->GetFloat(kBmpClipU, t); if (u + w > 1.0f) { pb->SetValue(kBmpClipU, t, 1.0f-w); if (pb->GetMap()) pb->GetMap()->Invalidate(kBmpClipU); } break; } case kBmpClipV: { float v = val.f; float h = pb->GetFloat(kBmpClipH, t); if (v + h > 1.0f) { pb->SetValue(kBmpClipH, t, 1.0f-v); if (pb->GetMap()) pb->GetMap()->Invalidate(kBmpClipH); } break; } case kBmpClipH: { float h = val.f; float v = pb->GetFloat(kBmpClipV, t); if (v + h > 1.0f) { pb->SetValue(kBmpClipV, t, 1.0f-h); if (pb->GetMap()) pb->GetMap()->Invalidate(kBmpClipV); } break; } case kBmpDetailStartSize: case kBmpDetailStopSize: case kBmpDetailStartOpac: case kBmpDetailStopOpac: if( pb != NULL ) { if( IIsProcSettingDetailValues( pb ) ) break; // Ignore, since we're the ones setting 'em HWND dlg = pb->GetMap()->GetHWnd(); plDetailCurveCtrl *ctrl = GET_DETAIL_CURVE_CTRL( dlg, IDC_DETAIL_CURVE_CTRL ); if( ctrl != NULL ) { if( id == kBmpDetailStartSize || id == kBmpDetailStartOpac ) ctrl->SetStartPoint( (float)pb->GetInt( kBmpDetailStartSize, t ) / 100.f, (float)pb->GetInt( kBmpDetailStartOpac, t ) / 100.f ); else ctrl->SetEndPoint( (float)pb->GetInt( kBmpDetailStopSize, t ) / 100.f, (float)pb->GetInt( kBmpDetailStopOpac, t ) / 100.f ); } // Make sure start is less than end if( id == kBmpDetailStartSize ) { int end = pb->GetInt( kBmpDetailStopSize, t ); if( val.i > end ) pb->SetValue( kBmpDetailStopSize, t, val.i ); } else if( id == kBmpDetailStopSize ) { int start = pb->GetInt( kBmpDetailStartSize, t ); if( val.i < start ) pb->SetValue( kBmpDetailStartSize, t, val.i ); } } break; case kBmpUseDetail: if( pb != NULL ) { HWND dlg = pb->GetMap()->GetHWnd(); EnableWindow( GetDlgItem( dlg, IDC_DETAIL_CURVE_CTRL ), (BOOL)val.i ); } break; } } void Get(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t, Interval &valid) { } // Gotta love hacks.... bool IIsProcSettingDetailValues( IParamBlock2 *pb ); }; static BMTexPBAccessor bmtex_accessor; //========================================================================================= // BMCropper //========================================================================================= class BMCropper : public CropCallback { IParamBlock2 *fPBlock; public: BMCropper(IParamBlock2* pblock) : fPBlock(pblock) {} float GetInitU() { return fPBlock->GetFloat(kBmpClipU); } float GetInitV() { return fPBlock->GetFloat(kBmpClipV); } float GetInitW() { return fPBlock->GetFloat(kBmpClipW); } float GetInitH() { return fPBlock->GetFloat(kBmpClipH); } BOOL GetInitMode() { return fPBlock->GetInt(kBmpCropPlace); } void SetValues(float u, float v, float w, float h, BOOL md); void OnClose(); }; void BMCropper::SetValues(float u, float v, float w, float h, BOOL md) { TimeValue t = GetCOREInterface()->GetTime(); if (u != fPBlock->GetFloat(kBmpClipU, t)) { fPBlock->SetValue(kBmpClipU, t, u); fPBlock->GetMap()->Invalidate(kBmpClipU); } if (v != fPBlock->GetFloat(kBmpClipV, t)) { fPBlock->SetValue(kBmpClipV, t, v); fPBlock->GetMap()->Invalidate(kBmpClipV); } if (w != fPBlock->GetFloat(kBmpClipW, t)) { fPBlock->SetValue(kBmpClipW, t, w); fPBlock->GetMap()->Invalidate(kBmpClipW); } if (h != fPBlock->GetFloat(kBmpClipH, t)) { fPBlock->SetValue(kBmpClipH, t, h); fPBlock->GetMap()->Invalidate(kBmpClipH); } if (md != fPBlock->GetInt(kBmpCropPlace)) { fPBlock->SetValue(kBmpCropPlace, t, md); fPBlock->GetMap()->Invalidate(kBmpCropPlace); } } void BMCropper::OnClose() { delete this; } class BitmapDlgProc : public ParamMap2UserDlgProc { friend class BMTexPBAccessor; PBBitmap *fLastBMap; bool fSettingDetailValues; /// Called to update the controls of the dialog /// Note: we're bad that we use a static here, but virtual void Update( TimeValue t, Interval &valid, IParamMap2 *map ) { ICustButton *bmSelectBtn; IParamBlock2 *pblock; int width, height; ParamMap2UserDlgProc::Update( t, valid, map ); if( fSettingDetailValues ) { // We're getting an update just because we changed detail values, so we // know we don't have to do anything ourselves return; } pblock = map->GetParamBlock(); // Update texture map button bmSelectBtn = GetICustButton( GetDlgItem( map->GetHWnd(), IDC_LAYER_NAME ) ); PBBitmap *pbbm = pblock->GetBitmap( kBmpBitmap, t ); if( pbbm ) { if( pbbm != fLastBMap ) { bmSelectBtn->SetText( (TCHAR *)pbbm->bi.Filename() ); // Init values for clamping spinners to powers of 2 width = IFloorPow2( pbbm->bi.Width() ); map->SetRange( kBmpExportWidth, 4.f, (float)width ); height = IFloorPow2( pbbm->bi.Height() ); map->SetRange( kBmpExportHeight, 4.f, (float)height ); IClampTexSizeSpinner( t, map, true ); ISetDetailCurveNumLevels( map, t ); } } else if( pbbm != fLastBMap ) bmSelectBtn->SetText( _T( "None" ) ); fLastBMap = pbbm; ReleaseICustButton( bmSelectBtn ); // Update detail curve control HWND dlg = map->GetHWnd(); plDetailCurveCtrl *ctrl = GET_DETAIL_CURVE_CTRL( dlg, IDC_DETAIL_CURVE_CTRL ); if( ctrl == NULL ) { // The control hasn't been created, so create it already! HWND basis; RECT r; // Create the detail map control basis = GetDlgItem( dlg, IDC_DETAIL_SAMPLE ); GetClientRect( basis, &r ); MapWindowPoints( basis, dlg, (POINT *)&r, 2 ); ctrl = TRACKED_NEW plDetailCurveCtrl( dlg, IDC_DETAIL_CURVE_CTRL, &r ); } EnableWindow( GetDlgItem( dlg, IDC_DETAIL_CURVE_CTRL ), (BOOL)pblock->GetInt( kBmpUseDetail, t ) ); if( ctrl != NULL ) { ctrl->SetStartPoint( (float)pblock->GetInt( kBmpDetailStartSize, t ) / 100.f, (float)pblock->GetInt( kBmpDetailStartOpac, t ) / 100.f ); ctrl->SetEndPoint( (float)pblock->GetInt( kBmpDetailStopSize, t ) / 100.f, (float)pblock->GetInt( kBmpDetailStopOpac, t ) / 100.f ); } } BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { static ICustButton* bmSelectBtn; switch (msg) { case WM_INITDIALOG: fLastBMap = NULL; fSettingDetailValues = false; break; /// Note: the following *could* be done in the accessor, except that you end up in an /// infinite loop updating the values. Not good. case CC_SPINNER_CHANGE: if( LOWORD( wParam ) == IDC_EXPORTWIDTH_SPINNER ) IClampTexSizeSpinner( t, map, true ); else if( LOWORD( wParam ) == IDC_EXPORTHEIGHT_SPINNER ) IClampTexSizeSpinner( t, map, false ); break; // Message from the detail curve that a point got dragged case PL_DC_POINT_DRAGGED: { plDetailCurveCtrl *ctrl = (plDetailCurveCtrl *)lParam; IParamBlock2 *pblock = map->GetParamBlock(); float x, y; fSettingDetailValues = true; if( wParam == PL_DC_START_POINT ) { ctrl->GetStartPoint( x, y ); pblock->SetValue( kBmpDetailStartSize, t, (int)( x * 100.f ) ); pblock->SetValue( kBmpDetailStartOpac, t, (int)( y * 100.f ) ); } else { ctrl->GetEndPoint( x, y ); pblock->SetValue( kBmpDetailStopSize, t, (int)( x * 100.f ) ); pblock->SetValue( kBmpDetailStopOpac, t, (int)( y * 100.f ) ); } map->UpdateUI( t ); fSettingDetailValues = false; } return 0; case WM_COMMAND: if( HIWORD( wParam ) == EN_CHANGE && LOWORD( wParam ) == IDC_EXPORTWIDTH ) IClampTexSizeSpinner( t, map, true ); else if( HIWORD( wParam ) == EN_CHANGE && LOWORD( wParam ) == IDC_EXPORTHEIGHT ) IClampTexSizeSpinner( t, map, false ); else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_BM_CROP_IMAGE) { IParamBlock2 *pblock = map->GetParamBlock(); PBBitmap *pbbm = pblock->GetBitmap(kBmpBitmap, t); if (pbbm) { if (!pbbm->bm) pbbm->bm = TheManager->Load(&pbbm->bi); BMCropper *cropper = TRACKED_NEW BMCropper(pblock); pbbm->bm->Display("Specify Cropping/Placement", BMM_CN, FALSE, TRUE, cropper); } // bm->DeleteThis(); return TRUE; } else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_LAYER_RELOAD) { // TEMP IParamBlock2 *pblock = map->GetParamBlock(); PBBitmap *pbbm = pblock->GetBitmap(kBmpBitmap, t); if (pbbm) { plLayerTex *layer = (plLayerTex*)map->GetParamBlock()->GetOwner(); layer->RefreshBitmaps(); layer->fMtlParams->MtlChanged(); layer->IChanged(); } return TRUE; } else if (LOWORD(wParam) == IDC_LAYER_NAME) { plPlasmaMAXLayer *layer = (plPlasmaMAXLayer *)map->GetParamBlock()->GetOwner(); if (layer == nil) return FALSE; BOOL selectedNewBitmap = layer->HandleBitmapSelection(); if(selectedNewBitmap) { IParamBlock2 *pblock = map->GetParamBlock(); //plLayerTex *layer = (plLayerTex*)map->GetParamBlock()->GetOwner(); //layer->SetBitmap(&bi); //layer->IChanged(); //BitmapInfo *bi = &layer->GetPBBitmap()->bi; bmSelectBtn = GetICustButton(GetDlgItem(hWnd,IDC_LAYER_NAME)); PBBitmap *pbbm = layer->GetPBBitmap(); bmSelectBtn->SetText(pbbm != nil ? (TCHAR*)pbbm->bi.Filename() : ""); ReleaseICustButton(bmSelectBtn); if (pbbm != nil) { // Init values for clamping spinners to powers of 2 int width = IFloorPow2( pbbm->bi.Width() ); map->SetRange( kBmpExportWidth, 4.f, (float)width ); int height = IFloorPow2( pbbm->bi.Height() ); map->SetRange( kBmpExportHeight, 4.f, (float)height ); if( width > 512 ) { height = (int)( 512.f * (float)( (float)height / (float)width ) ); width = 512; } else if( height > 512 ) { width = (int)( 512.f * (float)( (float)width / (float)height ) ); height = 512; } pblock->SetValue( kBmpExportWidth, t, width ); pblock->SetValue( kBmpExportLastWidth, t, width ); pblock->SetValue( kBmpExportHeight, t, height ); pblock->SetValue( kBmpExportLastHeight, t, height ); IClampTexSizeSpinner( t, map, true ); } return TRUE; } else { return FALSE; } } break; } return FALSE; } void DeleteThis() {}; void ISetDetailCurveNumLevels( IParamMap2 *map, TimeValue t ) { /// Set the level count on the detail control plDetailCurveCtrl *ctrl = GET_DETAIL_CURVE_CTRL( map->GetHWnd(), IDC_DETAIL_CURVE_CTRL ); if( ctrl != NULL ) { IParamBlock2 *pblock = map->GetParamBlock(); int w = pblock->GetInt( kBmpExportWidth, t ); int h = pblock->GetInt( kBmpExportHeight, t ); int numLevels = 0; while( w > 1 && h > 1 ) { w >>= 1; h >>= 1; numLevels++; } ctrl->SetNumLevels( numLevels ); } } /// Clamp texture sizes to a power of 2 void IClampTexSizeSpinner( TimeValue t, IParamMap2 *map, bool clampWidth ) { IParamBlock2 *pblock = map->GetParamBlock(); ParamID clampNew, clampOld; ParamID otherNew, otherOld; if( clampWidth ) { clampNew = kBmpExportWidth; clampOld = kBmpExportLastWidth; otherNew = kBmpExportHeight; otherOld = kBmpExportLastHeight; } else { clampNew = kBmpExportHeight; clampOld = kBmpExportLastHeight; otherNew = kBmpExportWidth; otherOld = kBmpExportLastWidth; } int lastVal = pblock->GetInt( clampOld, t ); int tempVal, newVal = pblock->GetInt( clampNew, t ); if( newVal < lastVal ) { lastVal = newVal; for( tempVal = 1; tempVal <= newVal; tempVal <<= 1 ); newVal = tempVal >> 1; } else { lastVal = newVal; for( tempVal = 1; tempVal < newVal; tempVal <<= 1 ); newVal = tempVal; } pblock->SetValue( clampNew, t, newVal ); pblock->SetValue( clampOld, t, newVal ); // And clamp aspect ratio PBBitmap *pbbm = pblock->GetBitmap( kBmpBitmap, t ); if( pbbm != NULL ) { int realWidth = pbbm->bi.Width(); int realHeight = pbbm->bi.Height(); float aspect; if( clampWidth ) aspect = (float)realHeight / (float)realWidth; else aspect = (float)realWidth / (float)realHeight; int value = newVal; value *= aspect; if( value < 4 ) { // Can't be below 4! value = 4; pblock->SetValue( otherNew, t, value ); pblock->SetValue( otherOld, t, value ); value = value / aspect; pblock->SetValue( clampNew, t, value ); pblock->SetValue( clampOld, t, value ); } else { pblock->SetValue( otherNew, t, value ); pblock->SetValue( otherOld, t, value ); } } ISetDetailCurveNumLevels( map, t ); } int IFloorPow2( int value ) { int v; for( v = 1; v <= value; v <<= 1 ); return v >> 1; } }; static BitmapDlgProc gBitmapDlgProc; // Gotta love hacks.... bool BMTexPBAccessor::IIsProcSettingDetailValues( IParamBlock2 *pb ) { BitmapDlgProc *proc = (BitmapDlgProc *)pb->GetMap()->GetUserDlgProc(); if( proc != NULL ) return proc->fSettingDetailValues; return false; } #endif