From e4b303a41477ce82b003710f0faf3e1b4f202f9d Mon Sep 17 00:00:00 2001 From: ronaldhordijk Date: Sun, 6 Feb 2005 09:14:17 +0000 Subject: [PATCH] Renderer splitup completed --- 2.02g/Source/Render.pas | 1087 ++++----------------------------- 2.02g/Source/Render32.pas | 18 +- 2.02g/Source/Render64.pas | 39 +- 2.02g/Source/RenderMM.pas | 659 ++++++++++++++++++++ 2.02g/Source/RenderThread.pas | 88 ++- 5 files changed, 883 insertions(+), 1008 deletions(-) create mode 100644 2.02g/Source/RenderMM.pas diff --git a/2.02g/Source/Render.pas b/2.02g/Source/Render.pas index 5428d08..8637990 100644 --- a/2.02g/Source/Render.pas +++ b/2.02g/Source/Render.pas @@ -50,13 +50,18 @@ type type TBaseRenderer = class private + FOnProgress: TOnProgress; procedure SetOnProgress(const Value: TOnProgress); protected FMaxMem: integer; FCompatibility: integer; FStop: boolean; - FOnProgress: TOnProgress; FCP: TControlPoint; + + procedure Progress(value: double); + + function GetSlice: integer; virtual; + function GetNrSlices: integer; virtual; public constructor Create; virtual; destructor Destroy; override; @@ -69,1029 +74,164 @@ type property OnProgress: TOnProgress read FOnProgress write SetOnProgress; - property compatibility : integer read Fcompatibility write Fcompatibility; - property MaxMem : integer read FMaxMem write FMaxMem; - + property NrSlices: integer + read GetNrSlices; + property Slice: integer + read GetSlice; end; type TRenderer = class private - Fcp: TControlPoint; - bm: TBitmap; - - oversample: int64; - filter_width: int64; - filter: array of array of extended; - - image_Width: int64; - image_Height: int64; - BucketWidth: int64; - BucketHeight: int64; - BucketSize: int64; - gutter_width: int64; - -// sample_density: double; - sample_density: extended; // mt - - Buckets: TBucketArray; - ColorMap: TColorMapArray; - accumulate: array of array of int64; - - bg: array[0..2] of extended; - vib_gam_n: int64; - vibrancy: double; - gamma: double; - - bounds: array[0..3] of extended; - size: array[0..1] of extended; - ppux, ppuy: extended; - - bUseAcculationBuffer: boolean; - bStop: boolean; + FRenderer: TBaseRenderer; FOnProgress: TOnProgress; + FCP: TControlPoint; + Fcompatibility: Integer; + FMaxMem: int64; - procedure SetOnProgress(const Value: TOnProgress); - - procedure CreateFilter; - procedure NormalizeFilter; - - procedure InitValues; - procedure InitBuffers; - procedure InitBitmap(w: int64 = 0; h: int64 = 0); - procedure ClearBuffers; - procedure ClearBuckets; - procedure CreateColorMap; - procedure CreateCamera; - - procedure FillAccumulation(Filter: double = 1); - - procedure AddPointsToBuckets(const points: TPointsArray); overload; - procedure AddPointsToBucketsAngle(const points: TPointsArray); overload; - + function GetNrSlices: integer; + function GetSlice: integer; + procedure Setcompatibility(const Value: Integer); + procedure SetMaxMem(const Value: int64); public - MaxMem: int64; - nrSlices: int64; - Slice: int64; - compatibility : integer; + constructor Create; destructor Destroy; override; procedure SetCP(CP: TControlPoint); function GetImage: TBitmap; - procedure SetPixels; - procedure CreateBM; - procedure CreateBMFromBuckets(YOffset: int64 = 0); - procedure CreateBMPrecise; + procedure Render; + procedure RenderMaxMem(MaxMem: Int64); - procedure RenderMaxMem(MaxMemory: int64 = 64); - procedure Render; overload; - procedure Render(Time: double); overload; procedure Stop; - procedure Test(var fracBlack, fracWhite, avgColor: Double); - property OnProgress: TOnProgress read FOnProgress - write SetOnProgress; + write FOnProgress; + + property Slice: integer + read GetSlice; + property NrSlices: integer + read GetNrSlices; + property MaxMem: int64 + read FMaxMem + write SetMaxMem; + property compatibility: Integer + read Fcompatibility + write Setcompatibility; end; implementation uses - Math, Sysutils; + Math, Sysutils, Render64, RenderMM; -{ TRenderer } - - -procedure TRenderer.ClearBuckets; -var - i: integer; -begin - for i := 0 to BucketSize - 1 do begin - buckets[i].Red := 0; - buckets[i].Green := 0; - buckets[i].Blue := 0; - buckets[i].Count := 0; - end; -end; - -procedure TRenderer.ClearBuffers; -var - i: integer; -begin - if bUseAcculationBuffer then - for i := 0 to BucketSize - 1 do begin - buckets[i].Red := 0; - buckets[i].Green := 0; - buckets[i].Blue := 0; - buckets[i].Count := 0; - - accumulate[i][0] := 0; - accumulate[i][1] := 0; - accumulate[i][2] := 0; - accumulate[i][3] := 0; - end - else - ClearBuckets; -end; - -procedure TRenderer.CreateBM; -var - i, j: integer; - - alpha: double; -// r,g,b: double; - ai, ri, gi, bi: int64; - bgtot: int64; - ls: double; - - ii, jj: integer; - fp: array[0..3] of double; - - Row: PLongintArray; - - vib, notvib: int64; - bgi: array[0..2] of int64; - bucketpos: int64; - filterValue: double; - filterpos: int64; -begin - vibrancy := vibrancy / vib_gam_n; - gamma := vib_gam_n / gamma; - - vib := round(vibrancy * 256.0); - notvib := 256 - vib; - - bgi[0] := round((256 * bg[0]) / vib_gam_n); - bgi[1] := round((256 * bg[1]) / vib_gam_n); - bgi[2] := round((256 * bg[2]) / vib_gam_n); - bgtot := RGB(bgi[2], bgi[1], bgi[0]); - - bucketpos := 0; - ai := 0; - ls := 0; - - for i := 0 to Image_Height - 1 do begin - if bStop then - Break; - - if assigned(FOnProgress) then - FOnProgress(i / Image_Height); - - Row := PLongintArray(bm.scanline[i]); - for j := 0 to Image_Width - 1 do begin - // todo filter - - if filter_width > 1 then begin - fp[0] := 0; - fp[1] := 0; - fp[2] := 0; - fp[3] := 0; - - for ii := 0 to filter_width - 1 do begin - for jj := 0 to filter_width - 1 do begin - filterValue := filter[ii, jj]; -// filterpos := (i * oversample + ii) * BucketWidth + j * oversample + jj; - filterpos := bucketpos + ii * BucketWidth + jj; - fp[0] := fp[0] + filterValue * accumulate[filterpos][0]; - fp[1] := fp[1] + filterValue * accumulate[filterpos][1]; - fp[2] := fp[2] + filterValue * accumulate[filterpos][2]; - fp[3] := fp[3] + filterValue * accumulate[filterpos][3]; - end; - end; - end else begin - fp[0] := accumulate[bucketpos][0]; - fp[1] := accumulate[bucketpos][1]; - fp[2] := accumulate[bucketpos][2]; - fp[3] := accumulate[bucketpos][3]; - end; - Inc(bucketpos, oversample); - - fp[0] := fp[0] / PREFILTER_WHITE; - fp[1] := fp[1] / PREFILTER_WHITE; - fp[2] := fp[2] / PREFILTER_WHITE; - fp[3] := fp[3] / PREFILTER_WHITE; - if (fp[3] > 0.0) then begin - alpha := power(fp[3], gamma); - ls := vib * alpha / fp[3]; - ai := round(alpha * 256); - if (ai < 0) then - ai := 0 - else if (ai > 256) then - ai := 256; - ai := 256 - ai; - end else begin - // no intesity so simply set the BG; - Row[j] := bgtot; - continue; - end; - - if (notvib > 0) then - ri := Round(ls * fp[0] + notvib * power(fp[0], gamma)) - else - ri := Round(ls * fp[0]); - ri := ri + (ai * bgi[0]) shr 8; - if (ri < 0) then - ri := 0 - else if (ri > 255) then - ri := 255; - - if (notvib > 0) then - gi := Round(ls * fp[1] + notvib * power(fp[1], gamma)) - else - gi := Round(ls * fp[1]); - gi := gi + (ai * bgi[1]) shr 8; - if (gi < 0) then - gi := 0 - else if (gi > 255) then - gi := 255; - - if (notvib > 0) then - bi := Round(ls * fp[2] + notvib * power(fp[2], gamma)) - else - bi := Round(ls * fp[2]); - bi := bi + (ai * bgi[2]) shr 8; - if (bi < 0) then - bi := 0 - else if (bi > 255) then - bi := 255; - - Row[j] := RGB(bi, gi, ri); - end; - - Inc(bucketpos, 2 * gutter_width); - Inc(bucketpos, (oversample - 1) * BucketWidth); - end; - bm.PixelFormat := pf24bit; -end; - -procedure TRenderer.CreateBMPrecise; -var - i, j: integer; - - alpha: double; - r, g, b: double; - ls: double; - - ii, jj: integer; - fp: array[0..3] of double; - - Row: PLongintArray; -begin - vibrancy := vibrancy / vib_gam_n; - gamma := vib_gam_n / gamma; - - bg[0] := 256 * bg[0] / vib_gam_n; - bg[1] := 256 * bg[1] / vib_gam_n; - bg[2] := 256 * bg[2] / vib_gam_n; - - for i := 0 to Image_Height - 1 do begin - if assigned(FOnProgress) then - FOnProgress(i / Image_Height); - - Row := PLongintArray(bm.scanline[i]); - - for j := 0 to Image_Width - 1 do begin - // todo filter - - fp[0] := 0; - fp[1] := 0; - fp[2] := 0; - fp[3] := 0; - for ii := 0 to filter_width - 1 do begin - for jj := 0 to filter_width - 1 do begin - fp[0] := fp[0] + filter[ii, jj] * accumulate[(i * oversample + ii) * BucketWidth + j * oversample + jj][0]; - fp[1] := fp[1] + filter[ii, jj] * accumulate[(i * oversample + ii) * BucketWidth + j * oversample + jj][1]; - fp[2] := fp[2] + filter[ii, jj] * accumulate[(i * oversample + ii) * BucketWidth + j * oversample + jj][2]; - fp[3] := fp[3] + filter[ii, jj] * accumulate[(i * oversample + ii) * BucketWidth + j * oversample + jj][3]; - end; - end; - - alpha := fp[3]; - if (alpha > 0.0) then begin - ls := vibrancy * 256.0 * power(alpha / PREFILTER_WHITE, gamma) / (alpha / PREFILTER_WHITE); - alpha := power(alpha / PREFILTER_WHITE, gamma); - if (alpha < 0.0) then - alpha := 0.0 - else if (alpha > 1.0) then - alpha := 1.0; - end else begin - ls := 0; - end; - - r := ls * fp[0] / PREFILTER_WHITE; - if (vibrancy < 1.0) then - r := r + (1.0 - vibrancy) * 256.0 * power(fp[0] / PREFILTER_WHITE, gamma); - r := r + ((1.0 - alpha) * bg[0]); - if (r < 0) then - r := 0 - else if (r > 255) then - r := 255; - - g := ls * fp[1] / PREFILTER_WHITE; - if (vibrancy < 1.0) then - g := g + (1.0 - vibrancy) * 256.0 * power(fp[1] / PREFILTER_WHITE, gamma); - g := g + ((1.0 - alpha) * bg[1]); - if (g < 0) then - g := 0 - else if (g > 255) then - g := 255; - - b := ls * fp[2] / PREFILTER_WHITE; - if (vibrancy < 1.0) then - b := b + (1.0 - vibrancy) * 256.0 * power(fp[2] / PREFILTER_WHITE, gamma); - b := b + ((1.0 - alpha) * bg[2]); - if (b < 0) then - b := 0 - else if (b > 255) then - b := 255; - - Row[j] := RGB(round(b), round(g), round(r)); - end; - end; - bm.PixelFormat := pf24bit; -end; - -procedure TRenderer.CreateCamera; -var - scale: double; - t0, t1: double; - corner0, corner1: double; - shift: int64; -begin - scale := power(2, fcp.zoom); - sample_density := fcp.sample_density * scale * scale; - ppux := fcp.pixels_per_unit * scale; - ppuy := fcp.pixels_per_unit * scale; - // todo field stuff - shift := 0; - t0 := gutter_width / (oversample * ppux); - t1 := gutter_width / (oversample * ppuy); - corner0 := fcp.center[0] - image_width / ppux / 2.0; - corner1 := fcp.center[1] - image_height / ppuy / 2.0; - bounds[0] := corner0 - t0; - bounds[1] := corner1 - t1 + shift; - bounds[2] := corner0 + image_width / ppux + t0; - bounds[3] := corner1 + image_height / ppuy + t1; //+ shift; - if abs(bounds[2] - bounds[0]) > 0.01 then - size[0] := 1.0 / (bounds[2] - bounds[0]) - else - size[0] := 1; - if abs(bounds[3] - bounds[1]) > 0.01 then - size[1] := 1.0 / (bounds[3] - bounds[1]) - else - size[1] := 1; -end; - -procedure TRenderer.CreateColorMap; -var - i: integer; -begin - for i := 0 to 255 do begin - ColorMap[i].Red := (fcp.CMap[i][0] * fcp.white_level) div 256; - ColorMap[i].Green := (fcp.CMap[i][1] * fcp.white_level) div 256; - ColorMap[i].Blue := (fcp.CMap[i][2] * fcp.white_level) div 256; -// cmap[i][3] := fcp.white_level; - end; -end; - -procedure TRenderer.CreateFilter; -var - i, j: integer; -begin - oversample := fcp.spatial_oversample; - filter_width := Round(2.0 * FILTER_CUTOFF * oversample * fcp.spatial_filter_radius); - // make sure it has same parity as oversample - if odd(filter_width + oversample) then - inc(filter_width); - - setLength(filter, filter_width, filter_width); - for i := 0 to filter_width - 1 do begin - for j := 0 to filter_width - 1 do begin - filter[i, j] := exp(-2.0 * power(((2.0 * i + 1.0) / filter_width - 1.0) * FILTER_CUTOFF, 2) * - power(((2.0 * j + 1.0) / filter_width - 1.0) * FILTER_CUTOFF, 2)); - end; - end; - Normalizefilter; -end; +{ TRenderThread } +/////////////////////////////////////////////////////////////////////////////// destructor TRenderer.Destroy; begin - if assigned(bm) then - bm.Free; + if assigned(FRenderer) then + FRenderer.Free; inherited; end; -procedure TRenderer.FillAccumulation(Filter: double); -var - k1, k2: double; - area: double; - ls: double; - i: integer; -begin - vibrancy := vibrancy + fcp.vibrancy; - gamma := gamma + fcp.gamma; - Inc(vib_gam_n); - - bg[0] := bg[0] + fcp.background[0] / 256; - bg[1] := bg[1] + fcp.background[1] / 256; - bg[2] := bg[2] + fcp.background[2] / 256; - - k1 := (Filter * fcp.Contrast * BRIGHT_ADJUST * fcp.brightness * 268 * PREFILTER_WHITE) / 256; - area := image_width * image_height / (ppux * ppuy); - k2 := (oversample * oversample * fcp.nbatches) / (fcp.Contrast * area * fcp.White_level * sample_density); - - for i := 0 to BucketWidth * BucketHeight - 1 do begin - if Buckets[i].count = 0 then - Continue; - ls := (k1 * log10(1 + Buckets[i].Count * k2)) / Buckets[i].Count; - accumulate[i, 0] := accumulate[i, 0] + Round(Buckets[i].Red * ls); - accumulate[i, 1] := accumulate[i, 1] + Round(Buckets[i].Green * ls); - accumulate[i, 2] := accumulate[i, 2] + Round(Buckets[i].Blue * ls); - accumulate[i, 3] := accumulate[i, 3] + Round(Buckets[i].Count * ls); - end; -end; - +/////////////////////////////////////////////////////////////////////////////// function TRenderer.GetImage: TBitmap; begin - Result := bm; -end; - -procedure TRenderer.InitBuffers; -begin - gutter_width := (filter_width - oversample) div 2; - BucketHeight := oversample * image_height + 2 * gutter_width; - Bucketwidth := oversample * image_width + 2 * gutter_width; - BucketSize := BucketWidth * BucketHeight; - - if high(buckets) <> (BucketSize - 1) then begin - SetLength(buckets, BucketSize); - if bUseAcculationBuffer then - SetLength(accumulate, BucketSize, 4); - end; -end; - -procedure TRenderer.InitValues; -begin - image_height := fcp.Height; - image_Width := fcp.Width; - - bUseAcculationBuffer := fcp.nbatches > 1; -// bUseAcculationBuffer := True; - - CreateFilter; - CreateCamera; - - InitBuffers; - - CreateColorMap; - - vibrancy := 0; - gamma := 0; - vib_gam_n := 0; - bg[0] := 0; - bg[1] := 0; - bg[2] := 0; -end; - -procedure TRenderer.NormalizeFilter; -var - i, j: integer; - t: double; -begin - t := 0; - for i := 0 to filter_width - 1 do - for j := 0 to filter_width - 1 do - t := t + filter[i, j]; - - for i := 0 to filter_width - 1 do - for j := 0 to filter_width - 1 do - filter[i, j] := filter[i, j] / t; -end; - -procedure TRenderer.RenderMaxMem(MaxMemory: int64); -const - Dividers: array[0..12] of integer = (1, 2, 3, 4, 5, 6, 7, 8, 10, 16, 20, 32, 64); -var - ApproxMemory: int64; - i: integer; -// height: double; - zoom_scale, center_base, center_y: double; -begin - bUseAcculationBuffer := fcp.nbatches > 1; - image_height := fcp.Height; - image_Width := fcp.Width; - oversample := fcp.spatial_oversample; - - MaxMemory := MaxMemory * 1000000 - 4 * image_height * image_width; - - if bUseAcculationBuffer then - ApproxMemory := 32 * oversample * oversample * image_height * image_width - else - ApproxMemory := 16 * oversample * oversample * image_height * image_width; - - if (MaxMemory < 0) then - Exit; - - nrSlices := 1 + ApproxMemory div MaxMemory; - - if nrSlices > Dividers[High(Dividers)] then begin - for i := High(Dividers) downto 0 do begin - if image_height <> (image_height div dividers[i]) * dividers[i] then begin - nrSlices := dividers[i]; - break; - end; - end; - end else begin - for i := 0 to High(Dividers) do begin - if image_height <> (image_height div dividers[i]) * dividers[i] then - continue; - if nrslices <= dividers[i] then begin - nrSlices := dividers[i]; - break; - end; - end; - end; - - fcp.sample_density := fcp.sample_density * nrslices; - fcp.height := fcp.height div nrslices; -// height := Fcp.Height / Fcp.pixels_per_unit; -// Slice location changed to code from Drave's flame 1.6 - mt - center_y := fcp.center[1]; - zoom_scale := power(2.0, fcp.zoom); - center_base := center_y - ((nrslices - 1) * fcp.height) / - (2 * fcp.pixels_per_unit * zoom_scale); - - InitValues; - InitBitmap(fcp.Width, NrSlices * fcp.Height); - - for i := 0 to NrSlices - 1 do begin - Slice := i; -// fcp.center[1] := center_base + Height * slice; - fcp.center[1] := center_base + fcp.height * slice / (fcp.pixels_per_unit * zoom_scale); - CreateCamera; - ClearBuffers; - SetPixels; - if bUseAcculationBuffer then begin - FillAccumulation; - CreateBM; - end else begin - CreateBMFromBuckets(Slice * fcp.height); - end; - end; - fcp.sample_density := fcp.sample_density / nrslices; - fcp.height := fcp.height * nrslices; -end; - - -procedure TRenderer.Render(Time: double); -//var -// i: integer; -begin -{ - if not Assigned(FCPS) or (FCPS.NrControlPoints = 0) then begin - if Assigned(FCP) then - Render(0); - exit; - end; - - FCP := FCPS.Cps[0]; - FCP.spatial_filter_radius := 0.4; - InitValues; - InitBitmap; - InitTemporalData; - ClearBuffers; - - for i := 0 to FCP.nbatches - 1 do begin - FCP := FCPS.GetCp(time + temporal_deltas[i]); - ClearBuckets; - CreateCamera; - CreateCMap; - SetPixelsi; - - if bUseAcculationBuffer then begin - FillAccumulation(temporal_filter[i]); - end else begin - CreateBMFromBuckets; - end; - - FCP.Free; - end; - if bUseAcculationBuffer then begin - CreateBM; - end; - - FCP := nil; - } + Result := nil; + if assigned(FRenderer) then + Result := FRenderer.GetImage; end; +/////////////////////////////////////////////////////////////////////////////// procedure TRenderer.SetCP(CP: TControlPoint); begin FCP := CP; -// FCPS := nil; -end; - -{ -procedure TRenderer.SetCPS(CPS: TControlPoints); -begin - FCPS := CPS; - FCP := nil; -end; -} - -procedure TRenderer.SetOnProgress(const Value: TOnProgress); -begin - FOnProgress := Value; -end; - - -procedure TRenderer.AddPointsToBuckets(const points: TPointsArray); -var - i: integer; - px, py: double; - bws, bhs: double; - bx, by: double; - wx, wy: double; -// R: double; -// V1, v2, v3: integer; - Bucket: PBucket; - MapColor: PColorMapColor; -begin - bws := (BucketWidth - 0.5) * size[0]; - bhs := (BucketHeight - 0.5) * size[1]; - bx := bounds[0]; - by := bounds[1]; - wx := bounds[2] - bounds[0]; - wy := bounds[3] - bounds[1]; - - for i := SUB_BATCH_SIZE - 1 downto 0 do begin - if bStop then - Exit; - - px := points[i].x - bx; - py := points[i].y - by; - - if ((px < 0) or (px > wx) or - (py < 0) or (py > wy)) then - continue; - - MapColor := @ColorMap[Round(points[i].c * 255)]; - Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth]; - - Inc(Bucket.Red, MapColor.Red); - Inc(Bucket.Green, MapColor.Green); - Inc(Bucket.Blue, MapColor.Blue); - Inc(Bucket.Count); - end; -end; - -procedure TRenderer.AddPointsToBucketsAngle(const points: TPointsArray); -var - i: integer; - px, py: double; - ca,sa: double; - nx, ny: double; - bws, bhs: double; - bx, by: double; - wx, wy: double; -// R: double; -// V1, v2, v3: integer; - Bucket: PBucket; - MapColor: PColorMapColor; -begin - - bws := (BucketWidth - 0.5) * size[0]; - bhs := (BucketHeight - 0.5) * size[1]; - bx := bounds[0]; - by := bounds[1]; - wx := bounds[2] - bounds[0]; - wy := bounds[3] - bounds[1]; - - ca := cos(FCP.FAngle); - sa := sin(FCP.FAngle); - - for i := SUB_BATCH_SIZE - 1 downto 0 do begin - if BStop then - Exit; - - px := points[i].x - FCP.Center[0]; - py := points[i].y - FCP.Center[1]; - - nx := px * ca + py * sa; - ny := -px * sa + py * ca; - - px := nx + FCP.Center[0] - bx; - py := ny + FCP.Center[1] - by; - - if ((px < 0) or (px > wx) or - (py < 0) or (py > wy)) then - continue; - - MapColor := @ColorMap[Round(points[i].c * 255)]; - Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth]; - - Inc(Bucket.Red, MapColor.Red); - Inc(Bucket.Green, MapColor.Green); - Inc(Bucket.Blue, MapColor.Blue); - Inc(Bucket.Count); - end; -end; - -procedure TRenderer.SetPixels; -var - i: integer; - nsamples: int64; - nrbatches: int64; - points: TPointsArray; -begin - SetLength(Points, SUB_BATCH_SIZE); - - nsamples := Round(sample_density * bucketSize / (oversample * oversample)); - nrbatches := Round(nsamples / (fcp.nbatches * SUB_BATCH_SIZE)); - Randomize; - - for i := 0 to nrbatches do begin - if bStop then - Exit; - - if (i and $F = 0) and assigned(FOnProgress) then - FOnProgress(i / nrbatches); - - // generate points - case Compatibility of - 0: fcp.iterate_Old(SUB_BATCH_SIZE, points); - 1: fcp.iterateXYC(SUB_BATCH_SIZE, points); - end; - - if FCP.FAngle = 0 then - AddPointsToBuckets(points) - else - AddPointsToBucketsAngle(points); - end; - - if assigned(FOnProgress) then - FOnProgress(1); -end; - -procedure TRenderer.Stop; -begin - bStop := True; -end; - -procedure TRenderer.CreateBMFromBuckets(YOffset: int64); -var - i, j: integer; - - alpha: double; -// r,g,b: double; - ai, ri, gi, bi: int64; - bgtot: int64; - ls: double; - ii, jj: integer; - fp: array[0..3] of double; - Row: PLongintArray; - vib, notvib: int64; - bgi: array[0..2] of int64; - bucketpos: int64; - filterValue: double; - filterpos: int64; - lsa: array[0..1024] of double; -var - k1, k2: double; - area: double; -begin - if fcp.gamma = 0 then - gamma := fcp.gamma - else - gamma := 1 / fcp.gamma; - vib := round(fcp.vibrancy * 256.0); - notvib := 256 - vib; - - bgi[0] := round(fcp.background[0]); - bgi[1] := round(fcp.background[1]); - bgi[2] := round(fcp.background[2]); - bgtot := RGB(bgi[2], bgi[1], bgi[0]); - - k1 := (fcp.Contrast * BRIGHT_ADJUST * fcp.brightness * 268 * PREFILTER_WHITE) / 256.0; - area := image_width * image_height / (ppux * ppuy); - k2 := (oversample * oversample) / (fcp.Contrast * area * fcp.White_level * sample_density); - - lsa[0] := 0; - for i := 1 to 1024 do begin - lsa[i] := (k1 * log10(1 + fcp.White_level * i * k2)) / (fcp.White_level * i); - end; - - if filter_width > 1 then begin - for i := 0 to BucketWidth * BucketHeight - 1 do begin - if Buckets[i].count = 0 then - Continue; - - ls := lsa[Min(1023, Buckets[i].Count)]; - - Buckets[i].Red := Round(Buckets[i].Red * ls); - Buckets[i].Green := Round(Buckets[i].Green * ls); - Buckets[i].Blue := Round(Buckets[i].Blue * ls); - Buckets[i].Count := Round(Buckets[i].Count * ls); - end; - end; - - ls := 0; - ai := 0; - bucketpos := 0; - for i := 0 to Image_Height - 1 do begin - if bStop then - Break; - - if assigned(FOnProgress) then - FOnProgress(i / Image_Height); - - Row := PLongintArray(bm.scanline[YOffset + i]); - for j := 0 to Image_Width - 1 do begin - if filter_width > 1 then begin - fp[0] := 0; - fp[1] := 0; - fp[2] := 0; - fp[3] := 0; - - for ii := 0 to filter_width - 1 do begin - for jj := 0 to filter_width - 1 do begin - filterValue := filter[ii, jj]; - filterpos := bucketpos + ii * BucketWidth + jj; - - fp[0] := fp[0] + filterValue * Buckets[filterpos].Red; - fp[1] := fp[1] + filterValue * Buckets[filterpos].Green; - fp[2] := fp[2] + filterValue * Buckets[filterpos].Blue; - fp[3] := fp[3] + filterValue * Buckets[filterpos].Count; - end; - end; - - fp[0] := fp[0] / PREFILTER_WHITE; - fp[1] := fp[1] / PREFILTER_WHITE; - fp[2] := fp[2] / PREFILTER_WHITE; - fp[3] := fcp.white_level * fp[3] / PREFILTER_WHITE; - end else begin - ls := lsa[Min(1023, Buckets[bucketpos].count)] / PREFILTER_WHITE; - - fp[0] := ls * Buckets[bucketpos].Red; - fp[1] := ls * Buckets[bucketpos].Green; - fp[2] := ls * Buckets[bucketpos].Blue; - fp[3] := ls * Buckets[bucketpos].Count * fcp.white_level; - end; - - Inc(bucketpos, oversample); - - if (fp[3] > 0.0) then begin - alpha := power(fp[3], gamma); - ls := vib * alpha / fp[3]; - ai := round(alpha * 256); - if (ai < 0) then - ai := 0 - else if (ai > 256) then - ai := 256; - ai := 256 - ai; - end else begin - // no intensity so simply set the BG; - Row[j] := bgtot; - continue; - end; - - if (notvib > 0) then - ri := Round(ls * fp[0] + notvib * power(fp[0], gamma)) - else - ri := Round(ls * fp[0]); - ri := ri + (ai * bgi[0]) shr 8; - if (ri < 0) then - ri := 0 - else if (ri > 255) then - ri := 255; - - if (notvib > 0) then - gi := Round(ls * fp[1] + notvib * power(fp[1], gamma)) - else - gi := Round(ls * fp[1]); - gi := gi + (ai * bgi[1]) shr 8; - if (gi < 0) then - gi := 0 - else if (gi > 255) then - gi := 255; - - if (notvib > 0) then - bi := Round(ls * fp[2] + notvib * power(fp[2], gamma)) - else - bi := Round(ls * fp[2]); - bi := bi + (ai * bgi[2]) shr 8; - if (bi < 0) then - bi := 0 - else if (bi > 255) then - bi := 255; - - Row[j] := RGB(bi, gi, ri); - end; - - Inc(bucketpos, 2 * gutter_width); - Inc(bucketpos, (oversample - 1) * BucketWidth); - end; - bm.PixelFormat := pf24bit; - - if assigned(FOnProgress) then - FOnProgress(1); -end; - -procedure TRenderer.InitBitmap(w, h: int64); -begin - if not Assigned(bm) then - bm := TBitmap.Create; - - bm.PixelFormat := pf32bit; - - if (w <> 0) and (h <> 0) then begin - bm.Width := w; - bm.Height := h; - end else begin - bm.Width := image_Width; - bm.Height := image_Height; - end; end; +/////////////////////////////////////////////////////////////////////////////// constructor TRenderer.Create; begin - MaxMem := 0; // mt - Slice := 0; - NrSlices := 1; -end; - -procedure TRenderer.Test(var fracBlack, fracWhite, avgColor: Double); -// Might have to take this out of class...only needs to see the bitmap; -var - x, y: integer; - Row: PLongintArray; - nrPixels: int64; - nrWhite: int64; - nrBlack: int64; - SumColor: int64; - c: int64; -begin - Render; - - nrPixels := fcp.Width * fcp.Height; - nrWhite := 0; - nrBlack := 0; - SumColor := 0; - for y := 0 to bm.Height - 1 do begin - Row := bm.ScanLine[y]; - for x := 0 to bm.Height - 1 do begin - c := (((Row[x] shr 16) and $FF) + ((Row[x] shr 8) and $FF) + (Row[x] and $FF)) div 3; - Inc(SumColor, c); - if c = 0 then Inc(nrBlack); - if c = 255 then Inc(nrWhite); - end; - end; - - fracBlack := nrBlack / nrPixels; - fracWhite := nrWhite / nrPixels; - avgColor := SumColor / nrPixels; end; +/////////////////////////////////////////////////////////////////////////////// procedure TRenderer.Render; begin -{ if not Assigned(FCP) then begin - if Assigned(FCPS) then - Render(0); - exit; - end; -} + if assigned(FRenderer) then + FRenderer.Free; - bStop := False; - - InitValues; - InitBitmap; - ClearBuffers; - SetPixels; - if bUseAcculationBuffer then begin - FillAccumulation; - CreateBM; + if MaxMem = 0 then begin + FRenderer := TRenderer64.Create; end else begin - CreateBMFromBuckets; + FRenderer := TRendererMM64.Create; + FRenderer.MaxMem := MaxMem end; + + FRenderer.SetCP(FCP); + FRenderer.compatibility := compatibility; + FRenderer.OnProgress := FOnProgress; + Frenderer.Render; end; +/////////////////////////////////////////////////////////////////////////////// +procedure TRenderer.Stop; +begin + + if assigned(FRenderer) then + FRenderer.Stop; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TRenderer.GetNrSlices: integer; +begin + if assigned(FRenderer) then + Result := FRenderer.Nrslices + else + Result := 1; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TRenderer.GetSlice: integer; +begin + if assigned(FRenderer) then + Result := FRenderer.Slice + else + Result := 1; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRenderer.Setcompatibility(const Value: Integer); +begin + Fcompatibility := Value; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRenderer.SetMaxMem(const Value: int64); +begin + FMaxMem := Value; +end; + +/////////////////////////////////////////////////////////////////////////////// + { TBaseRenderer } +/////////////////////////////////////////////////////////////////////////////// procedure TBaseRenderer.SetOnProgress(const Value: TOnProgress); begin FOnProgress := Value; end; +/////////////////////////////////////////////////////////////////////////////// constructor TBaseRenderer.Create; begin inherited Create; @@ -1099,6 +239,7 @@ begin FStop := False; end; +/////////////////////////////////////////////////////////////////////////////// procedure TBaseRenderer.SetCP(CP: TControlPoint); begin if assigned(FCP) then @@ -1107,12 +248,13 @@ begin FCP := Cp.Clone; end; +/////////////////////////////////////////////////////////////////////////////// procedure TBaseRenderer.Stop; begin FStop := True; end; - +/////////////////////////////////////////////////////////////////////////////// destructor TBaseRenderer.Destroy; begin if assigned(FCP) then @@ -1121,5 +263,32 @@ begin inherited; end; +/////////////////////////////////////////////////////////////////////////////// +function TBaseRenderer.GetNrSlices: integer; +begin + Result := 1; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TBaseRenderer.GetSlice: integer; +begin + Result := 0; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TBaseRenderer.Progress(value: double); +begin + if assigned(FOnprogress) then + FOnprogress(Value); +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRenderer.RenderMaxMem(MaxMem: Int64); +begin + FMaxMem := MaxMem; + Render; +end; + +/////////////////////////////////////////////////////////////////////////////// end. diff --git a/2.02g/Source/Render32.pas b/2.02g/Source/Render32.pas index 8bc3436..cecdc6c 100644 --- a/2.02g/Source/Render32.pas +++ b/2.02g/Source/Render32.pas @@ -358,7 +358,7 @@ end; procedure TRenderer32.SetPixels; var i: integer; - nsamples: Integer; + nsamples: Int64; nrbatches: Integer; points: TPointsArray; begin @@ -372,8 +372,8 @@ begin if FStop then Exit; - if (i and $F = 0) and assigned(FOnProgress) then - FOnProgress(i / nrbatches); + if (i and $F = 0) then + Progress(i / nrbatches); // generate points case Compatibility of @@ -387,8 +387,7 @@ begin AddPointsToBucketsAngle(points); end; - if assigned(FOnProgress) then - FOnProgress(1); + Progress(1); end; /////////////////////////////////////////////////////////////////////////////// @@ -456,8 +455,7 @@ begin if FStop then Break; - if assigned(FOnProgress) then - FOnProgress(i / Image_Height); + Progress(i / Image_Height); Row := PLongintArray(bm.scanline[YOffset + i]); for j := 0 to Image_Width - 1 do begin @@ -545,10 +543,10 @@ begin Inc(bucketpos, 2 * gutter_width); Inc(bucketpos, (oversample - 1) * BucketWidth); end; -// bm.PixelFormat := pf24bit; - if assigned(FOnProgress) then - FOnProgress(1); + bm.PixelFormat := pf24bit; + + Progress(1); end; /////////////////////////////////////////////////////////////////////////////// diff --git a/2.02g/Source/Render64.pas b/2.02g/Source/Render64.pas index 6779d99..97ff0d1 100644 --- a/2.02g/Source/Render64.pas +++ b/2.02g/Source/Render64.pas @@ -29,19 +29,19 @@ type type TColorMapColor = Record - Red : Integer; - Green: Integer; - Blue : Integer; + Red : Int64; + Green: Int64; + Blue : Int64; // Count: Integer; end; PColorMapColor = ^TColorMapColor; TColorMapArray = array[0..255] of TColorMapColor; TBucket = Record - Red : Integer; - Green: Integer; - Blue : Integer; - Count: Integer; + Red : Int64; + Green: Int64; + Blue : Int64; + Count: Int64; end; PBucket = ^TBucket; TBucketArray = array of TBucket; @@ -51,15 +51,15 @@ type private bm: TBitmap; - oversample: Integer; + oversample: Int64; filter_width: Integer; filter: array of array of extended; image_Width: Integer; image_Height: Integer; - BucketWidth: Integer; - BucketHeight: Integer; - BucketSize: Integer; + BucketWidth: Int64; + BucketHeight: Int64; + BucketSize: Int64; gutter_width: Integer; sample_density: extended; @@ -358,7 +358,7 @@ end; procedure TRenderer64.SetPixels; var i: integer; - nsamples: Integer; + nsamples: Int64; nrbatches: Integer; points: TPointsArray; begin @@ -372,8 +372,8 @@ begin if FStop then Exit; - if (i and $F = 0) and assigned(FOnProgress) then - FOnProgress(i / nrbatches); + if (i and $F = 0) then + Progress(i / nrbatches); // generate points case Compatibility of @@ -387,8 +387,7 @@ begin AddPointsToBucketsAngle(points); end; - if assigned(FOnProgress) then - FOnProgress(1); + Progress(1); end; /////////////////////////////////////////////////////////////////////////////// @@ -456,8 +455,7 @@ begin if FStop then Break; - if assigned(FOnProgress) then - FOnProgress(i / Image_Height); + Progress(i / Image_Height); Row := PLongintArray(bm.scanline[YOffset + i]); for j := 0 to Image_Width - 1 do begin @@ -539,7 +537,7 @@ begin else if (bi > 255) then bi := 255; - Row[j] := RGB(bi, gi, ri); + Row[j] := RGB(bi, gi, ri) + (ai shl 24); end; Inc(bucketpos, 2 * gutter_width); @@ -547,8 +545,7 @@ begin end; bm.PixelFormat := pf24bit; - if assigned(FOnProgress) then - FOnProgress(1); + Progress(1); end; /////////////////////////////////////////////////////////////////////////////// diff --git a/2.02g/Source/RenderMM.pas b/2.02g/Source/RenderMM.pas new file mode 100644 index 0000000..5dec8aa --- /dev/null +++ b/2.02g/Source/RenderMM.pas @@ -0,0 +1,659 @@ +{ + Flame screensaver Copyright (C) 2002 Ronald Hordijk + Apophysis Copyright (C) 2001-2004 Mark Townsend + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +} +unit RenderMM; + +interface + +uses + Windows, Graphics, + Render, Controlpoint; + +type + TOnProgress = procedure(prog: double) of object; + +type + TColorMapColor = Record + Red : Int64; + Green: Int64; + Blue : Int64; +// Count: Integer; + end; + PColorMapColor = ^TColorMapColor; + TColorMapArray = array[0..255] of TColorMapColor; + + TBucket = Record + Red : Int64; + Green: Int64; + Blue : Int64; + Count: Int64; + end; + PBucket = ^TBucket; + TBucketArray = array of TBucket; + +type + TRendererMM64 = class(TBaseRenderer) + private + bm: TBitmap; + + oversample: Integer; + filter_width: Integer; + filter: array of array of extended; + + image_Width: Integer; + image_Height: Integer; + BucketWidth: Integer; + BucketHeight: Integer; + BucketSize: Integer; + gutter_width: Integer; + + sample_density: extended; + + Buckets: TBucketArray; + ColorMap: TColorMapArray; + + bg: array[0..2] of extended; + vib_gam_n: Integer; + vibrancy: double; + gamma: double; + + bounds: array[0..3] of extended; + size: array[0..1] of extended; + ppux, ppuy: extended; + nrSlices: int64; + Slice: int64; + + procedure CreateFilter; + procedure NormalizeFilter; + + procedure InitValues; + procedure InitBuffers; + procedure InitBitmap(w: Integer = 0; h: Integer = 0); + procedure ClearBuffers; + procedure ClearBuckets; + procedure CreateColorMap; + procedure CreateCamera; + + procedure AddPointsToBuckets(const points: TPointsArray); overload; + procedure AddPointsToBucketsAngle(const points: TPointsArray); overload; + + procedure SetPixels; + procedure CreateBMFromBuckets(YOffset: Integer = 0); + + protected + function GetSlice: integer; override; + function GetNrSlices: integer; override; + + public + constructor Create; override; + destructor Destroy; override; + + function GetImage: TBitmap; override; + + procedure Render; override; + + end; + +implementation + +uses + Math, Sysutils; + +{ TRendererMM64 } + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.ClearBuckets; +var + i: integer; +begin + for i := 0 to BucketSize - 1 do begin + buckets[i].Red := 0; + buckets[i].Green := 0; + buckets[i].Blue := 0; + buckets[i].Count := 0; + end; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.ClearBuffers; +begin + ClearBuckets; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.CreateCamera; +var + scale: double; + t0, t1: double; + corner0, corner1: double; + shift: Integer; +begin + scale := power(2, fcp.zoom); + sample_density := fcp.sample_density * scale * scale; + ppux := fcp.pixels_per_unit * scale; + ppuy := fcp.pixels_per_unit * scale; + // todo field stuff + shift := 0; + t0 := gutter_width / (oversample * ppux); + t1 := gutter_width / (oversample * ppuy); + corner0 := fcp.center[0] - image_width / ppux / 2.0; + corner1 := fcp.center[1] - image_height / ppuy / 2.0; + bounds[0] := corner0 - t0; + bounds[1] := corner1 - t1 + shift; + bounds[2] := corner0 + image_width / ppux + t0; + bounds[3] := corner1 + image_height / ppuy + t1; //+ shift; + if abs(bounds[2] - bounds[0]) > 0.01 then + size[0] := 1.0 / (bounds[2] - bounds[0]) + else + size[0] := 1; + if abs(bounds[3] - bounds[1]) > 0.01 then + size[1] := 1.0 / (bounds[3] - bounds[1]) + else + size[1] := 1; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.CreateColorMap; +var + i: integer; +begin + for i := 0 to 255 do begin + ColorMap[i].Red := (fcp.CMap[i][0] * fcp.white_level) div 256; + ColorMap[i].Green := (fcp.CMap[i][1] * fcp.white_level) div 256; + ColorMap[i].Blue := (fcp.CMap[i][2] * fcp.white_level) div 256; +// cmap[i][3] := fcp.white_level; + end; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.CreateFilter; +var + i, j: integer; +begin + oversample := fcp.spatial_oversample; + filter_width := Round(2.0 * FILTER_CUTOFF * oversample * fcp.spatial_filter_radius); + // make sure it has same parity as oversample + if odd(filter_width + oversample) then + inc(filter_width); + + setLength(filter, filter_width, filter_width); + for i := 0 to filter_width - 1 do begin + for j := 0 to filter_width - 1 do begin + filter[i, j] := exp(-2.0 * power(((2.0 * i + 1.0) / filter_width - 1.0) * FILTER_CUTOFF, 2) * + power(((2.0 * j + 1.0) / filter_width - 1.0) * FILTER_CUTOFF, 2)); + end; + end; + Normalizefilter; +end; + +/////////////////////////////////////////////////////////////////////////////// +destructor TRendererMM64.Destroy; +begin + if assigned(bm) then + bm.Free; + + inherited; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TRendererMM64.GetImage: TBitmap; +begin + Result := bm; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.InitBuffers; +begin + gutter_width := (filter_width - oversample) div 2; + BucketHeight := oversample * image_height + 2 * gutter_width; + Bucketwidth := oversample * image_width + 2 * gutter_width; + BucketSize := BucketWidth * BucketHeight; + + if high(buckets) <> (BucketSize - 1) then begin + SetLength(buckets, BucketSize); + end; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.InitValues; +begin + image_height := fcp.Height; + image_Width := fcp.Width; + + CreateFilter; + CreateCamera; + + InitBuffers; + + CreateColorMap; + + vibrancy := 0; + gamma := 0; + vib_gam_n := 0; + bg[0] := 0; + bg[1] := 0; + bg[2] := 0; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.NormalizeFilter; +var + i, j: integer; + t: double; +begin + t := 0; + for i := 0 to filter_width - 1 do + for j := 0 to filter_width - 1 do + t := t + filter[i, j]; + + for i := 0 to filter_width - 1 do + for j := 0 to filter_width - 1 do + filter[i, j] := filter[i, j] / t; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.AddPointsToBuckets(const points: TPointsArray); +var + i: integer; + px, py: double; + bws, bhs: double; + bx, by: double; + wx, wy: double; +// R: double; +// V1, v2, v3: integer; + Bucket: PBucket; + MapColor: PColorMapColor; +begin + bws := (BucketWidth - 0.5) * size[0]; + bhs := (BucketHeight - 0.5) * size[1]; + bx := bounds[0]; + by := bounds[1]; + wx := bounds[2] - bounds[0]; + wy := bounds[3] - bounds[1]; + + for i := SUB_BATCH_SIZE - 1 downto 0 do begin + if FStop then + Exit; + + px := points[i].x - bx; + py := points[i].y - by; + + if ((px < 0) or (px > wx) or + (py < 0) or (py > wy)) then + continue; + + MapColor := @ColorMap[Round(points[i].c * 255)]; + Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth]; + + Inc(Bucket.Red, MapColor.Red); + Inc(Bucket.Green, MapColor.Green); + Inc(Bucket.Blue, MapColor.Blue); + Inc(Bucket.Count); + end; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.AddPointsToBucketsAngle(const points: TPointsArray); +var + i: integer; + px, py: double; + ca,sa: double; + nx, ny: double; + bws, bhs: double; + bx, by: double; + wx, wy: double; +// R: double; +// V1, v2, v3: integer; + Bucket: PBucket; + MapColor: PColorMapColor; +begin + + bws := (BucketWidth - 0.5) * size[0]; + bhs := (BucketHeight - 0.5) * size[1]; + bx := bounds[0]; + by := bounds[1]; + wx := bounds[2] - bounds[0]; + wy := bounds[3] - bounds[1]; + + ca := cos(FCP.FAngle); + sa := sin(FCP.FAngle); + + for i := SUB_BATCH_SIZE - 1 downto 0 do begin + if FStop then + Exit; + + px := points[i].x - FCP.Center[0]; + py := points[i].y - FCP.Center[1]; + + nx := px * ca + py * sa; + ny := -px * sa + py * ca; + + px := nx + FCP.Center[0] - bx; + py := ny + FCP.Center[1] - by; + + if ((px < 0) or (px > wx) or + (py < 0) or (py > wy)) then + continue; + + MapColor := @ColorMap[Round(points[i].c * 255)]; + Bucket := @buckets[Round(bws * px) + Round(bhs * py) * BucketWidth]; + + Inc(Bucket.Red, MapColor.Red); + Inc(Bucket.Green, MapColor.Green); + Inc(Bucket.Blue, MapColor.Blue); + Inc(Bucket.Count); + end; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.SetPixels; +var + i: integer; + nsamples: Int64; + nrbatches: Integer; + points: TPointsArray; +begin + SetLength(Points, SUB_BATCH_SIZE); + + nsamples := Round(sample_density * bucketSize / (oversample * oversample)); + nrbatches := Round(nsamples / (fcp.nbatches * SUB_BATCH_SIZE)); + Randomize; + + for i := 0 to nrbatches do begin + if FStop then + Exit; + + if (i and $F = 0) then + Progress(i / nrbatches); + + // generate points + case Compatibility of + 0: fcp.iterate_Old(SUB_BATCH_SIZE, points); + 1: fcp.iterateXYC(SUB_BATCH_SIZE, points); + end; + + if FCP.FAngle = 0 then + AddPointsToBuckets(points) + else + AddPointsToBucketsAngle(points); + end; + + Progress(1); +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.CreateBMFromBuckets(YOffset: Integer); +var + i, j: integer; + + alpha: double; +// r,g,b: double; + ai, ri, gi, bi: Integer; + bgtot: Integer; + ls: double; + ii, jj: integer; + fp: array[0..3] of double; + Row: PLongintArray; + vib, notvib: Integer; + bgi: array[0..2] of Integer; + bucketpos: Integer; + filterValue: double; + filterpos: Integer; + lsa: array[0..1024] of double; +var + k1, k2: double; + area: double; +begin + if fcp.gamma = 0 then + gamma := fcp.gamma + else + gamma := 1 / fcp.gamma; + vib := round(fcp.vibrancy * 256.0); + notvib := 256 - vib; + + bgi[0] := round(fcp.background[0]); + bgi[1] := round(fcp.background[1]); + bgi[2] := round(fcp.background[2]); + bgtot := RGB(bgi[2], bgi[1], bgi[0]); + + k1 := (fcp.Contrast * BRIGHT_ADJUST * fcp.brightness * 268 * PREFILTER_WHITE) / 256.0; + area := image_width * image_height / (ppux * ppuy); + k2 := (oversample * oversample) / (fcp.Contrast * area * fcp.White_level * sample_density); + + lsa[0] := 0; + for i := 1 to 1024 do begin + lsa[i] := (k1 * log10(1 + fcp.White_level * i * k2)) / (fcp.White_level * i); + end; + + if filter_width > 1 then begin + for i := 0 to BucketWidth * BucketHeight - 1 do begin + if Buckets[i].count = 0 then + Continue; + + ls := lsa[Min(1023, Buckets[i].Count)]; + + Buckets[i].Red := Round(Buckets[i].Red * ls); + Buckets[i].Green := Round(Buckets[i].Green * ls); + Buckets[i].Blue := Round(Buckets[i].Blue * ls); + Buckets[i].Count := Round(Buckets[i].Count * ls); + end; + end; + + ls := 0; + ai := 0; + bucketpos := 0; + for i := 0 to Image_Height - 1 do begin + if FStop then + Break; + + Progress(i / Image_Height); + + Row := PLongintArray(bm.scanline[YOffset + i]); + for j := 0 to Image_Width - 1 do begin + if filter_width > 1 then begin + fp[0] := 0; + fp[1] := 0; + fp[2] := 0; + fp[3] := 0; + + for ii := 0 to filter_width - 1 do begin + for jj := 0 to filter_width - 1 do begin + filterValue := filter[ii, jj]; + filterpos := bucketpos + ii * BucketWidth + jj; + + fp[0] := fp[0] + filterValue * Buckets[filterpos].Red; + fp[1] := fp[1] + filterValue * Buckets[filterpos].Green; + fp[2] := fp[2] + filterValue * Buckets[filterpos].Blue; + fp[3] := fp[3] + filterValue * Buckets[filterpos].Count; + end; + end; + + fp[0] := fp[0] / PREFILTER_WHITE; + fp[1] := fp[1] / PREFILTER_WHITE; + fp[2] := fp[2] / PREFILTER_WHITE; + fp[3] := fcp.white_level * fp[3] / PREFILTER_WHITE; + end else begin + ls := lsa[Min(1023, Buckets[bucketpos].count)] / PREFILTER_WHITE; + + fp[0] := ls * Buckets[bucketpos].Red; + fp[1] := ls * Buckets[bucketpos].Green; + fp[2] := ls * Buckets[bucketpos].Blue; + fp[3] := ls * Buckets[bucketpos].Count * fcp.white_level; + end; + + Inc(bucketpos, oversample); + + if (fp[3] > 0.0) then begin + alpha := power(fp[3], gamma); + ls := vib * alpha / fp[3]; + ai := round(alpha * 256); + if (ai < 0) then + ai := 0 + else if (ai > 256) then + ai := 256; + ai := 256 - ai; + end else begin + // no intensity so simply set the BG; + Row[j] := bgtot; + continue; + end; + + if (notvib > 0) then + ri := Round(ls * fp[0] + notvib * power(fp[0], gamma)) + else + ri := Round(ls * fp[0]); + ri := ri + (ai * bgi[0]) shr 8; + if (ri < 0) then + ri := 0 + else if (ri > 255) then + ri := 255; + + if (notvib > 0) then + gi := Round(ls * fp[1] + notvib * power(fp[1], gamma)) + else + gi := Round(ls * fp[1]); + gi := gi + (ai * bgi[1]) shr 8; + if (gi < 0) then + gi := 0 + else if (gi > 255) then + gi := 255; + + if (notvib > 0) then + bi := Round(ls * fp[2] + notvib * power(fp[2], gamma)) + else + bi := Round(ls * fp[2]); + bi := bi + (ai * bgi[2]) shr 8; + if (bi < 0) then + bi := 0 + else if (bi > 255) then + bi := 255; + + Row[j] := RGB(bi, gi, ri); + end; + + Inc(bucketpos, 2 * gutter_width); + Inc(bucketpos, (oversample - 1) * BucketWidth); + end; + + Progress(1); +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.InitBitmap(w, h: Integer); +begin + if not Assigned(bm) then + bm := TBitmap.Create; + + bm.PixelFormat := pf32bit; + + if (w <> 0) and (h <> 0) then begin + bm.Width := w; + bm.Height := h; + end else begin + bm.Width := image_Width; + bm.Height := image_Height; + end; +end; + +/////////////////////////////////////////////////////////////////////////////// +constructor TRendererMM64.Create; +begin + inherited Create; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRendererMM64.Render; +const + Dividers: array[0..15] of integer = (1, 2, 3, 4, 5, 6, 7, 8, 10, 16, 20, 32, 64, 128, 256, 512); +var + ApproxMemory, MaxMemory: int64; + i: integer; + zoom_scale, center_base, center_y: double; +begin + FStop := False; + + image_height := fcp.Height; + image_Width := fcp.Width; + oversample := fcp.spatial_oversample; + + // entered memory - imagesize + MaxMemory := FMaxMem * 1024 * 1024 - 4 * image_height * image_width; + + ApproxMemory := 32 * oversample * oversample * image_height * image_width; + + if (MaxMemory < 0) then + Exit; + + nrSlices := 1 + ApproxMemory div MaxMemory; + + if nrSlices > Dividers[High(Dividers)] then begin + for i := High(Dividers) downto 0 do begin + if image_height <> (image_height div dividers[i]) * dividers[i] then begin + nrSlices := dividers[i]; + break; + end; + end; + end else begin + for i := 0 to High(Dividers) do begin + if image_height <> (image_height div dividers[i]) * dividers[i] then + continue; + if nrslices <= dividers[i] then begin + nrSlices := dividers[i]; + break; + end; + end; + end; + + fcp.sample_density := fcp.sample_density * nrslices; + fcp.height := fcp.height div nrslices; + center_y := fcp.center[1]; + zoom_scale := power(2.0, fcp.zoom); + center_base := center_y - ((nrslices - 1) * fcp.height) / (2 * fcp.pixels_per_unit * zoom_scale); + + InitValues; + InitBitmap(fcp.Width, NrSlices * fcp.Height); + + for i := 0 to NrSlices - 1 do begin + Slice := i; + fcp.center[1] := center_base + fcp.height * slice / (fcp.pixels_per_unit * zoom_scale); + CreateCamera; + ClearBuffers; + SetPixels; + CreateBMFromBuckets(Slice * fcp.height); + end; + bm.PixelFormat := pf24bit; + + fcp.sample_density := fcp.sample_density / nrslices; + fcp.height := fcp.height * nrslices; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TRendererMM64.GetSlice: integer; +begin + Result := Slice; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TRendererMM64.GetNrSlices: integer; +begin + Result := NrSlices; +end; + +/////////////////////////////////////////////////////////////////////////////// +end. + diff --git a/2.02g/Source/RenderThread.pas b/2.02g/Source/RenderThread.pas index 9a623c8..eecc374 100644 --- a/2.02g/Source/RenderThread.pas +++ b/2.02g/Source/RenderThread.pas @@ -22,7 +22,7 @@ interface uses Classes, windows, Messages, Graphics, - controlPoint, Render, Render32, Render64; + controlPoint, Render, Render32, Render64, RenderMM; const WM_THREAD_COMPLETE = WM_APP + 5437; @@ -35,25 +35,40 @@ type FOnProgress: TOnProgress; FCP: TControlPoint; + Fcompatibility: Integer; + FMaxMem: int64; + + procedure Render; + function GetNrSlices: integer; + function GetSlice: integer; + procedure Setcompatibility(const Value: Integer); + procedure SetMaxMem(const Value: int64); public - MaxMem: int64; TargetHandle: HWND; - nrSlices: int64; - Slice: int64; - compatibility: integer; - procedure Execute; override; + constructor Create; destructor Destroy; override; procedure SetCP(CP: TControlPoint); function GetImage: TBitmap; + procedure Execute; override; - procedure Render; overload; procedure Terminate; property OnProgress: TOnProgress read FOnProgress write FOnProgress; + + property Slice: integer + read GetSlice; + property NrSlices: integer + read GetNrSlices; + property MaxMem: int64 + read FMaxMem + write SetMaxMem; + property compatibility: Integer + read Fcompatibility + write Setcompatibility; end; implementation @@ -63,7 +78,7 @@ uses { TRenderThread } - +/////////////////////////////////////////////////////////////////////////////// destructor TRenderThread.Destroy; begin if assigned(FRenderer) then @@ -72,6 +87,7 @@ begin inherited; end; +/////////////////////////////////////////////////////////////////////////////// function TRenderThread.GetImage: TBitmap; begin Result := nil; @@ -79,39 +95,43 @@ begin Result := FRenderer.GetImage; end; +/////////////////////////////////////////////////////////////////////////////// procedure TRenderThread.SetCP(CP: TControlPoint); begin FCP := CP; end; +/////////////////////////////////////////////////////////////////////////////// constructor TRenderThread.Create; begin - MaxMem := 0; // mt - Slice := 0; - NrSlices := 1; + MaxMem := 0; FreeOnTerminate := False; inherited Create(True); // Create Suspended; end; - +/////////////////////////////////////////////////////////////////////////////// procedure TRenderThread.Render; begin if assigned(FRenderer) then FRenderer.Free; - FRenderer := TRenderer64.Create; + if MaxMem = 0 then begin + FRenderer := TRenderer64.Create; + end else begin + FRenderer := TRendererMM64.Create; + FRenderer.MaxMem := MaxMem + end; + FRenderer.SetCP(FCP); FRenderer.compatibility := compatibility; FRenderer.OnProgress := FOnProgress; Frenderer.Render; end; +/////////////////////////////////////////////////////////////////////////////// procedure TRenderThread.Execute; begin -// if MaxMem = 0 then - Render; -// else -// RenderMaxMem(MaxMem); + Render; if Terminated then PostMessage(TargetHandle, WM_THREAD_TERMINATE, 0, 0) @@ -119,13 +139,45 @@ begin PostMessage(TargetHandle, WM_THREAD_COMPLETE, 0, 0); end; +/////////////////////////////////////////////////////////////////////////////// procedure TRenderThread.Terminate; begin inherited Terminate; if assigned(FRenderer) then - FRenderer.Stop; + FRenderer.Stop; end; +/////////////////////////////////////////////////////////////////////////////// +function TRenderThread.GetNrSlices: integer; +begin + if assigned(FRenderer) then + Result := FRenderer.Nrslices + else + Result := 1; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TRenderThread.GetSlice: integer; +begin + if assigned(FRenderer) then + Result := FRenderer.Slice + else + Result := 1; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRenderThread.Setcompatibility(const Value: Integer); +begin + Fcompatibility := Value; +end; + +/////////////////////////////////////////////////////////////////////////////// +procedure TRenderThread.SetMaxMem(const Value: int64); +begin + FMaxMem := Value; +end; + +/////////////////////////////////////////////////////////////////////////////// end.