Overview

A bug would be triggered if an imageSnapper was placed in paperSpace and then stretched or scaled followed by an undo/redo operation. The same problem occured with all classes derived from drawRect if the layer was set to bottom. In order to remedy this issue the previously named photoSnapperUndoHook has been moved into the drawRect super class and renamed drawRectUndoHook.

COMaterials

COMaterials have been changed to always use GMaterial3D. Previously WrappedImageMaterial3D was used for texture materials and ColorMaterial3D for color materials.

Compile Time Changes

AccessoryLocation

Commit ae48deba Removed the acceptAccessory() method in favor of the acceptLocation() method on AccessoryEnv.

Runtime/Behavior Changes

The global private bool _blockedUndoHookCB has been removed from photoSnapper and instead added as a public field in the drawRect parent class. This was done since this value needs to be checked during the drawRectUndoHook. Although it is only used by photoSnapper, it was moved to the parent class to avoid drawRect from needing a dependecy on photoSnapper. In order for the photoSnapper subclass to be able to read and modify its value, it was changed to a public variable.

old: cm/std/photo/photoSnapper.cm

private bool _blockUndoHookCB = false;

new: cm/abstract/draw/drawRect.cm

    /**
     * Block undo hook.
     */
    public bool blockUndoHookCB = false;

As a result we now instead modify this public field in cm/std/photo/photoSnapper.cm quickPropertyChanged():

old:

_blockUndoHookCB = true;
...
_blockUndoHookCB = false;

new:

blockUndoHookCB = true;
...
blockUndoHookCB = false;

As mentioned, the previously named photoSnapperUndoHook has been moved from PhotoSnapper to its parent class DrawRect and renamed drawRectUndoHook. As a result the hook registration has also been moved to the parent class:

cm/std/photo/photoSnapper.cm removed:

/**
 * Photo snapper undo hook.
 */
private void photoSnapperUndoHook(World w, UndoStep step) {
    if (_blockUndoHookCB) return;

    //double start = microTime();
    if (step and step.contains(UndoModifyOp)) {
	if (!w.isUndoRecording and !isUndoRestoreInProgress) {
	    Space{} affected(4);
	    for (PhotoSnapper s in step.modified) {
		if (s.space !in affected and s.space.isPaperSpace() and step.affects(s.space)) {
		    affected << s.space;
		}
	    }

	    if (affected.any) {
		View{} visited(4);
		for (space in affected) {
		    for (REDPaperView view in space.views, index=i) {
			if (view !in visited) {
			    view.invalidatePaperShape();
			    visited << view;
			}
		    }
		}
	    }
	}
    }
    //pln("Invalidate paper shape took: ", us(microTime - start));
}


old:

init {
    putAlternativesChangedHook("cm.std.photo.photoSnapper", function changedAlternativeHook);
    registerUndoHook("photoSnapperUndoHook", function photoSnapperUndoHook);
}

new:

init {
    putAlternativesChangedHook("cm.std.photo.photoSnapper", function changedAlternativeHook);
}

cm/abstract/draw/drawRect.cm added:

use cm.application;

added:

/**
 * Draw rect undo hook.
 */
private void drawRectUndoHook(World w, UndoStep step) {
    if (step and step.contains(UndoModifyOp)) {
	if (!w.isUndoRecording and !isUndoRestoreInProgress) {
	    Space{} affected(4);
	    for (DrawRect s in step.modified) {
		if (s.space !in affected and s.space.isPaperSpace() and step.affects(s.space) and s.drawLayer == bottomLayer and !s.blockUndoHookCB) {
		    affected << s.space;
		}
	    }

	    if (affected.any) {
		View{} visited(4);
		for (space in affected) {
		    for (REDPaperView view in space.views, index=i) {
			if (view !in visited) {
			    view.invalidatePaperShape();
			    visited << view;
			}
		    }
		}
	    }
	}
    }
}

added:

init {
    registerUndoHook("drawRectUndoHook", function drawRectUndoHook);
}

AccessoryEnv

Commit ae48deba In createAccessory() now checks to see if the AccessoryEnv accepts the location instead making a new accessory and asking the location if it accepts the accessory.

