Сценарий SDL2
Я работаю в области когнитивных наук, поэтому сложно передать контекст этого вопроса. Короче говоря, у нас есть существующая библиотека, которая сильно зависит от PyGame; нам нужно использовать SDL2 для конкретной экспериментальной задачи.
Наша библиотека расширяет базовый класс Exp
при разработке экспериментов; он находится в PyGame, имеет простую и хорошо протестированную подготовительную последовательность, а затем передает управление экспериментатору для завершения набора абстрактных методов, составляющих эксперимент.
Цель: при передаче обслуживания убить PyGame и переключиться на SDL2.
Проблема: приведенный ниже сценарий (сценарий SDL2) работает при использовании вне Exp
среды. Но когда он изменится совсем немного (Реализация эксперимента), произойдут две вещи:
- возникает исключение:
CALayer position contains NaN: [nan nan]
- После консультации с некоторыми внутренними ботаниками, которые подтвердили комментарий Брэда Оллреда к моему вопросу, решение: использование PyGame и В то же время SDL2 по существу всегда требует больше работы, чем замена PyGame на SDL2. Не делай этого.
Текущий подозреваемый Pygame и SDL2 конкурируют за пространство имен в двух местах, о чем свидетельствуют следующие выходные данные терминала при запуске программы:
objc[34300]: Class SDLTranslatorResponder is implemented in both /Library/Frameworks/SDL.framework/Versions/A/SDL and /Library/Frameworks/SDL2.framework/SDL2. One of the two will be used. Which one is undefined.
objc[34300]: Class SDLApplication is implemented in both /Library/Frameworks/SDL2.framework/SDL2 and /Library/Python/2.7/site-packages/pygame/sdlmain_osx.so. One of the two will be used. Which one is undefined.
Ниже представлен рабочий внешний скрипт и небольшие изменения, внесенные для его реализации в нашем контексте Exp. Наконец, внизу находится полный вывод ошибок.
Мы будем очень признательны за любые советы относительно того, в чем может заключаться эта проблема !!!
Реализация эксперимента
import sdl2
import sdl2.ext
import numpy
from PIL import Image
import time
import OpenGL.GL as gl
from scipy import misc
import os
stimDisplayRes = (1366,768) #pixel resolution of the stimDisplay
imgs = []
img_path = "path/to/jpgs"
# this loop just grabs our images; works fine in both scripts
for x in range(1, 450):
x = str(int(x * 2.5)).zfill(8)
path = os.path.join(img_path, "{0}.jpg".format(x))
imgs.append(numpy.array(Image.open(path)))
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
stimDisplay = sdl2.ext.Window("Experiment", size=stimDisplayRes,position=(0,0),flags=sdl2.SDL_WINDOW_OPENGL|sdl2.SDL_WINDOW_SHOWN| sdl2.SDL_WINDOW_FULLSCREEN_DESKTOP |sdl2.SDL_RENDERER_ACCELERATED | sdl2.SDL_RENDERER_PRESENTVSYNC)
glContext = sdl2.SDL_GL_CreateContext(stimDisplay.window)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.glOrtho(0, stimDisplayRes[0],stimDisplayRes[1], 0, 0, 1)
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glDisable(gl.GL_DEPTH_TEST)
sdl2.SDL_PumpEvents() # to show the windows
time.sleep(1)
def blitNumpy(numpyArray,xLoc,yLoc,xCentered=True,yCentered=True):
gl.glEnable(gl.GL_BLEND)
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
ID = gl.glGenTextures(1)
gl.glBindTexture(gl.GL_TEXTURE_2D, ID)
gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_REPLACE);
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP)
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP)
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
if len(numpyArray.shape)==3: #no alpha channel
gl.glTexImage2D( gl.GL_TEXTURE_2D , 0 , gl.GL_RGBA , numpyArray.shape[1] , numpyArray.shape[0] , 0 , gl.GL_RGB , gl.GL_UNSIGNED_BYTE , numpyArray )
elif len(numpyArray.shape)==4: #alpha channel
gl.glTexImage2D( gl.GL_TEXTURE_2D , 0 , gl.GL_RGBA , numpyArray.shape[1] , numpyArray.shape[0] , 0 , gl.GL_RGBA , gl.GL_UNSIGNED_BYTE , numpyArray )
gl.glEnable(gl.GL_TEXTURE_2D)
gl.glBindTexture(gl.GL_TEXTURE_2D, ID)
gl.glBegin(gl.GL_QUADS)
x1 = xLoc + 1.5 - 0.5
x2 = xLoc + numpyArray.shape[1] - 0.0 + 0.5
y1 = yLoc + 1.0 - 0.5
y2 = yLoc + numpyArray.shape[0] - 0.5 + 0.5
if xCentered:
x1 = x1 - numpyArray.shape[1]/2.0
x2 = x2 - numpyArray.shape[1]/2.0
if yCentered:
y1 = y1 - numpyArray.shape[0]/2.0
y2 = y2 - numpyArray.shape[0]/2.0
gl.glTexCoord2f( 0 , 0 )
gl.glVertex2f( x1 , y1 )
gl.glTexCoord2f( 1 , 0 )
gl.glVertex2f( x2 , y1 )
gl.glTexCoord2f( 1 , 1)
gl.glVertex2f( x2 , y2 )
gl.glTexCoord2f( 0 , 1 )
gl.glVertex2f( x1, y2 )
gl.glEnd()
gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
gl.glDeleteTextures([ID])
del ID
gl.glDisable(gl.GL_TEXTURE_2D)
return None
# this is a little loop we're using to get our "frame rate" right; if this is made to work, I'm good from here
i = 0
j = 0
start = time.time()
while time.time()-start<10:
time.sleep(.01) #pretend to do 5ms of other work per frame
gl.glClearColor(0,0,0,1)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
blitNumpy(imgs[i],0,0,xCentered=False,yCentered=False)
sdl2.SDL_GL_SwapWindow(stimDisplay.window)
i+= 1
if i == len(imgs):
i=0
j += 1
print j/(time.time()-start) # we just happen to need this metric
Консольный вывод
Я не репостю весь сценарий; Я буквально ничего не меняю, кроме того, что здесь добавлено:
class Experiment(ExpLib.Exp):
first_run = True #
# bunch of methods that don't interact with either PyGame or SDL2—science stuff
def trial(self, trial_factors, trial_num):
if self.first_run:
pygame.quit()
self.first_run = False
time.sleep(0.1) # maybe unnecessary; just giving PyGame a chance to be fully shut down
# this next call wraps the script above; the only difference is that
# blitNumpy becomes self.blitNumpy, and our FPS loop
self.sdl_trial()
# the experiment's code will go here if I can get this to fly
изображения, которые мы используем для загрузки SDL2, не отображаются явно (хотя окно SDL2 это делает)
Процесс завершен с кодом выхода 13
Контекст