Commit 44e66fbb authored by blanch's avatar blanch
Browse files

working on core profile

parent 9cfe42d0
# -*- coding: utf-8 -*-
"""
Basic matrix operations emulating OpenGL 3D transforms.
Copyright (c) 2010, Renaud Blanch <rndblnch at gmail dot com>
Licence: GPLv3 or higher <http://www.gnu.org/licenses/gpl.html>
"""
# imports ####################################################################
from math import (cos as _cos, sin as _sin,
radians as _radians, sqrt as _sqrt)
_sum = sum
# matrix construction ########################################################
def identity():
return [[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]]
def scale(sx=1., sy=1., sz=1.):
return [[sx, 0., 0., 0.],
[0., sy, 0., 0.],
[0., 0., sz, 0.],
[0., 0., 0., 1.]]
def translate(tx=0., ty=0., tz=0.):
return [[1., 0., 0., tx],
[0., 1., 0., ty],
[0., 0., 1., tz],
[0., 0., 0., 1.]]
def rotate(a=0., x=0., y=0., z=1.):
a = _radians(a)
s, c = _sin(a), _cos(a)
h = _sqrt(x*x + y*y + z*z)
x, y, z = x/h, y/h, z/h
sx, sy, sz = s*x, s*y, s*z
oc = 1.-c
return [[oc*x*x+c, oc*x*y-sz, oc*x*z+sy, 0.],
[oc*x*y+sz, oc*y*y+c, oc*y*z-sx, 0.],
[oc*x*z-sy, oc*y*z+sx, oc*z*z+c, 0.],
[0., 0., 0., 1.]]
def ortho(l, r, b, t, n, f):
w, h, d = r-l, t-b, f-n
return [[2./w, 0., 0., -(r+l)/w],
[0., 2./h, 0., -(t+b)/h],
[0., 0., -2./d, -(f+n)/d],
[0., 0., 0., 1. ]]
def frustum(l, r, b, t, n, f):
w, h, d = r-l, t-b, f-n
return [[2.*n/w, 0., (r+l)/w, 0. ],
[0., 2.*n/h, (t+b)/h, 0. ],
[0., 0., -(f+n)/d, -2.*f*n/d],
[0., 0., -1., 0. ]]
# manipulation ###############################################################
def matrix(n, m, f=lambda i, j: 0.):
I, J = range(n), range(m)
return [[f(i, j) for j in J] for i in I]
def size(A):
return len(A), len(A[0])
def transpose(A):
n, m = size(A)
return matrix(m, n, lambda i, j: A[j][i])
def column_major(A):
return [float(a) for line in transpose(A) for a in line]
def exclude(A, i, j):
return [R[:j]+R[j+1:] for R in A[:i]+A[i+1:]]
def top_left(A):
n, m = size(A)
return exclude(A, n-1, m-1)
# sum ########################################################################
def add(A, B):
n, p = size(A)
q, m = size(B)
assert (n, p) == (q, m)
return matrix(n, m, lambda i, j: A[i][j]+B[i][j])
def sub(A, B):
n, p = size(A)
q, m = size(B)
assert (n, p) == (q, m)
return matrix(n, m, lambda i, j: A[i][j]-B[i][j])
# product ####################################################################
def scalar(s, A):
n, m = size(A)
return matrix(n, m, lambda i, j: s*A[i][j])
def mul(A, B):
n, p = size(A)
q, m = size(B)
assert p == q
K = range(p)
return matrix(n, m, lambda i, j: _sum(A[i][k]*B[k][j] for k in K))
def product(A, *Bs):
for B in Bs:
A = mul(A, B)
return A
# inverse ####################################################################
def det(A):
n, m = size(A)
assert n == m
if n == 1:
return A[0][0]
else:
return sum(A[i][0]*cofactor(A, i, 0) for i in range(n))
def minor(A, i, j):
return det(exclude(A, i, j))
def cofactor(A, i, j):
return (-1)**(i+j)*minor(A, i, j)
def inverse(A):
n, m = size(A)
assert n == m
C = matrix(n, m, lambda i, j: cofactor(A, i, j))
I = range(n)
d = sum(A[i][0]*C[i][0] for i in I)
return scalar(1./d, transpose(C))
# -*- coding: utf-8 -*-
"""
Quaternion to have nice rotations in 3D.
Copyright (c) 2010, Renaud Blanch <rndblnch at gmail dot com>
Licence: GPLv3 or higher <http://www.gnu.org/licenses/gpl.html>
"""
# imports ####################################################################
from math import (cos as _cos, sin as _sin, atan2 as _atan2, asin as _asin,
sqrt as _sqrt)
from . import vector as _v
# quaternion #################################################################
def quaternion(theta=0, u=(1., 0., 0.)):
w = _cos(theta/2.)
x, y, z = (ui*_sin(theta/2.) for ui in u)
return w, (x, y, z)
def arcball(x, y):
h2 = x*x+y*y
if h2 > 1.:
h = _sqrt(h2)
v = x/h, y/h, 0.
else:
v = x, y, _sqrt(1.-h2)
return 0., v
def mul(P, Q):
w1, v1 = P
w2, v2 = Q
return (w1*w2 - _v.dot(v1, v2),
_v.sum(_v.mul(w1, v2), _v.mul(w2, v1), _v.cross(v1, v2)))
def product(P=quaternion(), *Qs):
for Q in Qs:
P = mul(P, Q)
return P
def matrix(Q):
w, (x, y, z) = Q
return [[1.-2.*(y*y+z*z), 2.*(x*y+w*z), 2.*(x*z-w*y), 0.],
[2.*(x*y-w*z), 1.-2.*(x*x+z*z), 2.*(y*z+w*x), 0.],
[2.*(x*z+w*y), 2.*(y*z-w*x), 1.-2.*(x*x+y*y), 0.],
[0., 0., 0., 1.]]
def euler_angles(Q):
w, (x, y, z) = Q
phi = _atan2(2.*(w*x+y*z), 1.-2.*(x*x+y*y))
theta = _asin(2*(w*y-x*z))
psi = _atan2(2.*(w*z+x*y), 1.-2.*(y*y+z*z))
return phi, theta, psi
def antipod(Q):
w, v = Q
return -w, _v.mul(-1., v)
def inverse(Q):
w, v = Q
return w, _v.mul(-1., v)
def rotate(Q, v):
_, v = product(Q, (0, v), inverse(Q))
return v
def theta_u(Q):
w, v = Q
norm = _v.norm(v)
theta = 2.*_atan2(norm, w)
u = _v.mul(1./norm, v)
return theta, u
def power(Q, a):
theta, u = theta_u(Q)
return quaternion(a*theta, u)
def slerp(Q0, Q1, a):
return mul(power(mul(Q1, inverse(Q0)), a), Q0)
# -*- coding: utf-8 -*-
"""
Basic 3D vector operations.
Copyright (c) 2010, Renaud Blanch <rndblnch at gmail dot com>
Licence: GPLv3 or higher <http://www.gnu.org/licenses/gpl.html>
"""
# imports ####################################################################
from math import sqrt as _sqrt
_sum = sum
# globals ####################################################################
def _zip_zero_pad(*ps):
len_max = max(len(p) for p in ps)
ps = [tuple(p) + (0.,)*(len_max-len(p)) for p in ps]
for t in zip(*ps):
yield t
_O = tuple()
_3D = 3
_X, _Y, _Z = range(_3D)
# vector #####################################################################
def vector(p1=_O, p0=_O):
return tuple(p1i-p0i for (p1i, p0i) in _zip_zero_pad(p1, p0))
def mul(a, v):
return tuple(a*vi for vi in v)
def add(u, v):
return tuple(ui+vi for (ui, vi) in _zip_zero_pad(u, v))
def sum(u=vector(), *vs):
for v in vs:
u = add(u, v)
return u
def sub(u, v):
return tuple(ui-vi for (ui, vi) in _zip_zero_pad(u, v))
def dot(u, v):
return _sum(ui*vi for (ui, vi) in _zip_zero_pad(u, v))
def cross(u, v):
assert len(u) == len(v) == _3D
return (u[_Y]*v[_Z]-u[_Z]*v[_Y],
u[_Z]*v[_X]-u[_X]*v[_Z],
u[_X]*v[_Y]-u[_Y]*v[_X])
def norm(v):
return _sqrt(dot(v, v))
def matrix(v):
return [[vi] for vi in v]
......@@ -30,6 +30,13 @@ from OpenGL.GL import (
glGenTextures, glTexParameter,
glGenBuffers, glBindBuffer, glBufferData,
glTexImage1D, glDeleteBuffers,
glDrawArrays, GL_ARRAY_BUFFER, GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER,
GL_STREAM_DRAW,
glDrawElements, GL_UNSIGNED_INT, glBindAttribLocation,
glBindVertexArray, glGenVertexArrays,
glEnableVertexAttribArray,
glGetAttribLocation,
glVertexAttribPointer, GL_FLOAT, glUseProgram,
)
from PyQt5.QtCore import (
......@@ -94,10 +101,12 @@ class AbstractMapView(QOpenGLWidget):
glActiveTexture(GL_TEXTURE0+DATA_UNIT)
set_uniform(self.program, 'values', DATA_UNIT)
glActiveTexture(GL_TEXTURE0+PALETTE_UNIT)
set_uniform(self.program, b'palette', PALETTE_UNIT)
set_uniform(self.program, 'palette', PALETTE_UNIT)
set_uniform(self.program, 'v_0', 0.)
set_uniform(self.program, 'v_1', 1.)
self.set_colormap()
self.va = None
def update_vs(self):
"""update min and max to keep program in sync with model"""
......
......@@ -3,11 +3,16 @@
# imports ###################################################################
from .AbstractMapView import *
import ctypes
from PyQt5.QtCore import QSize
from ..Interaction import *
from ..linalg import matrix as m
from .AbstractMapView import *
# map #######################################################################
......@@ -79,6 +84,7 @@ class MapView(AbstractMapView):
# selection texture
glActiveTexture(GL_TEXTURE0+SEL_UNIT)
set_uniform(program, 'selection', SEL_UNIT)
return program
def sizeHint(self):
......@@ -103,16 +109,21 @@ class MapView(AbstractMapView):
glViewport(0, 0, width, height)
tw, th = self.model.tex_width, self.model.tex_height
glMatrixMode(GL_TEXTURE)
glLoadIdentity()
glScale(1./tw, 1./th, 1.)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, width, 0, height, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# glMatrixMode(GL_TEXTURE)
# glLoadIdentity()
# glScale(1./tw, 1./th, 1.)
self.texture = m.scale(1./tw, 1./th)
# glMatrixMode(GL_PROJECTION)
# glLoadIdentity()
# glOrtho(0, width, 0, height, -1, 1)
projection = m.ortho(0, width, 0, height, -1, 1)
set_uniform(self.program, 'projection_matrix', m.column_major(projection))
# glMatrixMode(GL_MODELVIEW)
# glLoadIdentity()
modelview = m.identity()
set_uniform(self.program, 'modelview_matrix', m.column_major(modelview))
self.repaint()
......@@ -127,7 +138,7 @@ class MapView(AbstractMapView):
"""
# band using OpenGL texturing
glClear(GL_COLOR_BUFFER_BIT)
glEnable(GL_TEXTURE_2D)
# glEnable(GL_TEXTURE_2D)
glUseProgram(self.program)
# selection texture
......@@ -142,21 +153,66 @@ class MapView(AbstractMapView):
z = self.model.z
w, h = self.width(), self.height()
glMatrixMode(GL_TEXTURE)
glPushMatrix()
glTranslate(cx, cy, 0.)
glScale(1./z, 1./z, 1.)
glTranslate(-w//2, -h//2, 0.)
# glMatrixMode(GL_TEXTURE)
# glPushMatrix()
# glTranslate(cx, cy, 0.)
# glScale(1./z, 1./z, 1.)
# glTranslate(-w//2, -h//2, 0.)
texture = m.product(
self.texture,
m.translate(cx, cy),
m.scale(1./z, 1./z),
m.translate(-w//2, -h//2)
)
set_uniform(self.program, 'texture_matrix', m.column_major(texture))
"""
glBegin(GL_TRIANGLE_STRIP)
for x in [0, w]:
for y in [0, h]:
glTexCoord(x, y)
glVertex(x, y)
glEnd()
glPopMatrix()
"""
if self.va == None:
self.va = glGenVertexArrays(1)
glBindVertexArray(self.va)
for attrib in ['vertex', 'tex_coord']:
glEnableVertexAttribArray(glGetAttribLocation(self.program, attrib))
data_buffer = np.ravel([
[(x, y, 0.), # vertex
(x, y, 0.)] # tex_coord
for y in [0., h] for x in [0., w]
]).astype(np.float32)
# indicies_buffer = np.array([0, 1, 2, 3], dtype=np.uint)
self.array_id = glGenBuffers(1)
# self.elements_id = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.array_id)
glBufferData(GL_ARRAY_BUFFER, data_buffer, GL_STREAM_DRAW)
# glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.elements_id)
# glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies_buffer, GL_STATIC_DRAW)
del data_buffer
# del indicies_buffer
float_size = ctypes.sizeof(ctypes.c_float)
vertex_offset = ctypes.c_void_p(0 * float_size)
tex_coord_offset = ctypes.c_void_p(3 * float_size)
record_len = 6 * float_size
glBindBuffer(GL_ARRAY_BUFFER, self.array_id)
glVertexAttribPointer(glGetAttribLocation(self.program, 'vertex'), 3, GL_FLOAT, False,
record_len, vertex_offset)
glVertexAttribPointer(glGetAttribLocation(self.program, 'tex_coord'), 3, GL_FLOAT, False,
record_len, tex_coord_offset)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
# glPopMatrix()
glUseProgram(0)
glDisable(GL_TEXTURE_2D)
# glDisable(GL_TEXTURE_2D)
# glBindTexture(GL_TEXTURE_2D, 0)
......
......@@ -11,6 +11,8 @@ from PyQt5.QtGui import (
QColor
)
import math
# mini map ##################################################################
......
......@@ -106,7 +106,7 @@ MINIMAP_SHADER = """
const vec4 color = vec4(1., 1., 1., 1.);
in front_color;
in vec4 front_color;
out vec4 frag_color;
......
......@@ -15,9 +15,11 @@ from OpenGL.GL import (
glGetUniformLocation, glUseProgram,
GL_COMPILE_STATUS, GL_LINK_STATUS,
glUniform1fv, glUniform2fv, glUniform3fv, glUniform4fv,
glUniform1iv, glUniformMatrix3fv,
glUniform1iv, glUniformMatrix3fv, glUniformMatrix4fv,
)
from ..linalg import matrix as m
# utils #####################################################################
......@@ -74,6 +76,8 @@ _Uniforms = {
(4, ctypes.c_float): glUniform4fv,
(9, ctypes.c_float): lambda location, n, values:
glUniformMatrix3fv(location, n, GL_FALSE, values),
(16, ctypes.c_float): lambda location, n, values:
glUniformMatrix4fv(location, n, GL_FALSE, values),
(1, ctypes.c_int): glUniform1iv,
}
......@@ -84,7 +88,7 @@ def set_uniform(program, uniform, *values):
"""
v0, n = values[0], len(values)
if isinstance(v0, tuple):
if isinstance(v0, (tuple, list)):
l, t = len(v0), _c_types[type(v0[0])]
values = (t * (l*n))(*(u for value in values for u in value))
else:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment