Commits

kasicass committed d4b2022

video module, done

Comments (0)

Files changed (6)

+TARGET = sdl2pal
+
+FILES = \
+	src/video.c \
+	src/util.c \
+	src/main.c
+
+CFLAGS  = -g -Wall -O2 -fno-strict-aliasing
+LDFALGS = -lm -lSDL2
+
+$(TARGET):
+	gcc $(CFLAGS) -o $(TARGET) $(FILES) $(LDFALGS)
+
+clean:
+	rm -rf $(TARGET) $(TARGET).dSYM
+
+#include "video.h"
+
+static SDL_Color colors[256] = {
+	{0, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{0, 255, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+	{255, 0, 0, 0},
+};
+
+int main(int argc, char *argv[])
+{
+	SDL_Event event;
+	SDL_Rect rect;
+	int result;
+	
+	result = SDL_Init(SDL_INIT_VIDEO);
+	assert(result == 0);
+
+	result = VIDEO_Init(640, 480, false);
+	assert(result == 0);
+
+	VIDEO_SetPalette(colors);
+
+	while (true)
+	{
+		if (SDL_PollEvent(&event))
+		{
+			if (event.type == SDL_QUIT)
+				break;
+		}
+
+		rect.x = 10;
+		rect.y = 10;
+		rect.w = 100;
+		rect.h = 100;
+		result = SDL_FillRect(VIDEO_GetScreen(), &rect, 1);
+		assert(result == 0);
+
+		VIDEO_UpdateScreen(NULL);
+	}
+
+	SDL_Quit();
+	return 0;
+}
+
+#include "util.h"
+
+/*
+	Purpose:
+		Does a varargs printf into a temp buffer, so we don't need to have
+		varargs versions of all text functions.
+
+	Parameters:
+		[IN] format - the format string.
+
+	Return value:
+		Pointer to the result string.
+*/
+char *va(const char *format, ...)
+{
+	static char string[256];
+	va_list argptr;
+
+	va_start(argptr, format);
+	vsnprintf(string, 256, format, argptr);
+	va_end(argptr);
+
+	return string;
+}
+
+void UTIL_Delay(unsigned int ms)
+{
+	unsigned int t = SDL_GetTicks() + ms;
+
+	while (SDL_PollEvent(NULL));
+
+	while (SDL_GetTicks() < t)
+	{
+		SDL_Delay(1);
+		while (SDL_PollEvent(NULL));
+	}
+}
+
+#ifndef SDL2PAL_UTIL_H
+#define SDL2PAL_UTIL_H
+
+#include "common.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+char *va(const char *format, ...);
+
+void UTIL_Delay(unsigned int ms);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
 #include "video.h"
-
+#include "util.h"
 
 static struct
 {
 	SDL_Surface *screenReal;
 	SDL_Surface *screen;
 	SDL_Surface *screenBak;
+
+	Uint32 shakeTime;
+	Uint32 shakeLevel;
 } G;
 
 /*
 		SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_SHOWN);
 	assert(G.window != NULL);
 
-	G.renderer = SDL_CreateRenderer(window, -1, 0);
+	G.renderer = SDL_CreateRenderer(G.window, -1, 0);
 	assert(G.renderer != NULL);
 
 	G.screenReal = SDL_CreateRGBSurface(0, w, h, 8, 0, 0, 0, 0);
 	G.screenBak = SDL_CreateRGBSurface(0, 320, 200, 8, 0, 0, 0, 0);
 	assert(G.screenBak != NULL);
 
-	G.screenReal
+	G.shakeTime = G.shakeLevel = 0;
+
+	SDL_SetRenderDrawColor(G.renderer, 0, 0, 0, 255);
+	SDL_RenderClear(G.renderer);
 
 	// TODO, fullscreen
 
 
 	SDL_DestroyWindow(G.window);
 	G.window = NULL;
+
+	G.shakeTime = G.shakeLevel = 0;
+}
+
+/*
+	Purpose:
+		Update the screen surface to vga card.
+
+	Parameters:
+		[IN] surface - surface to render
+		[IN] rect - rect area to render, render the whole surface if it's NULL
+
+	Return value:
+		None.
+*/
+static void VIDEO_Present()
+{
+	SDL_Texture *texture;
+
+	texture = SDL_CreateTextureFromSurface(G.renderer, G.screenReal);
+	assert(texture != NULL);
+
+	SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
+	SDL_RenderCopy(G.renderer, texture, NULL, NULL);
+
+	SDL_DestroyTexture(texture);
+
+	SDL_RenderPresent(G.renderer);
 }
 
 /*
 	Return value:
 		None.
 */
-void VIDEO_UpdateScreen(const SDL_Rect *rect)
+void VIDEO_UpdateScreen(SDL_Rect *rect)
 {
 	SDL_Rect srcrect, dstrect;
 	Uint16 offset           = 240 - 200;
-	Uint16 screenRealHeight = G.window->h - offset;
-	Uint16 scrrenRealY      = offset / 2;
+	Uint16 screenRealHeight = G.screenReal->h - offset;
+	Uint16 screenRealY      = offset / 2;
 
 	if (rect != NULL)
 	{
+		dstrect.x = rect->x * G.screenReal->w / G.screen->w;
+		dstrect.y = (screenRealY + rect->y) * screenRealHeight / G.screen->h;
+		dstrect.w = rect->w * G.screenReal->w / G.screen->w;
+		dstrect.h = rect->h * screenRealHeight / G.screen->h;
+
+		SDL_SoftStretch(G.screen, rect, G.screenReal, &dstrect);
+		VIDEO_Present();
+	}
+	else if (G.shakeTime != 0)
+	{
+		srcrect.x = 0;
+		srcrect.y = 0;
+		srcrect.w = 320;
+		srcrect.h = 200 - G.shakeLevel;
+
+		dstrect.x = 0;
+		dstrect.y = screenRealY;
+		dstrect.w = 320 * G.screenReal->w / G.screen->w;
+		dstrect.h = (200 - G.shakeLevel) * screenRealHeight / G.screen->h;
+
+		if (G.shakeTime & 1)
+		{
+			srcrect.y = G.shakeLevel;
+		}
+		else
+		{
+			dstrect.y = (screenRealY + G.shakeLevel) * screenRealHeight / G.screen->h;
+		}
+
+		SDL_SoftStretch(G.screen, &srcrect, G.screenReal, &dstrect);
+
+		if (G.shakeTime & 1)
+		{
+			dstrect.y = (screenRealY + screenRealHeight - G.shakeLevel) * screenRealHeight / G.screen->h;
+		}
+		else
+		{
+			dstrect.y = screenRealY;
+		}
+
+		dstrect.h = G.shakeLevel * screenRealHeight / G.screen->h;
+		SDL_FillRect(G.screenReal, &dstrect, 0);
+
+		VIDEO_Present();
+		G.shakeTime--;
+	}
+	else
+	{
+		dstrect.x = 0;
+		dstrect.y = screenRealY;
+		dstrect.w = G.screenReal->w;
+		dstrect.h = screenRealHeight;
+
+		SDL_SoftStretch(G.screen, NULL, G.screenReal, &dstrect);
+		//SDL_FillRect(G.screenReal, &dstrect, 0xff0000);
+		VIDEO_Present();
 	}
 }
 
+/*
+	Purpose:
+		Set the palette of the screen.
 
-void VIDEO_SetPalette(SDL_Color palette[256]);
-SDL_Color *VIDEO_GetPalette(void);
+	Parameters:
+		[IN] palette - array of 256 colors.
 
-void VIDEO_Resize(Uint32 w, Uint32 h);
-void VIDEO_ToggleFullscreen(void);
-void VIDEO_SaveScreenshot(void);
-void VIDEO_BackupScreen(void);
-void VIDEO_RestoreScreen(void);
-void VIDEO_ShakeScreen(Uint16 shakeTime, Uint16 shakeLevel);
-void VIDEO_SwitchScreen(Uint16 speed);
-void VIDEO_FadeScreen(Uint16 speed);
+	Return value:
+		None.
+*/
+void VIDEO_SetPalette(SDL_Color colors[256])
+{
+	SDL_Palette *palette = SDL_AllocPalette(256);
+	assert(palette != NULL);
+
+	SDL_SetPaletteColors(palette, colors, 0, 256);
+	SDL_SetSurfacePalette(G.screenReal, palette);
+
+	SDL_FreePalette(palette);
+}
+
+/*
+	Purpose:
+		Get the current palette of the screen.
+
+	Parameters:
+		None.
+
+	Return value:
+		Pointer to the current palette.
+*/
+SDL_Color *VIDEO_GetPalette(void)
+{
+	return G.screenReal->format->palette->colors;
+}
+
+/*
+	Purpose:
+		This function is called when user resized the window.
+
+	Parameters:
+		[IN] w - width of the window after resizing.
+		[IN] h - height of the window after resizing.
+
+	Return value:
+		None.
+*/
+void VIDEO_Resize(Uint32 w, Uint32 h)
+{
+	// TODO
+}
+
+/*
+	Purpose:
+		Toggle fullscreen mode.
+
+	Parameters:
+		None.
+
+	Return value:
+		None.
+*/
+void VIDEO_ToggleFullscreen(void)
+{
+	// TODO
+}
+
+/*
+	Purpose:
+		Save the screenshot of current screen to a BMP file.
+
+	Parameters:
+		None.
+
+	Return value:
+		None.
+*/
+void VIDEO_SaveScreenshot(void)
+{
+	int i;
+	FILE *fp;
+	const char *file;
+
+	for (i = 0; i <= 9999; i++)
+	{
+		file = va("./scrn%.4d.bmp", i);
+		fp = fopen(file, "rb");
+		if (fp == NULL)
+		{
+			fclose(fp);
+			break;
+		}
+		fclose(fp);
+	}
+
+	if (i > 9999)
+		return;
+
+	SDL_SaveBMP(G.screenReal, file);
+}
+
+/*
+	Purpose:
+		Backup the screen buffer.
+
+	Parameters:
+		None.
+
+	Return value:
+		None.
+*/
+void VIDEO_BackupScreen(void)
+{
+	SDL_BlitSurface(G.screen, NULL, G.screenBak, NULL);
+}
+
+/*
+	Purpose:
+		Restore the screen buffer which has been saved with VIDEO_BackupScreen().
+
+	Parameters:
+		None.
+
+	Return value:
+		None.
+*/
+void VIDEO_RestoreScreen(void)
+{
+	SDL_BlitSurface(G.screenBak, NULL, G.screen, NULL);
+}
+
+/*
+	Purpose:
+		Set the screen shake time and level.
+
+	Parameters:
+		[IN] shakeTime  - how many times should we shake the screen.
+		[IN] shakeLevel - level of shaking.
+
+	Return value:
+		None.
+*/
+void VIDEO_ShakeScreen(Uint16 shakeTime, Uint16 shakeLevel)
+{
+	G.shakeTime  = shakeTime;
+	G.shakeLevel = shakeLevel;
+}
+
+/*
+	Purpose:
+		Swtich the screen from the backup screen buffer to the current screen buffer.
+		NOTE: This will destroy the backup buffer.
+
+	Parameters:
+		[IN] speed - speed of fading (the larger value, the slower).
+
+	Return value:
+		None.
+*/
+void VIDEO_SwitchScreen(Uint16 speed)
+{
+	int i, j;
+	const int rgIndex[6] = {0, 3, 1, 5, 2, 4};
+	SDL_Rect dstrect;
+
+	Uint16 offset           = 240 - 200;
+	Uint16 screenRealHeight = G.screenReal->h - offset;
+	Uint16 screenRealY      = offset / 2;
+
+	speed++;
+	speed *= 10;
+
+	for (i = 0; i < 6; i++)
+	{
+		for (j = rgIndex[i]; j < G.screen->pitch*G.screen->h; j += 6)
+		{
+			((unsigned char*)(G.screenBak->pixels))[j] = ((unsigned char*)(G.screen->pixels))[j];
+		}
+
+		// draw the backup buffer to the screen
+		dstrect.x = 0;
+		dstrect.y = screenRealY;
+		dstrect.w = G.screenReal->w;
+		dstrect.h = screenRealHeight;
+
+		SDL_SoftStretch(G.screenBak, NULL, G.screenReal, &dstrect);
+		VIDEO_Present();
+
+		UTIL_Delay(speed);
+	}
+}
+
+/*
+	Purpose:
+		Fade the screen from the backup screen buffer to the current screen buffer.
+		NOTE: This will destroy the backup buffer.
+
+	Parameters:
+		[IN] speed - speed of fading (the larger value, the slower).
+
+	Return value:
+		None.
+*/
+void VIDEO_FadeScreen(Uint16 speed)
+{
+	// TODO
+}
+
+/*
+	Purpose:
+		Return the screen surface for drawing.
+
+	Parameters:
+		None.
+
+	Return value:
+		the screen surface.
+*/
+SDL_Surface *VIDEO_GetScreen(void)
+{
+	return G.screen;
+}
+
 int VIDEO_Init(Uint32 w, Uint32 h, bool fullscreen);
 void VIDEO_Shutdown(void);
 
-void VIDEO_UpdateScreen(const SDL_Rect *rect);
+SDL_Surface *VIDEO_GetScreen(void);
+
+void VIDEO_UpdateScreen(SDL_Rect *rect);
 void VIDEO_SetPalette(SDL_Color palette[256]);
 SDL_Color *VIDEO_GetPalette(void);