⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dvdsubber-format.cpp

📁 DVD工具dvdsynth的源码
💻 CPP
字号:
/***********************************************************************
 Copyright 2002 Ben Rudiak-Gould.

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA,
 or visit <http://www.gnu.org/copyleft/gpl.html>.
***********************************************************************/


#include "DVDSubber-compile.h"
#include "DVDSubber-format.h"
#include "DVDSubber-render.h"

#include <string.h>
#include <malloc.h>


template<class T> static inline T Min(T a, T b) { return a<b?a:b; }
template<class T> static inline T Max(T a, T b) { return a<b?b:a; }


extern "C"
__declspec(dllimport)
int __stdcall WideCharToMultiByte(
	unsigned int codepage,
	unsigned long flags,
	const wchar_t* src,
	int cch,
	char* dst,
	int cb,
	const char* default_char,
	int* used_default_char);


class NullDrawable : public Drawable {
public:
	int GetAscent() const { return 0; }
	int GetHeight() const { return 0; }
	int GetWidth() const { return 0; }
	int GetOnTime() const { return 0; }
	int GetOffTime() const { return 0; }
	void DrawSelf(int time, DrawingBuf* buf, int left_times_2, int top) const {}
        unsigned* GetEventTimes(unsigned* buf, unsigned* bufend) const { return buf; }
	bool NothingToDraw(int time) const { return true; }
	char* GetPrintableText(char* buf, char* bufend) const { return buf; }
	int* GetSpaces(int, int* buf, int*) const { return buf; }
	Drawable* BreakAt(int) { return 0; }
};


class Text : public Drawable {
	wchar_t* text;
	FontInfo* font;
	unsigned char textcolor, halocolor;
	int spacing;
	int width;
	int time0, time1, time2, time3;

	unsigned GetColorAtTime(unsigned full_color, unsigned time) const;

public:
	Text(wchar_t* _text, FontInfo* _font, unsigned char _textcolor, unsigned char _halocolor, int _spacing, int _time0, int _time1, int _time2, int _time3) {
		text = _text;
		font = _font;
		textcolor = _textcolor;
		halocolor = _halocolor;
		spacing = _spacing;
		width = font->GetTextWidth(text, wcslen(text));
		time0 = _time0;
		time1 = _time1;
		time2 = _time2;
		time3 = _time3;
	}

	int GetAscent() const {
		return font->ascent + (spacing + font->external_leading);
	}
	int GetHeight() const {
		return font->height + (spacing + font->external_leading);
	}
	int GetWidth() const { return width; }
	int GetOnTime() const { return time0; }
	int GetOffTime() const { return time3; }

	void DrawSelf(int time, DrawingBuf* buf, int left_times_2, int top) const;

        unsigned* GetEventTimes(unsigned* buf, unsigned* bufend) const;

	bool NothingToDraw(int time) const { return time < time0 || time >= time3; }

	char* GetPrintableText(char* buf, char* bufend) const {
		return buf + WideCharToMultiByte(0, 0, text, -1, buf, bufend-buf, 0, 0) - 1;
	}

	int* GetSpaces(int left, int* buf, int* bufend) const;
	Drawable* BreakAt(int x);

	~Text() { free(text); }
};

// IntermediateColor(0x3E, 0, 4) -> 0x1E
// IntermediateColor(0x3E, 1, 4) -> 0x1E
// IntermediateColor(0x3E, 2, 4) -> 0x2E
// IntermediateColor(0x3E, 3, 4) -> 0x2E

static unsigned IntermediateColor(unsigned full_color, unsigned fade_pos, unsigned fade_len) {
   if (full_color == 0) return 0;
   // The rounding down is deliberate!
   return (full_color & 15) + 16 * (1 + ((full_color >> 4) - 1) * fade_pos / fade_len);
}

unsigned Text::GetColorAtTime(unsigned full_color, unsigned time) const {
   if (time < time0) {
      return 0;
   } else if (time < time1) {
      return IntermediateColor(full_color, time - time0, time1 - time0);
   } else if (time < time2) {
      return full_color;
   } else if (time < time3) {
      return IntermediateColor(full_color, time3 - time, time3 - time2);
   } else {
      return 0;
   }
}

