Compare commits
10 Commits
efc9b0fe5e
...
8bb88afa6b
| Author | SHA1 | Date | |
|---|---|---|---|
| 8bb88afa6b | |||
| a76ba3ccb7 | |||
| bbb1b3dfa9 | |||
| 29e3ba208e | |||
| 611b6def6a | |||
| 028348691a | |||
| 9f04ac67ba | |||
| 5f1ed533cf | |||
| cf74541678 | |||
| 2b23a6a7f1 |
Binary file not shown.
38
python/blobs.py
Normal file
38
python/blobs.py
Normal file
@ -0,0 +1,38 @@
|
||||
from scene import Scene
|
||||
|
||||
# Palette class (inherits from scene)
|
||||
class Blobs(Scene):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.title = "Squares"
|
||||
self.t = 0
|
||||
self.dir = True
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
def draw(self):
|
||||
clear(0)
|
||||
|
||||
for i in range(width):
|
||||
for j in range(height):
|
||||
c = cos(i / 10) + (sin(j / 10) + 2)
|
||||
#c2 = cos(i / 5) + sin(j / 5)
|
||||
pixel(i, j, 2 * c + self.t)
|
||||
|
||||
self.t += (1/5) * (1 if self.dir else - 1)
|
||||
|
||||
if(self.t > 64):
|
||||
self.t = 64
|
||||
self.dir = not self.dir
|
||||
|
||||
if(self.t < 0):
|
||||
self.t = 0
|
||||
self.dir = not self.dir
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
from scene import Scene
|
||||
from particles import Particles
|
||||
from triangles import Triangles
|
||||
from squares import Squares
|
||||
from blobs import Blobs
|
||||
from threeD import ThreeD
|
||||
|
||||
# Palette class (inherits from scene)
|
||||
class Palette(Scene):
|
||||
@ -17,7 +20,7 @@ class Palette(Scene):
|
||||
|
||||
for i in range(8):
|
||||
for j in range(8):
|
||||
rectangle(10 + (i * 20), 10 + (j * 20), 18, 18, (j * 8 + i))
|
||||
rect(10 + (i * 20), 10 + (j * 20), 18, 18, (j * 8 + i))
|
||||
text(str(j * 8 + i), 11 + (i * 20), 10 + (j * 20), 63)
|
||||
|
||||
class RGBTest(Scene):
|
||||
@ -26,11 +29,9 @@ class RGBTest(Scene):
|
||||
self.title = "RGB To Palette"
|
||||
|
||||
|
||||
scenes = [Particles(), Triangles(), Palette()]
|
||||
scenes = [ ThreeD(), Particles(), Squares(), Triangles(), Palette(), Blobs()]
|
||||
current_scene = 0
|
||||
|
||||
|
||||
|
||||
KEY_T = 84
|
||||
|
||||
switch = False
|
||||
@ -51,9 +52,5 @@ def update():
|
||||
scenes[current_scene].update()
|
||||
scenes[current_scene].draw()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
text("T to change scene", 255, 1,31)
|
||||
|
||||
|
||||
29
python/mechanical.py
Normal file
29
python/mechanical.py
Normal file
@ -0,0 +1,29 @@
|
||||
from scene import Scene
|
||||
|
||||
s = 128
|
||||
s2 = 120-12
|
||||
l = 15
|
||||
a = 80
|
||||
t = 0
|
||||
|
||||
# Palette class (inherits from scene)
|
||||
class Mechanical(Scene):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.title = "Squares"
|
||||
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
def draw(self):
|
||||
clear(0)
|
||||
rect(120 - s/2, 68 - s/2, s, s, 14)
|
||||
triangle(120-s/2, 68 - s/2, 120-s/2, 68+s/2,
|
||||
120 + s/2, 68+s/2, 15)
|
||||
line(119 + s / 2, 68 + s / 2, 119 + s2 / 2, 68 - s2/2, 15)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -102,7 +102,7 @@ class Particles(Scene):
|
||||
if(p.size < 0):
|
||||
self.waterParts.remove(p)
|
||||
|
||||
|
||||
|
||||
|
||||
if(mouse(0)):
|
||||
rad = sin(self.counter * 0.01) * 50
|
||||
@ -151,7 +151,3 @@ class Particles(Scene):
|
||||
# triangle(mouseX, mouseY, x2, y2, x3, y3, 9)
|
||||
|
||||
# lineTri(mouseX, mouseY, x2, y2, x3, y3, 8)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
python/squares.py
Normal file
25
python/squares.py
Normal file
@ -0,0 +1,25 @@
|
||||
from scene import Scene
|
||||
|
||||
# Palette class (inherits from scene)
|
||||
class Squares(Scene):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.title = "Squares"
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
def draw(self):
|
||||
clear(0)
|
||||
|
||||
for i in range(50):
|
||||
for j in range(27):
|
||||
rect(8 * i, 8 * j, 8, 8, (i + j) % 64)
|
||||
rectBorder(8 * i, 8 * j, 8, 8, (i + j + 1) % 64)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
165
python/threeD.py
Normal file
165
python/threeD.py
Normal file
@ -0,0 +1,165 @@
|
||||
from scene import Scene
|
||||
from triangles import draw_line
|
||||
import math
|
||||
|
||||
# Palette class (inherits from scene)
|
||||
class ThreeD(Scene):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.title = "Squares"
|
||||
self.t = 0
|
||||
|
||||
self.x = 0.01
|
||||
self.y = 0
|
||||
self.z = 0
|
||||
|
||||
self.a = 10
|
||||
self.b = 28
|
||||
self.c = 8.0/3.0
|
||||
|
||||
self.scale = 5
|
||||
|
||||
self.focal_length = 800
|
||||
self.screen_width = width * 4
|
||||
self.screen_height = height * 4
|
||||
self.lines = []
|
||||
|
||||
self.points = []
|
||||
|
||||
self.gradient = [4, 8, 6, 15, 18, 19, 26, 25, 24, 23, 16, 23, 22, 7, 5]
|
||||
self.gradient = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
|
||||
|
||||
def update(self):
|
||||
self.t += 0.00002
|
||||
|
||||
|
||||
if(len(self.points) > 1200):
|
||||
return
|
||||
|
||||
dx = (self.a * (self.y - self.x)) * self.t
|
||||
dy = (self.x * (self.b - self.z) - self.y) * self.t
|
||||
dz = (self.x * self.y - self.c * self.z) * self.t
|
||||
self.x += dx
|
||||
self.y += dy
|
||||
self.z += dz
|
||||
|
||||
self.points.append((self.x, self.y, self.z))
|
||||
|
||||
def line3D(self, x1, y1, z1, x2, y2, z2, c):
|
||||
self.lines.append(((x1, y1, z1), (x2, y2, z2), c))
|
||||
|
||||
|
||||
def draw(self):
|
||||
|
||||
self.lines.clear()
|
||||
clear(0)
|
||||
for i in range(len(self.points)):
|
||||
size = len(self.points)
|
||||
|
||||
if(i < size - 1):
|
||||
x, y, z = self.points[i]
|
||||
x2, y2, z2 = self.points[i + 1]
|
||||
|
||||
x *= self.scale
|
||||
y *= self.scale
|
||||
z *= self.scale
|
||||
x2 *= self.scale
|
||||
y2 *= self.scale
|
||||
z2 *= self.scale
|
||||
|
||||
self.line3D(x, y, z, x2, y2, z2, self.gradient[int(i / 5) % len(self.gradient)])
|
||||
|
||||
self.render_scene(self.focal_length, self.screen_width, self.screen_height, 0, self.t*500, self.t * 200, 0, 0, 300)
|
||||
|
||||
|
||||
def rotate_point(self, x, y, z, angle_x, angle_y, angle_z):
|
||||
"""Rotates a point around the X, Y, and Z axes."""
|
||||
# Rotation around the X axis
|
||||
cos_x, sin_x = math.cos(angle_x), math.sin(angle_x)
|
||||
y, z = y * cos_x - z * sin_x, y * sin_x + z * cos_x
|
||||
|
||||
# Rotation around the Y axis
|
||||
cos_y, sin_y = math.cos(angle_y), math.sin(angle_y)
|
||||
x, z = x * cos_y + z * sin_y, -x * sin_y + z * cos_y
|
||||
|
||||
# Rotation around the Z axis
|
||||
cos_z, sin_z = math.cos(angle_z), math.sin(angle_z)
|
||||
x, y = x * cos_z - y * sin_z, x * sin_z + y * cos_z
|
||||
|
||||
return x, y, z
|
||||
|
||||
def project_point(self, x, y, z, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z):
|
||||
|
||||
x, y, z = self.rotate_point(x, y, z, angle_x, angle_y, angle_z)
|
||||
|
||||
# Apply translation
|
||||
x += translate_x
|
||||
y += translate_y
|
||||
z += translate_z
|
||||
|
||||
"""Projects a 3D point onto a 2D screen using perspective projection."""
|
||||
if z == 0:
|
||||
z = 0.001 # Avoid division by zero
|
||||
|
||||
# Perspective projection formula
|
||||
screen_x = (x * focal_length) / z
|
||||
screen_y = (y * focal_length) / z
|
||||
|
||||
# Translate to screen coordinates (centered)
|
||||
screen_x += screen_width / 2
|
||||
screen_y += screen_height / 2
|
||||
|
||||
return screen_x, screen_y
|
||||
|
||||
def z_sort_lines(self, lines):
|
||||
"""Sorts lines based on their average Z values for depth ordering."""
|
||||
return sorted(lines, key=lambda line: (line[0][2] + line[1][2]) / 2, reverse=True)
|
||||
|
||||
def draw_3d_line(self, x1, y1, z1, x2, y2, z2, focal_length, screen_width, screen_height, color, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z):
|
||||
"""Draws a 3D line projected onto a 2D screen."""
|
||||
# Project the endpoints
|
||||
screen_x1, screen_y1 = self.project_point(x1, y1, z1, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z)
|
||||
screen_x2, screen_y2 = self.project_point(x2, y2, z2, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z)
|
||||
|
||||
screen_x12, screen_y12 = self.project_point(x1 + 5, y1, z1, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z)
|
||||
screen_x22, screen_y22 = self.project_point(x2 + 5, y2, z2, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z)
|
||||
|
||||
# Use the renderer to draw the line on the screen
|
||||
|
||||
line(screen_x1 / 4, screen_y1 / 4, screen_x2 / 4, screen_y2 / 4, color)
|
||||
|
||||
|
||||
def render_scene(self, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z):
|
||||
"""Renders the 3D lines in the scene with perspective projection and Z-sorting."""
|
||||
# Sort the lines by Z value (depth)
|
||||
sorted_lines = self.z_sort_lines(self.lines)
|
||||
i = 0
|
||||
# Draw each line
|
||||
for line in sorted_lines:
|
||||
(x1, y1, z1), (x2, y2, z2), c = line
|
||||
self.draw_3d_line(x1, y1, z1, x2, y2, z2, focal_length, screen_width, screen_height, c, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z)
|
||||
i += 1
|
||||
|
||||
# Example usage
|
||||
# renderer is an object that has a draw_line(x1, y1, x2, y2) function
|
||||
liines = [
|
||||
((-50, -50, -50), (50, -50, -50)),
|
||||
((50, -50, -50), (50, 50, -50)),
|
||||
((50, 50, -50), (-50, 50, -50)),
|
||||
((-50, 50, -50), (-50, -50, -50)),
|
||||
((-50, -50, 50), (50, -50, 50)),
|
||||
((50, -50, 50), (50, 50, 50)),
|
||||
((50, 50, 50), (-50, 50, 50)),
|
||||
((-50, 50, 50), (-50, -50, 50)),
|
||||
((-50, -50, -50), (-50, -50, 50)),
|
||||
((50, -50, -50), (50, -50, 50)),
|
||||
((50, 50, -50), (50, 50, 50)),
|
||||
((-50, 50, -50), (-50, 50, 50)),
|
||||
]
|
||||
|
||||
|
||||
|
||||
# Assuming you have a renderer object
|
||||
|
||||
@ -77,7 +77,7 @@ class Triangles(Scene):
|
||||
y = rnd(0, height)
|
||||
c = 0
|
||||
if(rnd(0,9) < 5):
|
||||
c = get_pixel(x -3 ,y-3)
|
||||
c = getPixel(x -3 ,y-3)
|
||||
else:
|
||||
c = 0
|
||||
|
||||
|
||||
BIN
resources/LineNumberDetailCenter.png
Normal file
BIN
resources/LineNumberDetailCenter.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 91 B |
BIN
resources/LineNumberDetailLeft.png
Normal file
BIN
resources/LineNumberDetailLeft.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 117 B |
BIN
resources/LineNumberDetailRight.png
Normal file
BIN
resources/LineNumberDetailRight.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 B |
@ -64,7 +64,23 @@ void Graphics::draw(StateManager* stateManager) {
|
||||
void Graphics::copyBufferToGPU() {
|
||||
Color* pixel_data = LoadImageColors(m_virtualScreenImageBuffer);
|
||||
for (int i = 0; i < m_screenWidth * m_screenHeight; ++i) {
|
||||
pixel_data[i] = GetColor(m_paletteByID[m_virtualScreenColorBuffer[i]]);
|
||||
uint32_t rgb = m_paletteByID[m_virtualScreenColorBuffer[i]];
|
||||
uint8_t r = rgb >> 16 & 0xFF;
|
||||
uint8_t g = rgb >> 8 & 0xFF;
|
||||
uint8_t b = rgb & 0xFF;
|
||||
|
||||
double dR = (double)r * 0.2126;
|
||||
double dG = (double)g * 0.7152;
|
||||
double dB = (double)b * 0.0722;
|
||||
|
||||
int gray = (int)(dR + dG + dB);
|
||||
double naiveGray = (r + g + b) / 3.0;
|
||||
//gray = (int)naiveGray;
|
||||
unsigned int out = 255;
|
||||
out |= gray << 8;
|
||||
out |= gray << 16;
|
||||
out |= gray << 24;
|
||||
pixel_data[i] = GetColor(rgb);
|
||||
}
|
||||
UpdateTexture(m_virtualScreen.texture, pixel_data);
|
||||
UnloadImageColors(pixel_data);
|
||||
@ -181,7 +197,7 @@ void Graphics::bindMethods(pkpy::VM *vm) {
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(vm->builtins, "get_pixel(x: int, y: int) -> int", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
||||
vm->bind(vm->builtins, "getPixel(x: int, y: int) -> int", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
||||
float x = pkpy::py_cast<float>(vm, args[0]);
|
||||
float y = pkpy::py_cast<float>(vm, args[1]);
|
||||
|
||||
@ -197,7 +213,7 @@ void Graphics::bindMethods(pkpy::VM *vm) {
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(vm->builtins, "rectangle(x: int, y: int, width: int, height: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
||||
vm->bind(vm->builtins, "rect(x: int, y: int, width: int, height: int, color: int)", [this](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 width = pkpy::py_cast<float>(vm, args[2]);
|
||||
@ -207,6 +223,16 @@ void Graphics::bindMethods(pkpy::VM *vm) {
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(vm->builtins, "rectBorder(x: int, y: int, width: int, height: int, color: int)", [this](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 width = pkpy::py_cast<float>(vm, args[2]);
|
||||
float height = pkpy::py_cast<float>(vm, args[3]);
|
||||
float paletteIndex = pkpy::py_cast<float>(vm, args[4]);
|
||||
this->RectBorder(x, y, width, height, paletteIndex);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(vm->builtins, "triangle(x1: int, y1: int, x2: int, y2: int, x3: int, y3: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
||||
float x1 = pkpy::py_cast<float>(vm, args[0]);
|
||||
float y1 = pkpy::py_cast<float>(vm, args[1]);
|
||||
@ -219,6 +245,16 @@ void Graphics::bindMethods(pkpy::VM *vm) {
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(vm->builtins, "line(x1: int, y1: int, x2: int, y2: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
||||
float x1 = pkpy::py_cast<float>(vm, args[0]);
|
||||
float y1 = pkpy::py_cast<float>(vm, args[1]);
|
||||
float x2 = pkpy::py_cast<float>(vm, args[2]);
|
||||
float y2 = pkpy::py_cast<float>(vm, args[3]);
|
||||
float paletteIndex = pkpy::py_cast<float>(vm, args[4]);
|
||||
this->Line(x1, y1, x2, y2, paletteIndex);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(vm->builtins, "text(t: string, x: int, y: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
||||
pkpy::PyObject* func_str = vm->builtins->attr("str");
|
||||
pkpy::PyObject* result = vm->call(func_str, args[0]);
|
||||
@ -243,7 +279,6 @@ void Graphics::Clear(int paletteIndex) {
|
||||
void Graphics::Pixel(int x, int y, int paletteIndex) {
|
||||
paletteIndex = Clamp(paletteIndex, 0, m_paletteByID.size() - 1);
|
||||
if(x < 0 || y < 0 || x >= m_screenWidth || y >= m_screenHeight) return;
|
||||
|
||||
m_virtualScreenColorBuffer[y * m_screenWidth + x] = paletteIndex;
|
||||
}
|
||||
|
||||
@ -389,14 +424,24 @@ void Graphics::RectBorder(int x, int y, int width, int height, int paletteIndex)
|
||||
}
|
||||
|
||||
void Graphics::Text(const std::string& s, int x, int y, int paletteIndex) {
|
||||
int currentX = 0;
|
||||
int currentY = y;
|
||||
|
||||
for (int i = 0; i < s.size(); ++i) {
|
||||
char c = s[i];
|
||||
std::string bitData = m_currentFont->GetCharData((int)c);
|
||||
for (int j = 0; j < bitData.size(); ++j) {
|
||||
if(bitData[j] == '1')
|
||||
Pixel(x + (j % m_currentFont->GetWidth()) + ((m_currentFont->GetWidth() + 1) * i), y + (j / m_currentFont->GetWidth()), paletteIndex);
|
||||
// Handle new lines
|
||||
if(c != '\n') {
|
||||
std::string bitData = m_currentFont->GetCharData((int) c);
|
||||
for (int j = 0; j < bitData.size(); ++j) {
|
||||
if (bitData[j] == '1'){
|
||||
Pixel(x + (j % m_currentFont->GetWidth()) + ((m_currentFont->GetWidth() + 1) * currentX),currentY + (j / m_currentFont->GetWidth()), paletteIndex);
|
||||
}
|
||||
|
||||
}
|
||||
currentX++;
|
||||
}else{
|
||||
currentX = 0;
|
||||
currentY += m_currentFont->GetHeight() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,6 +58,12 @@ void Pycron::StartGameLoop() {
|
||||
m_stateManager->OnKeyPressed(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (int button = MouseButton::MOUSE_BUTTON_LEFT; button < MouseButton::MOUSE_BUTTON_BACK; ++button) {
|
||||
if(IsMouseButtonPressed(button)){
|
||||
m_stateManager->OnMousePressed(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +71,7 @@ void Pycron::bindMethods() {
|
||||
m_vm->bind(m_vm->builtins, "rnd(min: float, max: float) -> int", getRandomNumber);
|
||||
m_vm->bind(m_vm->builtins, "sin(num: float) -> float", getSin);
|
||||
m_vm->bind(m_vm->builtins, "cos(num: float) -> float", getCos);
|
||||
m_vm->bind(m_vm->builtins, "tan(num: float) -> float", getTan);
|
||||
m_vm->bind(m_vm->builtins, "fps() -> int", getFPS);
|
||||
m_vm->bind(m_vm->builtins, "keyp(keycode: int) -> bool", getKeyPressed);
|
||||
m_vm->bind(m_vm->builtins, "key(keycode: int) -> bool", getKeyDown);
|
||||
@ -131,6 +138,11 @@ pkpy::PyObject* Pycron::getCos(pkpy::VM* vm, pkpy::ArgsView args) {
|
||||
return pkpy::py_var(vm, cos(num));
|
||||
}
|
||||
|
||||
pkpy::PyObject* Pycron::getTan(pkpy::VM* vm, pkpy::ArgsView args) {
|
||||
auto num = pkpy::py_cast<double>(vm, args[0]);
|
||||
return pkpy::py_var(vm, tan(num));
|
||||
}
|
||||
|
||||
pkpy::PyObject* Pycron::getFPS(pkpy::VM* vm, pkpy::ArgsView args) {
|
||||
return pkpy::py_var(vm, GetFPS());
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ public:
|
||||
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);
|
||||
static pkpy::PyObject* getTan(pkpy::VM* vm, pkpy::ArgsView args);
|
||||
static pkpy::PyObject* getFPS(pkpy::VM* vm, pkpy::ArgsView args);
|
||||
static pkpy::PyObject* getKeyPressed(pkpy::VM* vm, pkpy::ArgsView args);
|
||||
static pkpy::PyObject* getKeyDown(pkpy::VM* vm, pkpy::ArgsView args);
|
||||
|
||||
@ -13,5 +13,6 @@ public:
|
||||
virtual void OnExit() = 0;
|
||||
virtual void OnKeyPressed(int key) = 0;
|
||||
virtual void OnCharPressed(char character) = 0;
|
||||
virtual void OnMousePressed(int button) = 0;
|
||||
|
||||
};
|
||||
|
||||
@ -15,7 +15,6 @@ StateManager::~StateManager() {
|
||||
m_currentState = nullptr;
|
||||
delete m_gameState;
|
||||
delete m_editorState;
|
||||
delete m_graphics;
|
||||
}
|
||||
|
||||
|
||||
@ -31,13 +30,9 @@ void StateManager::ChangeState(StateManager::StateType state) {
|
||||
}
|
||||
|
||||
if(m_currentState){
|
||||
if(m_currentState == m_gameState){
|
||||
m_currentState->OnEnter();
|
||||
if(m_gameState->m_errorThrown){
|
||||
m_pycron->m_graphics->Text(m_gameState->m_previousError, 2, 2, 59);
|
||||
}
|
||||
}else{
|
||||
m_currentState->OnEnter();
|
||||
m_currentState->OnEnter();
|
||||
if(m_currentState == m_gameState && m_gameState->m_errorThrown){
|
||||
m_pycron->m_graphics->Text(m_gameState->m_previousError, 2, 2, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -53,13 +48,8 @@ void StateManager::Draw() {
|
||||
}
|
||||
|
||||
if(m_currentState){
|
||||
if(m_currentState == m_gameState){
|
||||
if(m_gameState->m_errorThrown){
|
||||
m_pycron->m_graphics->Text(m_gameState->m_previousError, 2, 2, 59);
|
||||
}
|
||||
else{
|
||||
m_currentState->Draw();
|
||||
}
|
||||
if(m_currentState == m_gameState && m_gameState->m_errorThrown){
|
||||
m_pycron->m_graphics->Text(m_gameState->m_previousError, 2, 2, 4);
|
||||
}
|
||||
else{
|
||||
m_currentState->Draw();
|
||||
@ -75,3 +65,7 @@ void StateManager::OnCharPressed(char c) {
|
||||
m_currentState->OnCharPressed(c);
|
||||
}
|
||||
|
||||
void StateManager::OnMousePressed(int button) {
|
||||
m_currentState->OnMousePressed(button);
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ public:
|
||||
|
||||
void OnKeyPressed(int key);
|
||||
void OnCharPressed(char c);
|
||||
void OnMousePressed(int button);
|
||||
|
||||
void RequestLoadGame();
|
||||
void RequestRunGame();
|
||||
|
||||
@ -7,23 +7,27 @@
|
||||
#include <algorithm>
|
||||
#include <raylib.h>
|
||||
#include "EditorState.h"
|
||||
#include <math.h>
|
||||
#include "../../Utilities.h"
|
||||
|
||||
|
||||
|
||||
EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphics(graphics){
|
||||
m_pythonTokenizer = new PythonTokenizer();
|
||||
|
||||
Token a(TokenType::Keyword, "Test");
|
||||
|
||||
std::string randomSource = Pycron::loadFileToString("../python/triangles.py");
|
||||
std::string randomSource = Pycron::loadFileToString("../python/threeD.py");
|
||||
//randomSource = Pycron::loadFileToString("../src/States/Editor/EditorState.cpp");
|
||||
|
||||
m_editorFrame = m_graphics->loadImage("../resources/EditorFrame.png");
|
||||
m_LineNumberDetailLeft = m_graphics->loadImage("../resources/LineNumberDetailLeft.png");
|
||||
m_LineNumberDetailCenter = m_graphics->loadImage("../resources/LineNumberDetailCenter.png");
|
||||
m_LineNumberDetailRight = m_graphics->loadImage("../resources/LineNumberDetailRight.png");
|
||||
|
||||
m_baseBackgroundColor = 56;
|
||||
m_shadowColor = 28;
|
||||
m_baseTextColor = 42;
|
||||
m_lineNumberBackgroundColor = 57;
|
||||
m_lineNumberTextColor = 6;
|
||||
m_lineNumberTextColor = 7;
|
||||
m_unknownTextColor = 4;
|
||||
m_identifierTextColor = 63;
|
||||
m_keywordTextColor = 31;
|
||||
@ -49,6 +53,9 @@ EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphic
|
||||
m_textWindowXOffset = 26;
|
||||
m_textWindowYOffset = 20;
|
||||
|
||||
m_lineNumberWindowXOffset = 3;
|
||||
m_lineNumberWindowYOffset = 20;
|
||||
|
||||
m_textWindowWidth = 330;
|
||||
m_textWindowHeight = 168;
|
||||
|
||||
@ -57,15 +64,12 @@ EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphic
|
||||
m_scrollX = 0;
|
||||
m_scrollY = 0;
|
||||
|
||||
m_lastFurthestColumn = 0;
|
||||
|
||||
m_cursorBlinkTimer = 0;
|
||||
m_cursorBlinkInterval = 0.5;
|
||||
|
||||
|
||||
|
||||
std::cout << (int)m_charWidth << "!\n";
|
||||
|
||||
m_width = (int)(m_textBounds->width / m_charWidth);
|
||||
std::cout << m_textBounds->width << " : " << (int)m_charWidth << " = " << m_width;
|
||||
m_height = (int)(m_textBounds->height / m_charHeight);
|
||||
|
||||
m_characterBuffer = std::vector<char>(m_width * m_height);
|
||||
@ -93,12 +97,11 @@ void EditorState::Draw() {
|
||||
if(m_dirty){
|
||||
Clear();
|
||||
m_dirty = false;
|
||||
|
||||
int cursorPos = m_scrollY + m_cursorY;
|
||||
|
||||
for (int i = 0; i < m_height; ++i) {
|
||||
|
||||
// if(i > m_text.size() - 1) break;
|
||||
// Line numbers TODO: maybe not have this as part of the buffer, instead as a custom bar. (Allows for more custom functionality such as bookmarks)
|
||||
// std::string lineNumber = std::to_string(std::abs(m_cursorY - i));
|
||||
// if(i == m_cursorY) lineNumber = std::to_string(m_cursorY);
|
||||
int index = i + m_scrollY;
|
||||
|
||||
if(index > m_text.size() - 1) break;
|
||||
@ -107,6 +110,23 @@ void EditorState::Draw() {
|
||||
auto tokens = m_pythonTokenizer->tokenizeLine(m_text[index]);
|
||||
|
||||
int currentPos = 0;
|
||||
if(index == cursorPos){
|
||||
std::string lineNumber = std::to_string(cursorPos);
|
||||
int offset = std::max((int)lineNumber.size() - 3, 0);
|
||||
bool collision = false;
|
||||
for (int j = 0; j < offset; ++j) {
|
||||
if(m_text[index].size() < offset) break;
|
||||
if(m_text[index][j] != ' '){
|
||||
collision = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!collision) offset = 0;
|
||||
currentPos = offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (int j = 0; j < tokens.size(); ++j) {
|
||||
int color = m_baseTextColor;
|
||||
TokenType type = tokens[j].type;
|
||||
@ -149,9 +169,25 @@ void EditorState::Draw() {
|
||||
|
||||
// Draw the cursor
|
||||
if(m_cursorVisible) {
|
||||
int x = m_cursorX * m_charWidth + m_textBounds->x;
|
||||
int currentLine = m_scrollY + m_cursorY;
|
||||
std::string lineNumber = std::to_string(currentLine);
|
||||
int offset = std::max((int)lineNumber.size() - 3, 0);
|
||||
|
||||
bool collision = false;
|
||||
for (int i = 0; i < offset; ++i) {
|
||||
if(m_text[currentLine].size() < offset) break;
|
||||
if(m_text[currentLine][i] != ' '){
|
||||
collision = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!collision) offset = 0;
|
||||
|
||||
int x = (m_cursorX + offset) * m_charWidth + m_textBounds->x;
|
||||
int y = m_cursorY * m_charHeight + m_textBounds->y;
|
||||
int index = m_cursorY * m_width + m_cursorX;
|
||||
|
||||
int index = m_cursorY * m_width + (m_cursorX + offset);
|
||||
|
||||
if(m_drawShadows) m_graphics->Rect(x, y, m_charWidth + 1, m_charHeight + 1, m_shadowColor);
|
||||
m_graphics->Rect(x - 1, y - 1, m_charWidth + 1, m_charHeight + 1, m_foregroundIndexBuffer[index]);
|
||||
@ -165,10 +201,54 @@ void EditorState::Draw() {
|
||||
m_cursorVisible = !m_cursorVisible;
|
||||
m_cursorBlinkTimer = 0.0;
|
||||
}
|
||||
|
||||
// Editor frame image
|
||||
m_graphics->Img(m_editorFrame, 0, 0);
|
||||
|
||||
// Line Numbers
|
||||
for (int i = 0; i < m_height; ++i) {
|
||||
|
||||
if(i + m_scrollY >= m_text.size()) return;
|
||||
|
||||
int lineNum = i + m_scrollY + 1;
|
||||
std::string lineNumber = std::to_string(lineNum);
|
||||
int delta = std::max(0, 3 - (int)lineNumber.size());
|
||||
lineNumber = std::string(delta, ' ') + lineNumber;
|
||||
lineNumber = lineNumber.substr(lineNumber.size() - 3);
|
||||
|
||||
int highlight = i == m_cursorY ? m_lineNumberTextColor : m_commentTextColor;
|
||||
|
||||
if(lineNum > 999){
|
||||
lineNumber[0] = ' ';
|
||||
int dotX = m_lineNumberWindowXOffset;
|
||||
int dotY = m_lineNumberWindowYOffset + (i * m_charHeight) + m_graphics->GetCurrentFontHeight() - 1;
|
||||
m_graphics->Pixel(dotX, dotY, highlight);
|
||||
m_graphics->Pixel(dotX + 2, dotY, highlight);
|
||||
m_graphics->Pixel(dotX + 4, dotY, highlight);
|
||||
}
|
||||
|
||||
m_graphics->Text(lineNumber, m_lineNumberWindowXOffset, m_lineNumberWindowYOffset + (i * m_charHeight), highlight);
|
||||
}
|
||||
|
||||
// Line Number Detail
|
||||
if(m_scrollY + 1 + m_cursorY > 999){
|
||||
int lineNum = m_scrollY + 1 + m_cursorY;
|
||||
std::string lineNumber = std::to_string(lineNum);
|
||||
|
||||
int lineNumberDetailXOffset = 3;
|
||||
int lineNumberDetailYOffset = 3;
|
||||
|
||||
int yOffset = m_lineNumberWindowYOffset - lineNumberDetailYOffset + (m_cursorY * (m_graphics->GetCurrentFontHeight() + 1));
|
||||
|
||||
m_graphics->Img(m_LineNumberDetailLeft, m_lineNumberWindowXOffset - lineNumberDetailXOffset, yOffset);
|
||||
for (int i = 0; i < lineNumber.size(); ++i) {
|
||||
int offset = m_lineNumberWindowXOffset + (i * 6);
|
||||
m_graphics->Img(m_LineNumberDetailCenter, offset, yOffset);
|
||||
}
|
||||
m_graphics->Img(m_LineNumberDetailRight, m_lineNumberWindowXOffset + (lineNumber.size() * 6), yOffset);
|
||||
m_graphics->Text(lineNumber, m_lineNumberWindowXOffset, yOffset + lineNumberDetailYOffset, m_lineNumberTextColor);
|
||||
}
|
||||
|
||||
|
||||
//m_graphics->RectBorder(m_textBounds->x, m_textBounds->y, m_textBounds->width, m_textBounds->height, 23);
|
||||
|
||||
}
|
||||
@ -182,39 +262,116 @@ void EditorState::OnExit() {
|
||||
}
|
||||
|
||||
void EditorState::OnKeyPressed(int key) {
|
||||
if(key == KEY_LEFT && m_cursorX > 0){
|
||||
m_cursorX--;
|
||||
}
|
||||
if(key == KEY_RIGHT && m_cursorX < m_width - 1){
|
||||
m_cursorX++;
|
||||
}
|
||||
if(key == KEY_UP){
|
||||
if( m_cursorY > 0)
|
||||
{
|
||||
m_cursorY--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_scrollY > 0)
|
||||
|
||||
|
||||
if (key == KEY_LEFT) {
|
||||
if (m_cursorX > 0) {
|
||||
m_cursorX--;
|
||||
m_lastFurthestColumn = m_cursorX;
|
||||
} else {
|
||||
if( m_cursorY > 0)
|
||||
{
|
||||
m_cursorY--;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scrollY--;
|
||||
}
|
||||
|
||||
if(m_scrollY < 0){
|
||||
m_scrollY = 0;
|
||||
}else{
|
||||
|
||||
m_cursorX = (int)m_text[m_scrollY + m_cursorY].size();
|
||||
m_lastFurthestColumn = m_cursorX;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (key == KEY_RIGHT) {
|
||||
if (m_cursorX < std::min(m_width - 1, (int) m_text[m_scrollY + m_cursorY].size())) {
|
||||
m_cursorX++;
|
||||
m_lastFurthestColumn = m_cursorX;
|
||||
} else {
|
||||
m_cursorX = 0;
|
||||
m_lastFurthestColumn = m_cursorX;
|
||||
|
||||
if(m_cursorY < std::min(m_height - 1, static_cast<int>(m_text.size()) - 1))
|
||||
{
|
||||
m_cursorY++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scrollY++;
|
||||
}
|
||||
|
||||
if(m_scrollY + m_height > m_text.size() - 1){
|
||||
m_scrollY = m_text.size() - 1 - m_height;
|
||||
}
|
||||
|
||||
if(m_scrollY < 0){
|
||||
m_scrollY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(key == KEY_UP){
|
||||
if(IsKeyDown(KEY_LEFT_SHIFT)){
|
||||
m_scrollY -= m_height;
|
||||
bool success = m_scrollY > 0;
|
||||
if(!success && m_cursorY > 0) m_cursorY--;
|
||||
}else{
|
||||
if( m_cursorY > 0)
|
||||
{
|
||||
m_cursorY--;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scrollY--;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_scrollY < 0){
|
||||
m_scrollY = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(key == KEY_DOWN )
|
||||
{
|
||||
if(m_cursorY < std::min(m_height - 1, static_cast<int>(m_text.size()) - 1))
|
||||
{
|
||||
m_cursorY++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_scrollY + m_height < m_text.size())
|
||||
if(IsKeyDown(KEY_LEFT_SHIFT)){
|
||||
m_scrollY += m_height;
|
||||
bool success = m_scrollY + m_height <= m_text.size() - 1;
|
||||
if(!success && m_cursorY < std::min(m_height - 1, static_cast<int>(m_text.size()) - 1)) m_cursorY++;
|
||||
}else{
|
||||
if(m_cursorY < std::min(m_height - 1, static_cast<int>(m_text.size()) - 1))
|
||||
{
|
||||
m_cursorY++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scrollY++;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_scrollY + m_height > m_text.size() - 1){
|
||||
m_scrollY = m_text.size() - 1 - m_height;
|
||||
}
|
||||
|
||||
if(m_scrollY < 0){
|
||||
m_scrollY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int currentLineLength = (int)m_text[m_scrollY + m_cursorY].size();
|
||||
|
||||
if(currentLineLength <= m_cursorX){
|
||||
m_cursorX = currentLineLength;
|
||||
}else{
|
||||
m_cursorX = std::min(m_lastFurthestColumn, currentLineLength);
|
||||
};
|
||||
|
||||
|
||||
m_cursorVisible = true;
|
||||
m_cursorBlinkTimer = 0;
|
||||
@ -228,6 +385,31 @@ void EditorState::OnCharPressed(char character){
|
||||
|
||||
}
|
||||
|
||||
void EditorState::OnMousePressed(int button) {
|
||||
int x = m_graphics->mouseX();
|
||||
int y = m_graphics->mouseY();
|
||||
|
||||
if(Utilities::RectContainsPoint(m_textBounds, x, y)){
|
||||
x -= m_textWindowXOffset;
|
||||
y -= m_textWindowYOffset;
|
||||
|
||||
x /= m_charWidth;
|
||||
y /= m_charHeight;
|
||||
|
||||
m_cursorY = std::min((int)m_text.size() - 1, y);
|
||||
m_cursorX = std::min((int)m_text[m_cursorY + m_scrollY].size(), x);
|
||||
|
||||
m_lastFurthestColumn = m_cursorX;
|
||||
|
||||
|
||||
|
||||
m_cursorVisible = true;
|
||||
m_cursorBlinkTimer = 0;
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EditorState::Clear() {
|
||||
for (int i = 0; i < m_width * m_height; ++i) {
|
||||
m_characterBuffer[i] = ' ';
|
||||
@ -236,6 +418,7 @@ void EditorState::Clear() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EditorState::Text(const std::string &text, int x, int y, int fg, int bg) {
|
||||
for (int i = 0; i < text.size(); ++i) {
|
||||
int charX = x + i;
|
||||
@ -253,7 +436,6 @@ void EditorState::Text(const std::string &text, int x, int y, int fg, int bg) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EditorState::LoadStringToBuffer(const std::string &text) {
|
||||
m_text.clear();
|
||||
|
||||
@ -272,7 +454,7 @@ void EditorState::LoadStringToBuffer(const std::string &text) {
|
||||
for (const auto& line : lines) {
|
||||
m_text.push_back(line);
|
||||
}
|
||||
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ public:
|
||||
void OnExit() override;
|
||||
void OnKeyPressed(int key) override;
|
||||
void OnCharPressed(char character) override;
|
||||
void OnMousePressed(int button) override;
|
||||
|
||||
private:
|
||||
pkpy::VM* m_vm;
|
||||
@ -29,6 +30,10 @@ private:
|
||||
// Editor images
|
||||
PycronImage* m_editorFrame;
|
||||
|
||||
PycronImage* m_LineNumberDetailLeft;
|
||||
PycronImage* m_LineNumberDetailCenter;
|
||||
PycronImage* m_LineNumberDetailRight;
|
||||
|
||||
// Size of the character in pixels
|
||||
uint8_t m_charWidth, m_charHeight;
|
||||
|
||||
@ -71,6 +76,9 @@ private:
|
||||
int m_textWindowXOffset;
|
||||
int m_textWindowYOffset;
|
||||
|
||||
int m_lineNumberWindowXOffset;
|
||||
int m_lineNumberWindowYOffset;
|
||||
|
||||
int m_textWindowWidth;
|
||||
int m_textWindowHeight;
|
||||
|
||||
@ -79,6 +87,8 @@ private:
|
||||
int m_scrollX;
|
||||
int m_scrollY;
|
||||
|
||||
int m_lastFurthestColumn;
|
||||
|
||||
bool m_dirty;
|
||||
|
||||
bool m_drawShadows;
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
GameState::GameState(pkpy::VM* vm, Graphics* graphics) :m_vm(vm), m_graphics(graphics){
|
||||
m_updateFunction = nullptr;
|
||||
m_previousError = "";
|
||||
|
||||
}
|
||||
|
||||
void GameState::Draw() {
|
||||
@ -26,11 +27,17 @@ void GameState::Draw() {
|
||||
}
|
||||
|
||||
void GameState::OnEnter() {
|
||||
m_graphics->Clear(0);
|
||||
PreProcessScripts();
|
||||
|
||||
}
|
||||
|
||||
void GameState::OnExit() {
|
||||
for(const auto& pair : m_vm->_lazy_modules){
|
||||
m_vm->_modules.del(pair.first);
|
||||
}
|
||||
m_vm->_lazy_modules.clear();
|
||||
|
||||
m_updateFunction = m_vm->None;
|
||||
}
|
||||
|
||||
@ -49,9 +56,6 @@ void GameState::PreProcessScripts() {
|
||||
pkpy::CodeObject_ code = m_vm->compile(main, MAIN_FILE, pkpy::EXEC_MODE, false);
|
||||
m_vm->_exec(code, m_vm->_main);
|
||||
m_updateFunction = m_vm->eval("update");
|
||||
// if(m_updateFunction == nullptr){
|
||||
// m_previousError = "";
|
||||
// }
|
||||
}catch(pkpy::Exception e){
|
||||
m_previousError = e.summary();
|
||||
std::cout << e.summary() << "\n";
|
||||
@ -82,9 +86,12 @@ std::unordered_map<std::string, std::string> GameState::readPythonFiles(const st
|
||||
}
|
||||
|
||||
void GameState::loadPythonModules(std::unordered_map<std::string, std::string> &fileContents) {
|
||||
m_vm->_lazy_modules.clear();
|
||||
|
||||
for(const auto& pair : fileContents){
|
||||
try{
|
||||
if(pair.first != MAIN_FILE){
|
||||
// parse out file name as module ex: test.py is test
|
||||
size_t pos = pair.first.find_last_of(".");
|
||||
if(pos == std::string::npos || pos == 0){
|
||||
throw pkpy::Exception("Invalid file name");
|
||||
@ -102,3 +109,7 @@ void GameState::OnCharPressed(char character) {
|
||||
|
||||
}
|
||||
|
||||
void GameState::OnMousePressed(int button) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ public:
|
||||
void OnExit() override;
|
||||
void OnKeyPressed(int key) override;
|
||||
void OnCharPressed(char character) override;
|
||||
void OnMousePressed(int button) override;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "Utilities.h"
|
||||
|
||||
namespace Utilities {
|
||||
Color ColorFromHex(int hexValue) {
|
||||
// Extract red, green, blue, and alpha components from the hexadecimal value
|
||||
@ -18,4 +19,8 @@ namespace Utilities {
|
||||
// Create and return the color
|
||||
return ColorFromNormalized({ rf, gf, bf, 1.0f }); // Alpha is set to 1.0 (fully opaque)
|
||||
}
|
||||
|
||||
bool RectContainsPoint(pycron::Rectangle* r, int x, int y){
|
||||
return x >= r->x && x <= r->x + r->width && y >= r->y && y <= r->y + r->height;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
#include "raylib.h"
|
||||
#include "Utilities.h"
|
||||
#include "Graphics/Rectangle.h"
|
||||
|
||||
|
||||
namespace Utilities {
|
||||
Color ColorFromHex(int hexValue);
|
||||
|
||||
bool RectContainsPoint(pycron::Rectangle* r, int x, int y);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user