Old : 
extend public bool createAccessory(AccGenBehavior behavior, AccLoc loc, CoreObject{} existing) {
 CoreObject acc = generateAccessory(behavior, loc);
  
 if (loc.acceptAccessory(acc)) {
  behavior.updateAccessory(acc, loc);
 ...
 }
 
New :
extend public bool createAccessory(AccGenBehavior behavior, AccLoc loc, CoreObject{} existing) {
 if (acceptLocation(loc)) {
   CoreObject acc = generateAccessory(behavior, loc);
   
   behavior.updateAccessory(acc, loc); 
 ...
 }

COMmaterials

Creating a COMaterial will always create a GMaterial3D. It will use a PBRMatSpec as its spec. Selecting a texture from the COMaterial dialog will set the baseTextureUrl of the spec, while selecting a color from the dialog will set the baseColorFactor of the spec.

cm/abstract/material/comMaterialDialog.cm and cm/abstract/industry/comMaterialDialog.cm:

Constructor:

old:
	    if (!tempMat)
	      tempMat = CustomerOwnMaterial("COMTEMP", "", colorMaterial3D( 125, 125, 125 ));

new:
	    if (!tempMat)
	      tempMat = CustomerOwnMaterial("COMTEMP", "", GMaterial3D());

cm/abstract/material/comMaterialDialog.cm

old:
    extend public void chooseBtnColorCB() {
	color c = chooseColorDialog(parent, tempMat.color2D);
	if (c.isColor) {
	    Material3D m = colorMaterial3D(c);
	    tempMat.updateMaterial3D(m);
	    setControlsEnable();
	    updateImage();
	}

new:

    extend public void chooseBtnColorCB() {
	color c = chooseColorDialog(parent, tempMat.color2D);
	if (c.isColor) {
	    PBRMatSpec spec();
	    spec.baseColorFactor = colorToColorF(c);
	    GMaterial3D m = GMaterial3D(spec);
	    tempMat.updateGMaterial3D(m);
	    setControlsEnable();
	    updateImage();
	}

old:

      extend public void browseUrl() {
	Url url = coreSettings.get("COMaterialDialog.wrappedImageFile").Url;
	int imageFileFilterIdx = coreSettings.safeGetInt("COMaterialDialog.fileFilterIdx");
	
	Int fileFilterIdx(imageFileFilterIdx);
	url = getOpenFileName(this, url, imageImportFilter, filterIndex=fileFilterIdx);
	
	if (url and url.isReadable) {
	    setLastUrlAndIndex(url, fileFilterIdx.v);
	    Material3D m = wrappedImageMaterial3D(url);
	
	    tempMat.updateMaterial3D(m);
	
	    updateImage();
	}

new:

      extend public void browseUrl() {
	Url url = coreSettings.get("COMaterialDialog.wrappedImageFile").Url;
	int imageFileFilterIdx = coreSettings.safeGetInt("COMaterialDialog.fileFilterIdx");
	
	Int fileFilterIdx(imageFileFilterIdx);
	url = getOpenFileName(this, url, imageImportFilter, filterIndex=fileFilterIdx);
	
	if (url and url.isReadable) {
	    setLastUrlAndIndex(url, fileFilterIdx.v);
	    PBRMatSpec spec();
	    spec.baseTextureUrl = url;
	    Material3D m = GMaterial3D(spec);
	
	    tempMat.updateGMaterial3D(m);
	
	    updateImage();
	}

cm/abstract/industry/comMaterialDialog.cm

old:
      extend public void chooseBtnColorCB() {
	 color c = chooseColorDialog(parent, tempMat.color2D);
	 if (c.isColor) {
	     tempMat.invalidate();
	     Material3D m = colorMaterial3D(c);
	     tempMat.updateMaterial3D(m);
	     tempMat._color2D = c;
	 
	     updateImage();
	 }


new:

       extend public void chooseBtnColorCB() {
	 color c = chooseColorDialog(parent, tempMat.color2D);
	 if (c.isColor) {
	     tempMat.invalidate();
	     PBRMatSpec spec();
	     spec.baseColorFactor = colorToColorF(c);
	     GMaterial3D m = GMaterial3D(spec);
	     tempMat.updateGMaterial3D(m);
	 
	     updateImage();
	 }

old:

    extend public void browseUrl() {
	 Url url = coreSettings.get("IndCOMaterialDialog.wrappedImageFile").Url;
	 int imageFileFilterIdx = coreSettings.safeGetInt("IndCOMaterialDialog.fileFilterIdx");

	 Int fileFilterIdx(imageFileFilterIdx);
	 url = getOpenFileName(this, url, imageImportFilter, filterIndex=fileFilterIdx);

	 if (url and url.isReadable) {
	     setLastUrlAndIndex(url, fileFilterIdx.v);
	     Material3D m = wrappedImageMaterial3D(url);
	     tempMat.updateMaterial3D(m);

	     updateImage();
	 }
     }


new:

     extend public void browseUrl() {
	 Url url = coreSettings.get("IndCOMaterialDialog.wrappedImageFile").Url;
	 int imageFileFilterIdx = coreSettings.safeGetInt("IndCOMaterialDialog.fileFilterIdx");

	 Int fileFilterIdx(imageFileFilterIdx);
	 url = getOpenFileName(this, url, imageImportFilter, filterIndex=fileFilterIdx);

	 if (url and url.isReadable) {
	     setLastUrlAndIndex(url, fileFilterIdx.v);
	     PBRMatSpec spec();
	     spec.baseTextureUrl = url;
	     Material3D m = GMaterial3D(spec);
	
	     tempMat.updateGMaterial3D(m);

	     updateImage();
	 }
     }

added:
private str[] gMatImportFilter() {
    return [$fileFilterGMatStr, $fileFilterGMatFilter, 
	    $allFilesFilter, "*.*"];
}

cm/abstract/industry/customerOwnMaterials.cm

added:
   extend public void updateGMaterial3D(Material3D mat) {
	material3D = mat;
	_color2D = nocolor;
    }

cm/std/assetTools/material/lab/mlGMaterial3D.cm

old:
    final public str{} textureLinksToBase() {
	if (?(str{}) links = misc.get("textureLinksToBase")) {
	    return links;
	}
	return null;
    }

new:
   final public str{} textureLinksToBase() {
	if (?(str{}) links = misc.?get("textureLinksToBase")) {
	    return links;
	}
	return null;
    }