Files
Fable3D/my3dengine/core.py
2026-02-04 21:31:57 +01:00

152 lines
4.7 KiB
Python

import sdl2
import sdl2.ext
from OpenGL.GL import *
import time
from sdl2 import SDL_GL_SetSwapInterval
from .key import Key
import numpy as np
import OpenGL.GL
class Vector3:
def __init__(self, x=0, y=0, z=0):
self.x = float(x)
self.y = float(y)
self.z = float(z)
def __add__(self, other):
return Vector3(self.x + other.x, self.y + other.y, self.z + other.z)
def __sub__(self, other):
return Vector3(self.x - other.x, self.y - other.y, self.z - other.z)
def __mul__(self, scalar):
return Vector3(self.x * scalar, self.y * scalar, self.z * scalar)
def to_list(self):
return [self.x, self.y, self.z]
def __repr__(self):
return f"Vector3({self.x}, {self.y}, {self.z})"
def debug_init():
@staticmethod
def init():
# Włącz przezroczystość (alpha blending)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
# Włącz test głębokości (żeby obiekty były dobrze rysowane w 3D)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LESS) # Domyślnie można zostawić, ale warto jawnie ustawić
# Włącz odrzucanie tylnych ścianek (culling)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK) # Możesz też użyć GL_FRONT, jeśli robisz np. odbicia
glFrontFace(GL_CCW) # Counter-clockwise - domyślnie standard OpenGL
# Głębia na 1.0 - domyślnie, ale dobrze ustawić jawnie
glClearDepth(1.0)
# V-Sync
SDL_GL_SetSwapInterval(1) # 1 = włączony VSync, 0 = wyłączony (lepszy FPS, może tearing)
# Gładkie linie i wielokąty (opcjonalne, zależnie od potrzeb)
glEnable(GL_LINE_SMOOTH)
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
glEnable(GL_POLYGON_SMOOTH)
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST)
# Antyaliasing multisampling (jeśli masz MSAA ustawione w SDL_GL)
glEnable(GL_MULTISAMPLE)
def normalize(v):
norm = np.linalg.norm(v)
if norm == 0:
return v
return v / norm
@staticmethod
def init():
glEnable(GL_BLEND)
glEnable(GL_DEPTH_TEST)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_CULL_FACE)
glFrontFace(GL_CCW)
glClearDepth(1.0)
SDL_GL_SetSwapInterval(1)
@staticmethod
def get_fullscreen():
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) # upewniamy się że SDL wystartował
mode = sdl2.SDL_DisplayMode()
if sdl2.SDL_GetDesktopDisplayMode(0, mode) != 0:
raise RuntimeError("Nie udało się pobrać trybu ekranu")
return mode.w, mode.h
class Window:
def __init__(self, title, width, height):
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
self.width = width
self.height = height
self.window = sdl2.SDL_CreateWindow(
title.encode("utf-8"),
sdl2.SDL_WINDOWPOS_CENTERED,
sdl2.SDL_WINDOWPOS_CENTERED,
width,
height,
sdl2.SDL_WINDOW_OPENGL | sdl2.SDL_WINDOW_SHOWN,
)
self.context = sdl2.SDL_GL_CreateContext(self.window)
glViewport(0, 0, width, height)
self.mouse_locked = True
sdl2.SDL_SetRelativeMouseMode(sdl2.SDL_TRUE)
sdl2.SDL_ShowCursor(sdl2.SDL_DISABLE)
def is_key_pressed(self, key: Key) -> bool:
keys = sdl2.SDL_GetKeyboardState(None)
return keys[key] != 0
def toggle_mouse_lock(self):
self.mouse_locked = not self.mouse_locked
if self.mouse_locked:
sdl2.SDL_SetRelativeMouseMode(sdl2.SDL_TRUE)
sdl2.SDL_ShowCursor(sdl2.SDL_DISABLE)
else:
sdl2.SDL_SetRelativeMouseMode(sdl2.SDL_FALSE)
sdl2.SDL_ShowCursor(sdl2.SDL_ENABLE)
def prepare_frame(self):
glViewport(0, 0, self.width, self.height)
glClearColor(0.1, 0.1, 0.1, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glEnable(GL_DEPTH_TEST)
def run(self, update_callback=None, cameras=[]):
last_time = time.time()
event = sdl2.SDL_Event()
running = True
while running:
while sdl2.SDL_PollEvent(event):
if event.type == sdl2.SDL_QUIT:
running = False
elif event.type == sdl2.SDL_KEYDOWN:
if event.key.keysym.scancode == sdl2.SDL_SCANCODE_ESCAPE:
self.toggle_mouse_lock()
now = time.time()
dt = now - last_time
last_time = now
self.prepare_frame()
if update_callback:
update_callback(dt, self)
sdl2.SDL_GL_SwapWindow(self.window)
glFlush()
sdl2.SDL_DestroyWindow(self.window)
sdl2.SDL_Quit()