xdraw.c (5888B)
1 #include <math.h> 2 #include <stdio.h> 3 4 #include <sys/ipc.h> 5 #include <sys/shm.h> 6 7 #include <xcb/xcb.h> 8 #include <xcb/shm.h> 9 #include <xcb/xcb_image.h> 10 11 #include "xdraw.h" 12 #include "common.h" 13 14 extern uint8_t running; 15 16 //window vars 17 uint8_t WindowResize = 0; 18 uint16_t WWidth = XREZ; 19 uint16_t WHeight = YREZ; 20 uint16_t RWidth = XREZ; 21 uint16_t RHeight = YREZ; 22 23 //xcb vars 24 xcb_connection_t *c; 25 xcb_screen_t *screen; 26 xcb_drawable_t win; 27 xcb_gcontext_t gc; 28 xcb_colormap_t colormap; 29 30 //shm vars 31 xcb_shm_segment_info_t shinfo; 32 uint32_t* bb; 33 xcb_pixmap_t bbpix; 34 35 36 //the color palette buffer 37 xcb_alloc_color_reply_t *colors[256]; 38 39 //for detecting when the window's closed 40 xcb_intern_atom_reply_t *delete_reply; 41 42 void InitWindow() 43 { 44 if (!XREZ || !YREZ) 45 { 46 running = 0; 47 } 48 49 c = xcb_connect (NULL, NULL); 50 51 screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; 52 53 //create window 54 win = xcb_generate_id(c); 55 uint32_t mask = XCB_CW_BACK_PIXEL | 56 XCB_CW_EVENT_MASK; 57 uint32_t winvals[2]; 58 winvals[0] = screen->black_pixel; 59 winvals[1] = XCB_EVENT_MASK_EXPOSURE | 60 XCB_EVENT_MASK_KEY_PRESS | 61 XCB_EVENT_MASK_STRUCTURE_NOTIFY | 62 XCB_EVENT_MASK_POINTER_MOTION | 63 XCB_EVENT_MASK_BUTTON_MOTION | 64 XCB_EVENT_MASK_BUTTON_2_MOTION; 65 xcb_create_window ( c, 66 XCB_COPY_FROM_PARENT, 67 win, 68 screen->root, 69 0, 0, 70 150, 150, 71 10, 72 XCB_WINDOW_CLASS_INPUT_OUTPUT, 73 screen->root_visual, 74 mask, winvals ); 75 gc = xcb_generate_id(c); 76 77 //create graphics context 78 mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; 79 uint32_t gcvals[2]; 80 gcvals[0] = screen->white_pixel; 81 gcvals[1] = 0; 82 xcb_create_gc ( c, 83 gc, 84 win, 85 mask, 86 gcvals ); 87 88 colormap = screen->default_colormap; 89 90 for (int i = 0; i < 256; i++) 91 { 92 colors[i] = NULL; 93 } 94 95 //set up to detect when the window is closed 96 xcb_intern_atom_cookie_t protocol_cookie = 97 xcb_intern_atom(c, 1, 12, "WM_PROTOCOLS"); 98 xcb_intern_atom_reply_t *protocol_reply = 99 xcb_intern_atom_reply(c, protocol_cookie, 0); 100 xcb_intern_atom_cookie_t delete_cookie = 101 xcb_intern_atom(c, 0, 16, "WM_DELETE_WINDOW"); 102 delete_reply = xcb_intern_atom_reply( c, delete_cookie, 0); 103 xcb_change_property ( c, 104 XCB_PROP_MODE_REPLACE, 105 win, 106 (*protocol_reply).atom, 107 4, 32, 1, 108 &(*delete_reply).atom ); 109 free(protocol_reply); 110 111 112 xcb_map_window(c, win); 113 114 //Shm stuff 115 xcb_shm_query_version_reply_t* shreply; 116 117 shreply = xcb_shm_query_version_reply( c, 118 xcb_shm_query_version(c), 119 NULL ); 120 121 if(!shreply || !shreply->shared_pixmaps) 122 { 123 printf("Shm error\n"); 124 running = 0; 125 } 126 127 shinfo.shmid = shmget( IPC_PRIVATE, 128 1920*1080*4, //todo: change to screen size 129 IPC_CREAT | 0600 ); 130 shinfo.shmaddr = shmat(shinfo.shmid, 0, 0); 131 shinfo.shmseg = xcb_generate_id(c); 132 xcb_shm_attach(c, shinfo.shmseg, shinfo.shmid, 0); 133 shmctl(shinfo.shmid, IPC_RMID, 0); 134 bb = (uint32_t*)shinfo.shmaddr; 135 136 137 bbpix = xcb_generate_id(c); 138 xcb_shm_create_pixmap ( c, bbpix, win, 139 1920, 1080, 140 screen->root_depth, 141 shinfo.shmseg, 0 ); 142 xcb_flush(c); 143 } 144 145 void LoadPalette(uint32_t *pal) 146 { 147 for (int i = 0; i < 256; ++i) 148 { 149 if (colors[i]) 150 { 151 free(colors[i]); 152 } 153 uint32_t col = *(pal + i); 154 int blue = (col & 0xff) * 257; 155 int green = ((col >> 8) & 0xff) * 257; 156 int red = ((col >> 16) & 0xff) * 257; 157 xcb_alloc_color_cookie_t coogie = xcb_alloc_color ( c, 158 colormap, 159 red, 160 green, 161 blue ); 162 colors[i] = xcb_alloc_color_reply(c, coogie, NULL); 163 } 164 } 165 166 //Update the width and height of the actual drawing area 167 void UpdateRScreen() 168 { 169 //preserve aspect ratio 170 float ratio; 171 172 ratio = (float)XREZ / (float)YREZ; 173 174 if ((WWidth) > (WHeight * ratio)) 175 { 176 RHeight = WHeight; 177 RWidth = (uint16_t)(RHeight * ratio); 178 } 179 else 180 { 181 RWidth = WWidth; 182 RHeight = (uint16_t)(RWidth / ratio); 183 } 184 } 185 186 void DrawPixel(uint16_t x, uint16_t y, uint8_t color) 187 { 188 if (color) 189 { 190 bb[y * 1920 + x] = colors[color]->pixel; 191 } 192 } 193 194 //Draw to the screen 195 void DrawBuffer(uint8_t* buf) 196 { 197 UpdateRScreen(); 198 199 double xratio = XREZ / (double)RWidth; 200 double yratio = YREZ / (double)RHeight; 201 double px, py; 202 for (int i = 0; i < RHeight; i++) 203 { 204 for (int j = 0; j < RWidth; j++) 205 { 206 uint8_t color; 207 px = floor(j * xratio); 208 py = floor(i * yratio); 209 color = *(buf + (uint32_t)((py * XREZ) + px)); 210 //draw to backbuffer 211 DrawPixel(j, i, color); 212 } 213 } 214 xcb_copy_area ( c, bbpix, win, gc, 215 0, 0, 0, 0, 216 RWidth, RHeight ); 217 xcb_flush(c); 218 } 219 220 void HandleEvents() 221 { 222 xcb_generic_event_t *e; 223 xcb_configure_notify_event_t *confevent; 224 xcb_motion_notify_event_t *motionevent; 225 WindowResize = 0; 226 e = xcb_poll_for_event(c); 227 if (e) 228 { 229 switch(e->response_type & ~0x80) 230 { 231 //close 232 case XCB_CLIENT_MESSAGE: 233 if ((*(xcb_client_message_event_t*)e).data.data32[0] 234 == (*delete_reply).atom) 235 { 236 running = 0; 237 free(delete_reply); 238 } 239 break; 240 //TODO: Pause rendering while the window is resizing? 241 case XCB_CONFIGURE_NOTIFY: 242 confevent = (xcb_configure_notify_event_t*)e; 243 if ( ( (confevent->width > 0) && 244 (WWidth != confevent->width) ) || 245 ( (confevent->height > 0) && 246 (WHeight != confevent->height) ) ) 247 { 248 WindowResize = 1; 249 WWidth = confevent->width; 250 WHeight = confevent->height; 251 } 252 break; 253 case XCB_MOTION_NOTIFY: 254 motionevent = (xcb_motion_notify_event_t*)e; 255 uint32_t x, y; 256 x = (uint32_t)motionevent->event_x; 257 y = (uint32_t)motionevent->event_y; 258 UpdateCursor(x, y); 259 if ( motionevent->state & XCB_BUTTON_MASK_2 ) 260 { 261 Mouse2Pressed(); 262 } 263 break; 264 } 265 } 266 free(e); 267 268 } 269 270 void Cleanup() 271 { 272 for (int i = 0; i < 256; ++i) 273 { 274 free(colors[i]); 275 } 276 xcb_shm_detach(c, shinfo.shmseg); 277 shmdt(shinfo.shmaddr); 278 279 xcb_free_pixmap(c, bbpix); 280 281 xcb_destroy_window(c, win); 282 xcb_disconnect(c); 283 }