hqOffline.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /*
  2. Example program for small3dlib. This is an offline (non-realtime) program
  3. which creates an animation of a scene with more complex shaders. The
  4. animation is output in image files (PPM format).
  5. author: Miloslav Ciz
  6. licene: CC0 1.0
  7. */
  8. #define S3L_RESOLUTION_X 800
  9. #define S3L_RESOLUTION_Y 600
  10. #define S3L_PIXEL_FUNCTION drawPixel
  11. #define S3L_PERSPECTIVE_CORRECTION 1
  12. #define S3L_STRICT_NEAR_CULLING 0
  13. #define S3L_SORT 0
  14. #define S3L_Z_BUFFER 1
  15. #include "../small3dlib.h"
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <math.h>
  19. #include "grassTexture.h"
  20. #include "grassNormalTexture.h"
  21. #include "sandTexture.h"
  22. #include "sandNormalTexture.h"
  23. #include "treeModel.h"
  24. #include "treeTexture.h"
  25. uint8_t frameBuffer[S3L_RESOLUTION_X * S3L_RESOLUTION_Y * 3];
  26. int frame = 0;
  27. #define GRID_W 16
  28. #define GRID_H 16
  29. int8_t heightMap[GRID_W * GRID_H] =
  30. {
  31. #define e -1
  32. e,e,e,e,e,e,e,e,e,e,e,e,e,e,e,e,
  33. e,0,0,0,0,1,0,0,1,1,1,0,0,0,0,e,
  34. e,0,0,0,0,1,0,1,1,1,1,1,0,0,0,e,
  35. e,0,0,1,1,1,1,3,2,1,1,1,1,0,0,e,
  36. e,0,0,0,1,1,2,4,3,2,1,2,1,1,0,e,
  37. e,0,1,2,2,2,2,4,4,2,2,2,2,1,0,e,
  38. e,1,2,2,3,3,6,6,6,3,6,3,5,3,1,e,
  39. e,0,2,2,3,7,8,7,7,6,6,6,6,6,2,e,
  40. e,0,3,3,3,8,8,9,8,7,2,3,6,6,2,e,
  41. e,0,0,2,3,4,7,7,7,6,1,1,4,3,0,e,
  42. e,0,0,1,3,6,3,5,6,6,3,1,2,0,0,e,
  43. e,0,0,0,3,3,3,6,6,6,6,1,0,0,0,e,
  44. e,0,0,1,1,2,3,5,5,5,2,0,0,0,0,e,
  45. e,0,1,2,0,0,2,4,4,2,2,0,0,0,0,e,
  46. e,0,0,0,0,0,1,3,3,0,0,0,0,0,0,e,
  47. e,e,e,e,e,e,e,e,e,e,e,e,e,e,e,e
  48. #undef e
  49. };
  50. float interpolate(float a, float b, float t)
  51. {
  52. return a * (1.0 - t) + b * t;
  53. }
  54. // 0, 1, 2 left for trees
  55. #define ISLAND_MODEL_INDEX 3
  56. #define WATER_MODEL_INDEX 4 // must be last, for transparency
  57. #define MODELS_TOTAL (WATER_MODEL_INDEX + 1)
  58. #define GRID_TRIANGLES ((GRID_W - 1) * (GRID_H - 1) * 2)
  59. S3L_Unit terrainVertices[GRID_W * GRID_H * 3];
  60. S3L_Unit terrainNormals[GRID_W * GRID_H * 3];
  61. S3L_Unit waterVertices[GRID_W * GRID_H * 3];
  62. S3L_Unit waterNormals[GRID_W * GRID_H * 3];
  63. S3L_Index gridTriangles[GRID_TRIANGLES * 3];
  64. S3L_Unit treeNormals[TREE_VERTEX_COUNT * 3];
  65. S3L_Model3D models[MODELS_TOTAL];
  66. S3L_Scene scene;
  67. uint32_t previousTriangle = 1000;
  68. S3L_Vec4 toLightDirection;
  69. S3L_Vec4 n0, n1, n2, v0, v1, v2;
  70. S3L_Vec4 uv0, uv1, uv2;
  71. void sampleTexture(const uint8_t *texture, int w, int h, float x, float y, uint8_t color[3])
  72. {
  73. // we do linear interpolation of the samples
  74. x = fmod(x,1.0);
  75. y = fmod(y,1.0);
  76. if (x < 0)
  77. x = 1.0 + x;
  78. if (y < 0)
  79. y = 1.0 + y;
  80. x *= w;
  81. y *= h;
  82. int intX0 = x;
  83. float xFract = x - intX0;
  84. int intY0 = y;
  85. float yFract = y - intY0;
  86. int intX1 = (intX0 + 1) % w;
  87. int intY1 = (intY0 + 1) % h;
  88. int index;
  89. int maxIndex = w * h * 3 - 1;
  90. uint8_t c0[3], c1[3], c2[3], c3[3];
  91. #define getColor(n,i0,i1)\
  92. index = S3L_clamp((intY##i0 * w + intX##i1) * 3,0,maxIndex);\
  93. c##n[0] = texture[index];\
  94. c##n[1] = texture[index + 1];\
  95. c##n[2] = texture[index + 2];\
  96. getColor(0,0,0);
  97. getColor(1,0,1);
  98. getColor(2,1,0);
  99. getColor(3,1,1);
  100. #undef getColor
  101. color[0] = interpolate(interpolate(c0[0],c1[0],xFract),interpolate(c2[0],c3[0],xFract),yFract);
  102. color[1] = interpolate(interpolate(c0[1],c1[1],xFract),interpolate(c2[1],c3[1],xFract),yFract);
  103. color[2] = interpolate(interpolate(c0[2],c1[2],xFract),interpolate(c2[2],c3[2],xFract),yFract);
  104. }
  105. void drawPixel(S3L_PixelInfo *p)
  106. {
  107. int16_t color[3];
  108. float u, v;
  109. float diffuseIntensity, specularIntensity, specularPower;
  110. S3L_Unit *normals;
  111. switch (p->modelIndex)
  112. {
  113. case 0:
  114. case 1:
  115. case 2:
  116. normals = treeNormals; break;
  117. case ISLAND_MODEL_INDEX:
  118. normals = terrainNormals; break;
  119. case WATER_MODEL_INDEX:
  120. default:
  121. normals = waterNormals; break;
  122. }
  123. if (p->triangleID != previousTriangle)
  124. {
  125. S3L_getIndexedTriangleValues(
  126. p->triangleIndex,
  127. scene.models[p->modelIndex].triangles,
  128. normals,3,&n0,&n1,&n2);
  129. S3L_getIndexedTriangleValues(
  130. p->triangleIndex,
  131. scene.models[p->modelIndex].triangles,
  132. scene.models[p->modelIndex].vertices,3,&v0,&v1,&v2);
  133. if (p->modelIndex != WATER_MODEL_INDEX &&
  134. p->modelIndex != ISLAND_MODEL_INDEX)
  135. {
  136. S3L_getIndexedTriangleValues(
  137. p->triangleIndex,
  138. scene.models[p->modelIndex].triangles,
  139. treeUVs,2,&uv0,&uv1,&uv2);
  140. }
  141. previousTriangle = p->triangleID;
  142. }
  143. S3L_correctBarycentricCoords(p->barycentric);
  144. S3L_Vec4 position;
  145. S3L_Vec4 normal;
  146. S3L_Vec4 toCameraDirection;
  147. S3L_Vec4 reflected;
  148. S3L_Unit blend = 0;
  149. position.x = S3L_interpolateBarycentric(v0.x,v1.x,v2.x,p->barycentric);
  150. position.y = S3L_interpolateBarycentric(v0.y,v1.y,v2.y,p->barycentric);
  151. position.z = S3L_interpolateBarycentric(v0.z,v1.z,v2.z,p->barycentric);
  152. normal.x = S3L_interpolateBarycentric(n0.x,n1.x,n2.x,p->barycentric);
  153. normal.y = S3L_interpolateBarycentric(n0.y,n1.y,n2.y,p->barycentric);
  154. normal.z = S3L_interpolateBarycentric(n0.z,n1.z,n2.z,p->barycentric);
  155. toCameraDirection.x = scene.camera.transform.translation.x - position.x;
  156. toCameraDirection.y = scene.camera.transform.translation.y - position.y;
  157. toCameraDirection.z = scene.camera.transform.translation.z - position.z;
  158. S3L_vec3Normalize(&toCameraDirection);
  159. if (p->modelIndex == WATER_MODEL_INDEX)
  160. {
  161. diffuseIntensity = 0.6;
  162. specularIntensity = 0.8;
  163. specularPower = 40.0;
  164. float dist;
  165. // create wavy normal map for water
  166. dist = position.x + position.z + frame * 5;
  167. normal.x += S3L_sin(dist) / 8;
  168. normal.z += S3L_cos(dist) / 8;
  169. dist = position.x - 2 * position.z + frame * 10;
  170. normal.x += S3L_sin(dist) / 16;
  171. normal.z += S3L_cos(dist) / 16;
  172. }
  173. else if (p->modelIndex == ISLAND_MODEL_INDEX)
  174. {
  175. diffuseIntensity = 0.5;
  176. specularIntensity = 0.7;
  177. specularPower = 10.0;
  178. u = position.x / ((float) S3L_F * 2);
  179. v = position.z / ((float) S3L_F * 2);
  180. uint8_t textureNormal[3];
  181. uint8_t textureNormal2[3];
  182. sampleTexture(sandNormalTexture,SANDNORMAL_TEXTURE_WIDTH,SANDNORMAL_TEXTURE_HEIGHT,u,v,textureNormal);
  183. sampleTexture(grassNormalTexture,GRASSNORMAL_TEXTURE_WIDTH,GRASSNORMAL_TEXTURE_HEIGHT,u / 2,v / 2,textureNormal2);
  184. blend = S3L_clamp(position.y * 4 - S3L_F,0,S3L_F);
  185. textureNormal[0] = S3L_interpolateByUnit(textureNormal[0],textureNormal2[0],blend);
  186. textureNormal[1] = S3L_interpolateByUnit(textureNormal[1],textureNormal2[1],blend);
  187. textureNormal[2] = S3L_interpolateByUnit(textureNormal[2],textureNormal2[2],blend);
  188. normal.x += (((int16_t) textureNormal[0]) - 128);
  189. normal.z += (((int16_t) textureNormal[1]) - 128);
  190. }
  191. else // tree
  192. {
  193. diffuseIntensity = 0.6;
  194. specularIntensity = 0.2;
  195. specularPower = 20.0;
  196. u = S3L_interpolateBarycentric(uv0.x,uv1.x,uv2.x,p->barycentric) / ((float) S3L_F);
  197. v = S3L_interpolateBarycentric(uv0.y,uv1.y,uv2.y,p->barycentric) / ((float) S3L_F);
  198. }
  199. S3L_vec3Normalize(&normal);
  200. S3L_reflect(toLightDirection,normal,&reflected);
  201. float diffuse = 0.5 - (S3L_vec3Dot(toLightDirection,normal) / ((float) S3L_F)) * 0.5;
  202. float specular = 0.5 + (S3L_vec3Dot(reflected,toCameraDirection) / ((float) S3L_F)) * 0.5;
  203. float fog = (p->depth / ((float) S3L_F * 20));
  204. if (fog > 1.0)
  205. fog = 1.0;
  206. float light = 0.9 * fog + diffuseIntensity * diffuse + specularIntensity * pow(specular,specularPower);
  207. int index = (p->y * S3L_RESOLUTION_X + p->x) * 3;
  208. if (p->modelIndex == WATER_MODEL_INDEX)
  209. {
  210. S3L_Unit waterDepth = (p->previousZ - p->depth) / 2;
  211. float transparency = waterDepth / ((float) (S3L_F / 3));
  212. transparency = transparency > 1.0 ? 1.0 : transparency;
  213. if (transparency < 0.2)
  214. transparency = transparency + 1.0 - transparency / 0.2;
  215. uint8_t previousColor[3];
  216. previousColor[0] = frameBuffer[index];
  217. previousColor[1] = frameBuffer[index + 1];
  218. previousColor[2] = frameBuffer[index + 2];
  219. float fresnel = 0.5 + (S3L_vec3Dot(toCameraDirection,normal) / ((float) S3L_F)) * 0.5;
  220. color[0] = interpolate(150,0,fresnel);
  221. color[1] = interpolate(230,10,fresnel);
  222. color[2] = interpolate(255,100,fresnel);
  223. color[0] = interpolate(previousColor[0],color[0] * light,transparency);
  224. color[1] = interpolate(previousColor[1],color[1] * light,transparency);
  225. color[2] = interpolate(previousColor[2],color[2] * light,transparency);
  226. }
  227. else if (p->modelIndex == ISLAND_MODEL_INDEX)
  228. {
  229. uint8_t textureColor[3];
  230. uint8_t textureColor2[3];
  231. sampleTexture(sandTexture,SAND_TEXTURE_WIDTH,SAND_TEXTURE_HEIGHT,u,v,textureColor);
  232. sampleTexture(grassTexture,GRASS_TEXTURE_WIDTH,GRASS_TEXTURE_HEIGHT,u / 2,v / 2,textureColor2);
  233. textureColor[0] = S3L_interpolateByUnit(textureColor[0],textureColor2[0],blend);
  234. textureColor[1] = S3L_interpolateByUnit(textureColor[1],textureColor2[1],blend);
  235. textureColor[2] = S3L_interpolateByUnit(textureColor[2],textureColor2[2],blend);
  236. color[0] = textureColor[0] * light;
  237. color[1] = textureColor[1] * light;
  238. color[2] = textureColor[2] * light;
  239. }
  240. else // tree
  241. {
  242. uint8_t textureColor[3];
  243. sampleTexture(treeTexture,TREE_TEXTURE_WIDTH,TREE_TEXTURE_HEIGHT,u,v,textureColor);
  244. color[0] = textureColor[0] * light;
  245. color[1] = textureColor[1] * light;
  246. color[2] = textureColor[2] * light;
  247. }
  248. frameBuffer[index] = S3L_clamp(color[0],0,255);
  249. frameBuffer[index + 1] = S3L_clamp(color[1],0,255);
  250. frameBuffer[index + 2] = S3L_clamp(color[2],0,255);
  251. }
  252. void createGeometry()
  253. {
  254. int i = 0;
  255. for (int y = 0; y < GRID_H; ++y)
  256. for (int x = 0; x < GRID_W; ++x)
  257. {
  258. terrainVertices[i] = (x - GRID_W / 2) * S3L_F;
  259. terrainVertices[i + 1] = (heightMap[i / 3] - 1) * S3L_F / 4;
  260. terrainVertices[i + 2] = (y - GRID_H / 2) * S3L_F;
  261. waterVertices[i] = terrainVertices[i];
  262. waterVertices[i + 1] = 0;
  263. waterVertices[i + 2] = terrainVertices[i + 2];
  264. i += 3;
  265. }
  266. i = 0;
  267. for (int y = 0; y < GRID_H - 1; ++y)
  268. for (int x = 0; x < GRID_W - 1; ++x)
  269. {
  270. S3L_Index indices[4];
  271. indices[0] = y * GRID_W + x;
  272. indices[1] = indices[0] + 1;
  273. indices[2] = indices[0] + GRID_W;
  274. indices[3] = indices[2] + 1;
  275. gridTriangles[i + 0] = indices[0];
  276. gridTriangles[i + 1] = indices[1];
  277. gridTriangles[i + 2] = indices[2];
  278. gridTriangles[i + 3] = indices[2];
  279. gridTriangles[i + 4] = indices[1];
  280. gridTriangles[i + 5] = indices[3];
  281. i += 6;
  282. }
  283. }
  284. void animateWater()
  285. {
  286. for (int i = 1; i < GRID_W * GRID_H * 3; i += 3)
  287. waterVertices[i] = S3L_F / 4 + sin(frame * 0.2) * S3L_F / 4;
  288. S3L_computeModelNormals(models[WATER_MODEL_INDEX],waterNormals,0);
  289. }
  290. void clearFrameBuffer()
  291. {
  292. memset(frameBuffer,255,S3L_RESOLUTION_X * S3L_RESOLUTION_Y * 3 * sizeof(uint8_t));
  293. }
  294. void saveImage(char *fileName)
  295. {
  296. printf("saving image file: %s\n",fileName);
  297. FILE *f = fopen(fileName,"w");
  298. fprintf(f,"P3\n%d %d\n255\n",S3L_RESOLUTION_X,S3L_RESOLUTION_Y);
  299. for (int i = 0; i < S3L_RESOLUTION_X * S3L_RESOLUTION_Y * 3; i += 3)
  300. fprintf(f,"%d %d %d\n",frameBuffer[i],frameBuffer[i + 1],frameBuffer[i + 2]);
  301. fclose(f);
  302. }
  303. int main()
  304. {
  305. createGeometry();
  306. toLightDirection.x = 10;
  307. toLightDirection.y = 10;
  308. toLightDirection.z = 10;
  309. toLightDirection.w = 0;
  310. S3L_vec3Normalize(&toLightDirection);
  311. treeModelInit();
  312. models[0] = treeModel;
  313. models[1] = treeModel;
  314. models[2] = treeModel;
  315. S3L_Unit scale = S3L_F / 4;
  316. S3L_transform3DSet(0,1.2 * S3L_F,-1.5 * S3L_F,0,0,0,scale,scale,scale,&(models[0].transform));
  317. S3L_transform3DSet(0.95 * S3L_F,1.3 * S3L_F,0,0,0,0,scale,scale * 1.3,scale,&(models[1].transform));
  318. S3L_transform3DSet(-2 * S3L_F,0.8 * S3L_F,1.5 * S3L_F,0,0,0,scale,scale,scale,&(models[2].transform));
  319. S3L_model3DInit(
  320. terrainVertices,
  321. GRID_W * GRID_H,
  322. gridTriangles,
  323. GRID_TRIANGLES,
  324. &(models[ISLAND_MODEL_INDEX]));
  325. S3L_computeModelNormals(models[ISLAND_MODEL_INDEX],terrainNormals,0);
  326. S3L_computeModelNormals(treeModel,treeNormals,0);
  327. S3L_model3DInit(
  328. waterVertices,
  329. GRID_W * GRID_H,
  330. gridTriangles,
  331. GRID_TRIANGLES,
  332. &(models[WATER_MODEL_INDEX]));
  333. S3L_sceneInit(models,MODELS_TOTAL,&scene);
  334. char fileName[] = "test00.ppm";
  335. S3L_Transform3D transform0, transform1;
  336. S3L_transform3DInit(&transform0);
  337. S3L_transform3DInit(&transform1);
  338. transform0.translation.x = -2 * S3L_F;
  339. transform0.translation.y = 5 * S3L_F;
  340. transform0.translation.z = -14 * S3L_F;
  341. transform0.rotation.x = -S3L_F / 12;
  342. transform1.rotation.y = S3L_F / 8;
  343. transform1.translation.x = 5 * S3L_F;
  344. transform1.translation.y = 6 * S3L_F;
  345. transform1.translation.z = 3 * S3L_F;
  346. transform1.rotation.x = transform0.rotation.x;
  347. transform1.rotation.y = transform0.rotation.y;
  348. int frames = 100;
  349. for (int i = 0; i < frames; ++i) // render the frames
  350. {
  351. animateWater();
  352. float t = i / ((float) frames);
  353. scene.camera.transform.translation.x = interpolate(transform0.translation.x,transform1.translation.x,t);
  354. scene.camera.transform.translation.y = interpolate(transform0.translation.y,transform1.translation.y,t);
  355. scene.camera.transform.translation.z = interpolate(transform0.translation.z,transform1.translation.z,t);
  356. scene.camera.transform.rotation.x = interpolate(transform0.rotation.x,transform1.rotation.x,t);
  357. scene.camera.transform.rotation.y = interpolate(transform0.rotation.y,transform1.rotation.y,t);
  358. clearFrameBuffer();
  359. S3L_newFrame();
  360. S3L_drawScene(scene);
  361. fileName[4] = '0' + (i / 10);
  362. fileName[5] = '0' + (i % 10);
  363. saveImage(fileName);
  364. frame++;
  365. }
  366. return 0;
  367. }