Recent Posts

Pages: [1] 2 3 ... 10
1
Eye Candies / BassBox Plugin 64-bit
« Last post by Patrice Terrier on September 19, 2024, 06:23:34 pm »
The purpose of this VS2022 application is to switch easily from one plugin to another to check the OpenGL FPO effects transposed to 64-bit.
Most of them inherit from the original 32-bit version written long ago in PowerBASIC.



To navigate from one plugin to another move the cursor to the left or right edge of the window, and click on the auto/hide arrow.

Use drag & drop to play a specific audio file, and see how the effects interact with it.

Here is the BBP API to use to communicate with the plugin DLL.
See in the WM_TIMER message the gl_DrawScene() code using BBP_RenderOpenGL to pass the wimdata pointer to the DLL.

Code: [Select]
#pragma once
typedef ULONGLONG QWORD;

const int BBP_RENDER       = 1;       // Render the scene.
const int BBP_CREATE       = 2;       // Retrieve Title, Name, Version, Render mode.
const int BBP_INIT         = 3;       // Init the OpenGL.
const int BBP_SIZE         = 4;       // The size of the control has changed.
const int BBP_KEYBOARD     = 5;       // All keyborad message.
const int BBP_MOUSE        = 6;       // All mouse messages.
const int BBP_DESTROY      = 7;       // Free Up resources.
const int BBP_NEWSOUND     = 8;       // We are playing a new sound file.

const int BBP_GDIPLUS      = 0;       // GDImage GDIPLUS compatible mode.
const int BBP_OPENGL       = 1;       // OpenGL mode.
const int BBP_DIRECTX      = 2;       // DirectX mode (for future extension).

const int BBP_SUCCESS      = 0;
const int BBP_ERROR        = -1;

typedef struct {
    UINT msg;                   // The plugin's message (see above constant list).
    HWND parent;                // The parent window handle.
    HDC dc;                     // The parent window DC (while in play mode).
    HGLRC rc;                   // The parent OpenGL RC (while in play mode).
    WORD lpeak;                 // The left audio channel peak value (while in play mode).
    WORD rpeak;                 // The right audio channel peak value (while in play mode).
    char title[32];             // Plugin's name or title.
    char author[64];            // Plugin's author name.
    DWORD version;              // LOWRD major, HIWRD minor.
    long renderto;              // BBP_GDIPLUS, BBP_OPENGL, BBP_DIRECTX.
    long backargb;              // Default ARGB color background.
    float* fftdata;             // dword pointer to the FFT() as single array.
    WORD fftsize;               // Size of the FFT array.

    UINT winmsg;                // True Windows message.
    WPARAM wparam;              // wParam
    LPARAM lparam;              // lParam

    short* wimdata;             // dword pointer to the wave MM_WIM_DATA.
    QWORD medialength;          // Media length.
    QWORD mediapos;             // Media pos.

    char reserved[50];          // Reserved for future extension.
} BBPLUGIN;

static FARPROC BBP_ProcHandle(IN FARPROC hProc, IN long RW) {
    static FARPROC WasHproc;
    if (RW) WasHproc = hProc;
    return WasHproc;
}

static long BBP_Plugin(OUT BBPLUGIN &BBP) {
    long nRet = BBP_ERROR;
    if (IsWindow(gP.hGL)) {
        HGLRC glRC = (HGLRC) (ZI_GetProperty(gP.hGL, ZI_GLRC));
        if (glRC) {
            long_proc (BBPLUGIN*);
            zProc hProc = (zProc) BBP_ProcHandle(0, 0);
            if (hProc) { nRet = hProc(&BBP); }
        }
    }
    return nRet;
}

static WCHAR* BBP_ActivePlugin(IN WCHAR* sPluginName, IN long RW) {
    static WCHAR sWasPluginName[MAX_PATH];
    if (RW) { wcscopy(sWasPluginName, sPluginName); }
    return sWasPluginName;
}

