News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Recent posts

#41
Windows API / Re: DLL pickle
Last post by TimoVJL - May 12, 2025, 05:29:21 PM
If component DLL have safeguard mechanism, it deny to unload as long there are a windows using it.
FindWindow can find windows by registered class.

Perhaps some component code show, how they work.

Dynamic-Link Library Best Practices

What is the HINSTANCE passed to CreateWindow and RegisterClass used for?
#42
Windows API / Re: DLL pickle
Last post by sinsi - May 12, 2025, 01:07:21 PM
Don't forget to unregister your window classes when your DLL shuts down dynamically
This talks about CS_GLOBALCLASS, are you using that flag?
#43
Windows API / Re: DLL pickle
Last post by NoCforMe - May 12, 2025, 12:34:27 PM
No; I'm calling an initialization function in another module (linked into the DLL) which calls RegisterClassEx(). No export.

Now I'm confused: let's say I did have a DLL export, "UnregisterMyClass()". Would the application that's using the DLL have to call that function? And how would it know when the proper time to do that is? Keep in kind that all windows of that class have to be destroyed before you can unregister the class.

No, I don't think that would work.

I've found some stuff online that may be of help, will post more later after I digest it.
#44
Windows API / Re: DLL pickle
Last post by sinsi - May 12, 2025, 12:29:21 PM
Do you have a DLL export to register your classes? Then you should also have a DLL export to unregister them I guess.
#45
Windows API / DLL pickle
Last post by NoCforMe - May 12, 2025, 09:40:12 AM
I'm in a pickle with a DLL.
The DLL registers a window class, in a different .obj module linked with the main DLL code.
Problem is, I just discovered that window classes registered by a DLL are not automatically unregistered when the DLL is unloaded (as they are when an application terminates). From the documentation for RegisterClassEx():

QuoteNo window classes registered by a DLL are unregistered when the DLL is unloaded. A DLL must explicitly unregister its classes when it is unloaded.

OK, so I need to unregister that class manually.

But that's a problem: I can't do it in the DLLMain() entry point, because of the restrictions on what you can do there:

QuoteYou should never perform the following tasks from within DllMain:
  • Call functions in User32.dll or Gdi32.dll. Some functions load another DLL, which may not be initialized.

UnregisterClass() is in User32.dll.

So how do I do this? I need to unregister when the DLL reason is DLL_PROCESS_DETACH. But I can't do it in the DLLmain() function.

I thought of sending a message somewhere else that could do this, but SendMessage() is also in User32.dll.
#46
UASM Assembler Development / Re: Riemann Zeta Function
Last post by jack - May 12, 2025, 08:17:24 AM
I updated my FreeBasic code
the Riemann zeta function now supports both negative and complex arguments
there's a bug in there somewhere, zeta(-20.1) gives the wrong sign, other than that the value is ok
the complex cosine is giving the wrong sign, any trig experts here?

fixed
sample output
Dim As complex x, y, z
Dim As Double rr, ri

for rr=-1 to 1 step .5
for ri=-1 to 1 step .5
x=complex(rr, ri)
y=zeta(x)
print using "zeta(##.####, ##.####) = ";x.re;x.im;
print using "##.################, ##.################";y.re;y.im
next
next

zeta(-1.0000, -1.0000) =  0.0168761517881836,  0.1141564804323963
zeta(-1.0000, -0.5000) = -0.0538894302820935,  0.0752004260118382
zeta(-1.0000,  0.0000) = -0.0833333333333334,  0.0000000000000000
zeta(-1.0000,  0.5000) = -0.0538894302820935, -0.0752004260118382
zeta(-1.0000,  1.0000) =  0.0168761517881836, -0.1141564804323963
zeta(-0.5000, -1.0000) = -0.0008178931340101,  0.2230716886972805
zeta(-0.5000, -0.5000) = -0.1407574606243030,  0.1580763818474494
zeta(-0.5000,  0.0000) = -0.2078862249773547,  0.0000000000000000
zeta(-0.5000,  0.5000) = -0.1407574606243030, -0.1580763818474494
zeta(-0.5000,  1.0000) = -0.0008178931340101, -0.2230716886972805
zeta( 0.0000, -1.0000) =  0.0033002236853245,  0.4181554491413226
zeta( 0.0000, -0.5000) = -0.2991978789224703,  0.3593711792648014
zeta( 0.0000,  0.0000) = -0.4999999999999991,  0.0000000000000000
zeta( 0.0000,  0.5000) = -0.2991978789224703, -0.3593711792648014
zeta( 0.0000,  1.0000) =  0.0033002236853245, -0.4181554491413226
zeta( 0.5000, -1.0000) =  0.1439364270771889,  0.7220997435316735
zeta( 0.5000, -0.5000) = -0.4593028903460181,  0.9612542845058791
zeta( 0.5000,  0.0000) = -1.4603545088095850,  0.0000000000000000
zeta( 0.5000,  0.5000) = -0.4593028903460181, -0.9612542845058791
zeta( 0.5000,  1.0000) =  0.1439364270771889, -0.7220997435316735
zeta( 1.0000, -1.0000) =  0.5821580597520036,  0.9268485643308069
zeta( 1.0000, -0.5000) =  0.5784330210993112,  1.9635494964529780
zeta( 1.0000,  0.0000) = -1.#IND000000000000, -1.#IND000000000000
zeta( 1.0000,  0.5000) =  0.5784330210993112, -1.9635494964529780
zeta( 1.0000,  1.0000) =  0.5821580597520036, -0.9268485643308069
#47
UASM Assembler Development / Re: Riemann Zeta Function
Last post by TimoVJL - May 12, 2025, 12:23:52 AM
A test project for pure C with Pelles C.
Just for testing those functions, no graphics.
#48
UASM Assembler Development / Re: Riemann Zeta Function
Last post by six_L - May 11, 2025, 03:38:00 PM
Hi,guga
good works!
:thumbsup:
I want to compare your image. Could you post an image of the following parameters?

step = 0.012
a = 1/2,b = [-1025.4712,-1015.1512]
Scale = 50:1
iterations = 860

Thank you in advance.

Regards
six_L
#49
UASM Assembler Development / Re: Riemann Zeta Function
Last post by guga - May 11, 2025, 12:51:03 AM
Hi Six_L you´re welcome.

Now, try this. (Added zoom with mouse wheel and pg up/down), also it starts (resets) with a space and not only the R key

// ZetaVisualizerFinal.c - Added Page Up/Page Down zoom, smoothed curve, fixed starting line
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <commdlg.h>
#include <vector>

#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")

using namespace Gdiplus;

// Global variables for animation and zoom
static float animationProgress = 0.0f; // 0.0 to 1.0
static const float ANIMATION_SPEED = 0.005f; // Adjust for faster/slower animation
static const UINT_PTR ANIMATION_TIMER_ID = 1;
static bool isAnimationRunning = false; // Track animation state
static float zoomFactor = 1.0f; // Zoom factor (1.0 = default, >1 zoom in, <1 zoom out)

// Complex number structure
typedef struct {
    double real;
    double imag;
} Complex;

// Complex arithmetic functions
Complex ComplexAdd(Complex a, Complex b) {
    Complex result;
    result.real = a.real + b.real;
    result.imag = a.imag + b.imag;
    return result;
}

Complex ComplexMul(Complex a, Complex b) {
    Complex result;
    result.real = a.real * b.real - a.imag * b.imag;
    result.imag = a.real * b.imag + a.imag * b.real;
    return result;
}

Complex ComplexSub(Complex a, Complex b) {
    Complex result;
    result.real = a.real - b.real;
    result.imag = a.imag - b.imag;
    return result;
}

Complex ComplexPowReal(Complex base, double exponent) {
    double r = sqrt(base.real * base.real + base.imag * base.imag);
    double theta = atan2(base.imag, base.real);
    double ln_r = log(r);
    double exponent_ln_r = exponent * ln_r;
    double exponent_theta = exponent * theta;
    Complex result;
    result.real = exp(exponent_ln_r) * cos(exponent_theta);
    result.imag = exp(exponent_ln_r) * sin(exponent_theta);
    return result;
}

