Exemple #1
0
def calculate_polycount(bsp_file):
    # triangle fan (num_tris + 2 = num_verts) so (num_edges - 2 = num_tris)
    face_tris = sum([f['numedges'] - 2 for f in bsp_file.FACES])
    disp_tris = 0
    try:
        disp_tris = len(list(bsp_file.DISP_TRIS))
    except AttributeError:
        ...
    # render_bsp.py vert & index counts
    vertices = []
    indices = []
    currentIndex = 0
    for face in bsp_file.FACES:
        if face["dispinfo"] == -1:
            faceVerts = bsp_file.verts_of(face)
            faceIndices = calcTriFanIndices(faceVerts, currentIndex)
        else:
            power = bsp_file.DISP_INFO[face['dispinfo']]['power']
            faceVerts = bsp_tool.disp_tris(bsp_file.dispverts_of(face), power)
            faceIndices = bsp_tool.disp_tris(range((2 ** power + 1) ** 2), power)
        vertices += faceVerts
        indices += faceIndices
        currentIndex = faceIndices[len(faceIndices) - 1] + 1
    return len(bsp_file.BRUSHES), len(bsp_file.FACES), face_tris, disp_tris, face_tris + disp_tris, len(vertices), len(indices)
Exemple #2
0
def main(width, height, bsp):
    SDL_Init(SDL_INIT_VIDEO)
    window = SDL_CreateWindow(bytes(bsp.filename, 'utf-8'),
                              SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                              width, height, SDL_WINDOW_OPENGL
                              | SDL_WINDOW_BORDERLESS)  #SDL_WINDOW_FULLSCREEN
    glContext = SDL_GL_CreateContext(window)
    glColor(0, 0, 0, 0)
    gluPerspective(90, width / height, 0.1, 4096 * 4)
    glPointSize(2)
    glPolygonMode(GL_BACK, GL_LINE)
    glEnable(GL_DEPTH_TEST)
    glColor(1, 1, 1)
    glFrontFace(GL_CW)

    FACE = iter(bsp.FACES)
    current_face = next(FACE)
    current_face_verts = bsp.verts_of(current_face)

    all_faces = []
    all_faces_map = []
    start = 0
    for face in bsp.FACES:
        if face['dispinfo'] == -1:
            f_verts = bsp.verts_of(face)
            out = f_verts[:3]
            f_verts = f_verts[3:]
            for vert in f_verts:
                out += [out[0], out[-1], vert]
            f_verts = out
            f_verts_len = len(f_verts)
            all_faces_map.append((start, f_verts_len))
            start += f_verts_len
        else:
            power = bsp.DISP_INFO[face['dispinfo']]['power']
            f_verts = bsp_tool.disp_tris(bsp.dispverts_of(face), power)
        all_faces += f_verts
##    all_faces = list(itertools.chain(*all_faces))

    NODE = iter(filter(lambda x: x['children'][1] < 0, bsp.NODES))
    NODE = sorted(bsp.NODES,
                  key=lambda node: sum(
                      [x[1] for x in node_faces(node, bsp, all_faces_map)]))
    current_node = NODE[0]
    current_node_index = 0
    draw_calls = node_faces(current_node, bsp, all_faces_map)
    current_node_aabb = aabb(current_node['mins'], current_node['maxs'])
    cnff = current_node['firstface']
    current_node_faces = all_faces_map[cnff:cnff + current_node['numfaces']]
    try:
        cn_start = current_node_faces[0][0]
        cn_count = sum([x[1] for x in current_node_faces])
    except:
        cn_start = 0
        cn_count = 0

    all_nodes = list(map(lambda x: aabb(x['mins'], x['maxs']), bsp.NODES))
    all_leaves = list(map(lambda x: aabb(x['mins'], x['maxs']), bsp.LEAVES))

    print(bsp.filename.upper(), end=' ')
    print('{:,}KB BSP'.format(bsp.bytesize // 1024), '>>>', end=' ')
    print('{:,} TRIS'.format(len(all_faces) // 9), end=' & ')
    print('{:,}KB VRAM'.format((len(all_faces) * 4) // 1024))
    print('{:,} NODES'.format(len(bsp.NODES)))

    # shader & vertex buffer would go here

    SDL_GL_SetSwapInterval(0)
    SDL_CaptureMouse(SDL_TRUE)
    SDL_WarpMouseInWindow(window, width // 2, height // 2)
    SDL_SetRelativeMouseMode(SDL_TRUE)
    SDL_SetWindowGrab(window, SDL_TRUE)

    cam_spawn = vector.vec3(0, 0, 0)
    init_speed = 128
    VIEW_CAMERA = camera.freecam(cam_spawn, None, init_speed)

    mousepos = vector.vec2()
    keys = []

    tickrate = 120
    event = SDL_Event()
    oldtime = time()
    while True:
        while SDL_PollEvent(ctypes.byref(event)) != 0:
            if event.type == SDL_QUIT or event.key.keysym.sym == SDLK_ESCAPE and event.type == SDL_KEYDOWN:
                SDL_GL_DeleteContext(glContext)
                SDL_DestroyWindow(window)
                SDL_Quit()
                return False
            if event.type == SDL_KEYDOWN:
                if event.key.keysym.sym not in keys:
                    keys.append(event.key.keysym.sym)
            if event.type == SDL_KEYUP:
                while event.key.keysym.sym in keys:
                    keys.remove(event.key.keysym.sym)
            if event.type == SDL_MOUSEMOTION:
                mousepos += vector.vec2(event.motion.xrel, event.motion.yrel)
                SDL_WarpMouseInWindow(window, width // 2, height // 2)
            if event.type == SDL_MOUSEWHEEL:
                VIEW_CAMERA.speed += event.wheel.y * 32
            if event.type == SDL_MOUSEBUTTONDOWN:
                if event.button.button not in keys:
                    keys.append(event.button.button)
            if event.type == SDL_MOUSEBUTTONUP:
                while event.button.button in keys:
                    keys.remove(event.button.button)

        dt = time() - oldtime
        while dt >= 1 / tickrate:
            VIEW_CAMERA.update(mousepos, keys, 1 / tickrate)
            if SDLK_BACKQUOTE in keys:
                #NODES
                print(current_node, draw_calls, sep='\n\n')
                cn_center = (current_node_aabb.mins +
                             current_node_aabb.maxs) / 2
                VIEW_CAMERA.position = cn_center
                while SDLK_BACKQUOTE in keys:
                    keys.remove(SDLK_BACKQUOTE)
            if SDLK_r in keys:
                VIEW_CAMERA = camera.freecam(cam_spawn, None, init_speed)
            if SDLK_LSHIFT in keys:
                VIEW_CAMERA.speed += VIEW_CAMERA.speed * .125
            if SDLK_LCTRL in keys:
                VIEW_CAMERA.speed -= VIEW_CAMERA.speed * .125
            if SDLK_LEFT in keys or SDL_BUTTON_LEFT in keys:
                current_node_index -= 1
                current_node = NODE[current_node_index]
                draw_calls = node_faces(current_node, bsp, all_faces_map)
                current_node_aabb = aabb(current_node['mins'],
                                         current_node['maxs'])
                VIEW_CAMERA.position = current_node_aabb.center
                cnff = current_node['firstface']
                current_node_faces = all_faces_map[cnff:cnff +
                                                   current_node['numfaces']]
                try:
                    cn_start = current_node_faces[0][0]
                    cn_count = sum([x[1] for x in current_node_faces])
                except:
                    cn_start = 0
                    cn_count = 0
                while SDLK_LEFT in keys:
                    keys.remove(SDLK_LEFT)
                while SDL_BUTTON_LEFT in keys:
                    keys.remove(SDL_BUTTON_LEFT)
            if SDLK_RIGHT in keys or SDL_BUTTON_RIGHT in keys:
                current_node_index += 1
                current_node = NODE[current_node_index]
                draw_calls = node_faces(current_node, bsp, all_faces_map)
                current_node_aabb = aabb(current_node['mins'],
                                         current_node['maxs'])
                VIEW_CAMERA.position = current_node_aabb.center
                cnff = current_node['firstface']
                current_node_faces = all_faces_map[cnff:cnff +
                                                   current_node['numfaces']]
                try:
                    cn_start = current_node_faces[0][0]
                    cn_count = sum([x[1] for x in current_node_faces])
                except:
                    cn_start = 0
                    cn_count = 0
                while SDLK_RIGHT in keys:
                    keys.remove(SDLK_RIGHT)
                while SDL_BUTTON_RIGHT in keys:
                    keys.remove(SDL_BUTTON_RIGHT)
            dt -= 1 / tickrate
            oldtime = time()

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glPushMatrix()
        VIEW_CAMERA.set()

        glPolygonMode(GL_FRONT, GL_LINE)
        ##        glUseProgram(0)
        glColor(1, 0, 1)
        glBegin(GL_LINES)
        current_node_aabb.draw()
        glEnd()

        glColor(1, 1, 1)
        glDrawArrays(GL_TRIANGLES, cn_start, cn_count)

        ##        glUseProgram(bsp_shader)
        glColor(1, .5, 0)
        glPolygonMode(GL_FRONT, GL_FILL)
        glPolygonMode(GL_BACK, GL_LINE)
        try:
            for draw_call in draw_calls:
                glDrawArrays(GL_TRIANGLES, draw_call[0], draw_call[1])
        except:
            pass

        #CENTER POINT


##        glUseProgram(0)
##        glBegin(GL_LINES)
##        glColor(1, 0, 0)
##        glVertex(0, 0, 0)
##        glVertex(128, 0, 0)
##        glColor(0, 1, 0)
##        glVertex(0, 0, 0)
##        glVertex(0, 128, 0)
##        glColor(0, 0, 1)
##        glVertex(0, 0, 0)
##        glVertex(0, 0, 128)
##        glEnd()

        glPopMatrix()
        SDL_GL_SwapWindow(window)
Exemple #3
0
def main(width, height, bsp):
    SDL_Init(SDL_INIT_VIDEO)
    window = SDL_CreateWindow(bytes(bsp.filename, 'utf-8'), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL) #| SDL_WINDOW_BORDERLESS) #SDL_WINDOW_FULLSCREEN
    glContext = SDL_GL_CreateContext(window)
    glClearColor(0, .5, 1, 0)
    
    try:
        light_environment = [e for e in bsp.ENTITIES if e.classname == 'light_environment'][0]
        light_environment.angles = tuple(map(float, light_environment.angles.split(' ')))
        light_environment.pitch = float(light_environment.pitch)
        light_environment._light = tuple(map(int, light_environment._light.split(' ')))
        light_environment._ambient = tuple(map(int, light_environment._ambient.split(' ')))
        sun_vector = vec3(1, 0, 0).rotate(light_environment.angles[2], -light_environment.pitch, light_environment.angles[1])
        sun_colour = (*[x / 255 for x in light_environment._light[:3]], light_environment._light[-1]) # vec4 (R, G, B) + Strength
        sun_ambient = (*[x / 255 for x in light_environment._ambient[:3]], light_environment._ambient[-1]) # vec4 (R, G, B) + Strength
        glClearColor(*sun_ambient[:3], 0)
    except: # no light_environment in .bsp
        sun_vector = vec3(1, 0, 0).rotate(0, 35, 108) # GOLDRUSH
        sun_colour = (1.00, 0.89, 0.73, 600)
        sun_ambient = (0.46, 0.45, 0.55, 350)
        glClearColor(*sun_ambient[:3], 0)
    
    gluPerspective(90, width / height, 0.1, 4096 * 4)
    glPointSize(4)
    glPolygonMode(GL_BACK, GL_LINE)
    glEnable(GL_DEPTH_TEST)
    glFrontFace(GL_CW)
    glEnable(GL_CULL_FACE)
    glColor(1, 1, 1)

    filtered_faces = [f for f in bsp.FACES if f.light_offset != -1] # no sky or trigger
##    filtered_faces = [f for f in bsp.FACES if f.disp_info == -1] # disp only
##    filtered_faces = [f for f in bsp.FACES if f.light_offset != -1 and x.disp_info == -1] # no sky, trigger or disp
##    filtered_faces = [f for f in bsp.FACES if f.styles == (-1, -1, -1, -1)] # unlit? faces
##    filtered_faces = bsp.FACES # no filter

    face_count = len(filtered_faces)
    current_face_index = 0
    current_face = filtered_faces[current_face_index]
    current_face_verts = [v[0] for v in bsp.verts_of(current_face)]

    all_faces = []
    all_faces_map = [] # [(start, length), ...]
    start = 0
    t1 = time()
    for face in filtered_faces:
        if face.disp_info == -1:
            f_verts = bsp.verts_of(face) # add to vertex buffer here and fan the indices
            out = f_verts[:3]
            f_verts = f_verts[3:]
            for vert in f_verts:
                out += [out[0], out[-1], vert]
            f_verts = out
            f_verts_len = len(f_verts)
            all_faces_map.append((start, f_verts_len))
            start += f_verts_len
        else: # face is a displacement
            power = bsp.DISP_INFO[face.disp_info].power
            f_verts = bsp.dispverts_of(face)
            f_verts = bsp_tool.disp_tris(f_verts, power)
            f_verts_len = len(f_verts)
            all_faces_map.append((start, f_verts_len))
            start += f_verts_len
        all_faces += f_verts
    slow_faces = all_faces.copy()
    all_faces = list(itertools.chain(*itertools.chain(*all_faces)))
    all_faces_size = len(all_faces)

    vertices = all_faces
    indices = range(all_faces_size)

##    print('compressing vertex buffer...')
##    vertices = []
##    indices = []
##    currentIndex = 0
##    for face in filtered_faces:
##        if face.disp_info == -1:
##            faceVerts = bsp.verts_of(face)
##            faceIndices = calcTriFanIndices(faceVerts, currentIndex)
##        else:
##            power = bsp.DISP_INFO[face.disp_info].power
##            faceVerts = bsp_tool.disp_tris(bsp.dispverts_of(face), power)
##            faceIndices = bsp_tool.disp_tris(range((2 ** power + 1) ** 2), power)
##        vertices += faceVerts
##        indices += faceIndices
##        currentIndex = faceIndices[-1] + 1 # ?
##    vertices = list(itertools.chain(*itertools.chain(*vertices)))

    RGB_LIGHTING = []
    for RGBE_texel in struct.iter_unpack('3Bb', bsp.RAW_LIGHTING):
##        RGB_texel = vec3(RGBE_texel[:3]) * (2 ** RGBE_texel[3])
##        RGB_texel = [clamp(int(x), 0, 255) for x in RGB_texel]
        RGB_LIGHTING.append(struct.pack('3Bb', *RGBE_texel))#, RGBE_texel[3]))
    RGB_LIGHTING = b''.join(RGB_LIGHTING)

    lightmap = [] # store on GPU (TextureArray?)
    for face in filtered_faces:
        lmap_start = face.light_offset
        if lmap_start != -1:
            bounds = face.lightmap_texture_size_in_luxels
            bounds = [x + 1 for x in bounds]
            num_styles = sum([1 if x is not -1 else 0 for x in face.styles])
            lmap_end = lmap_start + bounds[0] * bounds[1] * 4 * num_styles
            lmap_bytes = RGB_LIGHTING[lmap_start:lmap_end]
            lightmap.append([lmap_bytes, bounds])

    t2 = time()
    print(bsp.filename.upper(), end=' ')
    print(f'{bsp.bytesize // 1024:,}KB BSP', end=' >>> ')
    print(f'{len(all_faces) // 9:,} TRIS', end=' & ')
    print(f'{(len(all_faces) * 4) // 1024:,}KB VRAM')
    print(f'ASSEMBLED IN {(t2 - t1) * 1000:,.3f}ms')
    print()

    # SHADERS (check GLSL version)
    USING_ES = False
    try:
        vertShader = compileShader(open('shaders/bsp_lightmap.v', 'rb'), GL_VERTEX_SHADER)
        fragShader = compileShader(open('shaders/bsp_lightmap.f', 'rb'), GL_FRAGMENT_SHADER)
    except Exception as exc: # requires PyOpenGL changes described in older version of this repo
        USING_ES = True # if OpenGL 4.5 is not supported, switch to GLES 3.0
        vertShader = compileShader(open('shaders/bsp_faces_300_es.v', 'rb'), GL_VERTEX_SHADER)
        fragShader = compileShader(open('shaders/bsp_faces_300_es.f', 'rb'), GL_FRAGMENT_SHADER)
        raise exc # need to log error if issue is not GLSL version
    bsp_shader = compileProgram(vertShader, fragShader)
    glLinkProgram(bsp_shader)
    glUseProgram(bsp_shader) # must call UseProgram before setting uniforms

    # UNIFORMS
    if USING_ES:
        # GLES vertex attribs
        attrib_position = glGetAttribLocation(bsp_shader, 'vertexPosition')
        attrib_normal = glGetAttribLocation(bsp_shader, 'vertexNormal')
        attrib_texture_uv = glGetAttribLocation(bsp_shader, 'vertexTexCoord')
        attrib_lightmap_uv = glGetAttribLocation(bsp_shader, 'vertexLightCoord')
        attrib_colour_uv = glGetAttribLocation(bsp_shader, 'vertexColour')
##        ProjectionMatrixLoc = glGetUniformLocation(bsp_shader, 'ProjectionMatrix')
##        # https://www.khronos.org/opengl/wiki/GluPerspective_code
##        glUniformMatrix4f?(ProjectionMatrixLoc, ?, GL_FALSE, ...) # bad input?
    else: # glsl 450 core uniforms
        glUniform3f(glGetUniformLocation(bsp_shader, 'sun_vector'), *sun_vector)
        glUniform4f(glGetUniformLocation(bsp_shader, 'sun_colour'), *sun_colour)
        glUniform4f(glGetUniformLocation(bsp_shader, 'sun_ambient'), *sun_ambient)

    VERTEX_BUFFER, INDEX_BUFFER = glGenBuffers(2)
    glBindBuffer(GL_ARRAY_BUFFER, VERTEX_BUFFER)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, len(indices) * 4, np.array(indices, dtype=np.uint64), GL_STATIC_DRAW) # INDICES
    glBufferData(GL_ARRAY_BUFFER, len(vertices) * 4, np.array(vertices, dtype=np.float32), GL_STATIC_DRAW) # VERTICES
    glEnableVertexAttribArray(0)  #vertexPosition
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 52, GLvoidp(0))
    glEnableVertexAttribArray(1)  #vertexNormal
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 52, GLvoidp(12))
    glEnableVertexAttribArray(2) #vertexTexcoord
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 52, GLvoidp(24))
    glEnableVertexAttribArray(3) #vertexLightmapCoord
    glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 52, GLvoidp(32))
    glEnableVertexAttribArray(4) #reflectivityColour
    glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 52, GLvoidp(40))
    # displacement alpha (seperate format or shared?)

    glEnable(GL_TEXTURE_2D)
    glActiveTexture(GL_TEXTURE0)
    # texture = open('materials/obsolete.bmp', 'rb')
    texture = open('materials/dev/reflectivity_100.bmp', 'rb')
    texture.seek(54)
    # glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB4, 256, 256, 0, GL_BGR, GL_UNSIGNED_BYTE, texture.read())
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB4, 512, 512, 0, GL_BGR, GL_UNSIGNED_BYTE, texture.read())
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
    texture.close()
    del texture

    SDL_GL_SetSwapInterval(0)
    SDL_CaptureMouse(SDL_TRUE)
    SDL_WarpMouseInWindow(window, width // 2, height // 2)
    SDL_SetRelativeMouseMode(SDL_TRUE)
    SDL_SetWindowGrab(window, SDL_TRUE)

    cam_spawn = vec3(0, 0, 32)
    init_speed = 128
    VIEW_CAMERA = utils.camera.freecam(cam_spawn, None, init_speed)

    props = [e for e in bsp.ENTITIES if 'prop' in e.classname]

    mousepos = vec2()
    keys = []

    tickrate = 120
    oldtime = time()
    event = SDL_Event()
    while True:
        while SDL_PollEvent(ctypes.byref(event)) != 0:
            if event.type == SDL_QUIT or event.key.keysym.sym == SDLK_ESCAPE and event.type == SDL_KEYDOWN:
                SDL_GL_DeleteContext(glContext)
                SDL_DestroyWindow(window)
                SDL_Quit()
                return bsp
            if event.type == SDL_KEYDOWN:
                if event.key.keysym.sym not in keys:
                    keys.append(event.key.keysym.sym)
            if event.type == SDL_KEYUP:
                while event.key.keysym.sym in keys:
                    keys.remove(event.key.keysym.sym)
            if event.type == SDL_MOUSEMOTION:
                mousepos += vec2(event.motion.xrel, event.motion.yrel)
                SDL_WarpMouseInWindow(window, width // 2, height // 2)
            if event.type == SDL_MOUSEWHEEL:
                VIEW_CAMERA.speed += event.wheel.y * 32
            if event.type == SDL_MOUSEBUTTONDOWN:
                if event.button.button not in keys:
                    keys.append(event.button.button)
            if event.type == SDL_MOUSEBUTTONUP:
                while event.button.button in keys:
                    keys.remove(event.button.button)

        dt = time() - oldtime
        while dt >= 1 / tickrate:
            VIEW_CAMERA.update(mousepos, keys, 1 / tickrate)
            sun_vector = sun_vector.rotate(.05, 0, 0)
            glUseProgram(bsp_shader)
            glUniform3f(glGetUniformLocation(bsp_shader, 'sun_vector'), *sun_vector)
            # update projection matrix (GLES only)
            if SDLK_BACKQUOTE in keys:
                face_values = [f"{s}: {getattr(face, s)}" for s in face.__slots__]
                print(f'{bsp.filename}.FACES[{bsp.FACES.index(current_face)}]', *face_values, sep='\n')
                fe, ne = current_face.first_edge, current_face.num_edges
                se_loop = bsp.SURFEDGES[fe:fe + ne]
                e_loop = [bsp.EDGES[e] for e in se_loop]
                face_verts = [bsp.VERTICES[v] for v in itertools.chain(*e_loop)][::2]
                print(*[f"{v.x:.3f}, {v.y:.3f}, {v.z:.3f}" for v in face_verts], sep="\n")
                face_center = sum(map(vec3, current_face_verts), vec3()) / len(current_face_verts)
                face_normal = bsp.PLANES[current_face.plane_num].normal
                VIEW_CAMERA.position = face_center + vec3(face_normal) * 32
                while SDLK_BACKQUOTE in keys:
                    keys.remove(SDLK_BACKQUOTE)
                    
            if SDLK_r in keys:
                VIEW_CAMERA = utils.camera.freecam(cam_spawn, None, init_speed)
            if SDLK_LSHIFT in keys:
                VIEW_CAMERA.speed += 5
            if SDLK_LCTRL in keys:
                VIEW_CAMERA.speed -= 5
            if SDLK_LEFT in keys or SDL_BUTTON_LEFT in keys:
                current_face_index -= 1
                current_face = filtered_faces[current_face_index]
                current_face_verts = [v[0] for v in bsp.verts_of(current_face)]
                while SDLK_LEFT in keys:
                    keys.remove(SDLK_LEFT)
                while SDL_BUTTON_LEFT in keys:
                    keys.remove(SDL_BUTTON_LEFT)
            if SDLK_RIGHT in keys or SDL_BUTTON_RIGHT in keys:
                # filter to only displacements so I can debug this mess
                current_face_index += 1
                current_face = filtered_faces[current_face_index]
                current_face_verts = [v[0] for v in bsp.verts_of(current_face)]
                while SDLK_RIGHT in keys:
                    keys.remove(SDLK_RIGHT)
                while SDL_BUTTON_RIGHT in keys:
                    keys.remove(SDL_BUTTON_RIGHT)
            dt -= 1 / tickrate
            oldtime = time()

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glPushMatrix()
        VIEW_CAMERA.set()

        glPolygonMode(GL_FRONT, GL_FILL)
        glUseProgram(bsp_shader)
        for i, face in enumerate(all_faces_map):
            texture = lightmap[i]
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, texture[1][0], texture[1][1], 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, texture[0])
            glDrawArrays(GL_TRIANGLES, face[0], face[1])
        glDrawArrays(GL_TRIANGLES, 0, all_faces_size) # supported in gl3.0 Mesa?
##        glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, GLvoidp(0))

        # for when shaders are too much work
##        glUseProgram(0)
##        for i, f_map in enumerate(all_faces_map):
####            texture = lightmap[i]
####            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture[1][0], texture[1][1], 0, GL_RGBA, GL_UNSIGNED_BYTE, texture[0])
##            face = slow_faces[f_map[0]: f_map[0] + f_map[1]]
##            glBegin(GL_TRIANGLES)
##            for vertex in face:
##                pos, normal, uv, uv2, colour = vertex
##                glColor(*colour)
##                glTexCoord(*uv)
##                glVertex(*pos)
##            glEnd()

        # CENTER MARKER
##        glUseProgram(0)
##        glBegin(GL_LINES)
##        glColor(1, 0, 0)
##        glVertex(0, 0, 0)
##        glVertex(128, 0, 0)
##        glColor(0, 1, 0)
##        glVertex(0, 0, 0)
##        glVertex(0, 128, 0)
##        glColor(0, 0, 1)
##        glVertex(0, 0, 0)
##        glVertex(0, 0, 128)
##        glEnd()

        glUseProgram(0)
        # SELECTED FACE
        glDisable(GL_TEXTURE_2D)
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
        glColor(1, 1, 1)
        glDisable(GL_DEPTH_TEST)
        glBegin(GL_LINE_LOOP)
        for vertex in current_face_verts:
            glVertex(*vertex)
        glEnd()
        glBegin(GL_POINTS)
        for vertex in current_face_verts:
            glVertex(*vertex)
        glEnd()

        # THE SUN
        glPointSize(24)
        glBegin(GL_POINTS)
        glVertex(*(sun_vector * 4096))
        glEnd()

        glPointSize(18)
        glColor(1, 0, 1)
        glBegin(GL_POINTS)
        for p in props:
            position = [float(s) for s in p.origin.split()]
            glVertex(*position)
        glEnd()
        glPointSize(4)
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_TEXTURE_2D)

        glPopMatrix()
        SDL_GL_SwapWindow(window)
Exemple #4
0
def main(width, height, bsp):
    bsp = bsp_tool.bsp(bsp)
    SDL_Init(SDL_INIT_VIDEO)
    window = SDL_CreateWindow(bytes(bsp.filename, 'utf-8'), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL) #| SDL_WINDOW_BORDERLESS) #SDL_WINDOW_FULLSCREEN
    glContext = SDL_GL_CreateContext(window)
    glClearColor(0, .5, 1, 0)
    
    ent_dicts = []
    for e in bsp.ENTITIES[1:-1].split('}\n{'):
        ent_dicts.append(eval('{' + e.replace('" "', '": "').replace('"\n', '", ') + '}'))
    try:
        light_environment = [e for e in ent_dicts if e['classname'] == 'light_environment'][0]
        light_environment['angles'] = tuple(map(float, light_environment['angles'].split(' ')))
        light_environment['pitch'] = float(light_environment['pitch'])
        light_environment['_light'] = tuple(map(int, light_environment['_light'].split(' ')))
        light_environment['_ambient'] = tuple(map(int, light_environment['_ambient'].split(' ')))
        sun_vector = vec3(1, 0, 0).rotate(light_environment['angles'][2], -light_environment['pitch'], light_environment['angles'][1])
        sun_colour = (*[x / 255 for x in light_environment['_light'][:3]], light_environment['_light'][-1]) # vec4 (R, G, B) + Strength
        sun_ambient = (*[x / 255 for x in light_environment['_ambient'][:3]], light_environment['_ambient'][-1]) # vec4 (R, G, B) + Strength
        glClearColor(*sun_ambient[:3], 0)
    except: # no light_environment in .bsp (defaults to goldrush)
        sun_vector = vec3(1, 0, 0).rotate(0, 35, 108)
        sun_colour = (1.00, 0.89, 0.73, 600)
        sun_ambient = (0.46, 0.45, 0.55, 350)
        glClearColor(0, 0, 0, 0)
    
    gluPerspective(90, width / height, 0.1, 4096 * 4)
    glPointSize(4)
    glPolygonMode(GL_BACK, GL_LINE)
    glEnable(GL_DEPTH_TEST)
    glFrontFace(GL_CW)
    glEnable(GL_CULL_FACE)
    glColor(1, 1, 1)

    filtered_faces = list(filter(lambda x: x['lightofs'] != -1, bsp.FACES)) #no sky or trigger
##    filtered_faces = list(filter(lambda x: x['dispinfo'] != -1, bsp.FACES)) #disp only
##    filtered_faces = list(filter(lambda x: x['lightofs'] != -1 and x['dispinfo'] == -1, bsp.FACES)) #no sky, trigger or disp
##    filtered_faces = list(filter(lambda x: x['styles'] == (-1, -1, -1, -1), bsp.FACES))
##    filtered_faces = bsp.FACES

    face_count = len(filtered_faces)
    current_face_index = 0
    current_face = filtered_faces[current_face_index]
    current_face_verts = [v[0] for v in bsp.verts_of(current_face)]

    all_faces = []
    all_faces_map = []
    start = 0
    t1 = time()
    for face in filtered_faces:
        if face['dispinfo'] == -1:
            f_verts = bsp.verts_of(face) # add to vertex buffer here and fan the indices
            out = f_verts[:3]
            f_verts = f_verts[3:]
            for vert in f_verts:
                out += [out[0], out[-1], vert]
            f_verts = out
            f_verts_len = len(f_verts)
            all_faces_map.append((start, f_verts_len))
            start += f_verts_len
        else:
            power = bsp.DISP_INFO[face['dispinfo']]['power']
            f_verts = bsp.dispverts_of(face)
            f_verts = bsp_tool.disp_tris(f_verts, power)
        all_faces += f_verts
    slow_faces = all_faces.copy()
    all_faces = list(itertools.chain(*itertools.chain(*all_faces)))
    all_faces_size = len(all_faces)

    vertices = all_faces
    indices = range(all_faces_size)

##    print('compressing vertex buffer...')
##    vertices = []
##    indices = []
##    currentIndex = 0
##    for face in filtered_faces:
##        if face["dispinfo"] == -1:
##            faceVerts = bsp.verts_of(face)
##            faceIndices = calcTriFanIndices(faceVerts, currentIndex)
##        else:
##            power = bsp.DISP_INFO[face['dispinfo']]['power']
##            faceVerts = bsp_tool.disp_tris(bsp.dispverts_of(face), power)
##            faceIndices = bsp_tool.disp_tris(range((2 ** power + 1) ** 2), power)
##        vertices += faceVerts
##        indices += faceIndices
##        currentIndex = faceIndices[-1] + 1 # ?
##    vertices = list(itertools.chain(*itertools.chain(*vertices)))

##    RGB_LIGHTING = []
##    for RGBE_texel in struct.iter_unpack('3Bb', bsp.LIGHTING):
##        RGBA_texel = vec3(RGBE_texel[:-1]) * 2 ** RGBE_texel[-1]
##        RGBA_texel = [clamp(int(x) // 2, 0, 255) for x in RGBA_texel]
##        RGB_LIGHTING.append(struct.pack('3Bb', *RGBA_texel, RGBE_texel[3]))
##    RGB_LIGHTING = b''.join(RGB_LIGHTING)
##
##    lightmap = [] # store on GPU
##    for face in filtered_faces:
##        lmap_start = face['lightofs']
##        if lmap_start != -1:
##            bounds = face['LightmapTextureSizeinLuxels']
##            bounds = [x + 1 for x in bounds]
##            num_styles = sum([1 if x is not -1 else 0 for x in face['styles']])
##            lmap_end = lmap_start + bounds[0] * bounds[1] * 4 * num_styles
##            lmap_bytes = RGB_LIGHTING[lmap_start:lmap_end]
##            lightmap.append([lmap_bytes, bounds])

    t2 = time()
    print(bsp.filename.upper(), end=' ')
    print(f'{bsp.bytesize // 1024:,}KB BSP', end=' >>> ')
    print(f'{len(all_faces) // 9:,} TRIS', end=' & ')
    print(f'{(len(all_faces) * 4) // 1024:,}KB VRAM')
    print(f'ASSEMBLED IN {(t2 - t1) * 1000:,.3f}ms')
    print()

    # SHADERS (check GLSL version)
    USING_ES = False
    try:
        vertShader = compileShader(open('shaders/bsp_faces.v', 'rb'), GL_VERTEX_SHADER)
        fragShader = compileShader(open('shaders/bsp_faces.f', 'rb'), GL_FRAGMENT_SHADER)
    except Exception as exc: # requires PyOpenGL changes described elsewhere
        USING_ES = True # if OpenGL 4.5 is not supported, switch to GLES 3.0
        vertShader = compileShader(open('shaders/bsp_faces_300_es.v', 'rb'), GL_VERTEX_SHADER)
        fragShader = compileShader(open('shaders/bsp_faces_300_es.f', 'rb'), GL_FRAGMENT_SHADER)
        raise exc # need error log if issue is not GLSL version
    bsp_shader = compileProgram(vertShader, fragShader)
    glLinkProgram(bsp_shader)
    glUseProgram(bsp_shader) # must UseProgram to set uniforms

    # UNIFORMS
    if USING_ES:
        # GLES vertex attribs
        attrib_position = glGetAttribLocation(bsp_shader, 'vertexPosition')
        attrib_normal = glGetAttribLocation(bsp_shader, 'vertexNormal')
        attrib_texture_uv = glGetAttribLocation(bsp_shader, 'vertexTexCoord')
        attrib_lightmap_uv = glGetAttribLocation(bsp_shader, 'vertexLightCoord')
        attrib_colour_uv = glGetAttribLocation(bsp_shader, 'vertexColour')
##        ProjectionMatrixLoc = glGetUniformLocation(bsp_shader, 'ProjectionMatrix')
##        # https://www.khronos.org/opengl/wiki/GluPerspective_code
##        glUniformMatrix4fv(ProjectionMatrixLoc, 1, GL_FALSE, ProjectionMatrix) # bad input?
    else: # glsl 450 core uniforms
        glUniform3f(glGetUniformLocation(bsp_shader, 'sun_vector'), *sun_vector)
        glUniform4f(glGetUniformLocation(bsp_shader, 'sun_colour'), *sun_colour)
        glUniform4f(glGetUniformLocation(bsp_shader, 'sun_ambient'), *sun_ambient)

    VERTEX_BUFFER, INDEX_BUFFER = glGenBuffers(2)
    glBindBuffer(GL_ARRAY_BUFFER, VERTEX_BUFFER)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, len(indices) * 4, np.array(indices, dtype=np.uint32), GL_STATIC_DRAW) # INDICES
    glBufferData(GL_ARRAY_BUFFER, len(vertices) * 4, np.array(vertices, dtype=np.float32), GL_STATIC_DRAW) # VERTICES
    glEnableVertexAttribArray(0)  #vertexPosition
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 52, GLvoidp(0))
    glEnableVertexAttribArray(1)  #vertexNormal
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 52, GLvoidp(12))
    glEnableVertexAttribArray(2) #vertexTexcoord
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 52, GLvoidp(24))
    glEnableVertexAttribArray(3) #vertexLightmapCoord
    glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 52, GLvoidp(32))
    glEnableVertexAttribArray(4) #reflectivityColour
    glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 52, GLvoidp(40))
    # displacement alpha (seperate format or shared?)


    glEnable(GL_TEXTURE_2D)
    glActiveTexture(GL_TEXTURE0)
    # texture = open('materials/obsolete.bmp', 'rb')
    texture = open('materials/dev/reflectivity_100.bmp', 'rb')
    texture.seek(54)
    # glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB4, 256, 256, 0, GL_BGR, GL_UNSIGNED_BYTE, texture.read())
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB4, 512, 512, 0, GL_BGR, GL_UNSIGNED_BYTE, texture.read())
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    texture.close()
    del texture

    SDL_GL_SetSwapInterval(0)
    SDL_CaptureMouse(SDL_TRUE)
    SDL_WarpMouseInWindow(window, width // 2, height // 2)
    SDL_SetRelativeMouseMode(SDL_TRUE)
    SDL_SetWindowGrab(window, SDL_TRUE)

    cam_spawn = vec3(0, 0, 32)
    init_speed = 128
    VIEW_CAMERA = camera.freecam(cam_spawn, None, init_speed)

##    # http://heatmaps.tf/api.html
##    url_tail = '.json?fields=id,timestamp,killer_class,killer_weapon,killer_x,killer_y,killer_z,victim_class,victim_x,victim_y,victim_z,customkill,damagebits,death_flags,team&limit=1024'
####    heatmap = json.load(urllib.request.urlopen('http://heatmaps.tf/data/kills/' + bsp.filename[:-4] + url_tail)) # including the limit in the url is great for load times
##    heatmap = json.load(open('heatmaps.tf/pl_upward_complete.json'))
##    k_class = heatmap['fields'].index('killer_class')
##    k_wep = heatmap['fields'].index('killer_weapon')
##    MINI_SENTRY = -2
##    SENTRY = -1
##    WORLD = 0
##    SCOUT = 1
##    SNIPER = 2
##    SOLDIER = 3
##    DEMOMAN = 4
##    MEDIC = 5
##    HEAVY = 6
##    PYRO = 7
##    SPY = 8
##    ENGINEER = 9
##    k_x = heatmap['fields'].index('killer_x')
##    v_class = heatmap['fields'].index('victim_class')
##    v_x = heatmap['fields'].index('victim_x')
##    kill_range = lambda kill: (vec3(*kill[v_x:v_x + 3]) - vec3(*kill[k_x:k_x + 3])).magnitude()
##
##    filtered_kills = [*filter(lambda k: k[k_wep] == MINI_SENTRY, heatmap['kills'])][:1024]

    mousepos = vec2()
    keys = []

    tickrate = 120
    oldtime = time()
    event = SDL_Event()
    while True:
        while SDL_PollEvent(ctypes.byref(event)) != 0:
            if event.type == SDL_QUIT or event.key.keysym.sym == SDLK_ESCAPE and event.type == SDL_KEYDOWN:
                SDL_GL_DeleteContext(glContext)
                SDL_DestroyWindow(window)
                SDL_Quit()
                return bsp
            if event.type == SDL_KEYDOWN:
                if event.key.keysym.sym not in keys:
                    keys.append(event.key.keysym.sym)
            if event.type == SDL_KEYUP:
                while event.key.keysym.sym in keys:
                    keys.remove(event.key.keysym.sym)
            if event.type == SDL_MOUSEMOTION:
                mousepos += vec2(event.motion.xrel, event.motion.yrel)
                SDL_WarpMouseInWindow(window, width // 2, height // 2)
            if event.type == SDL_MOUSEWHEEL:
                VIEW_CAMERA.speed += event.wheel.y * 32
            if event.type == SDL_MOUSEBUTTONDOWN:
                if event.button.button not in keys:
                    keys.append(event.button.button)
            if event.type == SDL_MOUSEBUTTONUP:
                while event.button.button in keys:
                    keys.remove(event.button.button)

        dt = time() - oldtime
        while dt >= 1 / tickrate:
            VIEW_CAMERA.update(mousepos, keys, 1 / tickrate)
            # turning sun
            sun_vector = sun_vector.rotate(.05, 0, 0)
            glUseProgram(bsp_shader)
            glUniform3f(glGetUniformLocation(bsp_shader, 'sun_vector'), *sun_vector)
            #update projection matrix
            if SDLK_BACKQUOTE in keys:
##                print(VIEW_CAMERA)
                #FACES
                fe, ne = current_face['firstedge'], current_face['numedges']
                se_loop = bsp.SURFEDGES[fe:fe + ne]
                e_loop = [bsp.EDGES[e] for e in se_loop]
                print(f'{bsp.filename}.FACES[{bsp.FACES.index(current_face)}]', '\n'.join([f'{k} = {v}' for k,v in current_face.items()]), sep='\n')
                print('\n\t', '\n\t'.join([f'{bsp.VERTICES[v]}' for v in itertools.chain(*e_loop)][::2]), sep='', end='\n\n')
                
                face_center = sum(map(vec3, current_face_verts), vec3()) / len(current_face_verts)
                face_normal = bsp.PLANES[current_face['planenum']]['normal']
                VIEW_CAMERA.position = face_center + vec3(face_normal) * 32
                while SDLK_BACKQUOTE in keys:
                    keys.remove(SDLK_BACKQUOTE)
            if SDLK_r in keys:
                VIEW_CAMERA = camera.freecam(cam_spawn, None, init_speed)
            if SDLK_LSHIFT in keys:
                VIEW_CAMERA.speed += 5
            if SDLK_LCTRL in keys:
                VIEW_CAMERA.speed -= 5
            if SDLK_LEFT in keys or SDL_BUTTON_LEFT in keys:
                current_face_index -= 1
                current_face = filtered_faces[current_face_index]
                current_face_verts = [v[0] for v in bsp.verts_of(current_face)]
                while SDLK_LEFT in keys:
                    keys.remove(SDLK_LEFT)
                while SDL_BUTTON_LEFT in keys:
                    keys.remove(SDL_BUTTON_LEFT)
            if SDLK_RIGHT in keys or SDL_BUTTON_RIGHT in keys:
                current_face_index += 1
                current_face = filtered_faces[current_face_index]
                current_face_verts = [v[0] for v in bsp.verts_of(current_face)]
                while SDLK_RIGHT in keys:
                    keys.remove(SDLK_RIGHT)
                while SDL_BUTTON_RIGHT in keys:
                    keys.remove(SDL_BUTTON_RIGHT)
            dt -= 1 / tickrate
            oldtime = time()

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glPushMatrix()
        VIEW_CAMERA.set()

        glPolygonMode(GL_FRONT, GL_FILL)
        glUseProgram(bsp_shader)
##        for i, face in enumerate(all_faces_map):
##            texture = lightmap[i]
##            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture[1][0], texture[1][1], 0, GL_RGBA, GL_UNSIGNED_BYTE, texture[0])
##            glDrawArrays(GL_TRIANGLES, face[0], face[1])
##        glDrawArrays(GL_TRIANGLES, 0, all_faces_size) # supported in gl3.0 Mesa?
        glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, GLvoidp(0))

        # for when shaders are too much work
##        glBegin(GL_TRIANGLES)
##        for pos, normal, uv, uv2, colour in slow_faces[:2048]:
##            glColor(*colour)
##            glTexCoord(*uv)
##            glVertex(*pos)
##        glEnd()

        # CENTER MARKER
##        glUseProgram(0)
##        glBegin(GL_LINES)
##        glColor(1, 0, 0)
##        glVertex(0, 0, 0)
##        glVertex(128, 0, 0)
##        glColor(0, 1, 0)
##        glVertex(0, 0, 0)
##        glVertex(0, 128, 0)
##        glColor(0, 0, 1)
##        glVertex(0, 0, 0)
##        glVertex(0, 0, 128)
##        glEnd()

        glUseProgram(0)
        glDisable(GL_TEXTURE_2D)
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
        glColor(1, 1, 1)
        glDisable(GL_DEPTH_TEST)
##        glBegin(GL_LINE_LOOP)
##        for vertex in current_face_verts:
##            glVertex(*vertex)
##        glEnd()
##        glBegin(GL_POINTS)
##        for vertex in current_face_verts:
##            glVertex(*vertex)
##        glEnd()
        glPointSize(24)
        glBegin(GL_POINTS)
        glVertex(*(sun_vector * 4096))
        glEnd()
        glPointSize(4)
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_TEXTURE_2D)

##        glTranslate(0, 0, 64)
##        glBegin(GL_LINES)
##        for kill in filtered_kills:
##            glColor(*colorsys.hsv_to_rgb(kill[k_class] / 9, 1, .75))
##            glVertex(*kill[k_x:k_x + 3])
##            glColor(*colorsys.hsv_to_rgb(kill[v_class] / 9, 1, 1))
##            glVertex(*kill[v_x:v_x + 3])
##        glEnd()

        glPopMatrix()
        SDL_GL_SwapWindow(window)