static void MarqueeUpdate() {
    WCHAR drive[_MAX_DRIVE]; ClearMemory(drive, sizeof(drive));
    WCHAR dir[_MAX_DIR]; ClearMemory(dir, sizeof(dir));
    WCHAR fname[_MAX_FNAME]; ClearMemory(fname, sizeof(fname));
    WCHAR ext[_MAX_EXT]; ClearMemory(ext, sizeof(ext));
    wsplitpath(gB.audiofile, drive, dir, fname, ext);
    ClearMemory(gP.plugintitle, sizeof(gP.plugintitle));
    wcscopy(gP.plugintitle, gP.title, MAX_PATH * 2);
    Add_Str(gP.plugintitle, gP.version);
    Add_Str(gP.plugintitle, L" by "); Add_Str(gP.plugintitle, gP.author);
    Add_Str(gP.plugintitle, L", playing \""); Add_Str(gP.plugintitle, fname); Add_Str(gP.plugintitle, ext); Add_Str(gP.plugintitle, L"\"");
    ZD_SetObjectText(ID_COPYRIGHT, gP.plugintitle);
}

static void BBP_Reset() {
    BBPLUGIN BBP; ClearMemory(&BBP, sizeof(BBP));
    BBP.msg = BBP_CREATE;
    BBP_Plugin(BBP);

    ClearMemory(gP.title, sizeof(gP.title));
    wcscopy(gP.title, cswconv(BBP.title), strSize(gP.title));// C string to WCHAR
    ClearMemory(gP.author, sizeof(gP.author));
    wcscopy(gP.author, cswconv(BBP.author), strSize(gP.author));// C string to WCHAR

    BYTE majorVersion = (BYTE)(BBP.version & 0xFF);
    BYTE minorVersion = (BYTE)((BBP.version >> 8) & 0xFF);
    ClearMemory(gP.version, sizeof(gP.version));
    swprintf(gP.version, strSize(gP.version), L" (%d.%d)", majorVersion, minorVersion);

    MarqueeUpdate();

    //BBProc(BBP);
    if (BBP.renderto == BBP_OPENGL) {

        glDisable(GL_BLEND);
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_DEPTH_TEST);
        glDisable(GL_LIGHT0);
        glDisable(GL_LIGHT1);
        glDisable(GL_LIGHT2);
        glDisable(GL_LIGHT3);
        glDisable(GL_LIGHT4);
        glDisable(GL_LIGHT5);
        glDisable(GL_LIGHT6);
        glDisable(GL_LIGHT7);
        glDisable(GL_LIGHTING);
        glDisable(GL_COLOR_MATERIAL);
        glDisable(GL_ALPHA_TEST);
        glDisable(GL_NORMALIZE);

        glDisable(GL_LINE_SMOOTH);

        glGetError();

    }
}

//long BBProc (OUT BBPLUGIN &BBP);
static void BBP_Detached(IN HWND hWnd, OUT HMODULE &hLib) {
    BBPLUGIN BBP; ClearMemory(&BBP, sizeof(BBP));
    if (hLib) {
        BBP.msg = BBP_DESTROY;
        BBP.parent = hWnd;
        BBP_Plugin(BBP);
        //BBProc(BBP);

        // use brute force to delete any existing texture
        long Tmax = 64;
        long* DT = new long[Tmax]; memset(DT, 0, Tmax);
        for (long K = 0; K < Tmax; K++) { DT[K] = K; }
        glDeleteTextures(Tmax, (GLuint*)&DT[0]);
        delete[] DT;

        BBP_ProcHandle(0, 1); FreeLibrary(hLib); hLib = 0;
    }
}

static void BBP_ResizeOpenGL() {
    if (IsWindow(gP.hGL)) {
        BBPLUGIN BBP; ClearMemory(&BBP, sizeof(BBP));
        BBP.msg          = BBP_SIZE;
        BBP.parent       = gP.hGL;
        BBP_Plugin(BBP);
        //BBProc(BBP);
    }
}

// Load/unload plugin DLL to/from memory
static long BBP_LoadPlugin(IN HWND hWnd, IN WCHAR* zPlugin) {
    long nDone = BBP_ERROR;
    long nLen = lstrlen(zPlugin);
    if ((nLen) && (_wcsicmp(zPlugin, BBP_ActivePlugin(0,0)) != 0)) {
        if (FileExist(zPlugin)) {
            if (gP.hLib) BBP_Detached(hWnd, gP.hLib);
            gP.hLib = LoadLibrary(zPlugin);
            if (gP.hLib) {
                FARPROC hProc = GetProcAddress(gP.hLib, "BBProc");
                if (hProc) {
                    BBP_ProcHandle(hProc, 1);
                    BBP_ActivePlugin(zPlugin, 1);
                    // Reset plugin to default
                    BBP_Reset();
                    nDone = BBP_SUCCESS;
                }
            }
        }
    } else if (nLen == 0) {
        if (gP.hLib) BBP_Detached(hWnd, gP.hLib);
    }
    return nDone;
}

