-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchunkhandler.pyx
More file actions
3677 lines (3376 loc) · 163 KB
/
chunkhandler.pyx
File metadata and controls
3677 lines (3376 loc) · 163 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
DigDigRPG
Copyright (C) 2011 Jin Ju Yu
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
cdef extern from "stdlib.h":
ctypedef unsigned long size_t
void free(void *ptr)
void *malloc(size_t size)
void *realloc(void *ptr, size_t size)
size_t strlen(char *s)
char *strcpy(char *dest, char *src)
void *memset(void *str, int c, size_t n)
void *memcpy(void *str1, void *str2, size_t n)
void *memmove(void *str1, void *str2, size_t n)
cdef extern from "gl/gl.h":
ctypedef int GLint
ctypedef unsigned int GLenum
ctypedef unsigned int GLsizei
ctypedef void GLvoid
cdef void glVertexPointer(GLint size, GLenum type, GLsizei stride, GLvoid *pointer)
cdef void glTexCoordPointer(GLint size, GLenum type,GLsizei stride, GLvoid *pointer)
cdef void glColorPointer(GLint size, GLenum type,GLsizei stride, GLvoid *pointer)
cdef void glNormalPointer(GLenum type,GLsizei stride, GLvoid *pointer)
cdef void glIndexPointer(GLenum type, GLsizei stride, GLvoid *pointer)
cdef void glDrawElements(GLenum mode, GLsizei count, GLenum type,GLvoid *indices)
cdef void glDrawArrays( GLenum mode, GLint first, GLsizei count)
cdef extern from "genquads.h":
struct tChunk:
unsigned char *chunk
char *heights
unsigned char *colors
int x,y,z
ctypedef tChunk Chunk
struct tOctree:
tOctree *parent
tOctree **children
int filled
void *extra
ctypedef tOctree Octree
struct tXYZ:
float x,y,z
ctypedef tXYZ XYZ
struct tTorch:
int x
int y
int z
int face
ctypedef tTorch Torch
struct tChest:
int x
int y
int z
int frontFacing
ctypedef tChest Chest
struct tItem:
int type
float x
float y
float z
int idx
ctypedef tItem Item
struct tExtra:
Torch *torches
int torchLen
int torchIdx
Chest *chests
int chestLen
int chestIdx
Item *items
int itemLen
int itemIdx
ctypedef tExtra Extra
char HitBoundingBox(float minB[3],float maxB[3], float origin[3], float dir[3],float coord[3])
int InWater(float x, float y, float z, float vx, float vy, float vz)
int CheckCollide(float x, float y, float z, float vx, float vy, float vz, float bx, float by_, float bz, float ydiff)
void FixPos(float *fx, float *fy,float *fz, float ox,float oy,float oz,float nx,float ny,float nz, int bx, int by_, int bz, Octree *octrees[9], Chunk *chunks[9], int pos[9][3])
int PickWithMouse(XYZ vp, XYZ dirV, int pos[9][3], Octree *octrees[9], Chunk *chunks[9], int outCoords[3], int *outFace, int limit, float ydiff, float viewmat[16])
void FillHeights(Chunk *chunk)
void FillTrees(Chunk *chunk, char trees[1000])
void FillMap(unsigned char *chunkData)
void FillTerrain(unsigned char *chunkData, int *points, int len, int ox, int oy, int oz, int upward, int lwidth, int rwidth, int bwidth, int twidth, int heightlimit, unsigned char fill1, unsigned char fill2, unsigned char fill3)
void FillSea(unsigned char *chunkData, int *points, int len, int ox, int oy, int oz, int upward, int lwidth, int rwidth, int bwidth, int twidth, int heightlimit, unsigned char fill1, unsigned char fill2, unsigned char fill3, int depth)
void CalcRecursive(Chunk * chunk, Octree *octree, int x, int y, int z, int depth)
int IsPolyFront(int place, int x, int y, int z, float vx, float vy, float vz)
void GenQuad(float *quadBuffer, int place, int x, int y, int z)
Octree *AccessRecur(Octree *parent, int curx, int cury, int curz, int targetx, int targety, int targetz, int depth, int targetdepth)
Octree *AccessOctreeWithXYZ(Octree * root, int x, int y, int z, int targetdepth)
int CubeInFrustum(float x, float y, float z, double size, double frustum[6][4])
void GenQuads(float *tV[64], float *tT[64], unsigned char *tC[64], int tIdx[64], int tLen[64], float *nsV[64], float *nsT[64], unsigned char *nsC[64], int nsIdx[64], int nsLen[64], float *aV[64], float *aT[64], unsigned char *aC[64], int aIdx[64], int aLen[64], float *iV[64], float *iT[64], unsigned char *iC[64], int iIdx[64], int iLen[64], Octree *root, Octree *parent, Chunk *chunk, Octree **octrees, Chunk **chunks, int pos[9][3], int depth, double frustum[6][4], int x, int y, int z, int ox, int oy, int oz, float vx, float vy, float vz, int lx, int ly, int lz, int updateCoords[64*3], int drawIdx, float sunx, float suny, float sunz)
void GenIndexList(unsigned int *outIndexList, int *outIndexLen, float *quads, int quadLen, float vx, float vy, float vz)
cimport libc.stdio as stdio
cimport libc.math as cmath
import math
import numpy
import pickle
import random
cdef:
int TEST_SIZE = 9
enum OctreeFilledFlag:
OT_FILLED = 1 << 0
OT_HALFFILLED = 1 << 1
OT_EMPTY = 1 << 2
OT_COMPLETETRANSPARENT = 1 << 3
OT_PARTTRANSPARENT = 1 << 4
OT_XBLOCK = 1 << 5
OT_YBLOCK = 1 << 6
OT_ZBLOCK = 1 << 7
enum BlockFlags:
# 여기에 추가할 때 중간에 껴넣게 되면 맵 다 깨짐!
# 총 256가지의 블럭종류들만이 가능하다.
# 블럭에 컬러를 넣고 싶다면 또다른 확장 데이터가 필요함.
# 뭐 컬러 버퍼라던지 그런 chunk.chunk를 또 만들면 된다.
BLOCK_EMPTY
BLOCK_WATER
BLOCK_GLASS
BLOCK_LAVA
BLOCK_COBBLESTONE
BLOCK_LOG
BLOCK_WALL
BLOCK_BRICK
BLOCK_TNT
BLOCK_STONE
BLOCK_SAND
BLOCK_GRAVEL
BLOCK_WOOD
BLOCK_LEAVES
BLOCK_SILVER
BLOCK_GOLD
BLOCK_COALORE
BLOCK_IRONORE
BLOCK_DIAMONDORE
BLOCK_IRON
BLOCK_DIAMOND
BLOCK_CPU
BLOCK_CODE
BLOCK_ENERGY
BLOCK_KEYBIND
BLOCK_PANELSWITCH
BLOCK_LEVER
BLOCK_WALLSWITCH
BLOCK_NUMPAD
BLOCK_TELEPORT
BLOCK_JUMPER
BLOCK_ELEVATOR
BLOCK_ENGINECORE
BLOCK_CONSTRUCTIONSITE
BLOCK_AREASELECTOR
BLOCK_GOLDORE
BLOCK_SILVERORE
BLOCK_WOOL
BLOCK_GRASS
BLOCK_DIRT
BLOCK_INDESTRUCTABLE
BLOCK_CHEST
BLOCK_SPAWNER
BLOCK_SILVERSLOT
BLOCK_GOLDSLOT
BLOCK_DIAMONDSLOT
BLOCK_COLOR
struct Vertex:
float x,y,z
struct Quad:
Vertex v[4]
int NUM_TREE = 4
int MAX_DEPTH = 6
int STREAM_BUFFER_LEN = 7*7
int STREAM_BUFFER_SIZE = sizeof(Chunk *)*STREAM_BUFFER_LEN
int SIZE_CHUNK = 128*128*128
#음. 옥트리를 쓰는 것 까지는 좋은데, 애초부터 최대 맵크기를 정해두고 해야한다.
# 블럭 한개가 50센티라고 치고....
# 12번 차일드를 까면 되나? 근데..... 음.......옥트리를 쓸 필요가 없이 걍 선형으로 해야하네. 높이는 128이 끝이니까. 음.....
# 아 그럼 쿼드트리 쓰면 되는구만 높이는 128개를 다 가지고 있거나 한다?
# 적어도 16개로 나눠서 최종레벨에서는 data가 16x16x16의 청크가 되게 한다. 16x16x16짜리가 8개 맨 아래 바닥부터 위까지 있도록 한다.
# 아. 청크사이즈를 2x2x2로 한 다음에 이걸 또 2x2x2로 묶고 또 묶고 이러면서 이걸 바로 Octree로 만들어야겠다.
# 2x2x2로 묶어도 4x4x4를 검사해야 한다.
# Traverse는 펑션포인터로 하도록 하자. 다시다시 복습하는 셈 치고.
# Octree 자체는 큐브를 가지고 있을 필요가 없다. 꽉찬건지 아닌지의 값만 가지고 있으면 된다.
# Octree의 루트가 여러개가 있고, 이것은 Quadtree에 의해 관리되도록 하게 하자.
# 128x128x128을 2x2x2가 될 때 까지 나눈 옥트리를 쓰도록 하자.
# 음.. 이걸 쿼드트리로 관리할 필요도 없다. 파일별로 관리하도록 하자. 청크가 되도록 하자. 그래. 용량도 2메가 밖에 안됨.
# 옥트리 자체도 매번 계산할 게 아니라 생성할 때 한 번 계산하고 그냥 저장해버리도록 하자.
#
#
# Torch등의 오브젝트는 따로 저장하겠군....
"""
bool SphereInFrustum( float x, float y, float z, float radius )
{
int p;
for( p = 0; p < 6; p++ )
if( frustum[p][0] * x + frustum[p][1] * y + frustum[p][2] * z + frustum[p][3] <= -radius )
return false;
return true;
}
"""
class Vector2(object):
def __init__(self, x=0.0, y=0.0):
self.x = x
self.y = y
def length(self):
return math.sqrt(self.x ** 2 + self.y ** 2)
def normalised(self):
l = self.length()
if l == 0.0:
l = 1
return Vector2(self.x / l, self.y / l)
def __neg__(self):
return Vector2(-self.x, -self.y)
def __add__(self, other):
return Vector2(self.x + other.x, self.y + other.y)
def __radd__(self, other):
return self.__add__(other)
def __sub__(self, other):
return Vector2(self.x - other.x, self.y - other.y)
def __rsub__(self, other):
return self.__sub__(other)
def __mul__(self, other):
if type(other) in (int, float):
return Vector2(self.x * other, self.y * other)
else: # dot product
return self.x * other.x + self.y * other.y
def __rmul__(self, other):
return self.__mul__(other)
def __div__(self, other):
return Vector2(self.x / other, self.y / other)
def dotProduct(self, other):
return self.x * other.x + self.y * other.y
def __repr__(self):
return str([self.x, self.y])
def tangent(a, b):
return (a-b)/2.0
def CatmullRomSpline(p0, p1, p2, p3, resolution=0.1):
m0 = tangent(p1, p0)
m1 = tangent(p2, p0)
m2 = tangent(p3, p1)
m3 = tangent(p3, p2)
t = 0.0
a = []
b = []
c = []
while t < 1.0:
t_2 = t * t
_1_t = 1 - t
_2t = 2 * t
h00 = (1 + _2t) * (_1_t) * (_1_t)
h10 = t * (_1_t) * (_1_t)
h01 = t_2 * (3 - _2t)
h11 = t_2 * (t - 1)
result = Vector2(0.0,0.0)
result.x = h00 * p0.x + h10 * m0.x + h01 * p1.x + h11 * m1.x
result.y = h00 * p0.y + h10 * m0.y + h01 * p1.y + h11 * m1.y
a.append(result)
result = Vector2(0.0,0.0)
result.x = h00 * p1.x + h10 * m1.x + h01 * p2.x + h11 * m2.x
result.y = h00 * p1.y + h10 * m1.y + h01 * p2.y + h11 * m2.y
b.append(result)
result = Vector2(0.0,0.0)
result.x = h00 * p2.x + h10 * m2.x + h01 * p3.x + h11 * m3.x
result.y = h00 * p2.y + h10 * m2.y + h01 * p3.y + h11 * m3.y
c.append(result)
t+=resolution
out = []
for point in b:
out.append(point)
return out
cdef void *AllocExtra():
cdef Extra *extra
extra = <Extra*>malloc(sizeof(Extra))
memset(extra, 0, sizeof(Extra))
extra.torches = <Torch*>malloc(sizeof(Torch)*4)
extra.torchLen = 4
extra.chests = <Chest*>malloc(sizeof(Chest)*4)
extra.chestLen = 4
extra.items = <Item*>malloc(sizeof(Item)*4)
extra.itemLen = 4
return <void*>extra
cdef void FreeExtra(void *extra):
free((<Extra*>extra).chests)
free((<Extra*>extra).torches)
free((<Extra*>extra).items)
free(<Extra*>extra)
cdef Alloc(Octree *parent, int depth):
parent.parent = NULL
parent.children = NULL
parent.filled = OT_EMPTY
parent.extra = NULL
if depth == 7:
return
else:
parent.children = <Octree**>malloc(sizeof(Octree*)*8)
for i in range(8):
parent.children[i] = <Octree*>malloc(sizeof(Octree))
Alloc(parent.children[i], depth+1)
parent.children[i].parent = parent
if depth == 5:
parent.extra = AllocExtra()
cdef Octree *GenOctree():
cdef Octree *root
root = <Octree*>malloc(sizeof(Octree))
Alloc(root, 1)
return root
cdef FreeOctree(Octree *root):
if root.children:
for i in range(8):
FreeOctree(root.children[i])
free(root.children)
root.children = NULL
if root.extra:
FreeExtra(root.extra)
root.extra = NULL
free(root)
import shutil, os
class Quaternion:
def __init__(self, x = 0, y = 0, z = 0, w = 1):
self.x = x
self.y = y
self.z = z
self.w = w
def Length(self):
return math.sqrt(self.x**2+self.y**2+self.z**2+self.w**2)
def Normalized(self):
len = self.Length()
try:
factor = 1.0/len
x = self.x * factor
y = self.y * factor
z = self.z * factor
w = self.w * factor
except ZeroDivisionError:
x = self.x
y = self.y
z = self.z
w = self.w
return Quaternion(x,y,z,w)
def CreateFromAxisAngle(self, x, y, z, degrees):
angle = (degrees / 180.0) * math.pi
result = math.sin( angle / 2.0 )
self.w = math.cos( angle / 2.0 )
self.x = (x * result)
self.y = (y * result)
self.z = (z * result)
def CreateMatrix(self):
pMatrix = [0 for i in range(16)]
# First row
pMatrix[ 0] = 1.0 - 2.0 * ( self.y * self.y + self.z * self.z )
pMatrix[ 1] = 2.0 * (self.x * self.y + self.z * self.w)
pMatrix[ 2] = 2.0 * (self.x * self.z - self.y * self.w)
pMatrix[ 3] = 0.0
# Second row
pMatrix[ 4] = 2.0 * ( self.x * self.y - self.z * self.w )
pMatrix[ 5] = 1.0 - 2.0 * ( self.x * self.x + self.z * self.z )
pMatrix[ 6] = 2.0 * (self.z * self.y + self.x * self.w )
pMatrix[ 7] = 0.0
# Third row
pMatrix[ 8] = 2.0 * ( self.x * self.z + self.y * self.w )
pMatrix[ 9] = 2.0 * ( self.y * self.z - self.x * self.w )
pMatrix[10] = 1.0 - 2.0 * ( self.x * self.x + self.y * self.y )
pMatrix[11] = 0.0
# Fourth row
pMatrix[12] = 0
pMatrix[13] = 0
pMatrix[14] = 0
pMatrix[15] = 1.0
return pMatrix
def Conjugate(self):
x = -self.x
y = -self.y
z = -self.z
w = self.w
return Quaternion(x,y,z,w)
def __mul__(self, quat):
x = self.w*quat.x + self.x*quat.w + self.y*quat.z - self.z*quat.y;
y = self.w*quat.y - self.x*quat.z + self.y*quat.w + self.z*quat.x;
z = self.w*quat.z + self.x*quat.y - self.y*quat.x + self.z*quat.w;
w = self.w*quat.w - self.x*quat.x - self.y*quat.y - self.z*quat.z;
return Quaternion(x,y,z,w)
def __repr__(self):
return str([self.w, [self.x,self.y,self.z]])
def Dot(self, q):
q = q.Normalized()
self = self.Normalized()
return self.x*q.x + self.y*q.y + self.z*q.z + self.w*q.w
def Slerp(self, q, t):
import math
if t <= 0.0:
return Quaternion(self.x, self.y, self.z, self.w)
elif t >= 1.0:
return Quaternion(q.x, q.y, q.z, q.w)
cosOmega = self.Dot(q)
if cosOmega < 0:
cosOmega = -cosOmega
q2 = Quaternion(-q.x, -q.y, -q.z, -q.w)
else:
q2 = Quaternion(q.x, q.y, q.z, q.w)
if 1.0 - cosOmega > 0.00001:
omega = math.acos(cosOmega)
sinOmega = math.sin(omega)
oneOverSinOmega = 1.0 / sinOmega
k0 = math.sin((1.0 - t) * omega) / sinOmega
k1 = math.sin(t * omega) / sinOmega
else:
k0 = 1.0 - t
k1 = t
return Quaternion(
(k0 * self.x) + (k1 * q2.x),
(k0 * self.y) + (k1 * q2.y),
(k0 * self.z) + (k1 * q2.z),
(k0 * self.w) + (k1 * q2.w))
import OpenGL.GL as GL
class MapGen:
HEIGHTS = 0
def __init__(self):
self.map = {}
self.generatedCoords = {}
self.points = []
try:
self.chunkObjs = pickle.load(open("./map/patterns.pkl", "r"))
except:
self.chunkObjs = {}
def GenMap(self, multX, multY): # x,y,z는 4096의 배수이다. 새로 생성할 때마다 주변청크가 있다면 겹치는 2048 영역에도 뭔가 이어서 만든다.
# 음 또한 하여간에 이미 청크가 있는 영역만 안건드리면 된다.
# 4096의 의미는 산맥의 전체 길이가 4096을 넘지 않는다는 것 밖에 의미하는 게 없다.
# 호수 역시 넓어봐야 4096을 넘지 않는다.
# 기본적으로 이 게임에 호수는 있어도 바다는 없다? 바다 처럼 보이는 해변가도 있지만 바다는 없다. 육지를 기반으로 호수가 잔뜩 있는 맵.
# 바다를 기반으로 한 게 아님. 바다는 팔 수 없으니까.
# 아하...........
# 음. 아 무한맵 만드는 논문 읽어야함 ㅇㅇ
# 음......맵은 일단 쿼드트리로 terrain을 생성하고
# 현재 청크와 주변 8개 청크를 기준으로 쿼드트리를 생성한다.
# 그러다가 옆으로 가게 되면 현재 루트 쿼드트리를 새로운 루트의 차일드 쿼드트리로 바꾸어두고
# 새로운 맵을 생성.
# 새로운 맵을 생성할 때에는 4개의 청크를 한번에 생성해서 땅속의 자연 동굴이 256x256의 넓이를 가질 수 있게 한다.
# 또한, 자연동굴 같은 경우는 이어서 실시간으로 만드는 방법도 있을 것이다.
# 산맥이나 절벽같은 것도 terrain과는 별개로 해야한다.
# 아...생성하는 terrain은 128x128일 필요가 없다. 한번에 512x512의 heightmap을 만든다.
# 산맥/동굴의 높이 값은 height맵을 기준으로 하여 뿌려지겠지만, 맵과는 별개로 만들고
# 새로운 맵이 만들어질 때마다 랜덤 벡터로 계속 진행하게 한다.
# overhang은 절벽 오브젝트가 있는 곳에다가 만들면 된다.
# 절벽 오브젝트는 산이 있는 곳에다가 산의 옆에다가 딱 붙이면 된다.
# 또는 산의 타입이 전부 절벽, 일부만 절벽 이런 속성을 가지게 하면 될 듯 하다.
#
# 아 맵 생성할 때 하잇맵 하지 말고, 산/구덩이 이런식으로 거시적 수준에서 한다.
# 레이어를 두어서 3개의 레이어가 있는데, 첫번째는 크게 구덩이 파고 산 두고
# 그 구덩이 판 상태에서 다시 구덩이 안에다가 산을 두거나, 산 위에다가 구덩이를 둘 수 있게 2번째 레이어를 깐다.
# 3번째 레이어도 그렇게 하고 뭐 그런다.
#
# 일단 오브젝트들이 생성되면 그 부분은 더이상 새로운 오브젝트를 만들지 않는다.
#
# 음.......실시간 맵생성 뭐 이런거는....... 이미 마인크래프트에서 했자나?
# 그냥 스태틱 맵으로 해서... 오블리비언 식의 게임을 만들까? 땅을 파는 오블리비언 ㅠㅠ
# 땅 못파는 영역 몇개 두고 뭐 이래서.
# 1년동안 열심히 만들어 보자.
#
# 음........게임상에서 맵을 수정하기가 쉽도록 하는 펑션들을 만들어야겠다.
# 그래서 아예 게임상에서 맵을 생성하는 코드를 실행해서 게임 자체에서 맵 에디팅을...
#
# 청크단위로 맵을 생성하다 보면 동굴같은 게 두 청크에 이어져있는게 되지 않는다. 라지만,
# 동굴을 현재 청크까지만 뚫어놓고 새로운 청크 있으면 거기서 이어서 하면 되겠구만? 아하...
#
# 특별히 오브젝트가 없어도 맵 가장자리에다가 어떤 동굴 이어짐 오브젝트, 산맥 이어짐 오브젝트를 두고 거기서 이어서 가도록 만들면 된다.
# 다만, 이미 생성된 청크쪽으로는 갈 수 없다.
#
#
# 그 전에 일단 간단하게 80 높이의 땅만 만들어 보자...;;
#
#
#
# 동굴:
# 일단 점이 가진 넓이로 만든다.
# 그럼 다음 점이 가진 넓이로 이어진다. 다음 점은 45도 이내의 각도이다. 0도로 그대로 이어질 가능성이 50%이다.
# 밑으로도 내려가고 옆으로도 가고 뭐 이런다.
#
# 산:
# spline을 이용해서 만든다.
#
# 일단 산 만들자.
# 음 근데 gimp등으로 희안한 모양 만들어서 그라디에이션 뿌리면 한방인데 spline을 이용해서 만들 필요가 굳이 있을까 싶다.
#
# 미리 패턴들을 만들어두고 그걸 합쳐서 산맥을 만들던지
# 그런 패턴 자체를 PIL로 만들어서 합치던디 뭐 이러면 될텐데.
# spline으로 삼각형을 만들어서 그걸 그라디에이션으로 채우면 되는데?
#
# 여러 Y수준에서 스플라인을 만들면 기상천외한 모양의 산을 만들 수 있다.
#
# 원형이나 여러 형태의 스플라인 곡선들을 쌓아서 산을 만든다.
# 점들을 어떻게 할까. 줄어드는 각도로 할까? 랜덤하게 줄어드는 각도로 하고 그러다보면 스파이럴이 되던지 만나던지 하겟지.
q = Quaternion()
org = Vector2(0.0, 0.0)
v1 = Vector(1.0, 0.0, 0.0)
angle = 5
self.points = []
self.points += [org]
while angle <= 270:
q.CreateFromAxisAngle(0.0,1.0,0.0, angle)
matrix = q.CreateMatrix()
v2 = v1.MultMatrix(matrix)
v2 = Vector2(v2.x,v2.z) * (random.random()+1.0)
self.points += [self.points[-1]+v2]
angle += random.randint(5,10)
# 이걸 float으로 만들어 fillmap에 전달하면 fillmap이 채우는 간단한코드
# 이걸 C로 옮기면 땡 XX:
# 음 청크 리스트 역시 뭔가 쿼드트리로 바꿔줘야 하지 않을지. XXX:
# 너무 많이 로드하면 메모리 모자람 -_-;
# 현재 한번에 3x3를 로드하는데 대충 4x4정도만 메모리에 가지고 있으면 됨. 더가면 어차피 로드
# 돌아갈 가능성이 있으니 놔두고
#
# 자. 하여간에 그 다음엔 이 만든 산을 거꾸로 파느냐, 높이는 어디서 시작하느냐, 몇배로 늘리느냐, 위치 오프셋은 어디느냐에따라
# 여러가지 지형이 가능할 것이고
# 전부 풀땅으로만 채우지 말고 여러가지로 채우고, 밑으로 판 거에는 특히 물 등을 채우고 그러면 바다나 호수가 된다.
if len(self.points) >= 4:
1,2,3,4,5,6,7,8
lines = []
lines += CatmullRomSpline(self.points[0], self.points[1], self.points[2], self.points[3], 0.01)
for i in range(len(self.points)-4):
lines += CatmullRomSpline(self.points[i+1], self.points[i+2], self.points[i+3], self.points[i+4], 0.01)
lines += CatmullRomSpline(self.points[-3], self.points[-2], self.points[-1] , self.points[0], 0.1)
lines += CatmullRomSpline(self.points[-2], self.points[-1], self.points[0] , self.points[1], 0.1)
lines += CatmullRomSpline(self.points[-1], self.points[0], self.points[1] , self.points[2], 0.1)
#스케일 하고 정렬한다.
leftMost = lines[0]
rightMost = lines[0]
topMost = lines[0]
bottomMost = lines[0]
for point in lines:
if point.x > leftMost.x:
leftMost = point
for point in lines:
if point.y < topMost.y:
topMost = point
for point in lines:
if point.x < rightMost.x:
rightMost = point
for point in lines:
if point.y > bottomMost.y:
bottomMost = point
xdif = leftMost.x
ydif = bottomMost.y
lenX = rightMost.x - leftMost.x
lenY = topMost.y - bottomMost.y
factorX = multX / lenX
factorY = multY / lenY
lines2 = []
for point in lines:
point.x -= xdif
point.y -= ydif
point.x *= factorX
point.y *= factorY
point.x = int(point.x)
point.y = int(point.y)
lines2 += [(point.x, point.y)]
lines2 = list(set(lines2))
def bubblesort(items):
swapped = True
while swapped:
swapped = False
for i in range(len(items)-1):
# 일단 y값이 커야바꾼다.
# y값이 같다면 x값으로 바꾼다.
if items[i][1] > items[i+1][1]:
items[i], items[i+1] = items[i+1], items[i]
swapped = True
elif items[i][1] == items[i+1][1] and items[i][0] > items[i+1][0]:
items[i], items[i+1] = items[i+1], items[i]
swapped = True
bubblesort(lines2)
mylines = []
prevX,prevY = lines2[0]
prevEndX = prevX
mylines += [(prevX,prevY)]
odd = False
for point in lines2[1:]:
if point[1] != prevY:
if len(mylines) >= 2:
diff = point[1] - prevY
offset = 1
a,b = mylines[-2]
c,d = mylines[-1]
while diff > 1: # diff>=2
mylines += [(a, b+offset), (c, d+offset)]
diff -= 1
offset += 1
if not odd:
mylines += [(prevX, prevY)]
mylines += [(point[0], point[1])]
prevEndX = prevX
else:
mylines += [(prevEndX, prevY)]
mylines += [(point[0], point[1])]
prevX = point[0]
prevY = point[1]
odd = not odd
if not odd: # if even, 근데 왜 안됨?
mylines += [(prevEndX, prevY)]
return mylines
"""
이렇게 만들어진 곡선을 어떻게 렌더링하나?
원 안에 스캔라인으로 채우는 방식으로 해야하나?
청크 안에서 딱 맞춰져야 할텐데 이거참. 가장 left right top bottom점을 찾아서 청크에 맞춘 후에
scale을 적용하고
catmull로 나온 점들을 라인으로 간주하고는
그 라인들을 기준으로 폴리곤을 채운다는 발상?
가장 맨 위의 y값부터 1씩 증가하면서
가장 왼쪽의 x값을 찾고 가장 오른쪽의 x값을 찾고 스캔라인
x값은 어떻게 찾나? y값보다 작은 숫자중에 가장 큰 숫자, y값보다 큰 숫자중에 가장 작은 숫자
그걸 linearinterpolation해서 x값을 얻는다.
에이...pycairo쓰자^^
아니다. 그냥 여기서 만든 shape를 맨 윗층에 깔고, 그 아래로 y값은 한칸씩 감소시키고 테두리의 두께를 1씩 증가시키면서 산을 만들면 된다!!!!
http://www.cs.brown.edu/stc/summer/2ViewRender/2ViewRender_23.html
X값들의 리스트를 1픽셀 수준에서 만든다.
odd,even으로 폴리곤의 안쪽인지 바깥쪽인지 본다.
"""
"""
if (x,y,z) not in self.map:
self.generatedCoords[(x,y,z)] = None
#x,y,z에 대해 여러가지 쉐이프라던가 땅의 높이라던가 그런 걸 결정한다.
# x,y,z를 중심으로 여러가지 뭔가를 깔아두고, 만약 주변이 비어있다면 그 주변과 겹치는 부분에도 뭘 깔고,
# 만약 주변이 이미 제네레이트 되어 있다면 그 주변과는 겹치게 하지 않는다.
# 주변이라는 건 x,y,z 즉 Chunk를 각각 분리하는 좌표를 기준으로 한 주변 chunk 영역들.
# 높이가 서로 다른 부분은 인터폴레이션 영역이 있어서 인터폴레이션 영역안에 있는 건 그 특정한 방법의 인터폴레이션을 사용해서 한다.
# 음 일단 4방향 동서남북으로 서로 다른 인터폴레이션 방법을 쓰게 하거나, 산맥 같은 경우 산맵이 끝나는 끝지점에 특정한
# 인터폴레이션 방법을 사용해서 쓴다. 나머지 부분은.... 그냥 1칸씩 점점 올라가는 방법으로 하자.
size = 128
self.map[(x,y,z)] = []
heights = []
while len(heights) < 8:
# 바운더리가 생성되어있다면 제한하고 아니라면 제한 안해도 됨
x,y,z = (random.randint(32,96),random.randint(64,120),random.randint(32,96),)
rad = random.randint(64,96)
if x-rad >= 0 and x+rad < 128 and y-rad >= 0 and y+rad < 128 and z-rad >= 0 and z+rad < 128:
self.map[(x,y,z)] += [(self.HEIGHTS, (x,y,z), rad)]
mountains = []
# 벡터로 진행을 시키면서 패턴들을 연결한다. 아...패턴 쓸 핑요도 없음,
# rad와 랜덤벡터의 진행으로 한다.
# 이미 생성된 부분은 피한다.
# 마운틴은.... 사각형 안에 그냥 넣기엔 좀 그런 듯. 사각형을 완전 벗어남..
#
# 마운틴 레인지는 이런식으로 만들면 되겠고.
# 일반 맵의 높이 등도 달라야 하겠는데 하잇맵 생성을 하자.
doMts = random.randint(0,1)
if doMts:
while len(mountains) < 30:
rad = random.randint(10,40)
diffx = random.randint(4,32)
diffy = random.randint(4,32)
height = random.randint(16,32)
mountains += [(diffx, diffy, rad)]
"""
return self.map
def Save(self):
pickle.dump(self.chunkObjs, open("./map/patterns.pkl", "w"))
class Vector:
def __init__(self, x = 0, y = 0, z = 0, w=1.0):
self.x = x
self.y = y
self.z = z
self.w = w
def Length(self):
import math
return math.sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
def NormalizeByW(self):
x,y,z,w = self.x,self.y,self.z,self.w
w = float(w)
if w == 0.0:
w = 0.000001
x /= w
y /= w
z /= w
w = 1.0
return Vector(x,y,z,w)
def Normalized(self):
try:
newV = self.NormalizeByW()
factor = 1.0/newV.Length()
return newV.MultScalar(factor)
except ZeroDivisionError:
return Vector(self.x, self.y, self.z, self.w)
def Cross(self, vector):
newV = self.NormalizeByW()
vector = vector.NormalizeByW()
return Vector(*cross(newV.x,newV.y,newV.z,vector.x,vector.y,vector.z))
def Dot(self, vector):
newV = self.NormalizeByW()
newV = newV.Normalized()
vector = vector.NormalizeByW()
vector = vector.Normalized()
return newV.x*vector.x+newV.y*vector.y+newV.z*vector.z
def __add__(self, vec):
newV = self.NormalizeByW()
vec = vec.NormalizeByW()
a,b,c = newV.x,newV.y,newV.z
x,y,z = vec.x,vec.y,vec.z
return Vector(a+x,b+y,c+z)
def __sub__(self, vec):
newV = self.NormalizeByW()
vec = vec.NormalizeByW()
a,b,c = newV.x,newV.y,newV.z
x,y,z = vec.x,vec.y,vec.z
return Vector(a-x,b-y,c-z)
def MultScalar(self, scalar):
newV = self.NormalizeByW()
return Vector(newV.x*scalar, newV.y*scalar, newV.z*scalar)
def DivScalar(self, scalar):
newV = self.NormalizeByW()
return Vector(newV.x/scalar, newV.y/scalar, newV.z/scalar)
def __repr__(self):
return str([self.x, self.y, self.z, self.w])
def MultMatrix(self, mat):
tempVec = Vector()
tempVec.x = self.x*mat[0] + self.y*mat[1] + self.z*mat[2] + self.w*mat[3]
tempVec.y = self.x*mat[4] + self.y*mat[5] + self.z*mat[6] + self.w*mat[7]
tempVec.z = self.x*mat[8] + self.y*mat[9] + self.z*mat[10] + self.w*mat[11]
tempVec.w = self.x*mat[12] + self.y*mat[13] + self.z*mat[14] + self.w*mat[15]
return tempVec
def normalize(x, y, z):
factor = 1.0/math.sqrt(x**2+y**2+z**2)
return x*factor, y*factor, z*factor
def cross(x,y,z,x2,y2,z2):
return ((y*z2-z*y2),(z*x2-x*z2),(x*y2-y*x2))
def dot(x,y,z,x2,y2,z2):
return x*x2+y*y2+z*z2
cdef class Chunks:
cdef Chunk **chunks
cdef Octree **octrees
# cdef float quads[32768*4*3]
# cdef float texs[32768*4*2]
# cdef float normals[32768*4*3]
# cdef unsigned char colors[32768*4*3]
# cdef int curIdx
cdef float *tV[64]
cdef float *tT[64]
cdef unsigned char *tC[64] # terrain
cdef int tIdx[64]
cdef int tLen[64]
cdef float *nsV[64]
cdef float *nsT[64]
cdef unsigned char *nsC[64] # no sun
cdef int nsIdx[64]
cdef int nsLen[64]
cdef float *aV[64]
cdef float *aT[64]
cdef unsigned char *aC[64] # alpha
cdef int aIdx[64]
cdef int aLen[64]
cdef float *iV[64]
cdef float *iT[64]
cdef unsigned char *iC[64] # item
cdef int iIdx[64]
cdef int iLen[64]
cdef unsigned int indexList[32768*4*3]
cdef int updateCoords[64*3]
cdef int lastX
cdef int lastY
cdef int lastZ
mapgen = MapGen()
curDrawnCoords = [[(-1,-1,-1) for i in range(64)]]
cdef int curBlock
def __cinit__(self):
self.chunks = <Chunk**>malloc(sizeof(Chunk *)*STREAM_BUFFER_LEN)
self.octrees = <Octree **>malloc(sizeof(Octree *)*STREAM_BUFFER_LEN)
memset(self.chunks, 0, sizeof(Chunk *)*STREAM_BUFFER_LEN)
memset(self.octrees, 0, sizeof(Octree *)*STREAM_BUFFER_LEN)
memset(self.tIdx, 0, sizeof(int)*64)
memset(self.nsIdx, 0, sizeof(int)*64)
memset(self.aIdx, 0, sizeof(int)*64)
memset(self.iIdx, 0, sizeof(int)*64)
memset(self.tLen, 0, sizeof(int)*64)
memset(self.nsLen, 0, sizeof(int)*64)
memset(self.aLen, 0, sizeof(int)*64)
memset(self.iLen, 0, sizeof(int)*64)
self.lastX = -1
self.lastY = -1
self.lastZ = -1
self.curBlock = -1
def __dealloc__(self):
for i in range(64):
if self.tLen[i] != 0:
free(self.tV[i])
free(self.tT[i])
free(self.tC[i])
if self.nsLen[i] != 0:
free(self.nsV[i])
free(self.nsT[i])
free(self.nsC[i])
if self.aLen[i] != 0:
free(self.aV[i])
free(self.aT[i])
free(self.aC[i])
if self.iLen[i] != 0:
free(self.iV[i])
free(self.iT[i])
free(self.iC[i])
for i in range(STREAM_BUFFER_LEN):
if self.chunks[i]:
free(self.chunks[i])
self.chunks[i] = NULL
FreeOctree(self.octrees[i])
self.octrees[i] = NULL
free(self.chunks)
free(self.octrees)
def Save(self):
self.mapgen.Save()
for i in range(STREAM_BUFFER_LEN):
if self.chunks[i] and self.octrees[i]:
self.SaveToDisk(self.chunks[i])
self.SaveToDiskColor(self.chunks[i])
self.SaveItems(self.octrees[i], self.chunks[i].x, self.chunks[i].z)
cdef void SaveItems(self, Octree *octree, int x,int z):
self.SaveTorches(octree, x, z)
self.SaveChests(octree, x, z)
#self.SaveOthers(octree, x, z)
"""
cdef SaveOthers(self, Octree *octree, int x, int z):
cdef int *buffer
cdef int bufferLen
cdef int bufferIdx
bufferLen = 4
bufferIdx = 0
buffer = <int *>malloc(sizeof(int)*bufferLen)
cdef int xx[7]
cdef int yy[7]
cdef int zz[7]
self.SaveOther(&buffer, &bufferLen, &bufferIdx, octree, xx,yy,zz, 1)
cdef:
char fnbuffer[256]
char *path = "./map/%d/%d.others"
char *path2 = "./map/%d/%d.otherslen"
stdio.FILE *fp
try:
os.mkdir("./map/%d" % z)
except:
pass
stdio.sprintf(fnbuffer, path, z, x)
if bufferIdx != 0:
fp = stdio.fopen(fnbuffer, "wb")
if fp != NULL:
stdio.fwrite(buffer, sizeof(int), bufferLen, fp)
stdio.fclose(fp)
stdio.sprintf(fnbuffer, path2, z, x)
fp = stdio.fopen(fnbuffer, "wb")
if fp != NULL:
stdio.fwrite(&bufferIdx, sizeof(int), 1, fp)
stdio.fclose(fp)
free(buffer)
"""
cdef SaveChests(self, Octree *octree, int x, int z):
cdef int *buffer
cdef int bufferLen
cdef int bufferIdx
bufferLen = 4
bufferIdx = 0
buffer = <int *>malloc(sizeof(int)*bufferLen)
cdef int xx[7]
cdef int yy[7]
cdef int zz[7]
self.SaveChest(&buffer, &bufferLen, &bufferIdx, octree, xx,yy,zz, 1)
cdef:
char fnbuffer[256]
char *path = "./map/%d/%d.chests"
char *path2 = "./map/%d/%d.chestslen"
stdio.FILE *fp
try:
os.mkdir("./map/%d" % z)
except:
pass
stdio.sprintf(fnbuffer, path, z, x)
if bufferIdx != 0:
fp = stdio.fopen(fnbuffer, "wb")
if fp != NULL:
stdio.fwrite(buffer, sizeof(int), bufferLen, fp)
stdio.fclose(fp)
stdio.sprintf(fnbuffer, path2, z, x)
fp = stdio.fopen(fnbuffer, "wb")
if fp != NULL:
stdio.fwrite(&bufferIdx, sizeof(int), 1, fp)
stdio.fclose(fp)
free(buffer)
cdef SaveTorches(self, Octree *octree, int x, int z):
cdef int *buffer
cdef int bufferLen
cdef int bufferIdx
bufferLen = 4
bufferIdx = 0
buffer = <int *>malloc(sizeof(int)*bufferLen)
cdef int xx[7]
cdef int yy[7]
cdef int zz[7]
self.SaveTorch(&buffer, &bufferLen, &bufferIdx, octree, xx,yy,zz, 1)
cdef:
char fnbuffer[256]
char *path = "./map/%d/%d.torches"
char *path2 = "./map/%d/%d.torcheslen"
stdio.FILE *fp
try:
os.mkdir("./map/%d" % z)
except:
pass
stdio.sprintf(fnbuffer, path, z, x)