from casioplot import * from img import * import math WIDTH = 100 HEIGHT = 100 TEX_WIDTH = TEXTURE_GRAPH90_WIDTH TEX_HEIGHT = TEXTURE_GRAPH90_HEIGHT zbuf = [32768 for i in range(WIDTH*HEIGHT)] def edge(p1, p2, p3): return (p3[0] - p1[0]) * (p2[1] - p1[1]) - (p3[1] - p1[1]) * (p2[0] - p1[0]) def edge_start(x1, y1, x2, y2, px, py): return (y2 - y1) * (px - x1) - (x2 - x1) * (py - y1) def triangle(p1, p2, p3, zbuf, color): x1, y1, z1, zn1, w1, h1 = p1 x2, y2, z2, zn2, w2, h2 = p2 x3, y3, z3, zn3, w3, h3 = p3 if zn1 < 0 or zn2 < 0 or zn3 < 0: return min_x = max(0, min(x1, min(x2, x3))) max_x = min(WIDTH-1, max(x1, max(x2, x3))) min_y = max(0, min(y1, min(y2, y3))) max_y = min(HEIGHT-1, max(y1, max(y2, y3))) area = edge(p1, p2, p3) if area < 1: return w0 = w1 * z1 h0 = h1 * z1 w1 = w2 * z2 h1 = h2 * z2 w2 = w3 * z3 h2 = h3 * z3 u0_start = edge_start(x2, y2, x3, y3, min_x, min_y) u0_step_x = y3 - y2 u0_step_y = x2 - x3 u1_start = edge_start(x3, y3, x1, y1, min_x, min_y) u1_step_x = y1 - y3 u1_step_y = x3 - x1 u2_start = edge_start(x1, y1, x2, y2, min_x, min_y) u2_step_x = y2 - y1 u2_step_y = x1 - x2 z_num_start = int((u0_start * zn1 + u1_start * zn2 + u2_start * zn3) / area) z_num_step_x = int((u0_step_x * zn1 + u1_step_x * zn2 + u2_step_x * zn3) / area) z_num_step_y = int((u0_step_y * zn1 + u1_step_y * zn2 + u2_step_y * zn3) / area) z_div_start = u0_start * z1 + u1_start * z2 + u2_start * z3 z_div_step_x = u0_step_x * z1 + u1_step_x * z2 + u2_step_x * z3 z_div_step_y = u0_step_y * z1 + u1_step_y * z2 + u2_step_y * z3 for x in range(min_x, max_x+1): u0 = u0_start u1 = u1_start u2 = u2_start z_num = z_num_start z_div = z_div_start for y in range(min_y, max_y+1): if (u0 | u1 | u2) > 0 and zbuf[y*WIDTH+x] > z_num: if color is None: w = int(((u0 * w0 + u1 * w1 + u2 * w2) // z_div) % TEX_WIDTH) h = int(((u0 * h0 + u1 * h1 + u2 * h2) // z_div) % TEX_HEIGHT) row = TEXTURE_GRAPH90[h] c = (row[3*w], row[3*w+1], row[3*w+2]) else: c = color # Put pixel r = c[0] * (32768-z_num) >> 15 g = c[1] * (32768-z_num) >> 15 b = c[2] * (32768-z_num) >> 15 set_pixel(x, y, (r, g, b)) zbuf[y*WIDTH+x] = z_num u0 += u0_step_y u1 += u1_step_y u2 += u2_step_y z_num += z_num_step_y z_div += z_div_step_y u0_start += u0_step_x u1_start += u1_step_x u2_start += u2_step_x z_num_start += z_num_step_x z_div_start += z_div_step_x CAMERA_NEAR = 10 CAMERA_FAR = 60 SCREEN_CENTER_X = WIDTH // 2 SCREEN_CENTER_Y = HEIGHT // 2 SCREEN_SCALE = 15 def world2camera(vertices, camera): camera_vertices = [] cx, cy, cz, ca1, ca2 = camera for x, y, z, w, h in vertices: x -= cx y -= cy z -= cz sin1 = math.sin(-ca1) cos1 = math.cos(-ca1) x, z = cos1*x - sin1*z, sin1*x + cos1*z sin2 = math.sin(-ca2) cos2 = math.cos(-ca2) y, z = cos2*y + sin2*z, -sin2*y + cos2*z camera_vertices.append((x, y, z, w, h)) return camera_vertices def camera2screen(vertices): screen = [] for x, y, z, w, h in vertices: screen.append(( int(+x * CAMERA_NEAR * SCREEN_SCALE / z + SCREEN_CENTER_X), int(-y * CAMERA_NEAR * SCREEN_SCALE / z + SCREEN_CENTER_Y), (1 << 15) / z, int((1 << 15) * (z - CAMERA_NEAR) / CAMERA_FAR), w*TEX_WIDTH, h*TEX_HEIGHT)) return screen vertices = [ (-5,-9, 5, 0, 1), (-5,-9, 7, 0, 0), (-5,+9, 5, 0, 0), (-5,+9, 7, 0, 0), (+5,-9, 5, 1, 1), (+5,-9, 7, 0, 0), (+5,+9, 5, 1, 0), (+5,+9, 7, 0, 0), ] faces = [ # Bottom square (0, 1, 4), (4, 1, 5), # Top square (2, 6, 3), (3, 6, 7), # Front square (0, 4, 2), (2, 4, 6), # Left square (0, 2, 1), (1, 2, 3), # Right square (4, 5, 6), (6, 5, 7), # Back square (1, 3, 5), (5, 3, 7), ] camera = [0, 17, -20, 0, -0.5] # x, y, z, ha, va BLACK = (0x00, 0x00, 0x00) GRAY1 = (0x40, 0x40, 0x40) GRAY2 = (0x80, 0x80, 0x80) GRAY3 = (0xc0, 0xc0, 0xc0) GRAY4 = (0xe0, 0xe0, 0xe0) colors = [GRAY4, GRAY4, GRAY3, GRAY3, None, None, GRAY2, GRAY2, GRAY2, GRAY2, GRAY1, GRAY1] for i in range(33): angle = math.pi / 16 * i camera[0] = 30 * math.sin(angle) camera[2] = -30 * math.cos(angle) + 6 camera[3] = angle for y in range(HEIGHT): for x in range(WIDTH): set_pixel(x, y, BLACK) for i in range(WIDTH*HEIGHT): zbuf[i] = 32768 v_camera = world2camera(vertices, camera) v_screen = camera2screen(v_camera) for i in range(len(faces)): p1, p2, p3 = faces[i] triangle(v_screen[p1], v_screen[p2], v_screen[p3], zbuf, colors[i]) show_screen()