Complex ComplexPow(Complex base, Complex exponent) {
    double r = sqrt(base.real * base.real + base.imag * base.imag);
    double theta = atan2(base.imag, base.real);
    Complex ln_base;
    ln_base.real = log(r);
    ln_base.imag = theta;
    Complex exponent_ln_base = ComplexMul(exponent, ln_base);
    double magnitude = exp(exponent_ln_base.real);
    Complex result;
    result.real = magnitude * cos(exponent_ln_base.imag);
    result.imag = magnitude * sin(exponent_ln_base.imag);
    return result;
}

Complex ComplexDiv(Complex a, Complex b) {
    double denom = b.real * b.real + b.imag * b.imag;
    Complex result;
    result.real = (a.real * b.real + a.imag * b.imag) / denom;
    result.imag = (a.imag * b.real - a.real * b.imag) / denom;
    return result;
}

Complex ComplexScale(Complex a, double scalar) {
    Complex result;
    result.real = a.real * scalar;
    result.imag = a.imag * scalar;
    return result;
}

Complex ComplexNeg(Complex a) {
    Complex result;
    result.real = -a.real;
    result.imag = -a.imag;
    return result;
}

// Complex logarithm: ln(z) = ln(|z|) + i * arg(z)
Complex ComplexLn(Complex z) {
    Complex result;
    result.real = log(sqrt(z.real * z.real + z.imag * z.imag));
    result.imag = atan2(z.imag, z.real);
    return result;
}

// Generate prime numbers using Sieve of Eratosthenes
std::vector<int> GeneratePrimes(int limit) {
    std::vector<bool> isPrime(limit + 1, true);
    isPrime[0] = isPrime[1] = false;
    for (int i = 2; i * i <= limit; i++) {
        if (isPrime[i]) {
            for (int j = i * i; j <= limit; j += i) {
                isPrime[j] = false;
            }
        }
    }

    std::vector<int> primes;
    for (int i = 2; i <= limit; i++) {
        if (isPrime[i]) {
            primes.push_back(i);
        }
    }
    return primes;
}

// Zeta function using Euler product: ζ(z) = exp(-∑_p ln(1 - p^(-z)))
Complex Zeta(Complex z, int iterations) {
    static std::vector<int> primes;
    if (primes.empty()) {
        primes = GeneratePrimes(1000);
    }

    Complex sum = { 0.0, 0.0 };
    Complex one = { 1.0, 0.0 };
    Complex p_complex, p_neg_z, term;

    int count = 0;
    for (int p : primes) {
        if (count >= iterations) break;
        p_complex.real = (double)p;
        p_complex.imag = 0.0;

        Complex neg_z = ComplexNeg(z);
        p_neg_z = ComplexPow(p_complex, neg_z);
        term = ComplexSub(one, p_neg_z);
        Complex ln_term = ComplexLn(term);
        sum = ComplexAdd(sum, ComplexNeg(ln_term));
        count++;
    }

    double magnitude = exp(sum.real);
    Complex result;
    result.real = magnitude * cos(sum.imag);
    result.imag = magnitude * sin(sum.imag);
    return result;
}

// Draw the enhanced Zeta function visualization
void DrawEnhancedZeta(HDC hdc, int width, int height, float progress) {
    Graphics graphics(hdc);
    graphics.SetSmoothingMode(SmoothingModeAntiAlias);
    graphics.SetCompositingQuality(CompositingQualityHighQuality);
    graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);

    // Dark gradient background
    LinearGradientBrush background(
        Point(0, 0),
        Point(width, height),
        Color(255, 10, 20, 50),
        Color(255, 0, 0, 0));
    graphics.FillRectangle(&background, 0, 0, width, height);

    // Set up coordinate system
    REAL centerX = width / 2.0f;
    REAL centerY = height / 2.0f;
    REAL scale = (REAL)min(width, height) / 4.0f;
    REAL unitScale = (scale / 12.0f) * zoomFactor; // Adjusted with zoom factor

    // Draw subtle grid lines (step of 4 units)
    Pen gridPen(Color(50, 100, 100, 150), 0.3f);
    // Horizontal axis: Im(ζ(s)), up to ±32
    for (int i = -8; i <= 8; i++) { // ±32, step 4
        REAL gridPos = i * 4 * unitScale;
        graphics.DrawLine(&gridPen,
            0.0f, centerY + gridPos,
            (REAL)width, centerY + gridPos);
    }
    // Vertical axis: Re(ζ(s)), up to ±24
    for (int i = -6; i <= 6; i++) { // ±24, step 4
        REAL gridPos = i * 4 * unitScale;
        graphics.DrawLine(&gridPen,
            centerX + gridPos, 0.0f,
            centerX + gridPos, (REAL)height);
    }

    // Draw glowing axes
    LinearGradientBrush axisBrush(
        Point(0, (int)centerY),
        Point(width, (int)centerY),
        Color(150, 200, 200, 255),
        Color(50, 100, 100, 100));
    Pen axisPen(&axisBrush, 1.8f);
    graphics.DrawLine(&axisPen, 0.0f, centerY, (REAL)width, centerY);
    graphics.DrawLine(&axisPen, centerX, 0.0f, centerX, (REAL)height);

    // Draw critical line
    LinearGradientBrush criticalBrush(
        Point((int)centerX, 0),
        Point((int)centerX, height),
        Color(150, 255, 150, 50),
        Color(50, 100, 255, 50));
    Pen criticalPen(&criticalBrush, 2.0f);
    REAL criticalX = centerX + scale * 0.5f;
    graphics.DrawLine(&criticalPen, criticalX, 0.0f, criticalX, (REAL)height);

    // Compute Zeta function points and store them
    const int iterations = 200;
    const double t_start = 0.0;
    const double t_end = 30.0;
    const double t_step = 0.02;
    double t_max = t_start + progress * (t_end - t_start);

    // Collect points for the curve
    std::vector<PointF> points;
    for (double t = t_start; t <= t_max; t += t_step) {
        Complex s = { 0.5, t };
        Complex zeta = Zeta(s, iterations);

        REAL x = centerX + (REAL)zeta.imag * unitScale;
        REAL y = centerY - (REAL)zeta.real * unitScale;
        points.push_back(PointF(x, y));
    }

    // Draw the Zeta curve as a smooth spline
    GraphicsPath path;
    if (!points.empty()) {
        path.AddCurve(points.data(), (INT)points.size(), 0.5f); // Tension = 0.5 for smoothness
    }

    // Neon gradient for Zeta curve
    Color colors[] = {
        Color(200, 255, 50, 50),
        Color(200, 255, 165, 0),
        Color(200, 255, 0, 255),
        Color(200, 50, 50, 255)
    };
    REAL positions[] = { 0.0f, 0.33f, 0.67f, 1.0f };
    LinearGradientBrush pathBrush(
        Point(0, (int)(centerY - scale)),
        Point(0, (int)(centerY + scale)),
        Color(255, 255, 255, 255),
        Color(255, 255, 255, 255));
    pathBrush.SetInterpolationColors(colors, positions, 4);

    // Draw glow and main curve
    Pen glowPen(&pathBrush, 5.0f);
    glowPen.SetColor(Color(100, 255, 255, 255));
    graphics.DrawPath(&glowPen, &path);
    Pen zetaPen(&pathBrush, 2.5f);
    graphics.DrawPath(&zetaPen, &path);

    // Add annotations with adjusted positions
    Font font(L"Cambria Math", 16, FontStyleBold);
    Font smallFont(L"Cambria Math", 12, FontStyleRegular);
    SolidBrush shadowBrush(Color(80, 0, 0, 0));
    SolidBrush textBrush(Color(255, 230, 230, 230));
    StringFormat format;
    format.SetAlignment(StringAlignmentCenter);

    // Title: "ζ(s) where s = ½ + ti"
    Font bigFont(L"Cambria Math", 20, FontStyleBold);
    graphics.DrawString(L"ζ(s) where s = ½ + ti", -1, &bigFont,
        PointF(centerX + 4.0f, 24.0f), &format, &shadowBrush);
    graphics.DrawString(L"ζ(s) where s = ½ + ti", -1, &bigFont,
        PointF(centerX, 20.0f), &format, &textBrush);

    // Critical line label: "Re(s) = ½"
    graphics.DrawString(L"Re(s) = ½", -1, &font,
        PointF(criticalX + 4.0f, 60.0f), &format, &shadowBrush);
    graphics.DrawString(L"Re(s) = ½", -1, &font,
        PointF(criticalX, 56.0f), &format, &textBrush);

    // Axis label: "Im(ζ(s))"
    REAL imLabelX = (REAL)width - 100.0f;
    graphics.DrawString(L"Im(ζ(s))", -1, &font,
        PointF(imLabelX + 4.0f, centerY - 24.0f), &shadowBrush);
    graphics.DrawString(L"Im(ζ(s))", -1, &font,
        PointF(imLabelX, centerY - 20.0f), &textBrush);

    // Axis label: "Re(ζ(s))"
    graphics.DrawString(L"Re(ζ(s))", -1, &font,
        PointF(centerX + 14.0f, (REAL)height - 44.0f), &shadowBrush);
    graphics.DrawString(L"Re(ζ(s))", -1, &font,
        PointF(centerX + 10.0f, (REAL)height - 40.0f), &textBrush);

    // Coordinate labels for horizontal axis (Im(ζ(s))): -32 to 32, step 4
    for (int i = -8; i <= 8; i++) {
        int value = i * 4;
        REAL xPos = centerX + value * unitScale;
        WCHAR label[16];
        swprintf(label, 16, L"%d", value);
        graphics.DrawString(label, -1, &smallFont,
            PointF(xPos + 2.0f, centerY + 16.0f), &format, &shadowBrush);
        graphics.DrawString(label, -1, &smallFont,
            PointF(xPos, centerY + 12.0f), &format, &textBrush);
    }

    // Coordinate labels for vertical axis (Re(ζ(s))): -24 to 24, step 4
    StringFormat nearFormat;
    nearFormat.SetAlignment(StringAlignmentNear);
    for (int i = -6; i <= 6; i++) {
        int value = i * 4;
        REAL yPos = centerY - value * unitScale;
        WCHAR label[16];
        if (value == 0) {
            swprintf(label, 16, L"0");
        }
        else {
            swprintf(label, 16, L"%di", value);
        }
        graphics.DrawString(label, -1, &smallFont,
            PointF(centerX - 30.0f + 2.0f, yPos + 2.0f), &nearFormat, &shadowBrush);
        graphics.DrawString(label, -1, &smallFont,
            PointF(centerX - 30.0f, yPos), &nearFormat, &textBrush);
    }

    // Add animated non-trivial zero markers
    double zeros[] = { 14.1347, 21.0220, 25.0109, 30.4249 };
    int numZeros = sizeof(zeros) / sizeof(zeros[0]);
    for (int i = 0; i < numZeros; i++) {
        if (zeros[i] <= t_max) {
            Complex s = { 0.5, zeros[i] };
            Complex zeta = Zeta(s, iterations);
            REAL x = centerX + (REAL)zeta.imag * unitScale;
            REAL y = centerY - (REAL)zeta.real * unitScale;

            LinearGradientBrush zeroBrush(
                Point((int)(x - 10.0f), (int)(y - 10.0f)),
                Point((int)(x + 10.0f), (int)(y + 10.0f)),
                Color(200, 255, 100, 100),
                Color(0, 255, 255, 255));
            graphics.FillEllipse(&zeroBrush, x - 7.0f, y - 7.0f, 14.0f, 14.0f);

            Pen zeroPen(Color(150, 255, 255, 255), 1.0f);
            graphics.DrawEllipse(&zeroPen, x - 7.0f, y - 7.0f, 14.0f, 14.0f);
        }
    }
}

