Thu, 02 Dec 2010 23:30:13 +0000
add video emulation
src/main.c | file | annotate | diff | revisions |
1.1 --- a/src/main.c Thu Dec 02 23:03:13 2010 +0000 1.2 +++ b/src/main.c Thu Dec 02 23:30:13 2010 +0000 1.3 @@ -19,6 +19,99 @@ 1.4 exit(EXIT_FAILURE); 1.5 } 1.6 1.7 +/** 1.8 + * @brief Set the pixel at (x, y) to the given value 1.9 + * @note The surface must be locked before calling this! 1.10 + * @param surface SDL surface upon which to draw 1.11 + * @param x X co-ordinate 1.12 + * @param y Y co-ordinate 1.13 + * @param pixel Pixel value (from SDL_MapRGB) 1.14 + */ 1.15 +void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) 1.16 +{ 1.17 + int bpp = surface->format->BytesPerPixel; 1.18 + /* Here p is the address to the pixel we want to set */ 1.19 + Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; 1.20 + 1.21 + switch (bpp) { 1.22 + case 1: 1.23 + *p = pixel; 1.24 + break; 1.25 + 1.26 + case 2: 1.27 + *(Uint16 *)p = pixel; 1.28 + break; 1.29 + 1.30 + case 3: 1.31 + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { 1.32 + p[0] = (pixel >> 16) & 0xff; 1.33 + p[1] = (pixel >> 8) & 0xff; 1.34 + p[2] = pixel & 0xff; 1.35 + } 1.36 + else { 1.37 + p[0] = pixel & 0xff; 1.38 + p[1] = (pixel >> 8) & 0xff; 1.39 + p[2] = (pixel >> 16) & 0xff; 1.40 + } 1.41 + break; 1.42 + 1.43 + case 4: 1.44 + *(Uint32 *)p = pixel; 1.45 + break; 1.46 + 1.47 + default: 1.48 + break; /* shouldn't happen, but avoids warnings */ 1.49 + } // switch 1.50 +} 1.51 + 1.52 + 1.53 +/** 1.54 + * @brief Refresh the screen. 1.55 + * @param surface SDL surface upon which to draw. 1.56 + */ 1.57 +void refreshScreen(SDL_Surface *s) 1.58 +{ 1.59 + // Lock the screen surface (if necessary) 1.60 + if (SDL_MUSTLOCK(s)) { 1.61 + if (SDL_LockSurface(s) < 0) { 1.62 + fprintf(stderr, "ERROR: Unable to lock screen!\n"); 1.63 + exit(EXIT_FAILURE); 1.64 + } 1.65 + } 1.66 + 1.67 + // Map the foreground and background colours 1.68 + Uint32 fg = SDL_MapRGB(s->format, 0, 255, 0); // green foreground 1.69 + Uint32 bg = SDL_MapRGB(s->format, 0, 0, 0); // black background 1.70 + 1.71 + // Refresh the 3B1 screen area first. TODO: only do this if VRAM has actually changed! 1.72 + uint32_t vram_address = 0; 1.73 + for (int y=0; y<348; y++) { 1.74 + for (int x=0; x<720; x+=16) { // 720 pixels, monochrome, packed into 16bit words 1.75 + // Get the pixel 1.76 + uint16_t val = RD16(state.vram, vram_address, sizeof(state.vram)-1); 1.77 + vram_address += 2; 1.78 + // Now copy it to the video buffer 1.79 + for (int px=0; px<16; px++) { 1.80 + if (val & 1) 1.81 + putpixel(s, x+px, y, fg); 1.82 + else 1.83 + putpixel(s, x+px, y, bg); 1.84 + } 1.85 + } 1.86 + } 1.87 + 1.88 + // TODO: blit LEDs and status info 1.89 + 1.90 + // Unlock the screen surface 1.91 + if (SDL_MUSTLOCK(s)) { 1.92 + SDL_UnlockSurface(s); 1.93 + } 1.94 + 1.95 + // Trigger a refresh -- TODO: partial refresh depending on whether we 1.96 + // refreshed the screen area, status area, both, or none. Use SDL_UpdateRect() for this. 1.97 + SDL_Flip(s); 1.98 +} 1.99 + 1.100 /**************************** 1.101 * blessed be thy main()... 1.102 ****************************/ 1.103 @@ -80,7 +173,8 @@ 1.104 1.105 // Is it time to run the 60Hz periodic interrupt yet? 1.106 if (clock_cycles > CLOCKS_PER_60HZ) { 1.107 - // TODO: refresh screen 1.108 + // Refresh the screen 1.109 + refreshScreen(screen); 1.110 // TODO: trigger periodic interrupt (if enabled) 1.111 // decrement clock cycle counter, we've handled the intr. 1.112 clock_cycles -= CLOCKS_PER_60HZ;