CPU Rasters¶
The acron.raster module holds the pixel work a game does on the CPU
and that has no business in an interpreted loop: painting a HUD instrument,
baking a noise field, resampling a panorama. It is plain C++ over engine
types (Texture, PfmFile, PNMImage, PTA_float), so a C++-only
game uses it as it is, and the Python tier (acron.hud, acron.noise,
acron.hdri) is a thin layer over it: see Menus, HUDs and Text,
Procedural Content and Materials and PBR.
RasterPainterAn anti-aliased 2D painter over an RGBA8 store, for the drawing RmlUi cannot do: a minimap, a compass tape, a dial, a scope trace. Coordinates are a 2D canvas’s (y down, texel centres at +0.5, angles from +x toward +y);
fill_rect,line,lines,polyline,polygon,disc,arcandblitcompute their coverage analytically over their own bounding box and composite “over” once (linesandpolylinetake the union of their segments, so joints do not darken). The store is kept in the texture’s own layout – BGRA, bottom row first, premultiplied – soupload()is a memcpy into aTextureRAM image, skipped when nothing was drawn. Draw the card withTransparencyAttrib.M_premultiplied_alpha.ValueNoiseValue noise on exact 32-bit integer hashing:
hash2i,vnoise,fbm,ridgedand the periodicpvn, andmake_field/make_field_floatto evaluate one of them on a regular grid (a 2048-square six-octave fbm in about a tenth of a second). The results are bit-identical across machines and to the Python scalar twin inacron.noise: the source is compiled with floating-point contraction off and without fast math, so no fused multiply-add rounds differently, and it uses only IEEE-exact operations (nosinorexpfrom the C library).fbmandridgedsum at most 64 octaves, and none gives 0; a coordinate that is not finite samples 0.PanoramaRemapequirect_to_cube_faceresamples an equirectangularPfmFileonto one face of a cube map (bilinear or nearest, any channel count), in the face order and orientationTexturePool.load_cube_mapuses; headless, so an asset build needs no GPU.
Painting¶
A painter is the size of the texture it fills. Colours are straight
(not premultiplied) RGBA; the painter premultiplies as it composites.
get_pixel reads a texel back as a colour and get_data the whole store
as bytes, for tests. upload returns whether it wrote: an unchanged
painter costs nothing, and mark_dirty forces the next upload. From Python
the point lists of lines, polyline and polygon may be any flat
sequence of floats (x0, y0, x1, y1, ...).
#include "rasterPainter.h"
PT(RasterPainter) painter = new RasterPainter(256, 128);
PT(Texture) hud = new Texture("hud");
painter->clear(LColorf(0, 0, 0, 0));
painter->fill_rect(8, 8, 240, 20, LColorf(0.1, 0.2, 0.3, 0.8));
PTA_float points;
for (float v : {10.0f, 100.0f, 60.0f, 70.0f, 110.0f, 100.0f}) {
points.push_back(v);
}
painter->polyline(points, LColorf(1, 0.3, 0.2, 1), 1.5f);
painter->arc(128, 64, 30, LColorf(1, 1, 1, 1), 2.0f, 0.0f, heading);
painter->upload(hud);
card.set_texture(hud);
card.set_transparency(TransparencyAttrib::M_premultiplied_alpha);
Noise fields¶
make_field evaluates one kind of noise – K_value, K_fbm,
K_ridged or K_periodic (pvn with period) – at
(x0 + i * dx, y0 + j * dy) for every column i and row j, and returns the
values row by row, the first row at y0: doubles from make_field,
floats (ready for a Texture RAM image or a heightfield) from
make_field_float. The other arguments are the scalar functions’ own.
#include "valueNoise.h"
PTA_float height = ValueNoise::make_field_float(
ValueNoise::K_fbm, 512, 512, 0.0, 0.0, 1.0 / 64, 1.0 / 64, 7, 5);
Panoramas¶
equirect_to_cube_face takes the face index (0 to 5, in the order
TexturePool.load_cube_map reads # files) and the face size, and
returns that face as a new PfmFile with the source’s channel count;
cube_face_direction is the (unnormalised) direction a face texel looks
along, for a caller that resamples by other rules.
#include "panoramaRemap.h"
PfmFile sky;
sky.read("sky.hdr");
for (int face = 0; face < 6; ++face) {
PfmFile out = PanoramaRemap::equirect_to_cube_face(sky, face, 512);
out.write("sky_" + format_string(face) + ".pfm");
}
make_field, make_field_float and equirect_to_cube_face are
BLOCKING: they release the GIL, so a loading thread can bake while the
game runs. Every result is deterministic.