Blocks.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /******************************************************************************/
  2. struct BlocksOcclusion // helper class used for Blocks Ambient Occlusion calculation
  3. {
  4. enum COMBINE_MODE : Byte // Combine Mode
  5. {
  6. ADD,
  7. MAX,
  8. };
  9. // get
  10. Int steps ()C {return _steps [0];} // get number of steps set during creation
  11. Int steps1 ()C {return _steps [1];} // get number of steps set during creation
  12. Flt strength ()C {return _strength[0];} // get occlusion strength set during creation
  13. Flt strength1()C {return _strength[1];} // get occlusion strength set during creation
  14. Bool angles ()C {return _angles ;}
  15. Int maxSteps ()C {return Max(_steps[0], _steps[1]);} // get max number of steps
  16. COMBINE_MODE aoCombineMode()C {return _aocm;} // get dual ambient occlusion combine mode
  17. // manage
  18. void create(Int steps=2, Flt strength=1.0f, Int steps_1=0, Flt strength_1=0.0f, COMBINE_MODE ao_combine_mode=ADD, Bool angles=false); // 'steps'=number of block steps used during occlusion calculation, bigger number will increase the quality however it will also reduce performance, 'strength'=occlusion strength 0..1 (0=no occlusion, 1=full occlusion), use 'steps_1 and strength_1 ao_combine_mode' for a secondary ambient occlusion effect (dual ambient occlusion), 'angles'=if include angle between light and surface normal when computing occlusion
  19. // operations, each of these methods recreate the entire 'BlocksOcclusion' by calling 'create', with just one parameter changed
  20. BlocksOcclusion& steps (Int steps );
  21. BlocksOcclusion& steps1 (Int steps );
  22. BlocksOcclusion& strength (Flt strength);
  23. BlocksOcclusion& strength1 (Flt strength);
  24. BlocksOcclusion& aoCombineMode(COMBINE_MODE aocm );
  25. BlocksOcclusion& angles (Bool on );
  26. BlocksOcclusion();
  27. #if !EE_PRIVATE
  28. private:
  29. #endif
  30. struct Node
  31. {
  32. Byte dir;
  33. VecI pos;
  34. UInt fraction_axis[4];
  35. Flt fraction [2];
  36. Memc<Node> nodes;
  37. #if EE_PRIVATE
  38. Node& init(C VecI &pos);
  39. #endif
  40. };
  41. Bool _angles;
  42. COMBINE_MODE _aocm;
  43. Int _steps [2];
  44. Flt _strength[2];
  45. Memc<Node> _nodes;
  46. };
  47. /******************************************************************************/
  48. struct Blocks
  49. {
  50. struct Light
  51. {
  52. Ball ball; // world space range and position (not 'Blocks' local position)
  53. Vec color; // light color (0, 0, 0) .. (1, 1, 1)
  54. Light& set(C Ball &ball, C Vec &color=1) {T.ball=ball; T.color=color; return T;}
  55. };
  56. // manage
  57. Blocks& del ( ); // delete manually
  58. Blocks& create(Int resolution, Int sub_division=1); // create Blocks capable of storing 'resolution' number of blocks in X Z dimensions, Y dimension will have no limit, 'sub_division'=sub division for mesh faces, 1..Inf
  59. // get / set
  60. Bool is ()C {return _levels.elms()>0;} // if has any data
  61. Int resolution ()C {return _resolution ;} // get resolution used at Blocks creation
  62. Int subDivision()C {return _sub_division ;} Blocks& subDivision(Int steps); // get/set mesh sub division, changing the 'subDivision' does not automatically rebuild the mesh, you should call 'setMesh' afterwards
  63. Bool hasBlock(C VecI &pos )C; // if there is a block at 'pos' local coordinates
  64. MaterialPtr material(C VecI &pos )C; // get block material at 'pos' local coordinates (this will return the 'top' material of the block)
  65. void get (C VecI &pos, MaterialPtr &top, MaterialPtr &side, MaterialPtr &bottom)C; // get all block materials at 'pos' local coordinates
  66. #if EE_PRIVATE
  67. Bool hasBlock(C VecI &pos, Int min_level_i)C;
  68. Bool set(Int x, Int y, Int z, Byte b);
  69. #endif
  70. Bool set(Int x, Int y, Int z, C MaterialPtr &material ); // set block to 'material' , true is returned if any change was made during this operation, this does not automatically rebuild the mesh or the physical body, after calling this method you should call 'setMesh' and 'setPhysBody'
  71. Bool set(Int x, Int y, Int z, C MaterialPtr &top, C MaterialPtr &side, C MaterialPtr &bottom); // set block material to 'top side bottom', true is returned if any change was made during this operation, this does not automatically rebuild the mesh or the physical body, after calling this method you should call 'setMesh' and 'setPhysBody'
  72. // mesh
  73. Blocks& setMesh(Flt tex_scale, C BlocksOcclusion *occl=null, C BoxI *local_box=null, C VecI2 &blocks_pos=0, C BlocksMap *map=null, C MemPtr<Light> &lights=null, Bool optimize=false, Flt max_face_length=-1); // set Blocks mesh, 'tex_scale'=texture coordinates scale, 'occl'=Blocks occlusion object used for ambient occlusion calculation (use null for no AO), 'local_box'=if specified then the mesh will only be updated in specified local coordinates (use null for setting entire mesh), 'blocks_pos'=position of this Blocks object inside the 'BlocksMap' (based on this position neighbors will be obtained from the map), 'map'=map of all Blocks objects (you should pass a pointer to your custom class that extends from 'BlocksMap' to provide custom 'findBlocks' method which will be used for finding neighbors to this Blocks object), 'lights'=array of world space lights, 'optimize'=if automatically optimize the mesh by welding coplanar faces which will result in faster rendering ('max_face_length'=max allowed face length, -1=no limit)
  74. void setShader() {_mesh.setShader();} // reset mesh shader
  75. // physics
  76. Blocks& setPhysBody(C Matrix &matrix, C BoxI *local_box=null, Bool create_actor=false); // set Blocks physical body, 'matrix'=matrix of this 'Blocks' object, 'local_box'=if specified then the physical body will only be updated in specified local coordinates (use null for setting entire physical body), 'create_actor'=if automatically re-create the actor after updating the physical body
  77. Blocks& delActor(); // delete blocks actor
  78. Blocks& createActor(); // create blocks actor from the physical body ('setPhysBody' should be called earlier)
  79. // operations
  80. Bool raycast(C Vec &start, C Vec &move, Vec *hit_pos=null, Vec *hit_normal=null, C Matrix *matrix=null)C; // raycast from 'start' local position along 'move' vector, returns true if collision occurred and sets 'hit_pos' to its position and 'hit_normal' to its normal vector, 'matrix'=matrix of this 'Blocks' object
  81. // clean
  82. Blocks& cleanLevels (); // clean Blocks from unused Y levels
  83. Blocks& cleanMaterials(); // clean Blocks from unused materials
  84. // draw
  85. void draw (C MatrixM &matrix)C {if(Frustum(_mesh, matrix))_mesh.draw (matrix);} // 'matrix'=matrix of this 'Blocks' object
  86. void drawShadow(C MatrixM &matrix)C {if(Frustum(_mesh, matrix))_mesh.drawShadow(matrix);} // 'matrix'=matrix of this 'Blocks' object
  87. // io
  88. Bool save(File &f, Bool include_mesh_and_phys_body, CChar *path=null)C; // save to file, 'include_mesh_and_phys_body' if include mesh and physical body in the file, when enabled you don't need to build the mesh and physical body after load, 'path'=path at which resource is located (this is needed so that the sub-resources can be accessed with relative path), false on fail
  89. Bool load(File &f , CChar *path=null) ; // load from file , 'path'=path at which resource is located (this is needed so that the sub-resources can be accessed with relative path), false on fail
  90. #if EE_PRIVATE
  91. Bool cleanMtrlCombos(Bool is[256], Byte remap[256]);
  92. void zero();
  93. #endif
  94. Blocks();
  95. #if !EE_PRIVATE
  96. private:
  97. #endif
  98. struct Level
  99. {
  100. Int y;
  101. Byte *_map;
  102. PhysPart phys;
  103. Actor actor;
  104. #if EE_PRIVATE
  105. void init(Int resolution ) {AllocZero(Free(_map), resolution*resolution);}
  106. void init(Int resolution, Int y) {T.y=y; init(resolution);}
  107. Byte& map(Int x, Int z, Int resolution) {return _map[x+z*resolution];}
  108. Byte map(Int x, Int z, Int resolution)C {return ConstCast(T).map(x, z, resolution);}
  109. Bool wallX (Int x, Int z, Int res )C {return (InRange(x-1, res) ? map(x-1, z , res)!=0 : false) != (InRange(x, res) ? map(x, z, res)!=0 : false);}
  110. Bool wallZ (Int x, Int z, Int res )C {return (InRange(z-1, res) ? map(x , z-1, res)!=0 : false) != (InRange(z, res) ? map(x, z, res)!=0 : false);}
  111. Bool wallBack (Int x, Int z, Int res )C {return map(x, z, res) && (InRange(z-1, res) ? ! map(x, z-1, res) : true);}
  112. Bool wallForward(Int x, Int z, Int res )C {return map(x, z, res) && (InRange(z+1, res) ? ! map(x, z+1, res) : true);}
  113. Bool wallLeft (Int x, Int z, Int res )C {return map(x, z, res) && (InRange(x-1, res) ? ! map(x-1, z, res) : true);}
  114. Bool wallRight (Int x, Int z, Int res )C {return map(x, z, res) && (InRange(x+1, res) ? ! map(x+1, z, res) : true);}
  115. Bool wallBottom (Int x, Int z, Int res, C Level *down)C {return map(x, z, res) && (down ? !down->map(x , z, res) : true);}
  116. Bool wallTop (Int x, Int z, Int res, C Level *up )C {return map(x, z, res) && (up ? !up ->map(x , z, res) : true);}
  117. void createPhysBody(C Matrix &matrix, Int res, C Level *down, C Level *up);
  118. void createActor ( ) {actor.create(phys, 0);}
  119. Bool save(File &f, Int resolution, Bool include_mesh_and_phys_body)C;
  120. Bool load(File &f, Int resolution, Bool include_mesh_and_phys_body) ;
  121. #endif
  122. void del();
  123. ~Level() {del();}
  124. Level() {y=0; _map=null;}
  125. NO_COPY_CONSTRUCTOR(Level);
  126. };
  127. struct MtrlCombo
  128. {
  129. Byte top, side, bottom; // material indexes in '_materials'
  130. #if EE_PRIVATE
  131. MtrlCombo& set(Byte top, Byte side, Byte bottom) {T.top=top; T.side=side; T.bottom=bottom; return T;}
  132. #endif
  133. };
  134. Int _resolution, _sub_division;
  135. MaterialPalette _materials;
  136. Memc<MtrlCombo> _mtrl_combos;
  137. Memc<Level> _levels;
  138. Mesh _mesh;
  139. #if EE_PRIVATE
  140. struct LightEx : Light
  141. {
  142. Vec world_pos;
  143. };
  144. struct Neighbors
  145. {
  146. C Blocks *l, *r, *b, *f, *lb, *lf, *rb, *rf;
  147. void clear();
  148. void set (C Blocks *l, C Blocks *r, C Blocks *b, C Blocks *f, C Blocks *lb, C Blocks *lf, C Blocks *rb, C Blocks *rf, Int resolution);
  149. Neighbors(C Blocks *l, C Blocks *r, C Blocks *b, C Blocks *f, C Blocks *lb, C Blocks *lf, C Blocks *rb, C Blocks *rf, Int resolution);
  150. Neighbors(C BlocksMap *map, Int x, Int y, Int resolution);
  151. };
  152. struct LevelBrightness // precalculated brightness of a blocks level
  153. {
  154. struct Point
  155. {
  156. Color brightness[6]; // brightness of each direction , DIR_ENUM
  157. Byte computed_dir ; // if brightness of direction is computed, DIR_FLAG
  158. Int computed_y ; // y coordinates of the computed brightness
  159. void clear() {computed_dir=0;}
  160. };
  161. Int size, min_level_i;
  162. Memt<Point> points;
  163. C Blocks &blocks;
  164. C Neighbors &neighbors;
  165. C BlocksOcclusion *occl;
  166. C BlocksMap *map;
  167. C VecI2 &blocks_pos;
  168. C MemtN<LightEx, 256> &lights;
  169. LevelBrightness(C Blocks &blocks, C Neighbors &neighbors, C BlocksOcclusion *occl, C BlocksMap *map, C VecI2 &blocks_pos, C MemtN<LightEx, 256> &lights);
  170. // operations
  171. void clear();
  172. void clear(Int min_x, Int min_z, Int max_x, Int max_z);
  173. LevelBrightness& setLevelI(Int level_i);
  174. // get
  175. Point& point (Int x, Int z) {return points[x+z*size];}
  176. C Color& brightness(Int x, Int y, Int z, DIR_ENUM dir);
  177. };
  178. struct Part
  179. {
  180. struct Vtx
  181. {
  182. Vec pos;
  183. Vec2 tex;
  184. Color col;
  185. void set(C Vec &pos, C Vec2 &tex, C Color &col) {T.pos=pos; T.tex=tex; T.col=col;}
  186. };
  187. Memc<Vtx > vtxs ;
  188. Memc<VecI4> quads;
  189. Bool is()C {return vtxs.elms()!=0;}
  190. void create(MeshBase &base);
  191. };
  192. static Int CompareLevel(C Level &level, C Int &y) {return Compare(level.y, y);}
  193. Int findLevelI(Int y )C;
  194. Level* findLevel (Int y, Int from);
  195. C Level* findLevel (Int y, Int from)C {return ConstCast(T).findLevel(y, from);}
  196. Level* findLevel (Int y );
  197. C Level* findLevel (Int y )C {return ConstCast(T).findLevel(y);}
  198. Level* toLevel (Int y, Int &last);
  199. C Level* toLevel (Int y, Int &last)C {return ConstCast(T).toLevel(y, last);}
  200. Level& getLevel (Int y );
  201. UInt occlusion(C BlocksOcclusion::Node &node, C VecI &pos, AXIS_TYPE axis, Int min_level_i, C Neighbors &neighbors)C;
  202. Byte brightness(C BlocksOcclusion *occl, Int x, Int y, Int z, AXIS_TYPE axis, UInt dir_flag, Int min_level_i, C Neighbors &neighbors)C;
  203. void buildLevel(Flt tex_scale, MemPtrN<Part, 256> parts, Int min_x, Int min_z, Int max_x, Int max_z, Int level_i, C Neighbors &neighbors, LevelBrightness (&lb)[2]);
  204. #endif
  205. };
  206. /******************************************************************************/
  207. struct BlocksMap // extend this class to provide your own 'findBlocks' method
  208. {
  209. // manage
  210. void create(Int resolution, C Matrix &base_matrix); // 'resolution'=resolution of all 'Blocks' in this map, 'base_matrix'=transformation matrix of Blocks at (0, 0) coordinates
  211. // get
  212. Int resolution()C {return _resolution ;} // get resolution
  213. Matrix baseMatrix()C {return _base_matrix;} // get base matrix
  214. Matrix matrix (Int x, Int y)C; // get transformation matrix of 'Blocks' at (x, y) coordinates, it will be calculated based on 'resolution' and 'base_matrix'
  215. // operations
  216. Bool raycast(C Vec &start, C Vec &move, Vec *hit_pos=null, Vec *hit_normal=null)C; // raycast from 'start' local position along 'move' vector, returns true if collision occurred and sets 'hit_pos' to its position and 'hit_normal' to its normal vector
  217. Vec light(C Vec &pos, C BlocksOcclusion *occl=null, C MemPtr<Blocks::Light> &lights=null)C; // calculate light at 'pos' position, 'lights'=lights present in the scene
  218. // custom
  219. virtual Blocks* findBlocks(Int x, Int y)C {return null;} // override this method and return pointer to 'Blocks' at specified location
  220. BlocksMap();
  221. private:
  222. Int _resolution;
  223. Matrix _base_matrix;
  224. };
  225. /******************************************************************************/