void Text::DrawSelf(int time, DrawingBuf* buf, int left_times_2, int top) const {
   unsigned tc = GetColorAtTime(textcolor, time);
   unsigned hc = GetColorAtTime(halocolor, time);
   if (tc || hc) {
      int left = left_times_2 / 2;
      top += (spacing + font->external_leading);
      RenderText(text, font, tc, hc, buf->ptr, buf->width, buf->height, buf->xstride, buf->ystride, left, top);
      int height = font->height;
      buf->left = Max(0, Min(buf->left, left-2));
      buf->right = Min(buf->width, Max(buf->right, left+width+2));
      buf->top = Max(0, Min(buf->top, top-2));
      buf->bottom = Min(buf->height, Max(buf->bottom, top+height+2));
   }
}

unsigned* Text::GetEventTimes(unsigned* buf, unsigned* bufend) const {
   unsigned oldtc = 0, oldhc = 0;
   if (buf < bufend) {
      *buf++ = time0 * 4;
   }
   int t = time0 + 1;
   while (t < time3) {
      if (buf >= bufend) {
         break;
      }
      unsigned newtc = GetColorAtTime(textcolor, t);
      unsigned newhc = GetColorAtTime(halocolor, t);
      if (newtc != oldtc || newhc != oldhc) {
         oldtc = newtc;
         oldhc = newhc;
         *buf++ = t * 4 + 1;
      }
      if (t == time1 && time1 < time2) {
         t = time2;
      } else {
         ++t;
      }
   }
   if (buf < bufend) {
      *buf++ = time3 * 4 + 2;
   }
   return buf;
}

int* Text::GetSpaces(int left, int* buf, int* bufend) const {
	left += font->width_of_space / 2;
	for (wchar_t* p = text; *p; ++p) {
		if (*p == 32) {
			if (buf < bufend) {
				*buf++ = left + font->GetTextWidth(text, p - text);
			}
		}
	}
	return buf;
}


Drawable* Text::BreakAt(int x) {
	for (wchar_t* p = text; *p; ++p) {
		if (*p == 32) {
			int left_width = font->GetTextWidth(text, p - text);
			if (left_width <= x && x < left_width + font->width_of_space) {
				*p = 0;
				this->width = left_width;
				return new Text(p+1, font, textcolor, halocolor, spacing, time0, time1, time2, time3);
			}
		}
	}
	return 0;
}


Drawable* new_Text(wchar_t* text, FontInfo* font, unsigned char textcolor, unsigned char halocolor, int spacing, int time0, int time1, int time2, int time3) {
	return new Text(text, font, textcolor, halocolor, spacing, time0, time1, time2, time3);
}


/********************************************************************
********************************************************************/


class TextLine : public Drawable {
	Drawable *l, *r;
	int max_ascent, max_descent;
public:
	TextLine(Drawable* _l, Drawable* _r) {
		l = _l; r = _r;
		int l_ascent = l->GetAscent();
		int r_ascent = r->GetAscent();
		max_ascent = Max(l_ascent, r_ascent);
		max_descent = Max(l->GetHeight() - l_ascent, r->GetHeight() - r_ascent);
	}

	int GetAscent() const {
		return max_ascent;
	}
	int GetHeight() const {
		return max_ascent + max_descent;
	}
	int GetWidth() const {
		return l->GetWidth() + r->GetWidth();
	}
	int GetOnTime() const {
		return Min(l->GetOnTime(), r->GetOnTime());
	}
	int GetOffTime() const {
		return Max(l->GetOffTime(), r->GetOffTime());
	}

	void DrawSelf(int time, DrawingBuf* buf, int left_times_2, int top) const {
		l->DrawSelf(time, buf, left_times_2, top + max_ascent - l->GetAscent());
		left_times_2 += l->GetWidth() * 2;
		r->DrawSelf(time, buf, left_times_2, top + max_ascent - r->GetAscent());
	}

	unsigned* GetEventTimes(unsigned* buf, unsigned* bufend) const {
		buf = l->GetEventTimes(buf, bufend);
		buf = r->GetEventTimes(buf, bufend);
		return buf;
	}