static long BBP_AttachPlugin(WCHAR* zPlugin) {
    gP.pluginloaded = 0;
    if (IsWindow(gP.hGL)) {
        if (BBP_LoadPlugin(gP.hGL, zPlugin) == BBP_SUCCESS) {
            gP.pluginloaded = -1;
            BBPLUGIN BBP; ClearMemory(&BBP, sizeof(BBP));
            BBP.msg          = BBP_INIT;
            BBP.parent       = gP.hGL;
            BBP.dc           = (HDC) ZI_GetProperty(gP.hGL, ZI_GLDC);
            BBP.rc           = (HGLRC) ZI_GetProperty(gP.hGL, ZI_GLRC);
            BBP.backargb     = 0;
            BBP_Plugin(BBP);

            //if (IsWindowVisible(gP.hGL)) { SetMetadataText(ID_VIDEO_SIZE, gB.plugintitle); }

            BBP.msg          = BBP_SIZE;
            BBP_Plugin(BBP);

            wcscopy(gP.bin.lastplugin, zPlugin);

            gP.pluginloaded = -1;
        }
    }
    return gP.pluginloaded;
}

static void BBP_RenderOpenGL(IN DWORD nLevel, IN short* pInt) {

    BBPLUGIN BBP; ClearMemory(&BBP, sizeof(BBP));

    HDC glDC = (HDC) (ZI_GetProperty(gP.hGL, ZI_GLDC));
    HGLRC glRC = (HGLRC) (ZI_GetProperty(gP.hGL, ZI_GLRC));
    if (glRC) {

        BBP.msg          = BBP_RENDER;
        BBP.parent       = gP.hGL;
        BBP.dc           = glDC;
        BBP.rc           = glRC;
        BBP.lpeak        = SolvePeak(LOWORD(nLevel), 128);
        BBP.rpeak        = SolvePeak(HIWORD(nLevel), 128);
        BBP.backargb     = 0;
        BBP.fftdata      = (float*) BassChannelGetData();
        BBP.fftsize      = 256;
        BBP.medialength  = gB.medialength;
        BBP.mediapos     = gB.mediapos;
        BBP.wimdata      = pInt;

        BBP_Plugin(BBP);
        //BBProc(BBP);

        // Refresh display
        SwapBuffers(glDC);

        InvalidateRect(gP.hGL, NULL, 0);
        UpdateWindow(gP.hGL);
    }
    ReleaseDC(gP.hGL, glDC);
}

static void BBP_NewSound() {
    BBPLUGIN BBP; ClearMemory(&BBP, sizeof(BBP));
    BBP.msg = BBP_NEWSOUND;
    BBP_Plugin(BBP);
}


Next, I shall post the source code of each plugin, in case you would like to write your owns, and share them on this forum.

Each plugin must be saved in the \BBplugin folder using the sub \Texture folder to store the textures.
Each plugin name must be prefixed by "bbp_" to be detected by Plugin64.exe that remembers the name of the last one used.


Plugins_dll.7z (plugin DLL source code)
bbp_Bubble.dll
bbp_CubicDream.dll
bbp_Fahrenheit.dll
bbp_FireWorks.dll
bbp_Helios.dll
bbp_Impulse.dll
bbp_Laserbeam.dll
bbp_Matrix.dll
bbp_Oscillo.dll
bbp_Popup.dll
bbp_Ring.dll
bbp_Vortex.dll


2
Eye Candies / BassBox64 (updated)
« Last post by Patrice Terrier on August 28, 2024, 10:14:19 am »
The previous post has been updated with a new version.

New:
Preprocess mouse messages to use either left or right button to fire a WM_COMMAND.
Save window coordinates.
Memory foot print reduction.
Further optimization.

