mirror of https://github.com/adamdruppe/arsd.git
Merge pull request #431 from analogjupiter/pixmappaint
Add Pixmap Paint module
This commit is contained in:
commit
82b815fdf3
|
@ -28,7 +28,7 @@ Future release, likely May 2024 or later.
|
||||||
|
|
||||||
Nothing is planned for it at this time.
|
Nothing is planned for it at this time.
|
||||||
|
|
||||||
arsd.pixmappresenter was added.
|
arsd.pixmappresenter and arsd.pixmappaint were added.
|
||||||
|
|
||||||
## 11.0
|
## 11.0
|
||||||
|
|
||||||
|
|
39
core.d
39
core.d
|
@ -189,6 +189,45 @@ version(Posix) {
|
||||||
=========================
|
=========================
|
||||||
+/
|
+/
|
||||||
|
|
||||||
|
/++
|
||||||
|
Casts value `v` to type `T`.
|
||||||
|
|
||||||
|
$(TIP
|
||||||
|
This is a helper function for readability purposes.
|
||||||
|
The idea is to make type-casting as accessible as `to()` from `std.conv`.
|
||||||
|
)
|
||||||
|
|
||||||
|
---
|
||||||
|
int i = cast(int)(foo * bar);
|
||||||
|
int i = castTo!int(foo * bar);
|
||||||
|
|
||||||
|
int j = cast(int) round(floatValue);
|
||||||
|
int j = round(floatValue).castTo!int;
|
||||||
|
|
||||||
|
int k = cast(int) floatValue + foobar;
|
||||||
|
int k = floatValue.castTo!int + foobar;
|
||||||
|
|
||||||
|
auto m = Point(
|
||||||
|
cast(int) calc(a.x, b.x),
|
||||||
|
cast(int) calc(a.y, b.y),
|
||||||
|
);
|
||||||
|
auto m = Point(
|
||||||
|
calc(a.x, b.x).castTo!int,
|
||||||
|
calc(a.y, b.y).castTo!int,
|
||||||
|
);
|
||||||
|
---
|
||||||
|
|
||||||
|
History:
|
||||||
|
Added on April 24, 2024.
|
||||||
|
Renamed from `typeCast` to `castTo` on May 24, 2024.
|
||||||
|
+/
|
||||||
|
auto ref T castTo(T, S)(auto ref S v) {
|
||||||
|
return cast(T) v;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
alias typeCast = castTo;
|
||||||
|
|
||||||
// enum stringz : const(char)* { init = null }
|
// enum stringz : const(char)* { init = null }
|
||||||
|
|
||||||
/++
|
/++
|
||||||
|
|
16
dub.json
16
dub.json
|
@ -681,13 +681,27 @@
|
||||||
"arsd-official:color_base":"*"
|
"arsd-official:color_base":"*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "pixmappaint",
|
||||||
|
"description": "2D drawing companion library of Pixmap Presenter.",
|
||||||
|
"targetType": "library",
|
||||||
|
"sourceFiles": ["pixmappaint.d"],
|
||||||
|
"dependencies": {
|
||||||
|
"arsd-official:color_base":"*",
|
||||||
|
"arsd-official:core":"*"
|
||||||
|
},
|
||||||
|
"dflags-dmd": ["-mv=arsd.pixmappaint=$PACKAGE_DIR/pixmappaint.d"],
|
||||||
|
"dflags-ldc": ["--mv=arsd.pixmappaint=$PACKAGE_DIR/pixmappaint.d"],
|
||||||
|
"dflags-gdc": ["-fmodule-file=arsd.pixmappaint=$PACKAGE_DIR/pixmappaint.d"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "pixmappresenter",
|
"name": "pixmappresenter",
|
||||||
"description": "High-level display library. Designed to blit fully-rendered frames to the screen.",
|
"description": "High-level display library. Designed to blit fully-rendered frames to the screen.",
|
||||||
"targetType": "library",
|
"targetType": "library",
|
||||||
"sourceFiles": ["pixmappresenter.d"],
|
"sourceFiles": ["pixmappresenter.d"],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"arsd-official:color_base":"*",
|
"arsd-official:core":"*",
|
||||||
|
"arsd-official:pixmappaint":"*",
|
||||||
"arsd-official:simpledisplay":"*"
|
"arsd-official:simpledisplay":"*"
|
||||||
},
|
},
|
||||||
"dflags-dmd": ["-mv=arsd.pixmappresenter=$PACKAGE_DIR/pixmappresenter.d"],
|
"dflags-dmd": ["-mv=arsd.pixmappresenter=$PACKAGE_DIR/pixmappresenter.d"],
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -87,7 +87,6 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
import arsd.pixmappresenter;
|
import arsd.pixmappresenter;
|
||||||
import arsd.simpledisplay : MouseEvent;
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Internal resolution of the images (“frames”) we will render.
|
// Internal resolution of the images (“frames”) we will render.
|
||||||
|
@ -157,8 +156,22 @@
|
||||||
+/
|
+/
|
||||||
module arsd.pixmappresenter;
|
module arsd.pixmappresenter;
|
||||||
|
|
||||||
import arsd.color;
|
import arsd.core;
|
||||||
import arsd.simpledisplay;
|
|
||||||
|
/++
|
||||||
|
While publicly importing `arsd.simpledisplay` is not actually necessary,
|
||||||
|
most real-world code would eventually import said module as well anyway.
|
||||||
|
|
||||||
|
More importantly, this public import prevents users from facing certain
|
||||||
|
symbol clashes in their code that would occur in modules importing both
|
||||||
|
`pixmappresenter` and `simpledisplay`.
|
||||||
|
For instance both of these modules happen to define different types
|
||||||
|
as `Pixmap`.
|
||||||
|
+/
|
||||||
|
public import arsd.simpledisplay;
|
||||||
|
|
||||||
|
///
|
||||||
|
public import arsd.pixmappaint;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
## TODO
|
## TODO
|
||||||
|
@ -166,9 +179,6 @@ import arsd.simpledisplay;
|
||||||
- More comprehensive documentation
|
- More comprehensive documentation
|
||||||
- Additional renderer implementations:
|
- Additional renderer implementations:
|
||||||
- a `ScreenPainter`-based renderer
|
- a `ScreenPainter`-based renderer
|
||||||
- a legacy OpenGL renderer (maybe)
|
|
||||||
- Is there something in arsd that serves a similar purpose to `Pixmap`?
|
|
||||||
- Can we convert to/from it?
|
|
||||||
- Minimum window size
|
- Minimum window size
|
||||||
- to ensure `Scaling.integer` doesn’t break “unexpectedly”
|
- to ensure `Scaling.integer` doesn’t break “unexpectedly”
|
||||||
- More control over timing
|
- More control over timing
|
||||||
|
@ -176,129 +186,14 @@ import arsd.simpledisplay;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
///
|
///
|
||||||
alias Pixel = Color;
|
alias Pixmap = arsd.pixmappaint.Pixmap;
|
||||||
|
|
||||||
///
|
|
||||||
alias ColorF = arsd.color.ColorF;
|
|
||||||
|
|
||||||
///
|
|
||||||
alias Size = arsd.color.Size;
|
|
||||||
|
|
||||||
///
|
|
||||||
alias Point = arsd.color.Point;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
alias WindowResizedCallback = void delegate(Size);
|
alias WindowResizedCallback = void delegate(Size);
|
||||||
|
|
||||||
// verify assumption(s)
|
|
||||||
static assert(Pixel.sizeof == uint.sizeof);
|
|
||||||
|
|
||||||
// is the Timer class available on this platform?
|
// is the Timer class available on this platform?
|
||||||
private enum hasTimer = is(Timer == class);
|
private enum hasTimer = is(Timer == class);
|
||||||
|
|
||||||
/// casts value `v` to type `T`
|
|
||||||
auto ref T typeCast(T, S)(auto ref S v) {
|
|
||||||
return cast(T) v;
|
|
||||||
}
|
|
||||||
|
|
||||||
@safe pure nothrow @nogc {
|
|
||||||
///
|
|
||||||
Pixel rgba(ubyte r, ubyte g, ubyte b, ubyte a = 0xFF) {
|
|
||||||
return Pixel(r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
Pixel rgb(ubyte r, ubyte g, ubyte b) {
|
|
||||||
return rgba(r, g, b, 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/++
|
|
||||||
Pixel data container
|
|
||||||
+/
|
|
||||||
struct Pixmap {
|
|
||||||
|
|
||||||
/// Pixel data
|
|
||||||
Pixel[] data;
|
|
||||||
|
|
||||||
/// Pixel per row
|
|
||||||
int width;
|
|
||||||
|
|
||||||
@safe pure nothrow:
|
|
||||||
|
|
||||||
///
|
|
||||||
this(Size size) {
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
this(Pixel[] data, int width) @nogc
|
|
||||||
in (data.length % width == 0) {
|
|
||||||
this.data = data;
|
|
||||||
this.width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// undocumented: really shouldn’t be used.
|
|
||||||
// carries the risks of `length` and `width` getting out of sync accidentally.
|
|
||||||
deprecated("Use `size` instead.")
|
|
||||||
void length(int value) {
|
|
||||||
data.length = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/++
|
|
||||||
Changes the size of the buffer
|
|
||||||
|
|
||||||
Reallocates the underlying pixel array.
|
|
||||||
+/
|
|
||||||
void size(Size value) {
|
|
||||||
data.length = value.area;
|
|
||||||
width = value.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
|
||||||
void size(int totalPixels, int width)
|
|
||||||
in (totalPixels % width == 0) {
|
|
||||||
data.length = totalPixels;
|
|
||||||
this.width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
@safe pure nothrow @nogc:
|
|
||||||
|
|
||||||
/// Height of the buffer, i.e. the number of lines
|
|
||||||
int height() inout {
|
|
||||||
if (width == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeCast!int(data.length / width);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Rectangular size of the buffer
|
|
||||||
Size size() inout {
|
|
||||||
return Size(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Length of the buffer, i.e. the number of pixels
|
|
||||||
int length() inout {
|
|
||||||
return typeCast!int(data.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/++
|
|
||||||
Number of bytes per line
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
width × Pixel.sizeof
|
|
||||||
+/
|
|
||||||
int pitch() inout {
|
|
||||||
return (width * int(Pixel.sizeof));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clears the buffer’s contents (by setting each pixel to the same color)
|
|
||||||
void clear(Pixel value) {
|
|
||||||
data[] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// viewport math
|
// viewport math
|
||||||
private @safe pure nothrow @nogc {
|
private @safe pure nothrow @nogc {
|
||||||
|
|
||||||
|
@ -341,7 +236,7 @@ private @safe pure nothrow @nogc {
|
||||||
|
|
||||||
Point offsetCenter(const Size drawing, const Size canvas) {
|
Point offsetCenter(const Size drawing, const Size canvas) {
|
||||||
auto delta = canvas.deltaPerimeter(drawing);
|
auto delta = canvas.deltaPerimeter(drawing);
|
||||||
return (typeCast!Point(delta) >> 1);
|
return (castTo!Point(delta) >> 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,8 +276,8 @@ Viewport calculateViewport(const ref PresenterConfig config) @safe pure nothrow
|
||||||
case Scaling.contain:
|
case Scaling.contain:
|
||||||
const float scaleF = karContainScalingFactorF(config.renderer.resolution, config.window.size);
|
const float scaleF = karContainScalingFactorF(config.renderer.resolution, config.window.size);
|
||||||
size = Size(
|
size = Size(
|
||||||
typeCast!int(scaleF * config.renderer.resolution.width),
|
castTo!int(scaleF * config.renderer.resolution.width),
|
||||||
typeCast!int(scaleF * config.renderer.resolution.height),
|
castTo!int(scaleF * config.renderer.resolution.height),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -400,8 +295,8 @@ Viewport calculateViewport(const ref PresenterConfig config) @safe pure nothrow
|
||||||
case Scaling.cover:
|
case Scaling.cover:
|
||||||
const float fillF = karCoverScalingFactorF(config.renderer.resolution, config.window.size);
|
const float fillF = karCoverScalingFactorF(config.renderer.resolution, config.window.size);
|
||||||
size = Size(
|
size = Size(
|
||||||
typeCast!int(fillF * config.renderer.resolution.width),
|
castTo!int(fillF * config.renderer.resolution.width),
|
||||||
typeCast!int(fillF * config.renderer.resolution.height),
|
castTo!int(fillF * config.renderer.resolution.height),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -652,7 +547,7 @@ final class OpenGl3PixmapRenderer : PixmapRenderer {
|
||||||
0, 0,
|
0, 0,
|
||||||
_poc.config.renderer.resolution.width, _poc.config.renderer.resolution.height,
|
_poc.config.renderer.resolution.width, _poc.config.renderer.resolution.height,
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
typeCast!(void*)(_poc.framebuffer.data.ptr)
|
castTo!(void*)(_poc.framebuffer.data.ptr)
|
||||||
);
|
);
|
||||||
|
|
||||||
glUseProgram(_shader.shaderProgram);
|
glUseProgram(_shader.shaderProgram);
|
||||||
|
@ -707,7 +602,7 @@ final class OpenGl3PixmapRenderer : PixmapRenderer {
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * GLfloat.sizeof, null);
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * GLfloat.sizeof, null);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * GLfloat.sizeof, typeCast!(void*)(2 * GLfloat.sizeof));
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * GLfloat.sizeof, castTo!(void*)(2 * GLfloat.sizeof));
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,7 +783,7 @@ final class OpenGl1PixmapRenderer : PixmapRenderer {
|
||||||
0, 0,
|
0, 0,
|
||||||
_poc.config.renderer.resolution.width, _poc.config.renderer.resolution.height,
|
_poc.config.renderer.resolution.width, _poc.config.renderer.resolution.height,
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
typeCast!(void*)(_poc.framebuffer.data.ptr)
|
castTo!(void*)(_poc.framebuffer.data.ptr)
|
||||||
);
|
);
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
|
Loading…
Reference in New Issue