	bool NothingToDraw(int time) const {
		return l->NothingToDraw(time) && r->NothingToDraw(time);
	}

	char* GetPrintableText(char* buf, char* bufend) const {
		buf = l->GetPrintableText(buf, bufend);
		buf = r->GetPrintableText(buf, bufend);
		return buf;
	}

	int* GetSpaces(int left, int* buf, int* bufend) const {
		buf = l->GetSpaces(left, buf, bufend);
		buf = r->GetSpaces(left + l->GetWidth(), buf, bufend);
                return buf;
	}
	Drawable* BreakAt(int x) {
		Drawable* mid = l->BreakAt(x);
		if (mid) {
			TextLine* result = new TextLine(mid, r);
			r = new NullDrawable;
			return result;
		} else {
			Drawable* rr = r->BreakAt(x - l->GetWidth());
			if (rr) {
				return rr;
			}
		}
		return 0;
	}
};


Drawable* new_TextLine(Drawable* l, Drawable* r) {
	return new TextLine(l,r);
}


/********************************************************************
********************************************************************/


class TextLines : public Drawable {
	Drawable *t, *b;
	int max_width;
	int align;
public:
	TextLines(Drawable* _t, Drawable* _b, int _align) {
		t = _t;
		b = _b;
		max_width = Max(t->GetWidth(), b->GetWidth());
		align = _align;
	}

	int GetAscent() const {
		return 0;
	}
	int GetHeight() const {
		return t->GetHeight() + b->GetHeight();
	}
	int GetWidth() const {
		return max_width;
	}
	int GetOnTime() const {
		return Min(t->GetOnTime(), b->GetOnTime());
	}
	int GetOffTime() const {
		return Max(t->GetOffTime(), b->GetOffTime());
	}

	void DrawSelf(int time, DrawingBuf* buf, int left_times_2, int top) const {
		t->DrawSelf(time, buf, left_times_2 + (max_width - t->GetWidth()) * (align+1), top);
		top += t->GetHeight();
		b->DrawSelf(time, buf, left_times_2 + (max_width - b->GetWidth()) * (align+1), top);
	}

	unsigned* GetEventTimes(unsigned* buf, unsigned* bufend) const {
		buf = t->GetEventTimes(buf, bufend);
		buf = b->GetEventTimes(buf, bufend);
		return buf;
	}

	bool NothingToDraw(int time) const {
		return t->NothingToDraw(time) && b->NothingToDraw(time);
	}

	char* GetPrintableText(char* buf, char* bufend) const {
		buf = t->GetPrintableText(buf, bufend);
		if (buf < bufend) *buf++ = '|';
		buf = b->GetPrintableText(buf, bufend);
		return buf;
	}

	int* GetSpaces(int left, int* buf, int* bufend) const { return buf; }
	Drawable* BreakAt(int x) { return 0; }
};


Drawable* new_TextLines(Drawable* t, Drawable* b, int align) {
	return new TextLines(t,b,align);
}


/********************************************************************
********************************************************************/


class TextBox : public Drawable {
	Drawable* lines;
	bool vertical;
	int xoffs_times_2, yoffs;

	int BestBreakPoint(int* spaces, int num_spaces, int width) {
		int best_n = -1, best_dist = width;
		for (int n=0; n < num_spaces; ++n) {
			int dist = spaces[n]*2 - width;
			if (dist < 0) dist = -dist;
			if (dist < best_dist) {
				best_dist = dist;
				best_n = n;
			}
		}
		return spaces[best_n];
	}
public:
	TextBox(Drawable* _lines, int left, int top, int right, int bottom, int linealign, int boxalign, bool _vertical) {
		lines = _lines;
		vertical = _vertical;
		int width = lines->GetWidth();
		if (width > right-left) {
			int spaces[500];
			int num_spaces = lines->GetSpaces(0, spaces, spaces + 500) - spaces;
			int bp = BestBreakPoint(spaces, num_spaces, width);
			if (bp >= 0) {
				Drawable* newline = lines->BreakAt(bp);
				if (newline) {
					lines = new TextLines(lines, newline, linealign);
					width = lines->GetWidth();
				}
			}
		}
		if (width > right-left) {
			char buf[2048];
			strcpy(buf, "box overflow: ");
			char* p = buf + strlen(buf);
			p = lines->GetPrintableText(p, buf + sizeof(buf) - 1);
			*p = 0;
			extern ICompilerCallbacks* g_compiler_callbacks;
			g_compiler_callbacks->Warning(buf);
		}
		int height = lines->GetHeight();
		xoffs_times_2 = left*2 + (right-left-width) * (boxalign%3);
		yoffs = top + (bottom-top-height) * (2 - boxalign/3) / 2;
	}