// Helper function to get PNG encoder CLSID
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
    UINT num = 0, size = 0;
    Gdiplus::GetImageEncodersSize(&num, &size);
    if (size == 0) return -1;

    ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);

    for (UINT j = 0; j < num; ++j) {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;
        }
    }

    free(pImageCodecInfo);
    return -1;
}

// Save visualization as PNG
void SaveAsPng(HWND hWnd, int width, int height, const WCHAR* filename) {
    Bitmap bitmap(width, height, PixelFormat32bppARGB);
    Graphics bitmapGraphics(&bitmap);
    bitmapGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
    bitmapGraphics.SetCompositingQuality(CompositingQualityHighQuality);
    bitmapGraphics.SetTextRenderingHint(TextRenderingHintAntiAlias);

    HDC hdc = bitmapGraphics.GetHDC();
    DrawEnhancedZeta(hdc, width, height, 1.0f);
    bitmapGraphics.ReleaseHDC(hdc);

    CLSID clsid;
    if (GetEncoderClsid(L"image/png", &clsid) != -1) {
        bitmap.Save(filename, &clsid, NULL);
        char msg[512];
        snprintf(msg, sizeof(msg), "Visualization saved as %S", filename);
        MessageBoxA(hWnd, msg, "Success", MB_OK | MB_ICONINFORMATION);
    }
    else {
        MessageBoxA(hWnd, "Failed to save PNG: PNG encoder not found", "Error", MB_OK | MB_ICONERROR);
    }
}

