commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
539
include/engine/gpu/gpu_spline.cpp
Normal file
539
include/engine/gpu/gpu_spline.cpp
Normal file
@ -0,0 +1,539 @@
|
||||
#include "gpu/gpu_types.h"
|
||||
#include "gpu/gpu_renderer.h"
|
||||
#include "log/log.h"
|
||||
#include "math/nmath.h"
|
||||
#include "memory/memory.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::GPU;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Render::Texture *Renderer::CreateRenderTexture(
|
||||
const char *name,
|
||||
uint width,
|
||||
uint height,
|
||||
Render::Texture::Format format,
|
||||
Render::Texture::AA aa
|
||||
)
|
||||
{
|
||||
__NTRACE("CreateRenderTexture")
|
||||
// __LOG_W__ << "CreateRenderTexture: name=" << name << ", size=" << width << "x" << height << "\n";
|
||||
|
||||
Render::Texture *tex = NewTexture(name);
|
||||
if (!tex)
|
||||
{
|
||||
__LOG_E__ << "CreateRenderTexture: NewTexture failed!\n";
|
||||
return nullptr;
|
||||
}
|
||||
// __LOG_W__ << "CreateRenderTexture: NewTexture succeeded, tex ptr=" << (void*)tex << "\n";
|
||||
|
||||
const Render::Texture::Usage usage =
|
||||
Render::Texture::Usage(
|
||||
Render::Texture::IsRenderTarget |
|
||||
Render::Texture::IsShaderResource
|
||||
);
|
||||
|
||||
// __LOG_W__ << "CreateRenderTexture: Calling tex->Create with format=" << format << ", aa=" << aa << "\n";
|
||||
if (tex->Create(nullptr, width, height, format, aa, usage))
|
||||
{
|
||||
// __LOG_W__ << "CreateRenderTexture: Success! Returning texture.\n";
|
||||
return tex;
|
||||
}
|
||||
|
||||
__LOG_E__ << "CreateRenderTexture: tex->Create failed!\n";
|
||||
tex->Free();
|
||||
return nullptr;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Renderer::ClearTexture(Render::Texture *target, const Color &clear_color)
|
||||
{
|
||||
__NTRACE("ClearTexture")
|
||||
// __LOG_W__ << "ClearTexture: Clearing target texture with color (" << clear_color.x << ", " << clear_color.y << ", " << clear_color.z << ", " << clear_color.w << ")\n";
|
||||
|
||||
if (!target)
|
||||
{
|
||||
__LOG_E__ << "ClearTexture: target is null!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
const uint tex_w = target->GetWidth();
|
||||
const uint tex_h = target->GetHeight();
|
||||
|
||||
// Use DrawSplineToTexture with clear_target=true to clear the texture
|
||||
// This is a workaround since Blit() doesn't work on RenderTarget textures
|
||||
// __LOG_W__ << "ClearTexture: Using DrawSplineToTexture method with clear...\n";
|
||||
|
||||
// Create a dummy 2-point array (not used since we're clearing)
|
||||
Array<Vector2> dummy_points;
|
||||
dummy_points.Allocate(2);
|
||||
dummy_points[0] = Vector2(0, 0);
|
||||
dummy_points[1] = Vector2(1, 1);
|
||||
|
||||
// Call DrawSplineToTexture with clear_target=true and zero width (no drawing)
|
||||
// This will fill the buffer with the clear color
|
||||
const uint pitch = tex_w * 4;
|
||||
const size_t buffer_size = pitch * tex_h;
|
||||
unsigned char *pixels = new unsigned char[buffer_size];
|
||||
|
||||
// Convert color to 8-bit RGBA
|
||||
const auto r = (unsigned char)(clear_color.x * 255.0f);
|
||||
const auto g = (unsigned char)(clear_color.y * 255.0f);
|
||||
const auto b = (unsigned char)(clear_color.z * 255.0f);
|
||||
const auto a = (unsigned char)(clear_color.w * 255.0f);
|
||||
|
||||
// __LOG_W__ << "ClearTexture: Filling buffer with RGBA(" << (int)r << ", " << (int)g << ", " << (int)b << ", " << (int)a << ")...\n";
|
||||
|
||||
// Fill with clear color (ABGR format)
|
||||
unsigned int pixel_value = (a << 24) | (b << 16) | (g << 8) | r;
|
||||
unsigned int *pixel_buffer = (unsigned int *)pixels;
|
||||
for (uint i = 0; i < tex_w * tex_h; ++i)
|
||||
{
|
||||
pixel_buffer[i] = pixel_value;
|
||||
}
|
||||
|
||||
// __LOG_W__ << "ClearTexture: Uploading via Blit...\n";
|
||||
target->Blit((const char *)pixels, tex_w, tex_h, 0, 0, Render::Texture::FormatRGBA8);
|
||||
|
||||
delete[] pixels;
|
||||
|
||||
// __LOG_W__ << "ClearTexture: Complete!\n";
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Renderer::BlitTextureToTexture(
|
||||
Render::Texture *src,
|
||||
Render::Texture *dst,
|
||||
const fRect *src_rect,
|
||||
const fRect *dst_rect
|
||||
)
|
||||
{
|
||||
__NTRACE("BlitTextureToTexture")
|
||||
|
||||
if (!src || !dst)
|
||||
return;
|
||||
|
||||
// Default rectangles (full texture)
|
||||
const fRect src_r = src_rect ? *src_rect : fRect(0, 0, 1, 1);
|
||||
const fRect dst_r = dst_rect ? *dst_rect : fRect(0, 0, 1, 1);
|
||||
|
||||
// Save current state
|
||||
const fRect old_viewport = viewport;
|
||||
|
||||
// Setup FBO for destination
|
||||
fx_fbo->SetColorTexture(dst);
|
||||
fx_fbo->SetDepthTexture(nullptr);
|
||||
SetCurrentFBO(fx_fbo);
|
||||
SetViewport(fRect(0, 0, (float)dst->GetWidth(), (float)dst->GetHeight()));
|
||||
|
||||
// Use existing RenderFullscreenQuad infrastructure
|
||||
RenderFullscreenQuad(*single_texture_program, src_r, dst_r, src);
|
||||
|
||||
// Restore state
|
||||
SetCurrentFBO(nullptr);
|
||||
SetViewport(old_viewport);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Vector2 Renderer::CatmullRomInterpolate(
|
||||
const Vector2 &p0,
|
||||
const Vector2 &p1,
|
||||
const Vector2 &p2,
|
||||
const Vector2 &p3,
|
||||
float t
|
||||
) const
|
||||
{
|
||||
// Catmull-Rom spline with tau = 0.5
|
||||
const float t2 = t * t;
|
||||
const float t3 = t2 * t;
|
||||
|
||||
// Manual calculation for Vector2
|
||||
Vector2 result;
|
||||
result.x = 0.5f * (
|
||||
(2.0f * p1.x) +
|
||||
(-p0.x + p2.x) * t +
|
||||
(2.0f * p0.x - 5.0f * p1.x + 4.0f * p2.x - p3.x) * t2 +
|
||||
(-p0.x + 3.0f * p1.x - 3.0f * p2.x + p3.x) * t3
|
||||
);
|
||||
result.y = 0.5f * (
|
||||
(2.0f * p1.y) +
|
||||
(-p0.y + p2.y) * t +
|
||||
(2.0f * p0.y - 5.0f * p1.y + 4.0f * p2.y - p3.y) * t2 +
|
||||
(-p0.y + 3.0f * p1.y - 3.0f * p2.y + p3.y) * t3
|
||||
);
|
||||
return result;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Renderer::TessellateSplineRibbon(
|
||||
const Array<Vector2> &control_points,
|
||||
float width_normalized,
|
||||
const Color &color,
|
||||
int samples_per_segment,
|
||||
bool soft_edge,
|
||||
SplineRibbon &out_ribbon
|
||||
)
|
||||
{
|
||||
__NTRACE("TessellateSplineRibbon")
|
||||
|
||||
const int num_control = control_points.GetCount();
|
||||
if (num_control < 2)
|
||||
return;
|
||||
|
||||
// For Catmull-Rom: we have num_control-1 segments
|
||||
const int num_segments = num_control - 1;
|
||||
if (num_segments < 1)
|
||||
return;
|
||||
|
||||
// Allocate arrays for sampled points
|
||||
const int total_samples = num_segments * samples_per_segment + 1;
|
||||
Array<Vector2> samples;
|
||||
Array<Vector2> tangents;
|
||||
samples.Allocate(total_samples);
|
||||
tangents.Allocate(total_samples);
|
||||
|
||||
// Sample the spline using Catmull-Rom interpolation
|
||||
int sample_idx = 0;
|
||||
for (int seg = 0; seg < num_segments; seg++)
|
||||
{
|
||||
// Get 4 control points (with duplication at boundaries)
|
||||
Vector2 p0 = (seg > 0) ? control_points[seg - 1] : control_points[seg];
|
||||
Vector2 p1 = control_points[seg];
|
||||
Vector2 p2 = control_points[seg + 1];
|
||||
Vector2 p3 = (seg < num_segments - 1) ? control_points[seg + 2] : control_points[seg + 1];
|
||||
|
||||
for (int s = 0; s < samples_per_segment; s++)
|
||||
{
|
||||
const float t = (float)s / (float)samples_per_segment;
|
||||
samples[sample_idx] = CatmullRomInterpolate(p0, p1, p2, p3, t);
|
||||
|
||||
// Compute tangent (derivative approximation)
|
||||
const float dt = 0.01f;
|
||||
const float t_next = (t + dt > 1.0f) ? 1.0f : t + dt;
|
||||
Vector2 p_next = CatmullRomInterpolate(p0, p1, p2, p3, t_next);
|
||||
Vector2 diff = p_next - samples[sample_idx];
|
||||
tangents[sample_idx] = diff.Normalized();
|
||||
|
||||
sample_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add final point
|
||||
samples[total_samples - 1] = control_points[num_control - 1];
|
||||
tangents[total_samples - 1] = tangents[total_samples - 2]; // Reuse last tangent
|
||||
|
||||
// Build ribbon geometry
|
||||
out_ribbon.positions.Allocate(total_samples * 2);
|
||||
out_ribbon.colors.Allocate(total_samples * 2);
|
||||
|
||||
for (int i = 0; i < total_samples; i++)
|
||||
{
|
||||
const Vector2 pos = samples[i];
|
||||
const Vector2 tangent = tangents[i];
|
||||
|
||||
// Perpendicular normal (2D rotation by 90 degrees)
|
||||
Vector2 normal(-tangent.y, tangent.x);
|
||||
|
||||
// Convert from normalized [0..1] texture space to clip space [-1..1]
|
||||
const float x_clip = pos.x * 2.0f - 1.0f;
|
||||
const float y_clip = 1.0f - pos.y * 2.0f; // Flip Y (texture origin top-left)
|
||||
|
||||
// Offset in clip space
|
||||
const Vector2 offset = normal * width_normalized;
|
||||
|
||||
// Left and right vertices
|
||||
out_ribbon.positions[i * 2 + 0] = Vector4(
|
||||
x_clip - offset.x,
|
||||
y_clip - offset.y,
|
||||
0.0f,
|
||||
1.0f
|
||||
);
|
||||
out_ribbon.positions[i * 2 + 1] = Vector4(
|
||||
x_clip + offset.x,
|
||||
y_clip + offset.y,
|
||||
0.0f,
|
||||
1.0f
|
||||
);
|
||||
|
||||
// Colors with soft edge via alpha gradient
|
||||
if (soft_edge)
|
||||
{
|
||||
// Apply alpha gradient on outer edges (30% opacity) vs center (full opacity)
|
||||
// But since we're using a ribbon with 2 vertices per sample, both get same alpha
|
||||
// To get true soft edge, we'd need a center vertex too, but for now just use the color as-is
|
||||
// TODO: Implement true soft edge with centerline vertex if needed
|
||||
out_ribbon.colors[i * 2 + 0] = color;
|
||||
out_ribbon.colors[i * 2 + 1] = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_ribbon.colors[i * 2 + 0] = color;
|
||||
out_ribbon.colors[i * 2 + 1] = color;
|
||||
}
|
||||
}
|
||||
|
||||
// Build indices (triangle list)
|
||||
const int num_quads = total_samples - 1;
|
||||
out_ribbon.indices.Allocate(num_quads * 6);
|
||||
|
||||
for (int i = 0; i < num_quads; i++)
|
||||
{
|
||||
const ushort i0 = (ushort)(i * 2);
|
||||
const ushort i1 = (ushort)(i * 2 + 1);
|
||||
const ushort i2 = (ushort)((i + 1) * 2);
|
||||
const ushort i3 = (ushort)((i + 1) * 2 + 1);
|
||||
|
||||
// Triangle 1
|
||||
out_ribbon.indices[i * 6 + 0] = i0;
|
||||
out_ribbon.indices[i * 6 + 1] = i2;
|
||||
out_ribbon.indices[i * 6 + 2] = i1;
|
||||
|
||||
// Triangle 2
|
||||
out_ribbon.indices[i * 6 + 3] = i1;
|
||||
out_ribbon.indices[i * 6 + 4] = i2;
|
||||
out_ribbon.indices[i * 6 + 5] = i3;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper: Draw a simple line to texture pixel data (Bresenham-like)
|
||||
static void DrawLineToPixels(unsigned char *pixels, uint width, uint height, uint pitch,
|
||||
int x0, int y0, int x1, int y1,
|
||||
unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
const int dx = abs(x1 - x0);
|
||||
const int dy = abs(y1 - y0);
|
||||
const int sx = (x0 < x1) ? 1 : -1;
|
||||
const int sy = (y0 < y1) ? 1 : -1;
|
||||
int err = dx - dy;
|
||||
|
||||
int x = x0, y = y0;
|
||||
while (true)
|
||||
{
|
||||
if (x >= 0 && x < (int)width && y >= 0 && y < (int)height)
|
||||
{
|
||||
int *pixel = (int*)(pixels + y * pitch + x * 4);
|
||||
|
||||
// Read destination pixel components (packed as in existing code: ABGR)
|
||||
const unsigned int dst = *pixel;
|
||||
const unsigned char dst_r = (unsigned char)(dst & 0xFF);
|
||||
const unsigned char dst_g = (unsigned char)((dst >> 8) & 0xFF);
|
||||
const unsigned char dst_b = (unsigned char)((dst >> 16) & 0xFF);
|
||||
const unsigned char dst_a = (unsigned char)((dst >> 24) & 0xFF);
|
||||
|
||||
// Source alpha (0..1)
|
||||
const float src_af = (float)a / 255.0f;
|
||||
const float inv = 1.0f - src_af;
|
||||
|
||||
// Standard 'over' compositing: out = src*src_a + dst*(1-src_a)
|
||||
const unsigned char out_r = (unsigned char)(r * src_af + dst_r * inv + 0.5f);
|
||||
const unsigned char out_g = (unsigned char)(g * src_af + dst_g * inv + 0.5f);
|
||||
const unsigned char out_b = (unsigned char)(b * src_af + dst_b * inv + 0.5f);
|
||||
const unsigned char out_a = (unsigned char)(a + dst_a * inv + 0.5f);
|
||||
|
||||
*pixel = (out_a << 24) | (out_b << 16) | (out_g << 8) | out_r; // ABGR packing (kept as original)
|
||||
}
|
||||
|
||||
if (x == x1 && y == y1) break;
|
||||
|
||||
const int e2 = 2 * err;
|
||||
if (e2 > -dy) { err -= dy; x += sx; }
|
||||
if (e2 < dx) { err += dx; y += sy; }
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::DrawSplineToTexture(
|
||||
Render::Texture *target,
|
||||
const Array<Vector2> &control_points,
|
||||
float width_pixels,
|
||||
const Color &color,
|
||||
int samples_per_segment,
|
||||
bool clear_target,
|
||||
bool soft_edge,
|
||||
const Color *border_color,
|
||||
float border_width,
|
||||
float margin
|
||||
)
|
||||
{
|
||||
__NTRACE("DrawSplineToTexture")
|
||||
// __LOG_W__ << "Drawing spline to texture (CPU-based method)...\n";
|
||||
|
||||
if (!target) {
|
||||
__LOG_E__ << "DrawSplineToTexture: target texture is null!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (control_points.GetCount() < 2) {
|
||||
__LOG_E__ << "DrawSplineToTexture: not enough control points!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
const uint tex_w = target->GetWidth();
|
||||
const uint tex_h = target->GetHeight();
|
||||
// __LOG_W__ << "Target texture size: " << tex_w << "x" << tex_h << "\n";
|
||||
|
||||
// Convert color to 8-bit RGBA
|
||||
const auto r = (unsigned char)(color.x * 255.0f);
|
||||
const auto g = (unsigned char)(color.y * 255.0f);
|
||||
const auto b = (unsigned char)(color.z * 255.0f);
|
||||
const auto a = (unsigned char)(color.w * 255.0f);
|
||||
|
||||
// __LOG_W__ << "Color: R=" << (int)r << " G=" << (int)g << " B=" << (int)b << " A=" << (int)a << "\n";
|
||||
|
||||
// Convert border color if provided
|
||||
unsigned char border_r = 0, border_g = 0, border_b = 0, border_a = 0;
|
||||
if (border_color && border_width > 0.0f) {
|
||||
border_r = (unsigned char)(border_color->x * 255.0f);
|
||||
border_g = (unsigned char)(border_color->y * 255.0f);
|
||||
border_b = (unsigned char)(border_color->z * 255.0f);
|
||||
border_a = (unsigned char)(border_color->w * 255.0f);
|
||||
// __LOG_W__ << "Border Color: R=" << (int)border_r << " G=" << (int)border_g << " B=" << (int)border_b << " A=" << (int)border_a << " Width=" << border_width << "\n";
|
||||
}
|
||||
|
||||
const int num_control = control_points.GetCount();
|
||||
const int num_segments = num_control - 1;
|
||||
|
||||
// Adjust control points with margin to avoid clipping
|
||||
Array<Vector2> adjusted_points;
|
||||
adjusted_points.Allocate(num_control);
|
||||
|
||||
if (margin > 0.0f) {
|
||||
// __LOG_W__ << "Applying margin: " << margin << "\n";
|
||||
|
||||
// Calculate the margin in normalized coordinates [0..1]
|
||||
const float margin_x = margin / (float)tex_w;
|
||||
const float margin_y = margin / (float)tex_h;
|
||||
|
||||
// Scale and offset control points to fit within margin bounds
|
||||
float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f;
|
||||
for (int i = 0; i < num_control; i++) {
|
||||
if (control_points[i].x < min_x) min_x = control_points[i].x;
|
||||
if (control_points[i].x > max_x) max_x = control_points[i].x;
|
||||
if (control_points[i].y < min_y) min_y = control_points[i].y;
|
||||
if (control_points[i].y > max_y) max_y = control_points[i].y;
|
||||
}
|
||||
|
||||
const float range_x = max_x - min_x;
|
||||
const float range_y = max_y - min_y;
|
||||
const float scale_x = (range_x > 0.0f) ? (1.0f - 2.0f * margin_x) / range_x : 1.0f;
|
||||
const float scale_y = (range_y > 0.0f) ? (1.0f - 2.0f * margin_y) / range_y : 1.0f;
|
||||
|
||||
for (int i = 0; i < num_control; i++) {
|
||||
adjusted_points[i].x = margin_x + (control_points[i].x - min_x) * scale_x;
|
||||
adjusted_points[i].y = margin_y + (control_points[i].y - min_y) * scale_y;
|
||||
}
|
||||
} else {
|
||||
// No margin, use original points
|
||||
for (int i = 0; i < num_control; i++) {
|
||||
adjusted_points[i] = control_points[i];
|
||||
}
|
||||
}
|
||||
|
||||
Array<Vector2> samples;
|
||||
samples.Allocate(num_segments * samples_per_segment + 1);
|
||||
|
||||
// Sample the spline using Catmull-Rom interpolation with adjusted points
|
||||
int sample_idx = 0;
|
||||
for (int seg = 0; seg < num_segments; seg++)
|
||||
{
|
||||
Vector2 p0 = (seg > 0) ? adjusted_points[seg - 1] : adjusted_points[seg];
|
||||
Vector2 p1 = adjusted_points[seg];
|
||||
Vector2 p2 = adjusted_points[seg + 1];
|
||||
Vector2 p3 = (seg < num_segments - 1) ? adjusted_points[seg + 2] : adjusted_points[seg + 1];
|
||||
|
||||
for (int s = 0; s < samples_per_segment; s++)
|
||||
{
|
||||
const float t = (float)s / (float)samples_per_segment;
|
||||
samples[sample_idx] = CatmullRomInterpolate(p0, p1, p2, p3, t);
|
||||
sample_idx++;
|
||||
}
|
||||
}
|
||||
samples[num_segments * samples_per_segment] = adjusted_points[num_control - 1];
|
||||
|
||||
// __LOG_W__ << "Generated " << samples.GetCount() << " sampled points\n";
|
||||
|
||||
// Create pixel buffer for drawing
|
||||
// __LOG_W__ << "Creating pixel buffer for CPU rendering...\n";
|
||||
|
||||
const uint pitch = tex_w * 4; // RGBA = 4 bytes per pixel
|
||||
const size_t buffer_size = pitch * tex_h;
|
||||
unsigned char *pixels = new unsigned char[buffer_size];
|
||||
|
||||
// __LOG_W__ << "Pixel buffer created. Size=" << buffer_size << " Pitch=" << pitch << "\n";
|
||||
|
||||
if (clear_target)
|
||||
{
|
||||
// Initialize with transparent black
|
||||
memset(pixels, 0, buffer_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read back the existing texture contents into the buffer so we can composite on top.
|
||||
// __LOG_W__ << "Reading existing texture pixels into buffer (for compositing)...\n";
|
||||
|
||||
// Setup FBO for readback
|
||||
fx_fbo->SetColorTexture(target);
|
||||
fx_fbo->SetDepthTexture(nullptr);
|
||||
SetCurrentFBO(fx_fbo);
|
||||
|
||||
fx_fbo->ReadColorPixels((char*)pixels, 0, 0, tex_w, tex_h);
|
||||
|
||||
// Restore
|
||||
SetCurrentFBO(nullptr);
|
||||
}
|
||||
|
||||
// __LOG_W__ << "Drawing spline lines...\n";
|
||||
|
||||
// Draw border first (if specified)
|
||||
if (border_color && border_width > 0.0f) {
|
||||
// __LOG_W__ << "Drawing border with width: " << border_width << "\n";
|
||||
const float total_width = width_pixels + border_width * 2.0f;
|
||||
|
||||
for (uint i = 0; i + 1 < samples.GetCount(); i++)
|
||||
{
|
||||
const int x0 = (int)(samples[i].x * (float)tex_w);
|
||||
const int y0 = (int)(samples[i].y * (float)tex_h);
|
||||
const int x1 = (int)(samples[i + 1].x * (float)tex_w);
|
||||
const int y1 = (int)(samples[i + 1].y * (float)tex_h);
|
||||
|
||||
for (int w = -(int)total_width/2; w <= (int)total_width/2; w++)
|
||||
{
|
||||
DrawLineToPixels(pixels, tex_w, tex_h, pitch,
|
||||
x0 + w, y0, x1 + w, y1, border_r, border_g, border_b, border_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw main spline on top
|
||||
for (uint i = 0; i + 1 < samples.GetCount(); i++)
|
||||
{
|
||||
// Convert from normalized [0..1] to pixel coordinates
|
||||
const int x0 = (int)(samples[i].x * (float)tex_w);
|
||||
const int y0 = (int)(samples[i].y * (float)tex_h);
|
||||
const int x1 = (int)(samples[i + 1].x * (float)tex_w);
|
||||
const int y1 = (int)(samples[i + 1].y * (float)tex_h);
|
||||
|
||||
// Draw line with width by drawing multiple parallel lines
|
||||
for (int w = -(int)width_pixels/2; w <= (int)width_pixels/2; w++)
|
||||
{
|
||||
DrawLineToPixels(pixels, tex_w, tex_h, pitch,
|
||||
x0 + w, y0, x1 + w, y1, r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
// __LOG_W__ << "Uploading pixel buffer to texture...\n";
|
||||
// Upload to texture using Blit
|
||||
target->Blit((const char *)pixels, tex_w, tex_h, 0, 0, Render::Texture::FormatRGBA8);
|
||||
|
||||
// __LOG_W__ << "Freeing pixel buffer...\n";
|
||||
delete[] pixels;
|
||||
// __LOG_W__ << "Buffer freed!\n";
|
||||
|
||||
// __LOG_W__ << "DrawSplineToTexture complete!\n";
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user