Bug fix:
In case of playing multiple audio files. The selection order was not respected.
When playing a sound tracker, the file name was truncated by the previous wsplitpath function.
3
The concept / ShaderPlay
« Last post by Patrice Terrier on August 08, 2024, 01:11:50 pm »
ShaderPlay is derivated from ORV64.
Its purpose is to play ShaderToy static animations.



It is written in C/C++ with VS2022, and does use TClib.lib to produce a tiny 15 Kb binary.
Each schader file is stored in a distinct subfolder, under the 3D_models parent folder.

The shader code file is using the .fs extension, it is sligthy different from the original ShaderToy to match the OR (ObjReader) specifications.

For the purpose of ShaderPlay, each project is provided with a specific sound track to shut down automatically the shader once audio comes to full completion (except when playing in loop mode).
4
The concept / ParticLines
« Last post by Patrice Terrier on July 24, 2024, 02:25:28 pm »
The original project was wriiten in Pascal by Jan Horn (passed in 2002).

This current VS2022 version has been converted from PowerBASIC (GDImage 5.00) to C/C++ (GDImage64 7.16).



The window is using the GDImage anti-aliased WGL_CreateWindow API to create the 3D container and to produce the smooth particle tail lines.

The WinLIFT theme is based on the Windows Seven style that was used by the year 2010.

TClib.lib is used to produce the small binary executable of only 17Kb.
5
Tips & Tricks / Re: CPU Meter
« Last post by Patrice Terrier on July 08, 2024, 06:16:49 pm »
This is version 2.00.

It has been reworked to match the CPU processor percentage computation used in Windows 11.

On previous Windows 10, they were using "Processor(_Total)\\% Processor Time"

The solution is to use PDH (Performance Data Helper) and the Processor Utility request
nStatus = PdhAddEnglishCounter(cpuQuery, L"\\Processor Information(_Total)\\% Processor Utility", NULL, &cpuTotal);

\\Processor Information(_Total)\\% Processor Utility
  • Description: This counter measures the percentage of processor utility across all processors.
  • Utility: It provides a more detailed and modern view of processor usage, taking into account various factors like the efficiency of processing and modern CPU architectures.
  • Availability: This counter is generally available on newer systems with modern processors. It can give a more accurate representation of CPU utilization in multi-core and hyper-threaded environments.
\\Processor(_Total)\\% Processor Time
  • Description: This counter measures the percentage of time the processor is busy executing a non-idle thread.
  • Utility: It is a more traditional counter that has been available in Windows for a long time. It reflects the CPU load by measuring the active time versus the idle time of the CPU.
  • Availability: This counter is widely available across different versions of Windows and provides a consistent measure of CPU usage.
Note:
The project use TCLib.lib to produce a tiny 29 Kb binary executable.

6
Eye Candies / BassBox64 (alias BB64) full VS2022 project
« Last post by Patrice Terrier on June 23, 2024, 07:15:47 pm »
BassBox64 (alias BB64)
is a C/C++ VS2022 64-bit version, using a totaly different GUI, with huge size optimization.
The OpenGL visual plugins are still those from the PowerBASIC 32-bit version.



When visual plugins are enabled, press the left or right mouse button to change them.
You can also use the mouse buttons to select a specific image background.



7
The 3D Model Collection / Praga R1
« Last post by Patrice Terrier on May 29, 2024, 01:18:03 pm »
The Praga R1 is a racing and sports car made by Czech car manufacturer Praga.



video
8
The concept / Re: Tutor_19 "Circular text" (C++ VS2022 GDImage64 tutorial)
« Last post by Patrice Terrier on April 20, 2024, 10:24:39 am »
And here is the PowerBASIC translation using the new GDImage.dll 32-bit version 7.01
9
The concept / D2D "Circular text"
« Last post by Patrice Terrier on April 14, 2024, 06:38:01 pm »
As a matter of comparison here is the code to draw a circular text using the D2D API

Code: [Select]
#include <windows.h>
#include <d2d1.h>
#include <dwrite.h>
#include <cmath>

#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib")

constexpr auto IDI_ICON1     = 101;

// Global pointers for Direct2D and DirectWrite interfaces
ID2D1Factory* pD2DFactory = nullptr;
ID2D1HwndRenderTarget* pRenderTarget = nullptr;
ID2D1SolidColorBrush* pBrush = nullptr;
IDWriteFactory* pDWriteFactory = nullptr;
IDWriteTextFormat* pTextFormat = nullptr;

