|
1 | 1 | namespace Polymesh { |
2 | 2 |
|
3 | | - class modelDepth { constructor(public mesh: model, public depth: number) { } } |
4 | | - |
5 | 3 | export class base { |
6 | 4 | protected __prop_upd: control.FrameCallback; __del: boolean; protected __unDel: boolean; protected __updateLoop: boolean; |
7 | 5 | public pos: Motion3; public rot: Motion3; |
@@ -156,313 +154,6 @@ namespace Polymesh { |
156 | 154 |
|
157 | 155 | } |
158 | 156 |
|
159 | | - export class view extends base { |
160 | | - |
161 | | - points: Vector3[]; zoom: number; near: number; far: number; tpoints: Vector3[]; viewport: Image; |
162 | | - |
163 | | - setViewport(viewport: Image) { |
164 | | - if (this.viewport.width === viewport.width && |
165 | | - this.viewport.height === viewport.height) return; |
166 | | - this.viewport = viewport; |
167 | | - } |
168 | | - |
169 | | - initView() { |
170 | | - this.points = [ |
171 | | - new Vector3(0, 0, 1/*, Math.idiv(this.near, 50)*/), |
172 | | - new Vector3(Math.SQRT1_2, 0, Math.SQRT1_2), |
173 | | - new Vector3(-Math.SQRT1_2, 0, Math.SQRT1_2), |
174 | | - new Vector3(0, Math.SQRT1_2, Math.SQRT1_2), |
175 | | - new Vector3(0, -Math.SQRT1_2, Math.SQRT1_2), |
176 | | - ]; |
177 | | - } |
178 | | - |
179 | | - pointUpdate() { |
180 | | - for (let i = 0; i < this.points.length; i++) this.tpoints[i] = rotatePoint3Dxyz(this.points[i], this.pos.toVector(), this.rot.toVector()); |
181 | | - } |
182 | | - |
183 | | - __onDel() { |
184 | | - this.points = []; |
185 | | - this.tpoints = []; |
186 | | - this.viewport = null; |
187 | | - this.zoom = null; |
188 | | - this.near = null; |
189 | | - this.far = null; |
190 | | - } |
191 | | - |
192 | | - __onLoop() { |
193 | | - this.viewport.fill(0); |
194 | | - this.pointUpdate(); |
195 | | - this.renderMshs(meshAny(), this.viewport); |
196 | | - } |
197 | | - |
198 | | - renderMshs(mshs: model[], output: Image, lineren?: boolean) { |
199 | | - if (this.isDel()) return; |
200 | | - const sorted = mshs.map(msh => new modelDepth(msh, msh.zDepth())) |
201 | | - if (sorted.length <= 0) return; |
202 | | - switch (sort) { |
203 | | - case 0x0: sorted.sort((a, b) => b.depth - a.depth); break; |
204 | | - case 0x1: quickSort(sorted, (a, b) => b.depth - a.depth); break; |
205 | | - case 0x2: |
206 | | - default: duoQuickSort(sorted, (a, b) => b.depth - a.depth); break; |
207 | | - } |
208 | | - for (const m of sorted) { |
209 | | - if (m.mesh.flag.invisible) continue; |
210 | | - this.render(m.mesh, output, lineren); |
211 | | - } |
212 | | - } |
213 | | - |
214 | | - constructor(undel?: boolean, viewport?: Image) { |
215 | | - super(undel); |
216 | | - if (viewport === undefined) viewport = scene.backgroundImage(); |
217 | | - this.viewport = viewport; |
218 | | - this.zoom = 1; |
219 | | - this.near = 150; |
220 | | - this.far = 0; |
221 | | - this.initView(); |
222 | | - this.tpoints = [] |
223 | | - } |
224 | | - |
225 | | - setPos(choice: number, x: number) { |
226 | | - switch (choice) { |
227 | | - case 0xC: if (this.zoom !== x) this.zoom = x; return |
228 | | - case 0xD: if (this.near !== x) this.near = x; this.initView(); return |
229 | | - case 0xE: if (this.far !== x) this.far = x; return |
230 | | - }; super.setPos(choice, x); |
231 | | - } |
232 | | - |
233 | | - changePos(choice: number, x: number) { |
234 | | - switch (choice) { |
235 | | - case 0xC: if (this.zoom !== this.zoom + x) this.zoom += x; return |
236 | | - case 0xD: if (this.near !== this.near + x) this.near += x; this.initView(); return |
237 | | - case 0xE: if (this.far !== this.far + x) this.far += x; return |
238 | | - }; super.changePos(choice, x); |
239 | | - } |
240 | | - |
241 | | - getPos(choice: number) { |
242 | | - switch (choice) { |
243 | | - case 0xC: return this.zoom |
244 | | - case 0xD: return this.near |
245 | | - case 0xE: return this.far |
246 | | - }; return super.getPos(choice); |
247 | | - } |
248 | | - |
249 | | - render(msh: model, output: Image, lineren?: boolean) { |
250 | | - if (this.isDel()) return; |
251 | | - if (msh.isDel()) return; |
252 | | - if (!msh || !output || msh.points.length <= 0 || msh.faces.length <= 0) return; |
253 | | - if (msh.flag.invisible) return; |
254 | | - |
255 | | - const dist = this.near, fardist = (this.far === 0 ? 0x7f : this.far), zoom = this.zoom; |
256 | | - |
257 | | - const centerX = output.width >>> 1, centerY = output.height >>> 1; |
258 | | - |
259 | | - let tmp = 0 |
260 | | - const cosX = fcos(camview.rot.x), sinX = fsin(camview.rot.x); |
261 | | - const cosY = fcos(camview.rot.y), sinY = fsin(camview.rot.y); |
262 | | - const cosZ = fcos(camview.rot.z), sinZ = fsin(camview.rot.z); |
263 | | - |
264 | | - // Transform vertices |
265 | | - const rotated = msh.pointCam((v) => { |
266 | | - let x = v.x - this.pos.x; |
267 | | - let y = v.y - this.pos.y; |
268 | | - let z = v.z - this.pos.z; |
269 | | - tmp = x * cosY + z * sinY, z = -x * sinY + z * cosY, x = tmp; // --- rotate around y --- |
270 | | - tmp = y * cosX - z * sinX, z = y * sinX + z * cosX, y = tmp; // --- rotate around x --- |
271 | | - tmp = x * cosZ - y * sinZ, y = x * sinZ + y * cosZ, x = tmp; // --- rotate around z --- |
272 | | - |
273 | | - const vsum = 1.1 * finv(psqrt((x * x) + (y * y) + (z * z))) |
274 | | - // camera offset |
275 | | - x += (x === 0 ? 0 : Math.sign(x) * vsum); |
276 | | - y += (y === 0 ? 0 : Math.sign(y) * vsum); |
277 | | - z += (z === 0 ? 0 : Math.sign(z) * vsum); |
278 | | - // Perspective |
279 | | - const scale = Math.abs(dist) * finv(Math.abs(dist) + z); |
280 | | - return new Vector3( |
281 | | - centerX + (x * scale * zoom), |
282 | | - centerY - (y * scale * zoom), |
283 | | - z |
284 | | - ); |
285 | | - }); |
286 | | - |
287 | | - // Sort triangles |
288 | | - const trisCMP = (a: Polymesh.FaceLOD, b: Polymesh.FaceLOD) => avgZ(rotated, b.indices) - avgZ(rotated, a.indices) |
289 | | - const tris = msh.vfaces.slice(); |
290 | | - //control.runInParallel(() => { |
291 | | - switch (sort) { |
292 | | - case 0x0: tris.sort((a, b) => trisCMP(a, b)); break; |
293 | | - case 0x1: quickSort(tris, (a, b) => trisCMP(a, b)); break; |
294 | | - case 0x2: |
295 | | - default: duoQuickSort(tris, (a, b) => trisCMP(a, b)); break; |
296 | | - } |
297 | | - //}) |
298 | | - |
299 | | - //pause(0); |
300 | | - |
301 | | - // Render |
302 | | - for (let i = 0;i < tris.length;i++) { |
303 | | - const t = tris[i] |
304 | | - const inds = t.indices; |
305 | | - if (inds.some(i => (rotated[i].z < -Math.abs(dist) || (fardist > 0 && rotated[i].z > Math.abs(fardist))))) continue; |
306 | | - //const inds_ = []; |
307 | | - //if (inds.length > 2) inds_[0] = [t.indices[0], t.indices[1], t.indices[2]]; |
308 | | - //if (inds.length > 3) inds_[1] = [t.indices[3], t.indices[1], t.indices[2]]; |
309 | | - const scale = (Math.abs(dist) * finv(Math.abs(dist) + avgZ(rotated, t.indices))); |
310 | | - // LOD calculating? |
311 | | - let im: Image = null |
312 | | - if (t.img) { |
313 | | - im = t.img; |
314 | | - if (msh.flag.texStream) { |
315 | | - let scaleD = finv(scale * zoom) * 0.2; |
316 | | - scaleD = Math.clamp(0, t.imgs.length-1, Math.round((1.25-scaleD) * (t.imgs.length-1))); |
317 | | - im = t.imgs[scaleD] |
318 | | - if (im == null) im = image.create(1, 1) |
319 | | - } |
320 | | - } |
321 | | - if (t.indices.length === 1) { |
322 | | - const idx = t.indices[0]; |
323 | | - const pt = rotated[idx]; |
324 | | - |
325 | | - // center image |
326 | | - const bq = new pt2_4( |
327 | | - pt.x, pt.y, |
328 | | - pt.x, pt.y, |
329 | | - pt.x, pt.y, |
330 | | - pt.x, pt.y, |
331 | | - ) |
332 | | - |
333 | | - const square = dist + (2048 * (scale * t.scale) * zoom) |
334 | | - if (im) { |
335 | | - // set scale image from camera distance |
336 | | - const halfW = (im.width * 0.33333333) * scale * t.scale * zoom; |
337 | | - const halfH = (im.height * 0.33333333) * scale * t.scale * zoom; |
338 | | - |
339 | | - bq.x0 += halfW, bq.y0 += halfH |
340 | | - bq.x1 -= halfW, bq.y1 += halfH |
341 | | - bq.x2 += halfW, bq.y2 -= halfH |
342 | | - bq.x3 -= halfW, bq.y3 -= halfH |
343 | | - if (bq.toArr.every(v => (isOutOfArea(v.x, v.y, output.width, output.height)))) continue; |
344 | | - } else { |
345 | | - bq.x0 += square, bq.y0 += square |
346 | | - bq.x1 -= square, bq.y1 += square |
347 | | - bq.x2 += square, bq.y2 -= square |
348 | | - bq.x3 -= square, bq.y3 -= square |
349 | | - if (bq.toArr.every(v => (isOutOfArea(v.x, v.y, output.width, output.height)))) continue; |
350 | | - } |
351 | | - } else if (isOutOfAreaOnFace(rotated, inds, output.width, output.height)) if (inds.every(i => isOutOfArea(rotated[i].x, rotated[i].y, output.width, output.height))) continue; |
352 | | - |
353 | | - const culling = msh.flag.cull |
354 | | - |
355 | | - // Backface culling |
356 | | - //if (culling) |
357 | | - // if ((inds_[0] && !shouldRenderFace(rotated, inds_[0], camview.pos, t.offset)) && |
358 | | - // (inds_[1] && !shouldRenderFace(rotated, inds_[1], camview.pos, t.offset))) continue; |
359 | | - |
360 | | - if (culling) if (shouldCull(avgXYZ(rotated, inds), t.offset)) continue; |
361 | | - |
362 | | - const idx = t.indices[0]; |
363 | | - const pt = rotated[idx]; |
364 | | - // center image |
365 | | - |
366 | | - let square = dist + (2048 * (scale * t.scale) * zoom) |
367 | | - |
368 | | - let halfW = square + dist; |
369 | | - let halfH = square + dist; |
370 | | - |
371 | | - if (t.img) { |
372 | | - // set scale image from camera distance |
373 | | - |
374 | | - halfW = (im.width * 0.33333333) * scale * t.scale * zoom; |
375 | | - halfH = (im.height * 0.33333333) * scale * t.scale * zoom; |
376 | | - |
377 | | - square = Polymesh.gcd(halfW, halfH) |
378 | | - }; |
379 | | - // when have 2D image billboard (indices.length == 1 and img) |
380 | | - if (t.indices.length === 1) { |
381 | | - if (pt.z < -Math.abs(dist)) continue; |
382 | | - |
383 | | - // when no image |
384 | | - if (!t.img) { fillCircleImage(output, pt.x, pt.y, square, t.color); continue; } |
385 | | - |
386 | | - // fill circle if image is empty |
387 | | - if (isEmptyImage(t.img)) { fillCircleImage(output, pt.x, pt.y, square, t.color); continue; } |
388 | | - |
389 | | - halfW *= 0.75; |
390 | | - halfH *= 0.75; |
391 | | - |
392 | | - // Draw Simple 2D image (billboard) as quad pixel on image |
393 | | - // use distortImage or drawing without perspective distortion |
394 | | - // I will use distortImage draw as vertex quad |
395 | | - distortImage(im, output, |
396 | | - pt.x + halfW, pt.y - halfH, |
397 | | - pt.x - halfW, pt.y - halfH, |
398 | | - pt.x - halfW, pt.y + halfH, |
399 | | - pt.x + halfW, pt.y + halfH |
400 | | - ); |
401 | | - continue; |
402 | | - } |
403 | | - |
404 | | - if (inds.length < 2) continue; |
405 | | - // Draw line canvas when have line color index |
406 | | - if (lineren) { |
407 | | - picDrawLine(output, rotated[inds[0]].x, rotated[inds[0]].y, rotated[inds[1]].x, rotated[inds[1]].y, t.color); |
408 | | - if (inds.length < 3) continue; |
409 | | - picDrawLine(output, rotated[inds[0]].x, rotated[inds[0]].y, rotated[inds[2]].x, rotated[inds[2]].y, t.color); |
410 | | - if (inds.length > 3) picDrawLine(output, rotated[inds[3]].x, rotated[inds[3]].y, rotated[inds[1]].x, rotated[inds[1]].y, t.color), picDrawLine(output, rotated[inds[3]].x, rotated[inds[3]].y, rotated[inds[2]].x, rotated[inds[2]].y, t.color); |
411 | | - else picDrawLine(output, rotated[inds[1]].x, rotated[inds[1]].y, rotated[inds[2]].x, rotated[inds[2]].y, t.color); |
412 | | - continue; |
413 | | - } |
414 | | - if (t.color > 0) { |
415 | | - // Draw line when no shape |
416 | | - if (inds.length < 3) { |
417 | | - picDrawLine(output, |
418 | | - rotated[inds[0]].x, rotated[inds[0]].y, |
419 | | - rotated[inds[1]].x, rotated[inds[1]].y, |
420 | | - t.color |
421 | | - ); |
422 | | - } |
423 | | - if (inds.length > 2) { |
424 | | - // Draw solid when is vertice shape |
425 | | - helpers.imageFillTriangle(output, |
426 | | - rotated[inds[0]].x, rotated[inds[0]].y, |
427 | | - rotated[inds[1]].x, rotated[inds[1]].y, |
428 | | - rotated[inds[2]].x, rotated[inds[2]].y, |
429 | | - t.color |
430 | | - ); |
431 | | - if (inds.length > 3) { |
432 | | - helpers.imageFillTriangle(output, |
433 | | - rotated[inds[3]].x, rotated[inds[3]].y, |
434 | | - rotated[inds[1]].x, rotated[inds[1]].y, |
435 | | - rotated[inds[2]].x, rotated[inds[2]].y, |
436 | | - t.color |
437 | | - ); |
438 | | - } |
439 | | - } |
440 | | - } |
441 | | - |
442 | | - if ((t.img && isEmptyImage(t.img)) || !t.img) continue; |
443 | | - |
444 | | - // Draw texture over |
445 | | - if (inds.length > 2) { |
446 | | - distortImage(im, output, |
447 | | - rotated[inds[3]].x, rotated[inds[3]].y, |
448 | | - rotated[inds[2]].x, rotated[inds[2]].y, |
449 | | - rotated[inds[0]].x, rotated[inds[0]].y, |
450 | | - rotated[inds[1]].x, rotated[inds[1]].y |
451 | | - ); |
452 | | - } else if (inds.length > 3) { |
453 | | - distortImage(im, output, |
454 | | - rotated[inds[3]].x, rotated[inds[3]].y, |
455 | | - rotated[inds[2]].x, rotated[inds[2]].y, |
456 | | - rotated[inds[0]].x, rotated[inds[0]].y, |
457 | | - rotated[inds[1]].x, rotated[inds[1]].y |
458 | | - ); |
459 | | - } |
460 | | - |
461 | | - } |
462 | | - |
463 | | - } |
464 | | - } |
465 | | - |
466 | 157 | export class model extends base { |
467 | 158 |
|
468 | 159 | _faces: Polymesh.Face[]; _points: Polymesh.Vector3[]; pivot: Polymesh.Vector3; |
|
0 commit comments