Je me suis mis en tête de faire fonctionner un petit écran oled que j'avais déjà testé sur arduino, sur la carte micropython en SPI, histoire de faire fonctionner un premier hardware sur cette carte. | ![]() |
J'ai pas mal cherché sur le web s'il y avait déjà eu des expériences du genre, mon but étant d'afficher du graphisme et pas seulement du texte.
J'ai quand même trouvé un super tutoriel de chez adafruit de Tonny Dicola qui se rapproche très fort de ce que je veux faire, celui ci fait référence au ESP8266, du coup un bon point pour la librairie en python, mais il existe des différences entre la pyboard 1.1 et l'ESP8266. Il va falloir vérifier quels sont les connectiques à faire entre la carte pyb et l'écran oled. L'écran oled que j'utilises étant différent de celui proposé dans le tutoriel.
Voici le matériel dont je dispose:
![]()
Ecran OLED I2C/SPI, 128x64 pixel
série 12864, 0.96 pouces,
module d'affichage SSD1306
|
![]() |
Analyse de l'écran OLED:
Il existe plusieurs sortes d'écrans OLEDS avec différents annotations sur les pinouts. Cette version-ci est SPI et I2C. Sur les versions I2C seules, on trouvera 4 pinouts (VCC,GND,SDL,SDA). Les versions SPI ont d'autres sorties, parfois nommées différemment. Voici un tableau comparatifs des différentes nomenclatures des sorties SPI sur ce genre d'écran:
pin OLED > | GND | VCC | D0 | D1 | RES | DC | CS |
SPI | masse | 3v3, 5v | CLK (clock) | MOSI | Reset | Data Command | Cable Select |
I2C | masse | 3v3, 5v | SCL | SDA | - | - | - |
Analyse de la connectique SPI de la carte micropython pyb v 1.1:

On peut observer que cette carte a plusieurs ports SPI disponibles.
/SS (CS)
|
SCK
|
MISO
|
MOSI
|
|
SPI (1)
|
X5
|
X6
|
X7
|
X8
|
(cpu name)
|
A4
|
A5
|
A6
|
A7
|
SPI (2)
|
Y5
|
Y6
|
Y7
|
Y8
|
(cpu name)
|
B12
|
B13
|
B14
|
B15
|
Il existe plusieurs notations pour le port SPI (exemple de notation sur le wiki).
On notera ici que l'écran OLED ne reprends pas les notations standard.
J'ai opté pour mon test du port SPI (2), (cela aura de l'importance dans le code lors de l'initialisation du port SPI) ce qui donne ceci pour la connectique:
J'ai opté pour mon test du port SPI (2), (cela aura de l'importance dans le code lors de l'initialisation du port SPI) ce qui donne ceci pour la connectique:

