§ Описание
Когда-то я очень хотел создать трехмерную графику на Бейсике, и вот спустя много лет, наконец-то, взялся за дело и сделал это. Но и не только. Помимо самой графики, также научился использовать буфер для того, чтобы рисовать сначала в нем, а потом показывать на экране. Это нерационально, но все-таки, это работает.Скриншот экрана окна Бейсика. А также можно скачать CRAFT.BMP, для источника данных.
§ Код
Основная программа1SCREEN 13 2 3CONST NEAR = 0.5 4 5TYPE vec2i 6 x AS INTEGER 7 y AS INTEGER 8END TYPE 9 10TYPE vec3 11 x AS SINGLE 12 y AS SINGLE 13 z AS SINGLE 14 u AS SINGLE 15 v AS SINGLE 16END TYPE 17 18TYPE trg 19 A1 AS SINGLE: A2 AS SINGLE: A3 AS SINGLE 20 B1 AS SINGLE: B2 AS SINGLE: B3 AS SINGLE 21 C1 AS SINGLE: C2 AS SINGLE: C3 AS SINGLE 22 D1 AS SINGLE: D2 AS SINGLE: D3 AS SINGLE 23END TYPE 24 25' Point list for triangle 26DIM SHARED vc(0 TO 7) AS vec3 27DIM SHARED tile(0 TO 15, 0 TO 15) AS INTEGER 28 29' Matrix operation (ma - camera, mb - operation) 30DIM SHARED ma(0 TO 3, 0 TO 3) AS SINGLE 31DIM SHARED mb(0 TO 3, 0 TO 3) AS SINGLE 32 33DIM SHARED cam AS vec3 34DIM SHARED rot AS vec3 35 36DIM wr(0 TO 3, 0 TO 3, 0 TO 3) AS INTEGER 37 38' Vertex (4 back, 4 front) 39DATA -1, 1, 1 40DATA 1, 1, 1 41DATA 1,-1, 1 42DATA -1,-1, 1 43DATA -1, 1,-1 44DATA 1, 1,-1 45DATA 1,-1,-1 46DATA -1,-1,-1 47 48FACES: 49 50' Quads faces a,b,c,d|tex 51DATA 0, 4, 7, 3 52DATA 0, 1, 5, 4 53DATA 4, 5, 6, 7 54DATA 1, 0, 3, 2 55DATA 2, 3, 7, 6 56DATA 5, 1, 2, 6 57 58' Read all vertexes 59FOR i = 0 TO 7: READ vc(i).x, vc(i).y, vc(i).z: NEXT 60 61' Sprites 62LOADPALETTE ' Loading Palette from CRAFT.BMP 63 64' Camera position 65cam.x = 1.5: cam.y = 3: cam.z = -4 66rot.x = 0: rot.y = 0: rot.z = 0 67 68' World definition 69wr(0,0,3)=1 70wr(0,0,2)=2 71wr(0,0,1)=3 72wr(0,0,0)=4 73 74wr(2,2,0)=1 75wr(2,1,2)=2 76 77CLEARBUF 78 79FOR k = 0 TO 3 80FOR i = 0 TO 3 81FOR j = 0 TO 3 82 83 t = wr(j, i, k) 84 IF t > 0 THEN 85 86 LOADTILE t MOD 16, t \ 16 87 DRAWCUBE 2*j, 2*i, 2*k 88 89 END IF 90NEXT 91NEXT 92NEXT 93 94RESTOREBUFОсновная процедура рисования треугольников.
1' Draw 1 or 2 Triangle 2SUB RENDER (p0 AS vec3, p1 AS vec3, p2 AS vec3) 3 4 DIM q(0 TO 2) AS vec3 5 DIM p(0 TO 3) AS vec3 6 7 q(0) = p0: q(1) = p1: q(2) = p2 8 9 DIM a AS vec3 10 DIM b AS vec3 11 DIM c AS vec3 12 DIM k AS INTEGER 13 14 k = 0 15 16 ' Apply camera transform 17 FOR i = 0 TO 2 18 19 ' Camera transform 20 qx = q(i).x * ma(0, 0) + q(i).y * ma(0, 1) + q(i).z * ma(0, 2) + ma(0, 3) 21 qy = q(i).x * ma(1, 0) + q(i).y * ma(1, 1) + q(i).z * ma(1, 2) + ma(1, 3) 22 qz = q(i).x * ma(2, 0) + q(i).y * ma(2, 1) + q(i).z * ma(2, 2) + ma(2, 3) 23 24 ' Copy new result 25 q(i).x = qx: q(i).y = qy: q(i).z = qz 26 27 NEXT 28 29 ' Search clipping 30 FOR i = 0 TO 2 31 32 a = q(i) 33 b = q((i + 1) MOD 3) 34 35 ' One point in front of NEAR 36 IF a.z >= NEAR OR b.z >= NEAR THEN 37 38 ' Add visible point 39 IF a.z >= NEAR THEN p(k) = a: k = k + 1 40 41 ' a.z must be >= b.z 42 IF (a.z < b.z) THEN SWAP a, b 43 44 ' Diffent sides, calc intermediate point 45 IF (a.z >= NEAR AND b.z < NEAR) THEN 46 47 t = (NEAR - b.z) / (a.z - b.z) 48 49 c.x = b.x + t * (a.x - b.x) 50 c.y = b.y + t * (a.y - b.y) 51 c.z = NEAR 52 c.u = b.u + t * (a.u - b.u) 53 c.v = b.v + t * (a.v - b.v) 54 55 p(k) = c: k = k + 1 56 57 END IF 58 59 END IF 60 61 NEXT 62 63 IF k = 3 OR k = 4 THEN DRAWTRI p(0), p(1), p(2) 64 IF k = 4 THEN DRAWTRI p(0), p(2), p(3) 65 66END SUB 67 68' Drawing triangle 69SUB DRAWTRI (a AS vec3, b AS vec3, c AS vec3) 70 71 ' Declare dimension 72 DIM p(0 TO 2) AS vec2i 73 DIM h(0 TO 2) AS vec3 74 DIM tri AS trg 75 DIM cb AS STRING * 320 76 DIM db(0 TO 319) AS SINGLE 77 78 ' Copy data 79 h(0) = a: h(1) = b: h(2) = c 80 81 ' Make UV-diff 82 FOR i = 1 TO 2 83 h(i).u = h(i).u - h(0).u 84 h(i).v = h(i).v - h(0).v 85 NEXT 86 87 ' Projection 88 FOR i = 0 TO 2 89 p(i).x = 160 + 100 * h(i).x / h(i).z 90 p(i).y = 100 - 100 * h(i).y / h(i).z 91 NEXT 92 93 ' Check front side 94 ABx = p(1).x - p(0).x: ABy = p(1).y - p(0).y 95 ACx = p(2).x - p(0).x: ACy = p(2).y - p(0).y 96 97 IF ABy * ACx - ABx * ACy > 0 THEN EXIT SUB 98 99 ' Sorting 100 FOR i = 0 TO 2 101 FOR j = i + 1 TO 2 102 IF p(i).y > p(j).y THEN SWAP p(i), p(j) 103 NEXT 104 NEXT 105 106 ' Get projection & calculate triangle 107 CALC h(0), h(1), h(2), tri 108 109 ' Top -> Bottom. Get diff (C.x - A.x) / (C.y - A.y) 110 Ax = p(0).x 111 ACy = (p(2).y - p(0).y): IF ACy = 0 THEN ACy = 1 112 AC = (p(2).x - p(0).x) / ACy 113 ABz = h(1).z - h(0).z 114 ACz = h(2).z - h(0).z 115 116 FOR i = 0 TO 1 117 118 ' Get diff (B/C.x - A/B.x) / (B/B.y - A/B.y) 119 Bx = p(i).x 120 By = p(i + 1).y 121 ABy = By - p(i).y: IF ABy = 0 THEN ABy = 1 122 AB = (p(i + 1).x - p(i).x) / ABy 123 124 ' Y0..Y1-1; Y1..Y2 125 IF i = 0 THEN By = By - 1 126 127 ' Drawing lines 128 FOR y = p(i).y TO By 129 130 IF y >= 0 AND y <= 199 THEN 131 132 ' Row has been opened 133 th = 0 134 135 x1 = INT(Ax) 136 x2 = INT(Bx) 137 IF x1 > x2 THEN SWAP x1, x2 138 139 ' Show Only visible area 140 IF x1 < 320 AND x2 >= 0 THEN 141 142 ' Corrections 143 x1 = x1 - 2 144 x2 = x2 + 2 145 146 IF x1 < 0 THEN x1 = 0 147 IF x2 > 319 THEN x2 = 319 148 149 ' Start position 150 dx = x1 - 160 151 dy = 100 - y 152 dz = 100 153 154 ' Coord calc 155 u = dx * tri.A1 + dy * tri.A2 + dz * tri.A3 156 v = dx * tri.B1 + dy * tri.B2 + dz * tri.B3 157 D = dx * tri.C1 + dy * tri.C2 + dz * tri.C3 158 159 FOR x = x1 TO x2 160 161 ' Triangle visible 162 IF D <> 0 AND u >= 0 AND v >= 0 AND u + v < D THEN 163 164 ux = u / D 165 vx = v / D 166 cz = h(0).z + ux * ABz + vx * ACz 167 168 ' Open Row 169 IF th = 0 THEN 170 171 th = 1 172 DEF SEG = VARSEG(cb): BLOAD "TMP\CX" + STR$(y) + ".BIN", VARPTR(cb): DEF SEG 173 DEF SEG = VARSEG(db(0)): BLOAD "TMP\DX" + STR$(y) + ".BIN", VARPTR(db(0)): DEF SEG 174 175 END IF 176 177 ' Check depth buffer 178 IF cz < db(x) THEN 179 180 ' Texture coord and zcoord 181 tx = INT(h(0).u + ux * h(1).u + vx * h(2).u) 182 ty = INT(h(0).v + ux * h(1).v + vx * h(2).v) 183 184 ' Clamp 185 IF tx < 0 THEN tx = 0 ELSE IF tx > 15 THEN tx = 15 186 IF ty < 0 THEN ty = 0 ELSE IF ty > 15 THEN ty = 15 187 188 cl% = tile(tx, ty) 189 190 IF cl% <> 0 THEN 191 192 ' PSET (x, y), cl% 193 MID$(cb, 1 + x, 1) = CHR$(cl%) 194 db(x) = cz 195 196 END IF 197 198 END IF 199 200 END IF 201 202 u = u + tri.A1 203 v = v + tri.B1 204 D = D + tri.C1 205 206 NEXT 207 208 END IF 209 210 ' Save to temporary line 211 IF th > 0 THEN 212 DEF SEG = VARSEG(cb): BSAVE "TMP\CX" + STR$(y) + ".BIN", VARPTR(cb), 320: DEF SEG 213 DEF SEG = VARSEG(db(0)): BSAVE "TMP\DX" + STR$(y) + ".BIN", VARPTR(db(0)), 1280: DEF SEG 214 END IF 215 216 END IF 217 218 Ax = Ax + AC 219 Bx = Bx + AB 220 221 NEXT 222 223 NEXT 224 225END SUB 226 227' Draw cube for x,y,z 228SUB DRAWCUBE(x AS SINGLE, y AS SINGLE, z AS SINGLE) 229 230 DIM p(0 TO 2) AS vec3 231 232 ' Load camera and set cube position 233 MATIDENT 0 234 235 ' Camera rotation 236 CAMROT rot.z, 2 237 CAMROT rot.x, 0 238 CAMROT rot.y, 1 239 240 ' Set cube position 241 CAMTRAN x - cam.x, y - cam.y, z - cam.z 242 243 RESTORE FACES 244 245 ' 6 Faces (0..5) 246 FOR i = 0 TO 5 247 248 READ f0, f1, f2, f3 249 250 ' Triangle 1 251 p(0) = vc(f0): p(0).u = 0: p(0).v = 0 252 p(1) = vc(f1): p(1).u = 16: p(1).v = 0 253 p(2) = vc(f2): p(2).u = 16: p(2).v = 16 254 RENDER p(0), p(1), p(2) 255 256 ' Triangle 2 257 p(0) = vc(f0): p(0).u = 0: p(0).v = 0 258 p(1) = vc(f2): p(1).u = 16: p(1).v = 16 259 p(2) = vc(f3): p(2).u = 0: p(2).v = 16 260 RENDER p(0), p(1), p(2) 261 262 NEXT 263 264END SUB
1' Calculate parameters => tri 2SUB CALC (p0 AS vec3, p1 AS vec3, p2 AS vec3, t AS trg) 3 4 ' Coord triangle 5 Ax = p0.x: Ay = p0.y: Az = p0.z 6 Bx = p1.x: By = p1.y: Bz = p1.z 7 Cx = p2.x: Cy = p2.y: Cz = p2.z 8 9 ' Diff 10 ABx = Bx - Ax: ACx = Cx - Ax 11 ABy = By - Ay: ACy = Cy - Ay 12 ABz = Bz - Az: ACz = Cz - Az 13 14 ' u 15 t.A1 = (Ay * ACz - Az * ACy) 16 t.A2 = (Az * ACx - Ax * ACz) 17 t.A3 = (Ax * ACy - Ay * ACx) 18 19 ' v 20 t.B1 = (Az * ABy - Ay * ABz) 21 t.B2 = (Ax * ABz - Az * ABx) 22 t.B3 = (Ay * ABx - Ax * ABy) 23 24 ' D 25 t.C1 = (ABz * ACy - ABy * ACz) 26 t.C2 = (ABx * ACz - ABz * ACx) 27 t.C3 = (ABy * ACx - ABx * ACy) 28 29END SUBРабота с матрицами.
1' a - angle, axis - 0-X,1-Y,2-Z 2SUB CAMROT (a AS SINGLE, axis AS INTEGER) 3 4 sina = SIN(a) 5 cosa = COS(a) 6 7 MATIDENT 1 8 9 SELECT CASE axis 10 11 CASE 0: ' X Axis 12 13 mb(1, 1) = cosa: mb(1, 2) = -sina 14 mb(2, 1) = sina: mb(2, 2) = cosa 15 16 CASE 1: ' Y Axis 17 18 mb(0, 0) = cosa: mb(0, 2) = sina 19 mb(2, 0) = -sina: mb(2, 2) = cosa 20 21 CASE 2: ' Z Axis 22 23 mb(0, 0) = cosa: mb(0, 1) = -sina 24 mb(1, 0) = sina: mb(1, 1) = cosa 25 26 END SELECT 27 28 MATMULT 29 30END SUB 31 32' B = <translate matrix> 33SUB CAMTRAN (x AS SINGLE, y AS SINGLE, z AS SINGLE) 34 35 MATIDENT 1 36 37 mb(0, 3) = x 38 mb(1, 3) = y 39 mb(2, 3) = z 40 41 MATMULT 42 43END SUB 44 45' A=1, B=1 OR C=1 46SUB MATIDENT (id AS INTEGER) 47 48 FOR i = 0 TO 3 49 FOR j = 0 TO 3 50 51 SELECT CASE id 52 CASE 0: IF i = j THEN ma(i, j) = 1 ELSE ma(i, j) = 0 53 CASE 1: IF i = j THEN mb(i, j) = 1 ELSE mb(i, j) = 0 54 END SELECT 55 56 NEXT 57 NEXT 58 59END SUB 60 61' A = A x B 62SUB MATMULT 63 64 DIM mt(0 TO 3, 0 TO 3) AS SINGLE 65 66 ' Mult 67 FOR i = 0 TO 3 68 FOR j = 0 TO 3 69 70 s = 0 71 FOR k = 0 TO 3: s = s + ma(i, k) * mb(k, j): NEXT 72 mt(i, j) = s 73 74 NEXT 75 NEXT 76 77 ' Copy result to A 78 FOR i = 0 TO 3 79 FOR j = 0 TO 3 80 ma(i, j) = mt(i, j) 81 NEXT 82 NEXT 83 84END SUBОчистка буфера, загрузка и выгрузка.
1' Clear Color/ZBuf 2SUB CLEARBUF 3 4 DIM cb AS STRING * 320 5 DIM db(0 TO 319) AS SINGLE 6 7 FOR i = 0 TO 319 8 9 cb = cb + CHR$(0) 10 db(i) = 32767 11 12 NEXT 13 14 FOR i = 0 TO 199 15 16 DEF SEG = VARSEG(cb): BSAVE "TMP\CX" + STR$(i) + ".BIN", VARPTR(cb), 320: DEF SEG 17 DEF SEG = VARSEG(db(0)): BSAVE "TMP\DX" + STR$(i) + ".BIN", VARPTR(db(0)), 1280: DEF SEG 18 19 NEXT 20 21END SUB 22 23' Draw buffer on screen 24SUB RESTOREBUF 25 26 DIM cb AS STRING * 320 27 FOR y = 0 TO 199 28 DEF SEG = &HA000 29 BLOAD "TMP\CX" + STR$(y) + ".BIN", 320 * y 30 DEF SEG 31 NEXT 32 33END SUBЗагрузка тайлов Minecraft в память из BMP.
1' Read palette for DAC 2SUB LOADPALETTE 3 4DIM pal AS STRING * 3 5 6OPEN "CRAFT.BMP" FOR BINARY AS #1 7 8FOR i = 1 TO 255 9 10 GET #1, &H36 + 1 + i * 4, pal 11 OUT 968, i 12 OUT 969, ASC(MID$(pal, 3, 1)) \ 4 13 OUT 969, ASC(MID$(pal, 2, 1)) \ 4 14 OUT 969, ASC(MID$(pal, 1, 1)) \ 4 15 16NEXT i 17 18CLOSE #1 19 20END SUB 21 22' Load Tile 16x16 Into The DIM 23SUB LOADTILE (j AS INTEGER, i AS INTEGER) 24 25DIM dat AS STRING * 16 26 27OPEN "CRAFT.BMP" FOR BINARY AS #1 28FOR y = 0 TO 15 29 30 GET #1, &H437 + (255 - 16 * i - y) * 256 + 16 * j, dat 31 FOR x = 0 TO 15: tile(x, y) = ASC(MID$(dat, 1 + x, 1)): NEXT 32 33NEXT 34CLOSE #1 35 36END SUB