static void Initialize() {
    D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
    DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&pDWriteFactory));
}

static void CreateGraphicsResources(HWND hwnd) {
    if (!pRenderTarget) {
        RECT rc;
        GetClientRect(hwnd, &rc);
        D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
        pD2DFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hwnd, size), &pRenderTarget);

        pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(0xFF037BFA), &pBrush);

        pDWriteFactory->CreateTextFormat(
            L"Segoe GUI emoji",
            nullptr,
            DWRITE_FONT_WEIGHT_BOLD,
            DWRITE_FONT_STYLE_NORMAL,
            DWRITE_FONT_STRETCH_NORMAL,
            50.0f,
            L"", //locale
            &pTextFormat
        );

        pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
        pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
    }
}

static void DiscardGraphicsResources() {
    if (pBrush) pBrush->Release();
    if (pRenderTarget) pRenderTarget->Release();
    if (pTextFormat) pTextFormat->Release();
    pBrush = nullptr;
    pRenderTarget = nullptr;
    pTextFormat = nullptr;
}

static void OnPaint(HWND hwnd) {
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    CreateGraphicsResources(hwnd);
    pRenderTarget->BeginDraw();
    pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    D2D1_SIZE_F size = pRenderTarget->GetSize();

    const WCHAR* text = L"This is a Circular text using the D2D API.";
    const float radius = 200.0f;
    const D2D1_POINT_2F center = D2D1::Point2F(size.width / 2, size.height / 2);
    const size_t length = wcslen(text);
    const float angleStep = 360.0f / static_cast<float>(length);

    for (size_t i = 0; i < length; ++i) {
        WCHAR letter[2] = { text[i], 0 };

        float angle = DegreesToRadians(angleStep * i);
        D2D1_POINT_2F position = {
            center.x + cos(angle) * radius,
            center.y + sin(angle) * radius
        };

        D2D1_MATRIX_3X2_F rotation = D2D1::Matrix3x2F::Rotation(angleStep * i + 90, position);
        pRenderTarget->SetTransform(rotation);

        pRenderTarget->DrawText(
            letter,
            ARRAYSIZE(letter),
            pTextFormat,
            D2D1::RectF(position.x - 20, position.y - 20, position.x + 20, position.y + 20),
            pBrush
        );

        pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
    }

    HRESULT hr = pRenderTarget->EndDraw();
    if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET) {
        DiscardGraphicsResources();
    }
    EndPaint(hwnd, &ps);
}

static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        case WM_PAINT:
            OnPaint(hwnd);
            return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
    Initialize();

    // Register the window class
    const wchar_t CLASS_NAME[] = L"Sample Window Class";
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    // Create the window
    HWND hwnd = CreateWindowEx(
        0,
        CLASS_NAME,
        L"Circular Text with Direct2D",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 600,
        nullptr,
        nullptr,
        hInstance,
        nullptr
    );

    if (hwnd == nullptr) {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Run the message loop
    MSG msg = {};
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    DiscardGraphicsResources();
    if (pD2DFactory) pD2DFactory->Release();
    if (pDWriteFactory) pDWriteFactory->Release();

    return 0;
}
10
The concept / Tutor_19 "Circular text" (C++ VS2022 GDImage64 tutorial)
« Last post by Patrice Terrier on April 13, 2024, 07:32:58 pm »
About Tutor_19
Its purpose is to create one single or multiple circular text objects to use for logo or animaion.

It uses a new API named ZD_CreateCircularTextBitmap
using 7 parameters:
WCHAR* zText, the unicode string to create the circular text from.
WCHAR* zFont, the unicode string for the font to use (could be a .ttf private font).
long fontSize, the font size height.
long fontSyle, for example FontStyleBold.
long radius, the inner radius of the circular text.
DWORD ColrARGB, the ARGB color to use.
float step, the distance between each character.

The function returns a BITMAP handle that can be used by the ZD_DrawBitmapToCtrl API.

The AngleRotation procedure is using direct call to the GDIPLUS FLAT API to compute the correct rotation angle.

The window itself works in DWM transparent composited mode using the GDImage ZI_DwmEnable API.




Pages: [1] 2 3 ... 10