I am making a little game in PyOpenGL. I have run into a problem. The VBO takes only one texture. I have tried using a glTexSubImage3d, but I just cannot get it to work. I need to get multiple textures on a single VBO. There are no good tutorials explaining the point! Here is my code:
main.py
# imports
import random
import glfw
from OpenGL.GL import *
from OpenGL.GLU import *
# internal imports
from renderer 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)
# generate cube faces
def generate_faces(position):
x, y, z = position
X, Y, Z = x + 1, y + 1, z + 1
return [
# top
x, y, z,
x, y, Z,
X, y, Z,
X, y, z,
# bottom
x, Y, z,
X, Y, z,
X, Y, Z,
x, Y, Z,
# left
x, y, z,
x, Y, z,
x, Y, Z,
x, y, Z,
# right
X, y, z,
X, y, Z,
X, Y, Z,
X, Y, z,
# front
x, y, z,
x, Y, z,
X, Y, z,
X, y, z,
# back
x, y, Z,
X, y, Z,
X, Y, Z,
x, Y, Z,
]
defaultTexCoords = [
# top
0, 0,
0, 1,
1, 1,
1, 0,
# bottom
0, 0,
1, 0,
1, 1,
0, 1,
# left
0, 0,
0, 1,
1, 1,
1, 0,
# right
0, 0,
1, 0,
1, 1,
0, 1,
# front
0, 0,
0, 1,
1, 1,
1, 0,
# back
0, 0,
1, 0,
1, 1,
0, 1,
]
for i in range(-10, 10):
for j in range(-10, 10):
x = i
y = random.randint(-1, 1)
z = j
renderer.add(generate_faces([x, y, z]), defaultTexCoords)
camrot = [0, 0]
campos = [0, 0, 0]
# 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.0, 0.0, 0.0, 1.0)
glColor3f(1.0, 1.0, 1.0)
player.update()
player._translate()
renderer.render()
glfw.poll_events()
glfw.swap_buffers(window)
glfw.terminate()
renderer.py
# imports
import glfw
import pygame
from OpenGL.GL import *
from ctypes import *
import threading, time
event = threading.Event()
glfw.init()
def loadTexture(path):
texSurface = pygame.image.load(path)
texData = pygame.image.tostring(texSurface, "RGBA", 1)
width = texSurface.get_width()
height = texSurface.get_height()
texid = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texid)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, texData)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
return texid
class TerrainRenderer:
def __init__(self, window):
self.window = window
self.vertices = []
self.texCoords = []
VAO = glGenVertexArrays(1)
glBindVertexArray(VAO)
self.vbo, self.vbo_1 = glGenBuffers (2)
self.texture = loadTexture("assets/textures/block/bricks.png",)
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 render(self):
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.vertices.extend(posList)
self.texCoords.extend(texCoords)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, len(self.vertices) * 4, (c_float * len(self.vertices))(*self.vertices), GL_STATIC_DRAW)
glFlush()
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, None)
glTexCoordPointer(3, GL_FLOAT, 0, None)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
glBufferData(GL_ARRAY_BUFFER, len(self.texCoords) * 4, (c_float * len(self.texCoords))(*self.texCoords), GL_STATIC_DRAW)
glFlush()