Testing out python bindings, needs refactor

A disgusting little race condition has appeared, running will result in a black screen 70% of the time >:(

TODO:
lambda functions referencing non static graphics methods instead of making graphics methods static
state manager (everything is hodge podged into graphics and pycron objects)
sort math functions into relevant places (trig, random etc)
This commit is contained in:
Bobby Lucero 2024-04-21 23:33:39 -04:00
parent d7966bdcae
commit 66ce48776a
6 changed files with 165 additions and 22 deletions

View File

@ -47,5 +47,6 @@ if(EMSCRIPTEN)
endif()
file(COPY ${CMAKE_SOURCE_DIR}/resources DESTINATION ${CMAKE_BINARY_DIR})
file(COPY ${CMAKE_SOURCE_DIR}/python DESTINATION ${CMAKE_BINARY_DIR})

17
python/main.py Normal file
View File

@ -0,0 +1,17 @@
i = 0
def update():
global i
i += 1
clear(43)
x = sin(i * 0.071234) * 50 + 100
y = sin(i * 0.0236) * 20 + 80
circle(x + sin(i * 0.05) * 30, y + cos(i * 0.05) * 30, 5, 15)
circle(x + sin(i * 0.05) * 30, y + cos(i * 0.05) * 30, 3, 11)
circle(x + -sin(i * 0.05) * 30, y + -cos(i * 0.05) * 30, 5, 17)
circle(x + -sin(i * 0.05) * 30, y + -cos(i * 0.05) * 30, 3, 19)
clear(44)
circle(20,30, 5, 17)

View File

@ -6,6 +6,9 @@
#include "Graphics.h"
#include "../Utilities.h"
std::vector<Color> Graphics::palette;
Graphics::Graphics(int screenWidth, int screenHeight, int startupScale) : screenWidth(screenWidth), screenHeight(screenHeight){
startupScreenWidth = screenWidth * startupScale;
startupScreenHeight = screenHeight * startupScale;
@ -16,11 +19,19 @@ Graphics::Graphics(int screenWidth, int screenHeight, int startupScale) : screen
InitWindow(startupScreenWidth, startupScreenHeight, "test");
SetTargetFPS(60);
virtualScreen = LoadRenderTexture(screenWidth, screenHeight);
virtualScreenLocalBounds = {0.0f, 0.0f, (float)virtualScreen.texture.width, -(float)virtualScreen.texture.height };
updateFunction = nullptr;
calculateScreenPositionInWindow();
std::cout << origin.x << " : " << origin.y << std::endl;
std::cout << virtualScreenLocalBounds.width << " : " << virtualScreenLocalBounds.height << std::endl;
std::cout << virtualScreenWindowBounds.width << " : " << virtualScreenWindowBounds.height << std::endl;
}
void Graphics::draw() {
void Graphics::draw(pkpy::VM* vm) {
windowShouldClose = WindowShouldClose();
@ -32,18 +43,12 @@ void Graphics::draw() {
BeginTextureMode(virtualScreen);
//////////
ClearBackground(palette[1]);
DrawText(("Hello World " + std::to_string(GetFPS()) + " FPS").c_str(), 5, 5, 5, RAYWHITE);
DrawRectangle(3, 19, 33, 33, BLACK);
for (int i = 0; i < 8; ++i) {
for (int j = 0; j < 8; ++j) {
DrawRectangle(4 + i * 4, 20 + j * 4, 3, 3, palette[i + j * 8]);
}
try{
if(updateFunction != nullptr)
vm->call(updateFunction);
} catch(pkpy::Exception e){
std::cout << e.summary() << std::endl;
}
DrawCircleLines(mouseX(), mouseY(),3, palette[18]);
//////////
EndTextureMode();
@ -52,7 +57,7 @@ void Graphics::draw() {
void Graphics::renderVirtualScreen() {
BeginDrawing();
ClearBackground(palette[0]);
//ClearBackground(palette[16]);
DrawTexturePro(virtualScreen.texture, virtualScreenLocalBounds, virtualScreenWindowBounds, origin, 0.0f, WHITE);
EndDrawing();
}
@ -114,6 +119,48 @@ void Graphics::toggleFullScreen() {
calculateScreenPositionInWindow();
}
void Graphics::bindMethods(pkpy::VM *vm) {
vm->bind(vm->builtins, "clear(color: int)", reinterpret_cast<pkpy::NativeFuncC>(Clear));
vm->bind(vm->builtins, "pixel(x: int, y: int, color: int)", reinterpret_cast<pkpy::NativeFuncC>(Pixel));
vm->bind(vm->builtins, "circle(x: int, y: int, radius: float, color: int)", reinterpret_cast<pkpy::NativeFuncC>(Circle));
}
void Graphics::Clear(pkpy::VM* vm, pkpy::ArgsView args) {
int paletteIndex = pkpy::py_cast<int>(vm, args[0]);
if(paletteIndex < 0 || paletteIndex >= palette.size()) paletteIndex = 0;
ClearBackground(palette[paletteIndex]);
}
void Graphics::Pixel(pkpy::VM* vm, pkpy::ArgsView args) {
int x = pkpy::py_cast<int>(vm, args[0]);
int y = pkpy::py_cast<int>(vm, args[1]);
int paletteIndex = pkpy::py_cast<int>(vm, args[2]);
DrawPixel(x, y, palette[paletteIndex]);
}
void Graphics::Circle(pkpy::VM* vm, pkpy::ArgsView args) {
float x = pkpy::py_cast<float>(vm, args[0]);
float y = pkpy::py_cast<float>(vm, args[1]);
float radius = pkpy::py_cast<float>(vm, args[2]);
int paletteIndex = pkpy::py_cast<int>(vm, args[3]);
DrawCircle(x, y, radius, palette[paletteIndex]);
}
void Graphics::searchForDrawFunc(pkpy::VM* vm) {
updateFunction = vm->eval("update");
if(updateFunction == nullptr){
std::cout << "Can't find update function" << std::endl;
}
}
void Graphics::beginDraw() {
BeginTextureMode(virtualScreen);
}
void Graphics::endDraw() {
EndTextureMode();
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "raylib.h"
#include "pocketpy/vm.h"
#include <algorithm>
#include <vector>
@ -18,7 +19,6 @@ private:
Rectangle virtualScreenLocalBounds; // virtual screen bounds
RenderTexture2D virtualScreen; // actual pixel screen
std::vector<Color> palette;
private:
void renderVirtualScreen();
@ -31,15 +31,32 @@ public:
bool windowShouldClose;
static std::vector<Color> palette;
pkpy::PyObject* updateFunction;
public:
Graphics(int screenWidth, int screenHeight, int startupScale);
void draw();
void draw(pkpy::VM* vm);
void beginDraw();
void endDraw();
void loadPalette(std::string path);
int mouseX();
int mouseY();
void toggleFullScreen();
void bindMethods(pkpy::VM* vm);
void searchForDrawFunc(pkpy::VM* vm);
static void Clear(pkpy::VM* vm, pkpy::ArgsView args);
static void Pixel(pkpy::VM* vm, pkpy::ArgsView args);
static void Circle(pkpy::VM* vm, pkpy::ArgsView args);
};

View File

@ -1,10 +1,27 @@
//
// Created by Bobby Lucero on 4/20/24.
//
#include <fstream>
#include <sstream>
#include <random>
#include <cmath>
#include "Pycron.h"
#include "Utilities.h"
#include "Graphics/Graphics.h"
std::string loadFileToString(const std::string& filename) {
std::ifstream file(filename); // Open the file
std::stringstream buffer; // String stream to hold file content
if (file.is_open()) { // Check if file is open
buffer << file.rdbuf(); // Read the entire file into the buffer
file.close(); // Close the file
} else {
std::cerr << "Unable to open file: " << filename << std::endl;
}
return buffer.str(); // Return the content string
}
Pycron::Pycron() {
SetTraceLogLevel(LOG_ERROR);
@ -13,14 +30,21 @@ Pycron::Pycron() {
vm = new pkpy::VM();
bindMethods(vm);
graphics->bindMethods(vm);
std::string python = loadFileToString("../python/main.py");
graphics->beginDraw();
try {
pkpy::CodeObject_ code = vm->compile("return 'test'", "main.py", pkpy::EXEC_MODE, false);
pkpy::PyObject* obj = vm->_exec(code, vm->_main);
auto& str = pkpy::py_cast<pkpy::Str&>(vm, obj);
pkpy::CodeObject_ code = vm->compile(python, "main.py", pkpy::EXEC_MODE, false);
vm->_exec(code, vm->_main);
graphics->searchForDrawFunc(vm);
}catch (pkpy::Exception e) {
std::cout << e.summary() << std::endl;
}
graphics->endDraw();
}
@ -37,6 +61,38 @@ void Pycron::StartGameLoop() {
if (IsKeyPressed(KEY_F)) {
graphics->toggleFullScreen();
}
graphics->draw();
graphics->draw(vm);
}
}
}
void Pycron::bindMethods(pkpy::VM *vm) {
vm->bind(vm->builtins, "rnd(min: int, max: int) -> int", reinterpret_cast<pkpy::NativeFuncC>(getRandomNumber));
vm->bind(vm->builtins, "sin(num: float) -> float", reinterpret_cast<pkpy::NativeFuncC>(getSin));
vm->bind(vm->builtins, "cos(num: float) -> float", reinterpret_cast<pkpy::NativeFuncC>(getCos));
}
pkpy::PyObject* Pycron::getRandomNumber(pkpy::VM* vm, pkpy::ArgsView args) {
int min = pkpy::py_cast<int>(vm, args[0]);
int max = pkpy::py_cast<int>(vm, args[1]);
// Seed the random number generator with a random device
std::random_device rd;
std::mt19937 gen(rd());
// Define a uniform distribution for the range [min, max]
std::uniform_int_distribution<int> distribution(min, max);
// Generate a random number within the specified range
return pkpy::py_var(vm, distribution(gen));
}
pkpy::PyObject* Pycron::getSin(pkpy::VM* vm, pkpy::ArgsView args) {
auto num = pkpy::py_cast<double>(vm, args[0]);
return pkpy::py_var(vm, sin(num));
}
pkpy::PyObject* Pycron::getCos(pkpy::VM* vm, pkpy::ArgsView args) {
auto num = pkpy::py_cast<double>(vm, args[0]);
return pkpy::py_var(vm, cos(num));
}

View File

@ -17,6 +17,11 @@ public:
~Pycron();
void StartGameLoop();
void bindMethods(pkpy::VM* vm);
static pkpy::PyObject* getRandomNumber(pkpy::VM* vm, pkpy::ArgsView args);
static pkpy::PyObject* getSin(pkpy::VM* vm, pkpy::ArgsView args);
static pkpy::PyObject* getCos(pkpy::VM* vm, pkpy::ArgsView args);
};