pin OLED > | GND | VCC | D0 | D1 | RES | DC | CS |
noms SPI | CLK (clock) | MOSI | Reset | Data Command | Cable Select | ||
pin PyBoard > | GND | 3v3 | Y6 (SCK) | Y8 | Y1 | Y2 | Y3 (/SS) |
Ce qui est curieux, c'est qu'il semblerait que le D1 ne soit pas le DI (data in), mais plutot le MOSI
Idem pour le CS, Y3 alors que le SS est en Y5 sur la carte, ( software ? à vérifier ).
Idem pour le CS, Y3 alors que le SS est en Y5 sur la carte, ( software ? à vérifier ).
Code:
J'ai repris deux librairies que j'ai un peu adapté et compilée en une seule, les code originaux de la librarie SSD1306.py et gfx.py de chez adafruit.
Les modifs consistent en la suppression de la partie I2C du code SSD1306. Pour la partie GFX, je n'ai gardé que tout ce qui concerne le remplissage de forme, et j'ai ajouté la notion de polygones à 4 cotés pour mon application.
Le premier code est le main.py a copier dans la pyboard.
On note que dans le code lors de la définition du SPI, j'ai opté pour le Y3 pour le Chip Select(CS) et le Y2 pour le data command (DC).
Le second est la lib oled.
Les modifs consistent en la suppression de la partie I2C du code SSD1306. Pour la partie GFX, je n'ai gardé que tout ce qui concerne le remplissage de forme, et j'ai ajouté la notion de polygones à 4 cotés pour mon application.
Le premier code est le main.py a copier dans la pyboard.
On note que dans le code lors de la définition du SPI, j'ai opté pour le Y3 pour le Chip Select(CS) et le Y2 pour le data command (DC).
Le second est la lib oled.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this is main.py file for test library and conenct to spi on pyboard | |
# init SPI & oled | |
import pyb | |
from pyb import SPI | |
from pyb import Pin | |
from pyb import delay | |
import oled_spi | |
spi = SPI('Y', mode=SPI.MASTER, baudrate=8000000, polarity=0, phase=0) | |
display = oled_spi.OLED_SPI(128, 64, spi, dc=Pin('Y2'), res=Pin('Y1'), cs=Pin('Y3')) | |
dirX = 1 | |
youpiX = 15 | |
dirY = 1 | |
x = 64 | |
y = 32 | |
while True: | |
display.framebuf.fill(0) | |
x = x + dirX | |
y = y + dirY | |
x0 = x - 10 | |
x1 = x + 10 | |
y0 = y - 10 | |
y1 = y + 10 | |
if x0 < 0 or x1 > 128: | |
dirX = -dirX | |
#display.invert() | |
if y0 < 0 or y1 > 64: | |
dirY = -dirY | |
if x+15 > 64: | |
youpiX = -55 | |
elif x-55 < 0: | |
youpiX = 15 | |
display.quad(x0, y0, x1, y0, x0, y1, x1, y1, 1) | |
display.text("youpi",x+youpiX,y) | |
pyb.delay(10) | |
display.show() | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this library is come from adafruit library, adapted to my use. | |
# it is only spi on this version, from SSD1306.py | |
# gfx.py from adafruit if partially implemented here | |
# It is added quad filled polygons on this lib, adn remoce contour version of primitives | |
# MicroPython SSD1306 OLED driver, SPI interfaces | |
import time | |
import framebuf | |
from pyb import delay | |
# register definitions | |
SET_CONTRAST = const(0x81) | |
SET_ENTIRE_ON = const(0xa4) | |
SET_NORM_INV = const(0xa6) | |
SET_DISP = const(0xae) | |
SET_MEM_ADDR = const(0x20) | |
SET_COL_ADDR = const(0x21) | |
SET_PAGE_ADDR = const(0x22) | |
SET_DISP_START_LINE = const(0x40) | |
SET_SEG_REMAP = const(0xa0) | |
SET_MUX_RATIO = const(0xa8) | |
SET_COM_OUT_DIR = const(0xc0) | |
SET_DISP_OFFSET = const(0xd3) | |
SET_COM_PIN_CFG = const(0xda) | |
SET_DISP_CLK_DIV = const(0xd5) | |
SET_PRECHARGE = const(0xd9) | |
SET_VCOM_DESEL = const(0xdb) | |
SET_CHARGE_PUMP = const(0x8d) | |
class OLED_SPI: | |
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): | |
self.width = width | |
self.height = height | |
self.external_vcc = external_vcc | |
self.pages = self.height // 8 | |
self.rate = 10 * 1024 * 1024 | |
dc.init(dc.OUT, value=0) | |
res.init(res.OUT, value=0) | |
cs.init(cs.OUT, value=1) | |
self.spi = spi | |
self.dc = dc | |
self.res = res | |
self.cs = cs | |
self.buffer = bytearray((height // 8) * width) | |
self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height) | |
self.poweron() | |
self.init_display() | |
def init_display(self): | |
for cmd in ( | |
SET_DISP | 0x00, # off | |
# address setting | |
SET_MEM_ADDR, 0x00, # horizontal | |
# resolution and layout | |
SET_DISP_START_LINE | 0x00, | |
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 | |
SET_MUX_RATIO, self.height - 1, | |
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 | |
SET_DISP_OFFSET, 0x00, | |
SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12, | |
# timing and driving scheme | |
SET_DISP_CLK_DIV, 0x80, | |
SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1, | |
SET_VCOM_DESEL, 0x30, # 0.83*Vcc | |
# display | |
SET_CONTRAST, 0xff, # maximum | |
SET_ENTIRE_ON, # output follows RAM contents | |
SET_NORM_INV, # not inverted | |
# charge pump | |
SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, | |
SET_DISP | 0x01): # on | |
self.write_cmd(cmd) | |
self.framebuf.fill(0) | |
self.show() | |
def write_cmd(self, cmd): | |
self.cs.high() | |
self.dc.low() | |
self.cs.low() | |
self.spi.send(bytearray([cmd])) | |
self.cs.high() | |
def write_framebuf(self): | |
self.cs.high() | |
self.dc.high() | |
self.cs.low() | |
self.spi.send(self.buffer) | |
self.cs.high() | |
def poweron(self): | |
self.res.high() | |
time.sleep_ms(1) | |
self.res.low() | |
time.sleep_ms(10) | |
self.res.high() | |
def poweroff(self): | |
self.write_cmd(SET_DISP | 0x00) | |
def contrast(self, contrast): | |
self.write_cmd(SET_CONTRAST) | |
self.write_cmd(contrast) | |
def invert(self, invert): | |
self.write_cmd(SET_NORM_INV | (invert & 1)) | |
def show(self): | |
x0 = 0 | |
x1 = self.width - 1 | |
if self.width == 64: | |
# displays with width of 64 pixels are shifted by 32 | |
x0 += 32 | |
x1 += 32 | |
self.write_cmd(SET_COL_ADDR) | |
self.write_cmd(x0) | |
self.write_cmd(x1) | |
self.write_cmd(SET_PAGE_ADDR) | |
self.write_cmd(0) | |
self.write_cmd(self.pages - 1) | |
self.write_framebuf() | |
def line(self, x0, y0, x1, y1, col): | |
steep = abs(y1 - y0) > abs(x1 - x0) | |
if steep: | |
x0, y0 = y0, x0 | |
x1, y1 = y1, x1 | |
if x0 > x1: | |
x0, x1 = x1, x0 | |
y0, y1 = y1, y0 | |
dx = x1 - x0 | |
dy = abs(y1 - y0) | |
err = dx // 2 | |
ystep = 0 | |
if y0 < y1: | |
ystep = 1 | |
else: | |
ystep = -1 | |
while x0 <= x1: | |
if steep: | |
self.framebuf.pixel(y0, x0, col) | |
else: | |
self.framebuf.pixel(x0, y0, col) | |
err -= dy | |
if err < 0: | |
y0 += ystep | |
err += dx | |
x0 += 1 | |
def triangle_Flat(self, x0, y0, x1, y1, x2, y2, col): | |
'''flat triangle, Top parameter to define, TopFlat, else BotFlat''' | |
xT, xL, xR, yT, yB = x0, x1, x2, y0, y1 | |
# define top, sides | |
if y0 == y1: | |
xT, xL, xR, yT, yB = x2, x0, x1, y2, y0 | |
elif y0 == y2: | |
xT, xL, xR, yT, yB = x1, x0, x2, y1, y0 | |
#print ("Flat tri top-sides xT, xL, xR, yT, yB:", xT, xL, xR, yT, yB) | |
if xL > xR: # line begin from left to right | |
#print ("invert x sides") | |
xL,xR = xR,xL | |
if yB < yT: # write line from top to bottom | |
#print ("Top Flat case") | |
yT,yB = yB,yT | |
curxL = xL | |
curxR = xR | |
slopeL = -(xL - xT) / abs(yB - yT); | |
slopeR = -(xR - xT) / abs(yB - yT); | |
else: | |
#print ("Base Flat case") | |
curxL = xT | |
curxR = xT | |
slopeL = (xL - xT) / abs(yB - yT); | |
slopeR = (xR - xT) / abs(yB - yT); | |
#print ("xT, xL, xR, yT, yB, slopeL ,slopeR:", xT, xL, xR, yT, yB, slopeL ,slopeR) | |
for y in range (yT,yB): | |
#print("hLine curxL, curxR, y:", int(curxL), int(curxR),y) | |
#self.hline(int(curxL), int(curxR), y, col) # secure pour le clipping | |
x = int(curxL) | |
length = int(curxR)-x | |
self.framebuf.hline(x,y,length,col) # perf max | |
curxL = curxL + slopeL # * dir | |
curxR = curxR + slopeR # * dir | |
#delay(50) | |
#self.show() | |
def triangle(self, x0, y0, x1, y1, x2, y2, col): | |
# Filled triangle drawing function. Will draw a filled triangle around the points (x0, y0), (x1, y1), and (x2, y2). | |
# at first sort the three vertices by y-coordinate ascending so y0 is the topmost vertice | |
# here we know that y0 <= y1 <= y2 | |
#print ("tri datas orig v0,v1,v2 ", x0, y0, x1, y1, x2, y2) | |
if y0 > y1: | |
y0, y1 = y1, y0 | |
x0, x1 = x1, x0 | |
if y1 > y2: | |
y2, y1 = y1, y2 | |
x2, x1 = x1, x2 | |
if y0 > y1: | |
y0, y1 = y1, y0 | |
x0, x1 = x1, x0 | |
#print ("tri datas sorts v0,v1,v2 ", x0, y0, x1, y1, x2, y2) | |
if y0 == y1 and y1 == y2: # check for trivial: line | |
#print ("Case: hline") | |
#print ("x0, y0, x1, y1, x2, y2:", x0, y0, x1, y1, x2, y2) | |
self.framebuf.hline(x0,y0,x2-x0,col) | |
elif y0 == y1 or y1 == y2: # check for trivial case of top/bottom-flat triangle | |
#print ("Case: trivial flat tri") | |
self.triangle_Flat(x0, y0, x1, y1, x2, y2, col) | |
else: # general case - split the triangle in a topflat and bottom-flat one | |
#print ("Case: general tri") | |
xCut = x0 + float(y1 - y0) / float(y2 - y0) * (x2 - x0) | |
#print ("tri one half") | |
self.triangle_Flat(x0, y0, x1, y1, xCut, y1, col) | |
#print ("tri second half") | |
self.triangle_Flat(x2, y2, x1, y1, xCut, y1, col) | |
def quad(self, x0, y0, x1, y1, x2, y2, x3, y3, col): | |
# trivial case of regular rectangle | |
if x0 == x2 and x1 == x3 and y0 == y1 and y2 == y3: | |
self.rectangle(x0, y0, x3, y3, col) | |
#print ("rectangle") | |
return | |
# irregular rectangle | |
#print ("quad tri top") | |
self.triangle(int(x0), int(y0), int(x1), int(y1), int(x2), int(y2), col) | |
#print ("quad tri bot") | |
self.triangle(int(x2), int(y2), int(x3), int(y3), int(x1), int(y1), col) | |
def rectangle(self, x0, y0, x1, y1, col): | |
if y0>y1: | |
y0,y1 = y1,y0 | |
width = x1-x0 | |
for y in range(y0,y1): | |
self.framebuf.hline(x0,y,width,col) | |
def scroll(self, dx, dy): | |
self.framebuf.scroll(dx, dy) | |
def text(self, string, x, y, col=1): | |
self.framebuf.text(string, x, y, col) | |
Vous devriez voir un petit carré qui se balade sur l'écran avec un mot qui le suit a droite ou a gauche.

Notez bien:
spi = SPI('Y', mode=SPI.MASTER, baudrate=8000000, polarity=0, phase=0)
Le 'Y', correspond au second port SPI, comme décrit dans la doc pour la définition du constructeur du port.
spi = SPI('Y', mode=SPI.MASTER, baudrate=8000000, polarity=0, phase=0)
Le 'Y', correspond au second port SPI, comme décrit dans la doc pour la définition du constructeur du port.
Références:
- SPI sur wiki
- SPI pour la pyboard
- Tutoriel youtube ESP8266 et ecran OLED Adafruit Industries, tonny Dicola
- Tutoriel Adafruit ESP8266 + écran OLED, tonny Dicola
- Tutoriel youtube Oled sur arduino
- La carte Micropyhton (site officiel)
- La library code officielle de la pyboard
- Quick reference de la pyboard
- Code github original python driver adafruit SSD1306.py
- Tutoriel adafruit de la lib gfx.py
- Code github original python lib graphique adafruit gfx.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this is main.py file for test library and conenct to spi on pyboard | |
# init SPI & oled | |
import pyb | |
from pyb import SPI | |
from pyb import Pin | |
from pyb import delay | |
import oled_spi | |
spi = SPI('Y', mode=SPI.MASTER, baudrate=8000000, polarity=0, phase=0) | |
display = oled_spi.OLED_SPI(128, 64, spi, dc=Pin('Y2'), res=Pin('Y1'), cs=Pin('Y3')) | |
dirX = 1 | |
youpiX = 15 | |
dirY = 1 | |
x = 64 | |
y = 32 | |
while True: | |
display.framebuf.fill(0) | |
x = x + dirX | |
y = y + dirY | |
x0 = x - 10 | |
x1 = x + 10 | |
y0 = y - 10 | |
y1 = y + 10 | |
if x0 < 0 or x1 > 128: | |
dirX = -dirX | |
#display.invert() | |
if y0 < 0 or y1 > 64: | |
dirY = -dirY | |
if x+15 > 64: | |
youpiX = -55 | |
elif x-55 < 0: | |
youpiX = 15 | |
display.quad(x0, y0, x1, y0, x0, y1, x1, y1, 1) | |
display.text("youpi",x+youpiX,y) | |
pyb.delay(10) | |
display.show() | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this library is come from adafruit library, adapted to my use. | |
# it is only spi on this version, from SSD1306.py | |
# gfx.py from adafruit if partially implemented here | |
# It is added quad filled polygons on this lib, adn remoce contour version of primitives | |
# MicroPython SSD1306 OLED driver, SPI interfaces | |
import time | |
import framebuf | |
from pyb import delay | |
# register definitions | |
SET_CONTRAST = const(0x81) | |
SET_ENTIRE_ON = const(0xa4) | |
SET_NORM_INV = const(0xa6) | |
SET_DISP = const(0xae) | |
SET_MEM_ADDR = const(0x20) | |
SET_COL_ADDR = const(0x21) | |
SET_PAGE_ADDR = const(0x22) | |
SET_DISP_START_LINE = const(0x40) | |
SET_SEG_REMAP = const(0xa0) | |
SET_MUX_RATIO = const(0xa8) | |
SET_COM_OUT_DIR = const(0xc0) | |
SET_DISP_OFFSET = const(0xd3) | |
SET_COM_PIN_CFG = const(0xda) | |
SET_DISP_CLK_DIV = const(0xd5) | |
SET_PRECHARGE = const(0xd9) | |
SET_VCOM_DESEL = const(0xdb) | |
SET_CHARGE_PUMP = const(0x8d) | |
class OLED_SPI: | |
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): | |
self.width = width | |
self.height = height | |
self.external_vcc = external_vcc | |
self.pages = self.height // 8 | |
self.rate = 10 * 1024 * 1024 | |
dc.init(dc.OUT, value=0) | |
res.init(res.OUT, value=0) | |
cs.init(cs.OUT, value=1) | |
self.spi = spi | |
self.dc = dc | |
self.res = res | |
self.cs = cs | |
self.buffer = bytearray((height // 8) * width) | |
self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height) | |
self.poweron() | |
self.init_display() | |
def init_display(self): | |
for cmd in ( | |
SET_DISP | 0x00, # off | |
# address setting | |
SET_MEM_ADDR, 0x00, # horizontal | |
# resolution and layout | |
SET_DISP_START_LINE | 0x00, | |
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 | |
SET_MUX_RATIO, self.height - 1, | |
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 | |
SET_DISP_OFFSET, 0x00, | |
SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12, | |
# timing and driving scheme | |
SET_DISP_CLK_DIV, 0x80, | |
SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1, | |
SET_VCOM_DESEL, 0x30, # 0.83*Vcc | |
# display | |
SET_CONTRAST, 0xff, # maximum | |
SET_ENTIRE_ON, # output follows RAM contents | |
SET_NORM_INV, # not inverted | |
# charge pump | |
SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, | |
SET_DISP | 0x01): # on | |
self.write_cmd(cmd) | |
self.framebuf.fill(0) | |
self.show() | |
def write_cmd(self, cmd): | |
self.cs.high() | |
self.dc.low() | |
self.cs.low() | |
self.spi.send(bytearray([cmd])) | |
self.cs.high() | |
def write_framebuf(self): | |
self.cs.high() | |
self.dc.high() | |
self.cs.low() | |
self.spi.send(self.buffer) | |
self.cs.high() | |
def poweron(self): | |
self.res.high() | |
time.sleep_ms(1) | |
self.res.low() | |
time.sleep_ms(10) | |
self.res.high() | |
def poweroff(self): | |
self.write_cmd(SET_DISP | 0x00) | |
def contrast(self, contrast): | |
self.write_cmd(SET_CONTRAST) | |
self.write_cmd(contrast) | |
def invert(self, invert): | |
self.write_cmd(SET_NORM_INV | (invert & 1)) | |
def show(self): | |
x0 = 0 | |
x1 = self.width - 1 | |
if self.width == 64: | |
# displays with width of 64 pixels are shifted by 32 | |
x0 += 32 | |
x1 += 32 | |
self.write_cmd(SET_COL_ADDR) | |
self.write_cmd(x0) | |
self.write_cmd(x1) | |
self.write_cmd(SET_PAGE_ADDR) | |
self.write_cmd(0) | |
self.write_cmd(self.pages - 1) | |
self.write_framebuf() | |
def line(self, x0, y0, x1, y1, col): | |
steep = abs(y1 - y0) > abs(x1 - x0) | |
if steep: | |
x0, y0 = y0, x0 | |
x1, y1 = y1, x1 | |
if x0 > x1: | |
x0, x1 = x1, x0 | |
y0, y1 = y1, y0 | |
dx = x1 - x0 | |
dy = abs(y1 - y0) | |
err = dx // 2 | |
ystep = 0 | |
if y0 < y1: | |
ystep = 1 | |
else: | |
ystep = -1 | |
while x0 <= x1: | |
if steep: | |
self.framebuf.pixel(y0, x0, col) | |
else: | |
self.framebuf.pixel(x0, y0, col) | |
err -= dy | |
if err < 0: | |
y0 += ystep | |
err += dx | |
x0 += 1 | |
def triangle_Flat(self, x0, y0, x1, y1, x2, y2, col): | |
'''flat triangle, Top parameter to define, TopFlat, else BotFlat''' | |
xT, xL, xR, yT, yB = x0, x1, x2, y0, y1 | |
# define top, sides | |
if y0 == y1: | |
xT, xL, xR, yT, yB = x2, x0, x1, y2, y0 | |
elif y0 == y2: | |
xT, xL, xR, yT, yB = x1, x0, x2, y1, y0 | |
#print ("Flat tri top-sides xT, xL, xR, yT, yB:", xT, xL, xR, yT, yB) | |
if xL > xR: # line begin from left to right | |
#print ("invert x sides") | |
xL,xR = xR,xL | |
if yB < yT: # write line from top to bottom | |
#print ("Top Flat case") | |
yT,yB = yB,yT | |
curxL = xL | |
curxR = xR | |
slopeL = -(xL - xT) / abs(yB - yT); | |
slopeR = -(xR - xT) / abs(yB - yT); | |
else: | |
#print ("Base Flat case") | |
curxL = xT | |
curxR = xT | |
slopeL = (xL - xT) / abs(yB - yT); | |
slopeR = (xR - xT) / abs(yB - yT); | |
#print ("xT, xL, xR, yT, yB, slopeL ,slopeR:", xT, xL, xR, yT, yB, slopeL ,slopeR) | |
for y in range (yT,yB): | |
#print("hLine curxL, curxR, y:", int(curxL), int(curxR),y) | |
#self.hline(int(curxL), int(curxR), y, col) # secure pour le clipping | |
x = int(curxL) | |
length = int(curxR)-x | |
self.framebuf.hline(x,y,length,col) # perf max | |
curxL = curxL + slopeL # * dir | |
curxR = curxR + slopeR # * dir | |
#delay(50) | |
#self.show() | |
def triangle(self, x0, y0, x1, y1, x2, y2, col): | |
# Filled triangle drawing function. Will draw a filled triangle around the points (x0, y0), (x1, y1), and (x2, y2). | |
# at first sort the three vertices by y-coordinate ascending so y0 is the topmost vertice | |
# here we know that y0 <= y1 <= y2 | |
#print ("tri datas orig v0,v1,v2 ", x0, y0, x1, y1, x2, y2) | |
if y0 > y1: | |
y0, y1 = y1, y0 | |
x0, x1 = x1, x0 | |
if y1 > y2: | |
y2, y1 = y1, y2 | |
x2, x1 = x1, x2 | |
if y0 > y1: | |
y0, y1 = y1, y0 | |
x0, x1 = x1, x0 | |
#print ("tri datas sorts v0,v1,v2 ", x0, y0, x1, y1, x2, y2) | |
if y0 == y1 and y1 == y2: # check for trivial: line | |
#print ("Case: hline") | |
#print ("x0, y0, x1, y1, x2, y2:", x0, y0, x1, y1, x2, y2) | |
self.framebuf.hline(x0,y0,x2-x0,col) | |
elif y0 == y1 or y1 == y2: # check for trivial case of top/bottom-flat triangle | |
#print ("Case: trivial flat tri") | |
self.triangle_Flat(x0, y0, x1, y1, x2, y2, col) | |
else: # general case - split the triangle in a topflat and bottom-flat one | |
#print ("Case: general tri") | |
xCut = x0 + float(y1 - y0) / float(y2 - y0) * (x2 - x0) | |
#print ("tri one half") | |
self.triangle_Flat(x0, y0, x1, y1, xCut, y1, col) | |
#print ("tri second half") | |
self.triangle_Flat(x2, y2, x1, y1, xCut, y1, col) | |
def quad(self, x0, y0, x1, y1, x2, y2, x3, y3, col): | |
# trivial case of regular rectangle | |
if x0 == x2 and x1 == x3 and y0 == y1 and y2 == y3: | |
self.rectangle(x0, y0, x3, y3, col) | |
#print ("rectangle") | |
return | |
# irregular rectangle | |
#print ("quad tri top") | |
self.triangle(int(x0), int(y0), int(x1), int(y1), int(x2), int(y2), col) | |
#print ("quad tri bot") | |
self.triangle(int(x2), int(y2), int(x3), int(y3), int(x1), int(y1), col) | |
def rectangle(self, x0, y0, x1, y1, col): | |
if y0>y1: | |
y0,y1 = y1,y0 | |
width = x1-x0 | |
for y in range(y0,y1): | |
self.framebuf.hline(x0,y,width,col) | |
def scroll(self, dx, dy): | |
self.framebuf.scroll(dx, dy) | |
def text(self, string, x, y, col=1): | |
self.framebuf.text(string, x, y, col) | |
Aucun commentaire:
Enregistrer un commentaire