I'm really new to this community. I'm sorry for any mistakes in advance.I'm making a game like minecraft with GLFW and OpenGL. The problem is, I just can't render a VBO while I update it from another thread. Here is my code:
main.py
# imports
import glfw
from OpenGL.GL import *
from OpenGL.GLU import *
# internal imports
from core.renderer import *
from terrain import *
from player import *
if not glfw.init():
raise Exception("glfw can not be initialized!")
window = glfw.create_window(800, 500, "PyCraft", None, None)
glfw.make_context_current(window)
renderer = TerrainRenderer(window)
player = Player(window)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
# glEnable(GL_FOG)
glFogfv(GL_FOG_COLOR, (GLfloat * int(8))(0.5, 0.69, 1.0, 10))
glHint(GL_FOG_HINT, GL_DONT_CARE)
glFogi(GL_FOG_MODE, GL_LINEAR)
glFogf(GL_FOG_START, 3)
glFogf(GL_FOG_END, 10)
renderer.texture_manager.add_from_folder("assets/textures/block/")
renderer.texture_manager.save("atlas.png")
renderer.texture_manager.bind()
world = World(renderer, player)
world.generate()
# get window size
def get_window_size():
width, height = glfw.get_window_size(window)
return width, height
def _setup_3d():
w, h = get_window_size()
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(70, w / h, 0.1, 1000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def update_on_resize():
_setup_3d()
glViewport(0, 0, *get_window_size())
# mainloop
while not glfw.window_should_close(window):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
update_on_resize()
_setup_3d()
glClearColor(0.5, 0.7, 1, 1.0)
player.update()
player._translate()
glfw.poll_events()
glfw.swap_buffers(window)
glfw.terminate()
renderer.py:
# imports
import glfw, numpy
from OpenGL.GL import *
from ctypes import *
from core.texture_manager import *
glfw.init()
class VBOManager:
def __init__(self, renderer):
self.renderer = renderer
self.run()
def run(self):
for i in self.renderer.to_add[:self.renderer.to_add_count]:
self.renderer.vertices.extend(i[0])
self.renderer.texCoords.extend(i[1])
_ = i
self.renderer.to_add.remove(i)
glBindBuffer(GL_ARRAY_BUFFER, self.renderer.vbo)
glBufferSubData(GL_ARRAY_BUFFER, len(self.renderer.vertices), len(_[0]) * 4, (GLfloat * len(_[0]))(*_[0]))
glFlush()
glVertexPointer(3, GL_FLOAT, 0, None)
glTexCoordPointer(3, GL_FLOAT, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, self.renderer.vbo_1)
glBufferSubData(GL_ARRAY_BUFFER, len(self.renderer.texCoords), len(_[1]) * 4, (GLfloat * len(_[1]))(*_[1]))
glFlush()
class TerrainRenderer:
def __init__(self, window):
self.window = window
self.vertices = []
self.texCoords = []
self.to_add = []
self.to_add_count = 256
self.vbo, self.vbo_1 = glGenBuffers (2)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, 12 * 4, None, GL_STATIC_DRAW)
self.vbo_manager = VBOManager(self)
self.texture_manager = TextureAtlas()
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glEnableClientState (GL_VERTEX_ARRAY)
def load_assets_from(self, other_renderer):
self.texture_manager = other_renderer.texture_manager
def render(self):
try:
self.vbo_manager.run()
except RuntimeError:
pass
glClear (GL_COLOR_BUFFER_BIT)
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glBindBuffer (GL_ARRAY_BUFFER, self.vbo)
glVertexPointer (3, GL_FLOAT, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
glTexCoordPointer(2, GL_FLOAT, 0, None)
glDrawArrays (GL_QUADS, 0, len(self.vertices))
glDisable(GL_TEXTURE_2D)
glDisable(GL_BLEND)
def add(self, posList, texCoords):
self.to_add.append((numpy.array(posList), numpy.array(texCoords)))
def update_vbo(self):
pass
world.py
from terrain import *
from player import *
from core.renderer import *
import threading
import random
import glfw
def execute_with_delay(func, delay):
threading.Timer(delay, func).start()
class ThreadedChunkGenerator():
def __init__(self, world):
self.thread = threading.Thread(target=self.run, daemon=True)
self.world = world
self.event = threading.Event()
self.event.wait()
glfw.make_context_current(self.world.parent.window)
def run(self,):
glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window2 = glfw.create_window(300, 300, "Window 2", None, self.world.parent.window)
glfw.make_context_current(window2)
self.event.set()
renderer = TerrainRenderer(window2)
renderer.load_assets_from(self.world.parent)
while True:
for i in range(self.world.to_generate):
chunk = i
renderer = self.world.parent
chunk.generate(renderer)
self.world.renderer = renderer
self.world.to_generate = []
class World:
def __init__(self, renderer, player):
self.parent = renderer
self.chunks = {}
self.blocks = {}
self.position = (0 * 16, 0 * 16)
self.render_distance = 1
self.infgen_threshold = 1
self.block_types = all_blocks(renderer)
self.to_generate = []
self.player = player
self.thread = ThreadedChunkGenerator(self)
self.thread.start()
self.event = self.thread.event
self.event.wait()
def block_exists(self, position):
return position in self.blocks
def _add_chunk(self, position):
self.chunks[position] = Chunk(self.parent, self, position)
def add_chunk(self, position):
execute_with_delay(lambda: self._add_chunk(position), random.randrange(1, 2))
def generate(self):
for i in range(self.position[0] - self.render_distance, self.position[0] + self.render_distance + 1):
for j in range(self.position[1] - self.render_distance, self.position[1] + self.render_distance + 1):
if (i, j) not in self.chunks:
self.add_chunk((i, j))
def update_infgen(self, position):
player_pos = (position[0] // 16, position[2] // 16)
if player_pos[0] - self.position[0] > self.infgen_threshold:
self.position = (self.position[0] + 2, self.position[1])
self.generate()
elif player_pos[0] - self.position[0] < -self.infgen_threshold:
self.position = (self.position[0] - 2, self.position[1])
self.generate()
if player_pos[1] - self.position[1] > self.infgen_threshold:
self.position = (self.position[0], self.position[1] + 2)
self.generate()
elif player_pos[1] - self.position[1] < -self.infgen_threshold:
self.position = (self.position[0], self.position[1] - 2)
self.generate()
def render(self):
self.parent.render()
self.update_infgen(self.player.pos)
Right now, it shows no errors, just hangs the window before it even starts rendering. Any help will be highly appreciated.