From b28583c1ff5a3d8b09bdca98ac4099b7850e28ca Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 8 Sep 2023 13:25:25 +0200 Subject: [PATCH] On the train to Wien --- src/Tupfile | 2 -- src/well_of_text.nim | 41 +++++++++++--------------- src/wells.nim | 69 ++++++++++++++++++++++++++++++-------------- well_of_text.nimble | 2 +- 4 files changed, 66 insertions(+), 48 deletions(-) diff --git a/src/Tupfile b/src/Tupfile index 4d269aa..49593a4 100644 --- a/src/Tupfile +++ b/src/Tupfile @@ -1,4 +1,2 @@ include_rules : well_of_text.nim |> !nim_bin |> {bin} -: text_spans.nim |> !nim_bin |> {bin} -: wells.nim |> !nim_bin |> {bin} diff --git a/src/well_of_text.nim b/src/well_of_text.nim index a0daed2..0be7543 100644 --- a/src/well_of_text.nim +++ b/src/well_of_text.nim @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: ☭ Emery Hemingway # SPDX-License-Identifier: Unlicense -import std/[asyncdispatch, options, os, tables] +import std/[asyncdispatch, options, os, streams, tables] import preserves, syndicate, syndicate/[capabilities] import bumpy, pixie import sdl2 @@ -59,10 +59,9 @@ func rect(img: Image): bumpy.Rect = proc newApp(length: cint): App = ## Create a new square plane of `length` pixels. result = App( - topFrame: newFrame(length shl 1, length shl 1), + well: newWell(length, length), zoomFactor: 1.0, ) - app.well = newWell(length, length) discard createWindowAndRenderer( length, length, SDL_WINDOW_RESIZABLE, @@ -88,13 +87,14 @@ proc redraw(app: App) = app.renderer.setDrawColor(0x80, 0x80, 0x80) app.renderer.clear() - let wellRect = well.Rect + let wellRect = app.well.rect if viewPort.overlaps wellRect: - for (pane, rect) in well.intersectingPanes(viewPort) + for (index, rect) in app.well.intersectingPanes(viewPort): + let texture = app.well.texture(index, app.renderer, rect.wh * app.zoomFactor) + if texture.isNil: break let - texture = pane.texture(rect.wh *­app.zoomFactor) overlap = viewPort and rect - src = rect(overlap.xy - app.rect.xy, overlap.wh) + src = rect(overlap.xy - rect.xy, overlap.wh) var dst: bumpy.Rect dst.x = (overlap.x - viewPort.x) * (sdlViewPort.w / viewPort.w) dst.y = (overlap.y - viewPort.y) * (sdlViewPort.h / viewPort.h) @@ -107,6 +107,8 @@ proc redraw(app: App) = overlap.wh * app.zoomFactor var (sdlSrc, sdlDst) = (src.toSdl, dst.toSdl) app.renderer.copy(texture, addr sdlSrc, addr sdlDst) + else: + echo "no overlap of ", viewPort, " and ", wellRect app.renderer.present() proc resize(app: App) = @@ -126,18 +128,6 @@ proc recenter(app: App) = app.zoomFactor = 1.0 app.redraw() -proc setImage(app: App; image: Image) = - app.rect = image.rect - echo "create surface of ", image.width, "x", cint image.height, " pixels" - var - dataPtr = image.data[0].addr - surface = createRGBSurfaceFrom( - dataPtr, - cint image.width, cint image.height, - cint 32, cint 4*image.width, - rmask, gmask, bmask, amask) - app.texture = createTextureFromSurface(app.renderer, surface) - proc main() = discard sdl2.init(INIT_TIMER or INIT_VIDEO or INIT_EVENTS) @@ -145,7 +135,8 @@ proc main() = let typeface = readTypeface(typefacePath) - fontTODO = newFont(typeface, 48) + font = newFont(typeface) + # TODO app.redraw() @@ -164,15 +155,17 @@ proc main() = sdlTimeout = 500 asyncPollTimeout = 500 - let streamTODO = newFileStream(stdin) + let stream = newFileStream(stdin) + # TODO var evt = sdl2.defaultEvent mousePanning: bool - lineTODO: string + line: string while true: - if readLine(streamTODO, lineTODO): - app.well.append(line, fontTODO) + if readLine(stream, line): + # TODO + app.well.append(line, font) app.redraw() # asyncdispatch.poll(0) if waitEventTimeout(evt, sdlTimeout): diff --git a/src/wells.nim b/src/wells.nim index 786fe2a..5a5abe4 100644 --- a/src/wells.nim +++ b/src/wells.nim @@ -1,10 +1,12 @@ # SPDX-FileCopyrightText: ☭ Emery Hemingway # SPDX-License-Identifier: Unlicense -import std/[deques] -import pixie +import std/[deques, streams] +import bumpy, pixie, sdl2 type + Rect = bumpy.Rect + Pane* = ref object image: pixie.Image spans: seq[Span] @@ -24,12 +26,12 @@ proc newWell*(width, height: int): Well = proc margins*(well): Vec2 = well.dimensions / 9.0 -proc bounds*(well): Vec2 = well.margin * 7.0 +proc bounds*(well): Vec2 = well.margins * 7.0 proc rect*(well): Rect = result.wh = well.dimensions -proc rectAt(well, offset:­int):­Rect = +proc rectAt(well; offset: int): Rect = if offset < well.panes.len: let n = succ offset result.w = well.dimensions.x / float(2 * n) @@ -52,14 +54,14 @@ proc append*(well; text: string; font: Font) = assert well.panes.len > 0 let span = newSpan(text, font) while true: - pane = well.panes[0] + let pane = well.panes[0] pane.spans.add(span) var - arrangement = typeset(spans, frame.bounds) + arrangement = typeset(pane.spans, well.bounds) bounds = layoutBounds arrangement - assert bounds.x <= well.boundx.x - if bounds.bounds.y <= well.bounds.y: - doAssert pane.spans.len > 1, "text does not find on a single pane" + # assert bounds.x <= well.bounds.x + if bounds.y <= well.bounds.y: + doAssert pane.spans.len > 0, "text does not find on a single pane - " & $bounds & $well.bounds pane.arrangement = arrangement break else: @@ -70,6 +72,7 @@ proc append*(well; stream: Stream; font: Font) = while readLine(stream, line): append(well, line, font) +#[ proc render*(well; index: Natural; scale: float): Image = if index < well.panes.len: let dimensions = well.dimensions * scale @@ -77,17 +80,41 @@ proc render*(well; index: Natural; scale: float): Image = result = newImage(int dimensions.x, int dimensions.y) fill(result, rgba(255, 255, 255, 255)) fillText(well.panes[index].arrangment, translate(well.margin)) +]# - -iterator intersectingPanes(well; rect:­Rect): (Pane, Rect) = +iterator intersectingPanes*(well; rect: Rect): (int, Rect) = var i = 0 - while i <­well.panes.len: - let bounds = well.boundsAt(i) - if i and 3: - let quad = Rect(0, 0, bounds.x *­2.0, bounds.y * 2.0) - if not rect.overlaps quad: - # all further panes are non-intersecting - break - if rect.overlaps bounds: - yield (well.panes[i], bounds) - inc(i) + while i < well.panes.len: + let bounds = well.rectAt(i) + if (i and 3) == 3: + let quad = rect(vec2(0,0), bounds.wh * 2.0) + if not rect.overlaps quad: + # all further panes are non-intersecting + break + if rect.overlaps bounds: + yield (i, bounds) + inc(i) + +const + amask = uint32 0xff000000 + rmask = uint32 0x000000ff + gmask = uint32 0x0000ff00 + bmask = uint32 0x00ff0000 + +proc texture*(well; index: int; renderer: RendererPtr; wh: Vec2): TexturePtr = + # TODO:­caching + if index >= well.panes.len or wh.x < 4 or wh.y < 4: return nil + let pane = well.panes[index] + let + image = newImage(wh.x.int, wh.y.int) + zoom = wh / well.dimensions + margin = wh / 9.0 + if not pane.arrangement.isNil: + image.fillText(pane.arrangement, scale(zoom) * translate(margin)) + var surface = createRGBSurfaceFrom( + image.data[0].addr, wh.x.cint, wh.y.cint, cint 32, 4 * wh.x.cint, + rmask, gmask, bmask, amask, + ) + result = createTextureFromSurface(renderer, surface) + destroy(surface) + diff --git a/well_of_text.nimble b/well_of_text.nimble index ba4d03d..14f96a6 100644 --- a/well_of_text.nimble +++ b/well_of_text.nimble @@ -2,4 +2,4 @@ bin = @["well_of_text"] license = "Unlicense" requires: "nim", "syndicate", "sdl2" srcDir = "src" -version = "20230906" +version = "20230908"