sdl.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * m3dview/sdl.c
  3. *
  4. * Copyright (C) 2019 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief SDL2 interface for the simple portable Model 3D viewer
  27. * https://gitlab.com/bztsrc/model3d
  28. *
  29. */
  30. #include "viewer.h"
  31. #include <gl.h>
  32. #include <SDL.h>
  33. SDL_Window *window;
  34. int running = 1, px = 0, py = 0;
  35. #ifdef PREVIEW
  36. #include <SDL_image.h>
  37. #include <SDL2_rotozoom.h>
  38. #include <m3d.h>
  39. extern float pitch, yaw;
  40. extern m3d_t *model;
  41. /**
  42. * Save the rendered frame into a preview PNG file
  43. */
  44. void save_window(char *fn)
  45. {
  46. unsigned int i, j, k = 0, *pix = (unsigned int*)malloc(screenw * 4);
  47. unsigned long int l = 0;
  48. SDL_Surface *image = SDL_CreateRGBSurface(SDL_SWSURFACE, screenw, screenh, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
  49. SDL_Surface *scaled;
  50. if(!image) return;
  51. glReadBuffer(GL_FRONT);
  52. glReadPixels(0, 0, screenw, screenh, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
  53. if(pix) {
  54. for(i = 0; i < (unsigned int)screenh / 2; i++) {
  55. memcpy(pix, (unsigned char*)(image->pixels) + i * image->pitch, screenw * 4);
  56. memcpy((unsigned char*)(image->pixels) + i * image->pitch, (unsigned char*)(image->pixels) +
  57. (screenh - i - 1) * image->pitch, screenw * 4);
  58. memcpy((unsigned char*)(image->pixels) + (screenh - i - 1) * image->pitch, pix, screenw * 4);
  59. }
  60. free(pix);
  61. }
  62. for(i = 0; i < (unsigned int)screenh * image->pitch/4; i++)
  63. if(((unsigned int*)(image->pixels))[i] == 0xFFFFFFFF) ((unsigned int*)(image->pixels))[i] = 0;
  64. /*
  65. scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 240, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
  66. SDL_SetSurfaceBlendMode(scaled, SDL_BLENDMODE_BLEND);
  67. SDL_BlitScaled(image, NULL, scaled, NULL);
  68. */
  69. scaled = zoomSurface(image, 320.0/(double)screenw, 240.0/(double)screenh, 1);
  70. IMG_Init(IMG_INIT_PNG);
  71. IMG_SavePNG(scaled, fn);
  72. IMG_Quit();
  73. SDL_FreeSurface(image);
  74. SDL_FreeSurface(scaled);
  75. for(i = 0; i < model->numshape && k != 3; i++)
  76. for(j = 0; j < model->shape[i].numcmd && k != 3; j++)
  77. switch(model->shape[i].cmd[j].type) {
  78. case m3dc_bezu: case m3dc_nurbsu: k |= 1; break;
  79. case m3dc_bezn: case m3dc_nurbsn: k |= 2; break;
  80. case m3dc_bezun: case m3dc_nurbsun: k = 3; break;
  81. }
  82. for(i = 0; i < model->numvoxel; i++)
  83. l += model->voxel[i].w * model->voxel[i].h * model->voxel[i].d;
  84. printf("%s\n%s, %s\n%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%ld\n", model->name, model->license, model->author, model->numface,
  85. model->numface && model->face[0].texcoord[0] != -1U ? 1 : 0,
  86. model->numface && model->face[0].normal[0] != -1U && !(model->flags & M3D_FLG_GENNORM) ? 1 : 0,
  87. model->numshape, k & 1 ? 1 : 0, k & 2 ? 1 : 0, model->numvertex, model->nummaterial, model->numtexture,
  88. model->numbone, model->numaction,model->numlabel,l);
  89. }
  90. #endif
  91. /**
  92. * Set window title
  93. */
  94. void set_title(char *title)
  95. {
  96. SDL_SetWindowTitle(window, title);
  97. }
  98. /*
  99. * wrapper for Windows SDL support. This partialy came from SDL_windows_main.c
  100. */
  101. #ifdef __WIN32__
  102. #include <windows.h>
  103. static void UnEscapeQuotes(char *arg)
  104. {
  105. char *last = NULL;
  106. while (*arg) {
  107. if (*arg == '"' && (last != NULL && *last == '\\')) {
  108. char *c_curr = arg;
  109. char *c_last = last;
  110. while (*c_curr) {
  111. *c_last = *c_curr;
  112. c_last = c_curr;
  113. c_curr++;
  114. }
  115. *c_last = '\0';
  116. }
  117. last = arg;
  118. arg++;
  119. }
  120. }
  121. /* Parse a command line buffer into arguments */
  122. static int ParseCommandLine(char *cmdline, char **argv)
  123. {
  124. char *bufp;
  125. char *lastp = NULL;
  126. int argc, last_argc;
  127. argc = last_argc = 0;
  128. for (bufp = cmdline; *bufp;) {
  129. /* Skip leading whitespace */
  130. while (SDL_isspace(*bufp)) {
  131. ++bufp;
  132. }
  133. /* Skip over argument */
  134. if (*bufp == '"') {
  135. ++bufp;
  136. if (*bufp) {
  137. if (argv) {
  138. argv[argc] = bufp;
  139. }
  140. ++argc;
  141. }
  142. /* Skip over word */
  143. lastp = bufp;
  144. while (*bufp && (*bufp != '"' || *lastp == '\\')) {
  145. lastp = bufp;
  146. ++bufp;
  147. }
  148. } else {
  149. if (*bufp) {
  150. if (argv) {
  151. argv[argc] = bufp;
  152. }
  153. ++argc;
  154. }
  155. /* Skip over word */
  156. while (*bufp && !SDL_isspace(*bufp)) {
  157. ++bufp;
  158. }
  159. }
  160. if (*bufp) {
  161. if (argv) {
  162. *bufp = '\0';
  163. }
  164. ++bufp;
  165. }
  166. /* Strip out \ from \" sequences */
  167. if (argv && last_argc != argc) {
  168. UnEscapeQuotes(argv[last_argc]);
  169. }
  170. last_argc = argc;
  171. }
  172. if (argv) {
  173. argv[argc] = NULL;
  174. }
  175. return (argc);
  176. }
  177. int APIENTRY WinMain(__attribute__((unused)) HINSTANCE hInstance, __attribute__((unused)) HINSTANCE hPrevInstance,
  178. __attribute__((unused)) LPSTR lpCmdLine, __attribute__((unused)) int nCmdShow)
  179. {
  180. OPENFILENAME ofn;
  181. char *cmdline = GetCommandLine();
  182. int ret, argc = ParseCommandLine(cmdline, NULL);
  183. char **argv = SDL_stack_alloc(char*, argc+2);
  184. char fn[1024];
  185. ParseCommandLine(cmdline, argv);
  186. if(!argv[1]) {
  187. memset(&fn,0,sizeof(fn));
  188. memset(&ofn,0,sizeof(ofn));
  189. ofn.lStructSize = sizeof(ofn);
  190. ofn.hwndOwner = NULL;
  191. ofn.hInstance = hInstance;
  192. ofn.lpstrFilter = "Model Files (*.m3d, *.a3d)\0*.m3d;*.a3d\0All Files\0*\0\0";
  193. ofn.lpstrFile = fn;
  194. ofn.nMaxFile = sizeof(fn)-1;
  195. ofn.lpstrTitle = "Please Select A File To Open";
  196. ofn.Flags = OFN_FILEMUSTEXIST;
  197. if (GetOpenFileName(&ofn)) {
  198. argc++;
  199. argv[1] = fn;
  200. }
  201. }
  202. SDL_SetMainReady();
  203. ret = main(argc, argv);
  204. SDL_stack_free(argv);
  205. exit(ret);
  206. return ret;
  207. }
  208. #endif
  209. /**
  210. * Main procedure. Set up and main loop
  211. */
  212. int main(int argc, char **argv)
  213. {
  214. SDL_Event e;
  215. SDL_GLContext ctx;
  216. load(argc, argv);
  217. if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_EVENTS)) error("unable to initialize SDL");
  218. SDL_GL_LoadLibrary(NULL);
  219. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  220. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  221. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  222. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  223. SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
  224. SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
  225. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
  226. SDL_GL_SetSwapInterval(1);
  227. if(!(window = SDL_CreateWindow(wintitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screenw, screenh,
  228. SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE)))
  229. error("unable to create SDL window");
  230. ctx = SDL_GL_CreateContext(window);
  231. SDL_GL_MakeCurrent(window, ctx);
  232. #ifdef PREVIEW
  233. if(argc > 2) {
  234. pitch = -30;
  235. yaw = 30;
  236. setupgl();
  237. display(0);
  238. SDL_GL_SwapWindow(window);
  239. save_window(argv[2]);
  240. running = 0;
  241. } else
  242. #endif
  243. setupgl();
  244. while(running) {
  245. /* hadle events */
  246. if(SDL_PollEvent(&e)) {
  247. switch(e.type) {
  248. case SDL_QUIT: running = 0; break;
  249. case SDL_KEYDOWN:
  250. switch(e.key.keysym.sym) {
  251. case SDLK_q:
  252. case SDLK_ESCAPE: running = 0; break;
  253. case SDLK_UP: mousez++; break;
  254. case SDLK_DOWN: mousez--; break;
  255. case SDLK_LEFT: mousex = -10; mousey = 0; mousemove = 1; break;
  256. case SDLK_RIGHT: mousex = 10; mousey = 0; mousemove = 1;; break;
  257. case SDLK_PAGEUP: actionid--; break;
  258. case SDLK_TAB:
  259. case SDLK_PAGEDOWN: actionid++; break;
  260. case SDLK_COMMA: prevframe(); break;
  261. case SDLK_PERIOD: nextframe(); break;
  262. case SDLK_SPACE: continous(); break;
  263. case SDLK_m: domesh ^= 1; break;
  264. case SDLK_s: doskel ^= 1; break;
  265. case SDLK_0:
  266. case SDLK_1:
  267. case SDLK_2:
  268. case SDLK_3:
  269. case SDLK_4:
  270. case SDLK_5:
  271. case SDLK_6:
  272. case SDLK_7:
  273. case SDLK_8:
  274. case SDLK_9: fpsdiv(e.key.keysym.sym-SDLK_0); break;
  275. }
  276. break;
  277. case SDL_WINDOWEVENT:
  278. switch(e.window.event) {
  279. case SDL_WINDOWEVENT_CLOSE: running = 0; break;
  280. case SDL_WINDOWEVENT_RESIZED:
  281. case SDL_WINDOWEVENT_SIZE_CHANGED:
  282. screenw = e.window.data1;
  283. screenh = e.window.data2;
  284. glViewport(0, 0, screenw, screenh);
  285. break;
  286. }
  287. break;
  288. case SDL_MOUSEMOTION:
  289. mousex = e.motion.x - px;
  290. mousey = e.motion.y - py;
  291. px = e.motion.x; py = e.motion.y;
  292. mousemove = mousebtn;
  293. break;
  294. case SDL_MOUSEBUTTONDOWN:
  295. if(e.button.button == 1) mousebtn = 1;
  296. if(e.button.button == 2) zoomout();
  297. if(e.button.button == 3) zoomin();
  298. break;
  299. case SDL_MOUSEBUTTONUP:
  300. mousebtn = 0;
  301. break;
  302. case SDL_MOUSEWHEEL:
  303. if(e.wheel.y < 0) zoomout();
  304. else zoomin();
  305. break;
  306. }
  307. }
  308. /* render scene */
  309. display(SDL_GetTicks());
  310. SDL_GL_SwapWindow(window);
  311. }
  312. SDL_GL_DeleteContext(ctx);
  313. SDL_DestroyWindow(window);
  314. SDL_VideoQuit();
  315. SDL_GL_UnloadLibrary();
  316. SDL_Quit();
  317. cleanup();
  318. return 0;
  319. }