// Image To 3D converter and editor // by seltar PImage pic1, pic2, a; boolean has_saved = false; // SWITCH TO FALSE IF YOU WANT TO ENABLE THE SAVE boolean is_online = false; // SWITCH TO TRUE IF YOU WANT TO USE THE SAVE-TO-WEB FUNCTIONS, OR FALSE TO SAVE TO DISK boolean lock_on_target = false; boolean lock_on_color = false; boolean loaded_verts = false; boolean spacedown = false; boolean grid_on = false; // SWITCH TO TRUE IF YOU WANT THE GRID ON BY DEFAULT boolean do_smooth = true; // SWITCH TO FALSE IF YOU DON'T WANT SMOOTHING BY DEFAULT int smoothval = 10; int maxWidth = 350; int maxHeight = 350; String[] output; int[][] aPixels; int[][] values; int[][][] verts; int range = 5; int imX, imY = 0; int polyStart = 0; int maxPolys = 80000; int polys = 5; // higher = lower-res, minimum 1 int cVal = 0; // lock on color value float gVal = 3.5; // global extrudevalue float heightval = 4; // higher = lower-res float butx,buty,butz,rotAxis = 0; float pZoom,pX,pY = 0; int aX,aY,aZ,tX,tY,lastC = 0; int activeBtn = 0; int activeImage = 0; int activeImage2 = 1; PFont metaBold; blendmodes mode=new blendmodes(); color[] pic1List; color[] pic2List; String nodename = "output"; String filename = "output.asc"; String texfilename = "texture"; String[] imagename = {"face12.jpg","face02.jpg","face03.jpg","face04.jpg","face05.jpg","face06.jpg","face07.jpg","face01.jpg"}; button[] buttonList=new button[18]; String[] buttonNames={"Invert","Average","Multiply","Screen","Darken","Lighten","Difference","Negation","Exclusion","Overlay","Hardlight","Dodge","Burn","Reflect","Glow","Freeze","Heat","Stamp"}; imgbutton btnPrevBlend, btnNextBlend, btnPlus, btnMinus, btnCalculate, btnLockTarget, btnLockColor, btnResetFaces, btnHiRes, btnLoRes, btnX, btnY, btnZ, btnResetCam; imgbutton btnPrevImage, btnNextImage, btnPrevBlendImage, btnNextBlendImage, btnLoColorRange, btnHiColorRange, btnGrid, btnExtrudeVal, btnLoExtrudeVal, btnHiExtrudeVal; imgbutton btnSaveModel, btnSaveImage, btnLoSmoothVal, btnSmoothVal, btnHiSmoothVal; PImage imgLeft, imgRight, imgPlus, imgMinus, imgCalc, imgLockT, imgLockC, imgResetFaces, imgX, imgY, imgZ, imgGrid, imgExtrudeVal, imgResetCam; PImage imgLefton, imgRighton, imgPluson, imgMinuson, imgCalcon, imgLockTon, imgLockCon, imgResetFaceson, imgXon, imgYon, imgZon, imgGridon, imgExtrudeValon, imgResetCamon; PImage imgSave, imgSaveon, imgSmoothVal, imgSmoothValon; String gStatus = ""; /* Button btnFreeRot; Button btnZoomIn; Button btnZoomOut; Buttons rotate model Buttons move model */ void setup() { initImages(); initBasevars(); initButtons(); calculateMesh(); } void draw() { background(145,145,145); pushMatrix(); transformObject(); showVertices(1,1); show3dvertex(); popMatrix(); drawOriginal(); drawStatusbar(); drawButtons(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // INITIALIZERS //////////////////////////////////////////////////////////////////////////////////////////////////////////////// void initImages(){ imgLeft = loadImage("btnleft.gif"); imgRight = loadImage("btnright.gif"); imgPlus = loadImage("btnplus.gif"); imgMinus = loadImage("btnminus.gif"); imgCalc = loadImage("btncalc.gif"); imgLockT = loadImage("btnlocktarget.gif"); imgLockC = loadImage("btnlockcolor.gif"); imgResetFaces = loadImage("btnresetfaces.gif"); imgResetCam = loadImage("btnresetcam.gif"); imgX = loadImage("btnx.gif"); imgY = loadImage("btny.gif"); imgZ = loadImage("btnz.gif"); imgGrid = loadImage("btngrid.gif"); imgExtrudeVal = loadImage("btnheightval.gif"); imgSave = loadImage("btnsave.gif"); imgSmoothVal = loadImage("btnsmoothval.gif"); imgLefton = loadImage("btnlefton.gif"); imgRighton = loadImage("btnrighton.gif"); imgPluson = loadImage("btnpluson.gif"); imgMinuson = loadImage("btnminuson.gif"); imgCalcon = loadImage("btncalcon.gif"); imgLockTon = loadImage("btnlocktargeton.gif"); imgLockCon = loadImage("btnlockcoloron.gif"); imgResetFaceson = loadImage("btnresetfaceson.gif"); imgResetCamon = loadImage("btnresetcamon.gif"); imgXon = loadImage("btnxon.gif"); imgYon = loadImage("btnyon.gif"); imgZon = loadImage("btnzon.gif"); imgGridon = loadImage("btngridon.gif"); imgExtrudeValon = loadImage("btnheightvalon.gif"); imgSaveon = loadImage("btnsaveon.gif"); imgSmoothValon = loadImage("btnsmoothvalon.gif"); pic1 = loadImage(imagename[activeImage]); pic2 = loadImage(imagename[activeImage2]); a = pic1; } void initBasevars(){ size(a.width+50+a.width+95, a.height+40,P3D); println(width); println(height); framerate(36); imX = width-a.width-70; imY = 0; aPixels = new int[a.width][a.height]; values = new int[a.width][a.height]; verts = new int[a.width][a.height][5]; output = new String[a.width*a.height*3]; pic1List = new color[a.width*a.height]; pic2List = new color[a.width*a.height]; metaBold = loadFont("Arial.vlw"); textFont(metaBold, 15); textAlign(CENTER); for(int j=0;jimX && mouseXimY && mouseY=(imX+l-(polys/2))){ if(mouseY<=(imY+k+(polys/2))&&mouseY>=(imY+k-(polys/2))){ strokeWeight(3); stroke(color(0,255,0)); tX = imX+l-1; tY = imY+k-1; } } point((imX+l),(imY+k)); strokeWeight(1); noStroke(); } } strokeWeight(0); }else if(lock_on_color){ for(int k=polys;k= rval-range/2){ if(vgval <= gval+range/2 && vgval >= gval-range/2){ if(vbval <= bval+range/2 && vbval >= bval-range/2){ strokeWeight(3); stroke(color(0,255,0)); point(imX+l-1,imY+k-1); strokeWeight(1); noStroke(); } } } } } }else if(lock_on_target){ strokeWeight(3); stroke(color(0,255,0)); point(tX,tY); strokeWeight(1); noStroke(); } checkUnderMouse(imX,imY); } void checkUnderMouse(int imX, int imY){ if(!lock_on_target && !lock_on_color){ if(mouseX > imX && mouseX < imX+a.width-1){ if(mouseY > imY && mouseY < imY+a.height-1){ int j = mouseX - imX-1; int i = mouseY - imY-1; for(int k=polys;k=(imX+l-(polys/2))){ if(mouseY<=(imY+k+(polys/2))&&mouseY>=(imY+k-(polys/2))){ aX = verts[l][k][1]; aY = verts[l][k][2]+5; aZ = verts[l][k][3]; cVal = verts[l][k][4]; if(spacedown){ verts[l][k][2] += (int)gVal; verts[l][k][4] = 255; } } } if(!spacedown){ verts[l][k][4] = aPixels[l][k]; } } } } } }else if(lock_on_color){ if(tX != 0 && tY != 0){ int n = tX-imX+1; int m = tY-imY+1; cVal = verts[n][m][4]; aX = verts[n][m][1]; aY = verts[n][m][2]; aZ = verts[n][m][3]; for(int k=polys;k= rval-range/2){ if(vgval <= gval+range/2 && vgval >= gval-range/2){ if(vbval <= bval+range/2 && vbval >= bval-range/2){ if(spacedown){ verts[l][k][2] += (int)gVal; verts[l][k][4] = 255; }else{ verts[l][k][4] = aPixels[l][k]; } } } } } } } }else if(lock_on_target){ if(tX != 0 && tY != 0){ int l = tX-imX+1; int k = tY-imY+1; aX = verts[l][k][1]; aY = verts[l][k][2]+5; aZ = verts[l][k][3]; if(spacedown){ verts[l][k][2] += (int)gVal; verts[l][k][4] = 255; }else{ verts[l][k][4] = aPixels[l][k]; } } } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SMOOTHING THE HEIGHT-VALUES //////////////////////////////////////////////////////////////////////////////////////////////////////////////// int smoothVal(int x,int y,int am, int ps){ // x-value, y-value float corners; float sides; int minX = ps-1; int minY = ps-1; int maxX = (int)((ps*floor(a.height/ps))-1); int maxY = (int)((ps*floor(a.width/ps))-1); if(x == minX && y == minY){ corners = (values[y+ps][x+ps] ) / (am*4); sides = (values[y][x+ps] + values[y+ps][x] ) / (am*2); }else if(x == maxX && y == maxY){ corners = (values[y-ps][x-ps]) / (am*4); sides = (values[y][x-ps] + values[y-ps][x] ) / (am*2); }else if(x == minX && y == maxY){ corners = (values[y-ps][x+ps]) / (am*4); sides = (values[y][x+ps] + values[y-ps][x] ) / (am*2); }else if(x == maxX && y == minY){ corners = (values[y+ps][x-ps]) / (am*4); sides = (values[y][x-ps] + values[y+ps][x] ) / (am*2); }else if(x == minX){ corners = (values[y-ps][x+ps] + values[y+ps][x+ps] ) / (am*4); sides = (values[y][x+ps] + values[y-ps][x] + values[y+ps][x] ) / (am*2); }else if(y == minY){ corners = (values[y+ps][x-ps] + values[y+ps][x+ps] ) / (am*4); sides = (values[y][x-ps] + values[y][x+ps] + values[y+ps][x] ) / (am*2); }else if(x == maxX){ corners = (values[y-ps][x-ps] + values[y+ps][x-ps] ) / (am*4); sides = (values[y][x-ps] + values[y-ps][x] + values[y+ps][x] ) / (am*2); }else if(y == maxY){ corners = (values[y-ps][x-ps] + values[y-ps][x+ps]) / (am*4); sides = (values[y][x-ps] + values[y][x+ps] + values[y-ps][x]) / (am*2); }else{ corners = (values[y-ps][x-ps] + values[y-ps][x+ps] + values[y+ps][x-ps] + values[y+ps][x+ps] ) / (am*4); sides = (values[y][x-ps] + values[y][x+ps] + values[y-ps][x] + values[y+ps][x] ) / (am*2); } float center = values[y][x] / (am); return (int)((corners + sides + center)/2); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DISPLAYING THE VERTICES REALTIME SHADED //////////////////////////////////////////////////////////////////////////////////////////////////////////////// int showVertices(int type,int _scale){ int counter = 0; beginShape(QUADS); for(int i=polys; ipolyStart)){ if(!grid_on){ stroke(verts[j-polys][i-polys][4]); }else{ stroke(0); } fill(verts[j-polys][i-polys][4]); vertex(verts[j-polys][i-polys][1]/_scale,verts[j-polys][i-polys][2]/_scale,verts[j-polys][i-polys][3]/_scale); if(!grid_on){ stroke(verts[j-polys][i][4]); } fill(verts[j-polys][i][4]); vertex(verts[j-polys][i][1]/_scale,verts[j-polys][i][2]/_scale,verts[j-polys][i][3]/_scale); if(!grid_on){ stroke(verts[j][i][4]); } fill(verts[j][i][4]); vertex(verts[j][i][1]/_scale,verts[j][i][2]/_scale,verts[j][i][3]/_scale); if(!grid_on){ stroke(verts[j][i-polys][4]); } fill(verts[j][i-polys][4]); vertex(verts[j][i-polys][1]/_scale,verts[j][i-polys][2]/_scale,verts[j][i-polys][3]/_scale); } counter++; } } endShape(); return counter; } /// /// // SAVING BLENDED IMAGE TO SERVER /// boolean postNewItem (String[] Par, String[] Val, String strURL, String fname) { boolean ret = false; try { URL url; URLConnection urlConn; DataOutputStream dos; DataInputStream dis; String s = ""; String S = ""; String query = ""; // generate the query-string (for multiple parameters) for(int i = 0; i < Par.length; i++){ if(i == 0){ query += "?fname="+fname+"&nump="+Par.length+"&"; }else{ query += "&"; } query += "p"+(i+1)+"="+Par[i]; } url = new URL(strURL + query); urlConn = url.openConnection(); urlConn.setDoInput(true); urlConn.setDoOutput(true); urlConn.setUseCaches(false); urlConn.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); dos = new DataOutputStream (urlConn.getOutputStream()); // generate the post-string for (int i=0; i 0) S += "&"; S += Par[i] + "=" + Val[i]; } // SEND String message=S; dos.writeBytes(message); dos.flush(); dos.close(); // RECIEVE dis = new DataInputStream(urlConn.getInputStream()); s = dis.readLine(); dis.close(); println(s); if (s != "") { // Got Some reply ret = true; } else { ret = false; } } // end of "try" catch (MalformedURLException mue) { ; } catch (IOException ioe) { ; } return ret; } // end of postNewItem() method //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SAVING THE VERTICES AS AN ASCII-FILE FOR POSSIBILITY TO IMPORT INTO A 3D-TOOL //////////////////////////////////////////////////////////////////////////////////////////////////////////////// String[] saveAsc(int c){ int k = 9; output[0] = "*3DSMAX_ASCIIEXPORT\t200"; output[1] = "*COMMENT '2Dto3D Version 1,00 - Mon Mar 07 22:34:32 2005'"; output[2] = "*GEOMOBJECT {"; output[3] = "\t*NODE_NAME '"+nodename+"'"; output[4] = "\t*MESH {"; output[5] = "\t\t*TIMEVALUE 0"; output[6] = "\t\t*MESH_NUMVERTEX "; output[7] = "\t\t*MESH_NUMFACES "; output[8] = "\t\t*MESH_VERTEX_LIST {"; for(int i=0; i -145){ pZoom -= 0.5; } } if(key == UP){ if(pY > -45){ pY -= 0.5; } } if(key == DOWN){ if(pY < 45){ pY += 0.5; } } if(key == LEFT){ if(pX > -85){ pX -= 0.5; } } if(key == RIGHT){ if(pX < 85){ pX += 0.5; } } } void keyReleased(){ if(key == 32){ spacedown = false; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CLASSES //////////////////////////////////////////////////////////////////////////////////////////////////////////////// class imgbutton{ int myX, myY, myW, myH; String myTitle,myStatus; boolean myCheck, alive, active; PImage imgon,imgoff,current; imgbutton(int x, int y, String t, String S, PImage _imgon, PImage _imgoff, boolean _alive){ this.active = false; this.myCheck = false; this.myTitle = t; this.myStatus = S; this.myX=x; this.myY=y; this.alive = _alive; this.imgon = _imgon; this.imgoff = _imgoff; this.current = imgoff; this.myW=imgoff.width; this.myH=imgoff.height; } void check(int x, int y){ if(x>=myX && x<=(myX+myW) && y>=myY && y<=(myY+myH)){ this.myCheck=true; }else{ this.myCheck=false; } } void update(String t){ gStatus = t; } void use(){ if(alive){ if (myCheck){ gStatus = myStatus; current = imgon; }else{ if(!active){ current = imgoff; }else{ current = imgon; } } image(this.current,myX,myY); } } void click(){ if(alive){ if(myCheck){ if(myTitle=="LoCRange"){ if(range>1){ range -= 1; } }else if(myTitle=="HiCRange"){ if(range<255){ range += 1; } }else if(myTitle=="LockTarget"){ lock_on_target = !lock_on_target; if(lock_on_target){ active = true; }else{ active = false; } if(lock_on_color && lock_on_target){ lock_on_color = !lock_on_color; } }else if(myTitle=="LockColor"){ lock_on_color = !lock_on_color; if(lock_on_color){ active = true; }else{ active = false; } if(lock_on_color && lock_on_target){ lock_on_target = !lock_on_target; } }else if(myTitle=="LoSmoothVal"){ if(smoothval>2){ smoothval -= 1; calculateMesh(); resetFaces(); } }else if(myTitle=="HiSmoothVal"){ if(smoothval<50){ smoothval += 1; calculateMesh(); resetFaces(); } }else if(myTitle=="SmoothVal"){ do_smooth = !do_smooth; btnSmoothVal.active = do_smooth; calculateMesh(); resetFaces(); }else if(myTitle == "SaveModel"){ if(!has_saved){ if(is_online){ // TAKES A FAIR AMOUNT OF TIME (around 3MB of data being posted) String[] parameter = {"data"}; String[] output = saveAsc(lastC); String outval = join(output,"\n"); String[] value = { outval }; boolean worked = postNewItem(parameter, value, "http://wliia.org/projects/img_to_3d/models/savemodel.php",filename); if(worked){ }else{ println("ERROR"); } }else{ println("saving.."); String[] output = saveAsc(lastC); saveStrings(filename,output); has_saved = true; } } }else if(myTitle == "SaveImage"){ if(!has_saved){ if(is_online){ // TAKES A HUGE AMOUNT OF TIME AND SOMETHINGS WRONG IN THE PHP-SCRIPT String px_string = ""; for(int i = 0; i>16)).substring(6) + (Integer.toHexString(a.pixels[i]>>8)).substring(6) + (Integer.toHexString(a.pixels[i])).substring(6); } String[] parameter = {"width","height","pixels"}; String[] value = { ""+a.width, ""+a.height, px_string }; boolean worked = postNewItem(parameter, value, "http://wliia.org/projects/img_to_3d/textures/savetexture.php",texfilename+".jpg"); if(worked){ }else{ println("ERROR"); } }else{ a.save(texfilename+".tif"); } } }else if(myTitle=="Grid"){ grid_on = !grid_on; btnGrid.active = grid_on; }else if(myTitle=="LoExtrude"){ gVal -= 0.2; }else if(myTitle=="HiExtrude"){ gVal += 0.2; }else if(myTitle=="InvExtrude"){ gVal = gVal*-1; }else if(myTitle=="NextBlend"){ if(activeBtn>0){ activeBtn -= 1; } }else if(myTitle=="PrevBlend"){ if(activeBtn1){ polys -= 1; } }else if(myTitle=="LoRes"){ if(polys<25){ polys += 1; } }else if(myTitle=="Xaxis"){ if(!active){ rotAxis = 1; active = true; btnY.active = false; btnZ.active = false; }else{ rotAxis = -1; active = false; } }else if(myTitle=="Yaxis"){ if(!active){ rotAxis = 2; active = true; btnX.active = false; btnZ.active = false; }else{ rotAxis = -1; active = false; } }else if(myTitle=="Zaxis"){ if(!active){ rotAxis = 3; active = true; btnX.active = false; btnY.active = false; }else{ rotAxis = -1; active = false; } }else if(myTitle=="NextImage"){ if(activeImage < imagename.length-1){ activeImage++; pic1 = loadImage(imagename[activeImage]); a = pic1; } }else if(myTitle=="PrevImage"){ if(activeImage > 0){ activeImage--; pic1 = loadImage(imagename[activeImage]); a = pic1; } }else if(myTitle=="NextBlendImage"){ if(activeImage2 < imagename.length-1){ activeImage2++; pic2 = loadImage(imagename[activeImage2]); } }else if(myTitle=="PrevBlendImage"){ if(activeImage2 > 0){ activeImage2--; pic2 = loadImage(imagename[activeImage2]); } } } } } } class button{ int myX, myY, myH, myB; String myTitle; boolean myCheck, hasused; button(int x, int y, int _width, int _height, String t){ myX=x; myY=y; myH=_height; myB=_width; myTitle=t; hasused = false; } void check(int x, int y){ if(x>myX-myB/2 && x<(myX+myB-myB/2) && y>myY-myH/2 && y<(myY+myH-myH/2)){ myCheck=true; }else{ myCheck=false; } } void use(){ color cl1; color cl2; if (myCheck){ cl1=color(173,157,108); cl2=color(255,255,255); }else{ cl1=color(201,204,151); cl2=color(0,0,0); } fill(cl1); rectMode(CENTER); rect (myX,myY,myB,myH); fill(cl2); text (myTitle,myX,myY+3); } void click(){ if (myCheck){ for(int j=0;j>1; } return makeColor(); } color multiply(color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ theList[i]=(theList[i]*theList[i+3])>>8; } return makeColor(); } color screen(color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ theList[i]=255 - ((255-theList[i]) * (255-theList[i+3]) >>8); } return makeColor(); } color darken(color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if(theList[i]theList[i+3]){ theList[i]=theList[i]; }else{ theList[i]=theList[i+3]; } } return makeColor(); } color difference (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ theList[i]=abs(theList[i]-theList[i+3]); } return makeColor(); } color negation (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ theList[i]=255-abs(255-theList[i]-theList[i+3]); } return makeColor(); } color exclusion (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ theList[i]=theList[i]+theList[i+3]-(theList[i]*theList[i+3]>>7); } return makeColor(); } color overlay (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if (theList[i] < 128){ theList[i]=(theList[i]*theList[i+3])>>7; }else{ theList[i]= 255 -((255-theList[i])*(255-theList[i+3])>>7); } } return makeColor(); } color hardLight (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if (theList[i+3] < 128){ theList[i]=(theList[i]*theList[i+3])>>7; }else{ theList[i]= 255 -((255-theList[i])*(255-theList[i+3])>>7); } } return makeColor(); } color dodge (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if(theList[i+3]==255){ theList[i]= 255; }else{ int res = (theList[i] << 8) / (255-theList[i+3]); if (res>255) { theList[i]= 255; } else{ theList[i]=res; } } } return makeColor(); } color burn (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if(theList[i+3]==0){ theList[i]= 0; }else{ int res = 255 - (((255-theList[i]) << 8) / theList[i+3]); if (res<0) { theList[i]= 0; } else{ theList[i]=res; } } } return makeColor(); } color reflect (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if (theList[i+3]== 255){ theList[i]= 255; }else{ int res = theList[i]*theList[i] / (255-theList[i+3]); if (res > 255){ theList[i]= 255; }else{ theList[i]=res; } } } return makeColor(); } color glow (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if (theList[i]== 255){ theList[i]= 255; }else{ int res = theList[i+3]*theList[i+3] / (255-theList[i]); if (res > 255){ theList[i]= 255; }else{ theList[i]=res; } } } return makeColor(); } color freeze (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if (theList[i+3]==0){ theList[i+3]= 0; }else{ int res =int(255-sq(255-theList[i])/theList[i+3]); if (res < 0){ theList[i]= 0; }else{ theList[i]=res; } } } return makeColor(); } color heat (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ if (theList[i]==0){ theList[i]= 0; }else{ int res =int(255-sq(255-theList[i+3])/(theList[i])); if (res < 0){ theList[i]= 0; }else{ theList[i]=res; } } } return makeColor(); } color stamp (color cl1, color cl2 ){ makeList(cl1,cl2); for (int i=0;i<3;i++){ int res = theList[i] + 2*theList[i+3] - 256; if (res < 0){ theList[i]= 0; }else if (res > 255){ theList[i]= 255; }else{ theList[i]= res; } } return makeColor(); } }