Compare commits
4 Commits
5b449506cb
...
8c109a741b
Author | SHA1 | Date | |
---|---|---|---|
8c109a741b | |||
5b734c315d | |||
8170593d56 | |||
e6c943aab4 |
15
Rsconscript
15
Rsconscript
@ -2,10 +2,19 @@ configure do
|
|||||||
check_d_compiler
|
check_d_compiler
|
||||||
end
|
end
|
||||||
|
|
||||||
env do |env|
|
fart_env = env "fart" do |env|
|
||||||
env["DFLAGS"] += %w[-Werror -O2]
|
env["DFLAGS"] += %w[-Werror -O2]
|
||||||
env["D_IMPORT_PATH"] += %w[src]
|
env["D_IMPORT_PATH"] += %w[src]
|
||||||
|
|
||||||
sources = glob("src/**/*.d")
|
env["sources"] = glob("src/**/*.d")
|
||||||
env.Program("fart", sources)
|
env.Program("fart", "${sources}")
|
||||||
|
end
|
||||||
|
|
||||||
|
task "test" do
|
||||||
|
test_env = fart_env.clone "test" do |env|
|
||||||
|
env["DFLAGS"] += %w[-funittest]
|
||||||
|
env.Program("^/farttest", "${sources}")
|
||||||
|
end
|
||||||
|
test_env.process
|
||||||
|
sh test_env.expand("^/farttest")
|
||||||
end
|
end
|
||||||
|
43
src/fart/color.d
Normal file
43
src/fart/color.d
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
module fart.color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure to represent a RGBA color value.
|
||||||
|
*/
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
/** Red color component. */
|
||||||
|
double r;
|
||||||
|
|
||||||
|
/** Green color component. */
|
||||||
|
double g;
|
||||||
|
|
||||||
|
/** Blue color component. */
|
||||||
|
double b;
|
||||||
|
|
||||||
|
/** Alpha color component. */
|
||||||
|
double a;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert color to a 32-bit integer RGBA value.
|
||||||
|
*
|
||||||
|
* Each color component uses one byte.
|
||||||
|
*/
|
||||||
|
public ubyte[] rgba32() const
|
||||||
|
{
|
||||||
|
return [toubyte(r), toubyte(g), toubyte(b), toubyte(a)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale a floating point color component value to an unsigned 8-bit byte
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @param v
|
||||||
|
* Floating point color component value.
|
||||||
|
*
|
||||||
|
* @return Unsigned 8-bit byte value for the color component.
|
||||||
|
*/
|
||||||
|
private static ubyte toubyte(double v)
|
||||||
|
{
|
||||||
|
return cast(ubyte)(0xFF * v);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,7 @@
|
|||||||
|
import fart.png;
|
||||||
|
|
||||||
int main(string[] args)
|
int main(string[] args)
|
||||||
{
|
{
|
||||||
|
png_test();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
121
src/fart/png.d
Normal file
121
src/fart/png.d
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
module fart.png;
|
||||||
|
|
||||||
|
import std.zlib;
|
||||||
|
import std.math;
|
||||||
|
import std.digest;
|
||||||
|
|
||||||
|
import fart.bfile;
|
||||||
|
import fart.crc32;
|
||||||
|
import fart.hton;
|
||||||
|
|
||||||
|
private immutable ubyte[] HEADER = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
|
||||||
|
|
||||||
|
struct IHDR
|
||||||
|
{
|
||||||
|
uint width;
|
||||||
|
uint height;
|
||||||
|
ubyte bit_depth;
|
||||||
|
ubyte color_type;
|
||||||
|
ubyte compression;
|
||||||
|
ubyte filter;
|
||||||
|
ubyte interlace;
|
||||||
|
ubyte[0] end;
|
||||||
|
|
||||||
|
this(uint width, uint height)
|
||||||
|
{
|
||||||
|
this.width = htonl(width);
|
||||||
|
this.height = htonl(height);
|
||||||
|
this.bit_depth = 8;
|
||||||
|
this.color_type = 6;
|
||||||
|
this.compression = 0;
|
||||||
|
this.filter = 0;
|
||||||
|
this.interlace = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public const(void) * data()
|
||||||
|
{
|
||||||
|
return &this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public size_t data_length()
|
||||||
|
{
|
||||||
|
return end.offsetof;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IDAT
|
||||||
|
{
|
||||||
|
private const(ubyte)[] m_data;
|
||||||
|
|
||||||
|
this(ubyte[] data)
|
||||||
|
{
|
||||||
|
m_data = compress(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public const(void) * data()
|
||||||
|
{
|
||||||
|
return m_data.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public size_t data_length()
|
||||||
|
{
|
||||||
|
return m_data.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IEND
|
||||||
|
{
|
||||||
|
public const(void) * data()
|
||||||
|
{
|
||||||
|
return &this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public size_t data_length()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void write_chunk(Chunk)(BFile file, string chunk_type, Chunk chunk)
|
||||||
|
{
|
||||||
|
size_t chunk_data_length = chunk.data_length();
|
||||||
|
uint chunk_length_be32 = htonl(cast(uint)chunk_data_length);
|
||||||
|
file.writeObject(chunk_length_be32);
|
||||||
|
file.write(chunk_type);
|
||||||
|
const(ubyte)[] chunk_data = (cast(const(ubyte) *)chunk.data())[0..chunk_data_length];
|
||||||
|
file.write(chunk_data);
|
||||||
|
uint crc_be32 = htonl(crc32(chunk_type, chunk_data));
|
||||||
|
file.writeObject(crc_be32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write_png(string filename, uint width, uint height, ubyte[] data)
|
||||||
|
{
|
||||||
|
BFile file = BFile(filename);
|
||||||
|
file.write(HEADER);
|
||||||
|
IHDR ihdr = IHDR(width, height);
|
||||||
|
write_chunk(file, "IHDR", ihdr);
|
||||||
|
IDAT idat = IDAT(data);
|
||||||
|
write_chunk(file, "IDAT", idat);
|
||||||
|
IEND iend;
|
||||||
|
write_chunk(file, "IEND", iend);
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void png_test()
|
||||||
|
{
|
||||||
|
ubyte[] pixel_data = [];
|
||||||
|
for (size_t y = 0; y < 500; y++)
|
||||||
|
{
|
||||||
|
/* Filter method 0 (None) */
|
||||||
|
pixel_data ~= [0];
|
||||||
|
for (size_t x = 0; x < 500; x++)
|
||||||
|
{
|
||||||
|
ubyte r = cast(ubyte)(x / 2);
|
||||||
|
ubyte g = 0x80;
|
||||||
|
ubyte b = cast(ubyte)((500 - y) / 2);
|
||||||
|
ubyte a = cast(ubyte)((abs(cast(int)x - 250) + abs(cast(int)y - 250)) / 2);
|
||||||
|
pixel_data ~= [r, g, b, a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_png("out.png", 500, 500, pixel_data);
|
||||||
|
}
|
190
src/fart/vector.d
Normal file
190
src/fart/vector.d
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
module fart.vector;
|
||||||
|
|
||||||
|
import std.math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure to represent a 3-dimensional vector.
|
||||||
|
*/
|
||||||
|
struct Vector
|
||||||
|
{
|
||||||
|
/** Vector X coordinate. */
|
||||||
|
double x;
|
||||||
|
|
||||||
|
/** Vector Y coordinate. */
|
||||||
|
double y;
|
||||||
|
|
||||||
|
/** Vector Z coordinate. */
|
||||||
|
double z;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the cross product of two vectors.
|
||||||
|
*/
|
||||||
|
public Vector cross()(auto ref const Vector other) const
|
||||||
|
{
|
||||||
|
return Vector(y * other.z - z * other.y,
|
||||||
|
z * other.x - x * other.z,
|
||||||
|
x * other.y - y * other.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the dot product of two vectors.
|
||||||
|
*/
|
||||||
|
public double dot()(auto ref const Vector other) const
|
||||||
|
{
|
||||||
|
return x * other.x + y * other.y + z * other.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the magnitude of the vector.
|
||||||
|
*/
|
||||||
|
public double mag() const
|
||||||
|
{
|
||||||
|
return sqrt(mag2());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the squared magnitude of the vector.
|
||||||
|
*/
|
||||||
|
public double mag2() const
|
||||||
|
{
|
||||||
|
return x * x + y * y + z * z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize the vector to have unit length.
|
||||||
|
*/
|
||||||
|
public ref Vector normalize()
|
||||||
|
{
|
||||||
|
double mag = mag();
|
||||||
|
x /= mag;
|
||||||
|
y /= mag;
|
||||||
|
z /= mag;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a normalized vector in the same direction as this.
|
||||||
|
*/
|
||||||
|
public Vector normalized() const
|
||||||
|
{
|
||||||
|
double mag = mag();
|
||||||
|
return Vector(x / mag, y / mag, z / mag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project the vector onto a target vector.
|
||||||
|
*/
|
||||||
|
public Vector proj()(auto ref const Vector other) const
|
||||||
|
{
|
||||||
|
Vector on = other.normalized();
|
||||||
|
return on * dot(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two vectors.
|
||||||
|
*/
|
||||||
|
public Vector opBinary(string op : "+")(auto ref const Vector other) const
|
||||||
|
{
|
||||||
|
return Vector(x + other.x, y + other.y, z + other.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two vectors and assign to self.
|
||||||
|
*/
|
||||||
|
public Vector opOpAssign(string op : "+")(auto ref const Vector other)
|
||||||
|
{
|
||||||
|
x += other.x;
|
||||||
|
y += other.y;
|
||||||
|
z += other.z;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negate a vector.
|
||||||
|
*/
|
||||||
|
public Vector opUnary(string op : "-")() const
|
||||||
|
{
|
||||||
|
return Vector(-x, -y, -z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract two vectors.
|
||||||
|
*/
|
||||||
|
public Vector opBinary(string op : "-")(auto ref const Vector other) const
|
||||||
|
{
|
||||||
|
return Vector(x - other.x, y - other.y, z - other.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract two vectors and assign to self.
|
||||||
|
*/
|
||||||
|
public Vector opOpAssign(string op : "-")(auto ref const Vector other)
|
||||||
|
{
|
||||||
|
x -= other.x;
|
||||||
|
y -= other.y;
|
||||||
|
z -= other.z;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale a vector.
|
||||||
|
*/
|
||||||
|
public Vector opBinary(string op : "*")(double m) const
|
||||||
|
{
|
||||||
|
return Vector(x * m, y * m, z * m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale a vector.
|
||||||
|
*/
|
||||||
|
public Vector opBinaryRight(string op : "*")(double m) const
|
||||||
|
{
|
||||||
|
return Vector(x * m, y * m, z * m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the cross product of two vectors.
|
||||||
|
*/
|
||||||
|
public Vector opBinary(string op : "*")(auto ref const Vector other) const
|
||||||
|
{
|
||||||
|
return cross(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static immutable Vector X = Vector(1.0, 0.0, 0.0);
|
||||||
|
public static immutable Vector Y = Vector(0.0, 1.0, 0.0);
|
||||||
|
public static immutable Vector Z = Vector(0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
Vector v = Vector(1, 2, 3);
|
||||||
|
const Vector w = Vector(0, 4, 5);
|
||||||
|
|
||||||
|
Vector v_times_2 = v * 2;
|
||||||
|
assert(v_times_2.x == 2);
|
||||||
|
assert(v_times_2.y == 4);
|
||||||
|
assert(v_times_2.z == 6);
|
||||||
|
|
||||||
|
Vector v_plus_w = v + w;
|
||||||
|
assert(v_plus_w == Vector(1, 6, 8));
|
||||||
|
|
||||||
|
Vector v_minus_w = v - w;
|
||||||
|
assert(v_minus_w == Vector(1, -2, -2));
|
||||||
|
|
||||||
|
assert(v_minus_w.mag2() == 9.0);
|
||||||
|
assert(v_minus_w.mag() == 3.0);
|
||||||
|
|
||||||
|
v += v_minus_w;
|
||||||
|
assert(v == 2 * Vector.X + 0 * Vector.Y + Vector.Z);
|
||||||
|
|
||||||
|
assert(Vector.X * Vector.Y == Vector.Z);
|
||||||
|
assert(Vector.Y * Vector.Z == Vector.X);
|
||||||
|
assert(Vector.Z * Vector.X == Vector.Y);
|
||||||
|
assert(Vector.Y * Vector.X == -Vector.Z);
|
||||||
|
assert(Vector.Z * Vector.Y == -Vector.X);
|
||||||
|
assert(Vector.X * Vector.Z == -Vector.Y);
|
||||||
|
|
||||||
|
assert(w.proj(Vector.X) == Vector(0, 0, 0));
|
||||||
|
assert(w.proj(Vector.Y) == Vector(0, 4, 0));
|
||||||
|
assert(w.proj(Vector.Z) == Vector(0, 0, 5));
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user