// Open file dialog for saving PNG
void ShowSaveDialog(HWND hWnd, int width, int height) {
    WCHAR filename[MAX_PATH] = L"ZetaVisualization.png";
    OPENFILENAMEW ofn = { 0 };
    ofn.lStructSize = sizeof(OPENFILENAMEW);
    ofn.hwndOwner = hWnd;
    ofn.lpstrFilter = L"PNG Files (*.png)\0*.png\0All Files (*.*)\0*.*\0";
    ofn.lpstrFile = filename;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrDefExt = L"png";
    ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;

    if (GetSaveFileNameW(&ofn)) {
        SaveAsPng(hWnd, width, height, filename);
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    static int width, height;

    switch (message) {
    case WM_CREATE:
        break;

    case WM_TIMER:
        if (wParam == ANIMATION_TIMER_ID) {
            animationProgress += ANIMATION_SPEED;
            if (animationProgress > 1.0f) {
                animationProgress = 1.0f;
                KillTimer(hWnd, ANIMATION_TIMER_ID);
                isAnimationRunning = false;
            }
            InvalidateRect(hWnd, NULL, FALSE);
        }
        break;

    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);

        RECT rect;
        GetClientRect(hWnd, &rect);
        width = rect.right;
        height = rect.bottom;

        HDC memDC = CreateCompatibleDC(hdc);
        HBITMAP memBitmap = CreateCompatibleBitmap(hdc, width, height);
        HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);

        HBRUSH blackBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
        FillRect(memDC, &rect, blackBrush);

        DrawEnhancedZeta(memDC, width, height, animationProgress);

        BitBlt(hdc, 0, 0, width, height, memDC, 0, 0, SRCCOPY);

        SelectObject(memDC, oldBitmap);
        DeleteObject(memBitmap);
        DeleteDC(memDC);

        EndPaint(hWnd, &ps);
        break;
    }
    case WM_SIZE:
        width = LOWORD(lParam);
        height = HIWORD(lParam);
        InvalidateRect(hWnd, NULL, TRUE);
        break;

    case WM_MOUSEWHEEL: {
        short delta = GET_WHEEL_DELTA_WPARAM(wParam);
        float zoomStep = 1.1f;

        if (delta > 0) {
            // Scroll up: Zoom in
            zoomFactor *= zoomStep;
            if (zoomFactor > 3.0f) zoomFactor = 3.0f;
        }
        else if (delta < 0) {
            // Scroll down: Zoom out
            zoomFactor /= zoomStep;
            if (zoomFactor < 0.5f) zoomFactor = 0.5f;
        }

        InvalidateRect(hWnd, NULL, FALSE);
        break;
    }

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case 1001:
            ShowSaveDialog(hWnd, width, height);
            break;
        case 1002:
            if (!isAnimationRunning) {
                SetTimer(hWnd, ANIMATION_TIMER_ID, 16, NULL);
                isAnimationRunning = true;
            }
            break;
        case 1003:
            if (isAnimationRunning) {
                KillTimer(hWnd, ANIMATION_TIMER_ID);
                isAnimationRunning = false;
            }
            break;
        }
        break;

    case WM_KEYDOWN:
        switch (wParam) {
        case 'R': // Reset animation
        case VK_SPACE: // Also reset with Space key
            animationProgress = 0.0f;
            if (!isAnimationRunning) {
                SetTimer(hWnd, ANIMATION_TIMER_ID, 16, NULL);
                isAnimationRunning = true;
            }
            InvalidateRect(hWnd, NULL, FALSE);
            break;

        case VK_PRIOR: // Page Up: Zoom in
            zoomFactor *= 1.1f;
            if (zoomFactor > 3.0f) zoomFactor = 3.0f;
            InvalidateRect(hWnd, NULL, FALSE);
            break;

        case VK_NEXT: // Page Down: Zoom out
            zoomFactor /= 1.1f;
            if (zoomFactor < 0.5f) zoomFactor = 0.5f;
            InvalidateRect(hWnd, NULL, FALSE);
            break;
        }
        break;

    case WM_DESTROY:
        if (isAnimationRunning) {
            KillTimer(hWnd, ANIMATION_TIMER_ID);
        }
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProcA(hWnd, message, wParam, lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    HMENU hMenu = CreateMenu();
    HMENU hFileMenu = CreatePopupMenu();
    AppendMenuA(hFileMenu, MF_STRING, 1001, "Save As...");
    AppendMenuA(hFileMenu, MF_STRING, 1002, "Start Animation");
    AppendMenuA(hFileMenu, MF_STRING, 1003, "Pause Animation");
    AppendMenuA(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, "File");

    WNDCLASSA wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "ZetaVisualizer";
    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    RegisterClassA(&wc);

    HWND hWnd = CreateWindowA("ZetaVisualizer", "Riemann Zeta Function Visualizer",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        1200, 900, NULL, hMenu, hInstance, NULL);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }

    DestroyMenu(hMenu);
    GdiplusShutdown(gdiplusToken);
    return (int)msg.wParam;
}


Full project on this link: https://www.mediafire.com/file/kbwfvysh83cc33x/Zeta14.rar/file




#50
UASM Assembler Development / Re: Riemann Zeta Function
Last post by six_L - May 10, 2025, 11:22:29 PM
Hi,zedd/guga/jack
Thanks your help.
Quite useful information.
I am very interested in your Zeta algorithms. I need to learn hardly.

Zeta(z)=1/1^z+1/2^z+1/3^z+...+1/n^z+...
=1/(1-1/2^z) * 1/(1-1/3^z) * 1/(1-1/5^z) * 1/(1-1/7^z) * 1/(1-1/11^z) * ... * 1/(1-1/p^z)   
n: All natural numbers
z = a+bi, a != 1
p = All prime numbers

ln(Zeta(z)) = -[ln(1-1/2^z)+ln(1-1/3^z)+ln(1-1/5^z)+ln(1-1/7^z)+...+ln(1-1/p^z)]
                 = x
Zeta(z) = e^x

150 years ago, no computer, the great mathematicians used their pens to calculate the Zeta(z) Nontrivial zeros. That's a very difficult job. Admiring!

The problem with the previous images was due to the step value being too large.
now it works fine.