	int GetAscent() const { return 0; }
	int GetHeight() const { return 0; }
	int GetWidth() const { return 0; }
	int GetOnTime() const { return lines->GetOnTime(); }
	int GetOffTime() const { return lines->GetOffTime(); }

	void DrawSelf(int time, DrawingBuf* buf, int left_times_2, int top) const {
		// always called with left = top = 0
		if (!vertical) {
			lines->DrawSelf(time, buf, xoffs_times_2, yoffs);
		} else {
			DrawingBuf rotated_buf;
			rotated_buf.ptr = buf->ptr + (buf->width - 1) * buf->xstride;
			rotated_buf.width = buf->height;
			rotated_buf.height = buf->width;
			rotated_buf.xstride = buf->ystride;
			rotated_buf.ystride = -buf->xstride;
			rotated_buf.left = buf->top;
			rotated_buf.right = buf->bottom;
			rotated_buf.top = buf->width - buf->right;
			rotated_buf.bottom = buf->width - buf->left;
			lines->DrawSelf(time, &rotated_buf, xoffs_times_2, yoffs);
			buf->left = buf->width - rotated_buf.bottom;
			buf->right = buf->width - rotated_buf.top;
			buf->top = rotated_buf.left;
			buf->bottom = rotated_buf.right;
		}
	}

	unsigned* GetEventTimes(unsigned* buf, unsigned* bufend) const {
		return lines->GetEventTimes(buf, bufend);
	}

	bool NothingToDraw(int time) const {
		return lines->NothingToDraw(time);
	}

	char* GetPrintableText(char* buf, char* bufend) const { return buf; }

	int* GetSpaces(int left, int* buf, int* bufend) const { return buf; }
	Drawable* BreakAt(int x) { return 0; }
};


Drawable* new_TextBox(Drawable* lines, int left, int top, int right, int bottom, int linealign, int boxalign, bool vertical) {
	return new TextBox(lines, left, top, right, bottom, linealign, boxalign, vertical);
}


/********************************************************************
********************************************************************/


class TextBoxen : public Drawable {
	Drawable *a, *b;
	int min_on_time, max_off_time;
public:
	TextBoxen(Drawable* _a, Drawable* _b) {
		a = _a; b = _b;
		min_on_time = Min(a->GetOnTime(), b->GetOnTime());
		max_off_time = Max(a->GetOffTime(), b->GetOffTime());
	}

	int GetAscent() const { return 0; }
	int GetHeight() const { return 0; }
	int GetWidth() const { return 0; }
	int GetOnTime() const { return min_on_time; }
	int GetOffTime() const { return max_off_time; }

	void DrawSelf(int time, DrawingBuf* buf, int left_times_2, int top) const {
		if (time < min_on_time || time >= max_off_time)
			return;
		a->DrawSelf(time, buf, left_times_2, top);
		b->DrawSelf(time, buf, left_times_2, top);
	}

	unsigned* GetEventTimes(unsigned* buf, unsigned* bufend) const {
		buf = a->GetEventTimes(buf, bufend);
		buf = b->GetEventTimes(buf, bufend);
		return buf;
	}

	bool NothingToDraw(int time) const {
		return time < min_on_time || time >= max_off_time || (a->NothingToDraw(time) && b->NothingToDraw(time));
	}

	char* GetPrintableText(char* buf, char* bufend) const { return buf; }

	int* GetSpaces(int left, int* buf, int* bufend) const { return buf; }
	Drawable* BreakAt(int x) { return 0; }
};


Drawable* new_TextBoxen(Drawable* a, Drawable* b) {
	return new TextBoxen(a,b);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -